Files
AX-Copilot-Codex/src/AxCopilot/Handlers/JsonHandler.cs

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;
}
}