133 lines
5.0 KiB
C#
133 lines
5.0 KiB
C#
using System.Text.Json;
|
|
using System.Windows;
|
|
using AxCopilot.SDK;
|
|
using AxCopilot.Themes;
|
|
|
|
namespace AxCopilot.Handlers;
|
|
|
|
/// <summary>
|
|
/// JSON 검증/포맷 핸들러. "json" 프리픽스로 사용합니다.
|
|
/// 예: json → 클립보드의 JSON을 파싱하여 미리보기 표시
|
|
/// json {"a":1} → 인라인 JSON 파싱 + 미리보기
|
|
/// json minify → 클립보드 JSON 미니파이 → 클립보드 복사
|
|
/// json format → 클립보드 JSON 예쁘게 포맷 → 클립보드 복사
|
|
/// </summary>
|
|
public class JsonHandler : IActionHandler
|
|
{
|
|
public string? Prefix => "json";
|
|
|
|
public PluginMetadata Metadata => new(
|
|
"JsonFormatter",
|
|
"JSON 검증/포맷 — json 뒤에 내용 또는 명령 입력",
|
|
"1.0",
|
|
"AX");
|
|
|
|
private static readonly JsonSerializerOptions _prettyOpts = new() { WriteIndented = true };
|
|
private static readonly JsonSerializerOptions _compactOpts = new() { WriteIndented = false };
|
|
|
|
public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
|
|
{
|
|
var q = query.Trim();
|
|
|
|
// ─── 빈 쿼리 or format/minify: 클립보드에서 JSON 읽기 ─────────────────
|
|
if (string.IsNullOrWhiteSpace(q) || q.Equals("format", StringComparison.OrdinalIgnoreCase)
|
|
|| q.Equals("minify", StringComparison.OrdinalIgnoreCase)
|
|
|| q.Equals("min", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
string clipText = "";
|
|
try { clipText = Clipboard.GetText(); } catch { }
|
|
|
|
if (string.IsNullOrWhiteSpace(clipText))
|
|
return Task.FromResult<IEnumerable<LauncherItem>>(
|
|
[
|
|
new LauncherItem(
|
|
"클립보드가 비어 있습니다",
|
|
"클립보드에 JSON 텍스트를 복사한 뒤 실행하세요",
|
|
null, null, Symbol: Symbols.Clipboard)
|
|
]);
|
|
|
|
return Task.FromResult(BuildItems(clipText,
|
|
isMinify: q.StartsWith("min", StringComparison.OrdinalIgnoreCase)));
|
|
}
|
|
|
|
// ─── 인라인 JSON ──────────────────────────────────────────────────────
|
|
return Task.FromResult(BuildItems(q, isMinify: false));
|
|
}
|
|
|
|
private static IEnumerable<LauncherItem> BuildItems(string input, bool isMinify)
|
|
{
|
|
try
|
|
{
|
|
using var doc = JsonDocument.Parse(input, new JsonDocumentOptions
|
|
{
|
|
AllowTrailingCommas = true,
|
|
CommentHandling = JsonCommentHandling.Skip
|
|
});
|
|
|
|
// 포맷된 버전
|
|
var pretty = JsonSerializer.Serialize(doc.RootElement, _prettyOpts);
|
|
var compact = JsonSerializer.Serialize(doc.RootElement, _compactOpts);
|
|
|
|
// 루트 타입 정보
|
|
var rootType = doc.RootElement.ValueKind switch
|
|
{
|
|
JsonValueKind.Object => $"Object ({doc.RootElement.EnumerateObject().Count()}개 키)",
|
|
JsonValueKind.Array => $"Array ({doc.RootElement.GetArrayLength()}개 항목)",
|
|
_ => doc.RootElement.ValueKind.ToString()
|
|
};
|
|
|
|
var targetText = isMinify ? compact : pretty;
|
|
var actionLabel = isMinify ? "미니파이" : "포맷";
|
|
|
|
// 미리보기 (처음 100자)
|
|
var preview = compact.Length > 100 ? compact[..97] + "…" : compact;
|
|
|
|
return
|
|
[
|
|
new LauncherItem(
|
|
$"✅ 유효한 JSON — {rootType}",
|
|
$"{preview} · Enter로 {actionLabel} 결과 클립보드 복사",
|
|
null,
|
|
targetText,
|
|
Symbol: Symbols.JsonValid),
|
|
|
|
new LauncherItem(
|
|
"포맷 (Pretty Print) 복사",
|
|
$"{pretty.Length}자 · 들여쓰기 2스페이스",
|
|
null,
|
|
pretty,
|
|
Symbol: Symbols.JsonFormat),
|
|
|
|
new LauncherItem(
|
|
"미니파이 (Minify) 복사",
|
|
$"{compact.Length}자 · 공백 제거",
|
|
null,
|
|
compact,
|
|
Symbol: Symbols.JsonMinify),
|
|
];
|
|
}
|
|
catch (JsonException ex)
|
|
{
|
|
var msg = ex.Message.Length > 100 ? ex.Message[..97] + "…" : ex.Message;
|
|
return
|
|
[
|
|
new LauncherItem(
|
|
"❌ JSON 오류",
|
|
msg,
|
|
null,
|
|
null,
|
|
Symbol: Symbols.Error)
|
|
];
|
|
}
|
|
}
|
|
|
|
public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
|
|
{
|
|
if (item.Data is string text)
|
|
{
|
|
try { Clipboard.SetText(text); } catch { }
|
|
}
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|