Files
AX-Copilot-Codex/.decompiledproj/AxCopilot/Handlers/DiffHandler.cs

225 lines
8.8 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using AxCopilot.SDK;
using AxCopilot.Services;
using Microsoft.Win32;
namespace AxCopilot.Handlers;
public class DiffHandler : IActionHandler
{
private record DiffResult(string Text, int Added, int Removed, int Same);
private readonly ClipboardHistoryService? _clipHistory;
public string? Prefix => "diff";
public PluginMetadata Metadata => new PluginMetadata("Diff", "텍스트/파일 비교 — diff", "1.0", "AX");
public DiffHandler(ClipboardHistoryService? clipHistory = null)
{
_clipHistory = clipHistory;
}
public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
{
string text = query.Trim();
if (!string.IsNullOrWhiteSpace(text))
{
string[] array = text.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (array.Length == 2 && File.Exists(array[0]) && File.Exists(array[1]))
{
try
{
string textA = File.ReadAllText(array[0]);
string textB = File.ReadAllText(array[1]);
DiffResult diffResult = BuildDiff(textA, textB, Path.GetFileName(array[0]), Path.GetFileName(array[1]));
return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("파일 비교: " + Path.GetFileName(array[0]) + " ↔ " + Path.GetFileName(array[1]), $"{diffResult.Added}줄 추가, {diffResult.Removed}줄 삭제, {diffResult.Same}줄 동일 · Enter로 결과 복사", null, diffResult.Text, null, "\ue8a5")));
}
catch (Exception ex)
{
return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("파일 읽기 실패: " + ex.Message, "", null, null, null, "\uea39")));
}
}
if (array.Length >= 1 && (File.Exists(array[0]) || Directory.Exists(Path.GetDirectoryName(array[0]) ?? "")))
{
return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("비교할 파일 2개의 경로를 입력하세요", "예: diff C:\\a.txt C:\\b.txt", null, null, null, "\ue946")));
}
}
IReadOnlyList<ClipboardEntry> readOnlyList = _clipHistory?.History;
if (readOnlyList == null || readOnlyList.Count < 2)
{
return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("비교할 텍스트가 부족합니다", "클립보드에 2개 이상의 텍스트를 복사하거나, diff [파일A] [파일B]로 파일 비교", null, null, null, "\ue946")));
}
List<ClipboardEntry> list = readOnlyList.Where((ClipboardEntry e) => e.IsText).Take(2).ToList();
if (list.Count < 2)
{
return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("텍스트 히스토리가 2개 미만입니다", "텍스트를 2번 이상 복사하세요", null, null, null, "\ue946")));
}
ClipboardEntry clipboardEntry = list[1];
ClipboardEntry clipboardEntry2 = list[0];
DiffResult diffResult2 = BuildDiff(clipboardEntry.Text, clipboardEntry2.Text, "이전 (" + clipboardEntry.RelativeTime + ")", "최근 (" + clipboardEntry2.RelativeTime + ")");
List<LauncherItem> list2 = new List<LauncherItem>
{
new LauncherItem($"클립보드 비교: +{diffResult2.Added} -{diffResult2.Removed} ={diffResult2.Same}", "이전 복사 ↔ 최근 복사 · Enter로 결과 복사", null, diffResult2.Text, null, "\ue81c")
};
IEnumerable<string> enumerable = (from l in diffResult2.Text.Split('\n')
where l.StartsWith("+ ") || l.StartsWith("- ")
select l).Take(5);
foreach (string item in enumerable)
{
string symbol = (item.StartsWith("+ ") ? "\ue710" : "\ue711");
list2.Add(new LauncherItem(item, "", null, null, null, symbol));
}
list2.Add(new LauncherItem("파일 선택하여 비교", "파일 선택 대화 상자에서 2개의 파일을 골라 비교합니다", null, "__FILE_DIALOG__", null, "\ue8a5"));
return Task.FromResult((IEnumerable<LauncherItem>)list2);
}
public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)
{
object data = item.Data;
if (data is string s && s == "__FILE_DIALOG__")
{
await Task.Delay(200, ct);
Application current = Application.Current;
if (current == null)
{
return;
}
((DispatcherObject)current).Dispatcher.Invoke((Action)delegate
{
OpenFileDialog openFileDialog = new OpenFileDialog
{
Title = "비교할 첫 번째 파일 선택",
Filter = "텍스트 파일|*.txt;*.cs;*.json;*.xml;*.md;*.csv;*.log|모든 파일|*.*"
};
if (openFileDialog.ShowDialog() == true)
{
string fileName = openFileDialog.FileName;
openFileDialog.Title = "비교할 두 번째 파일 선택";
if (openFileDialog.ShowDialog() == true)
{
string fileName2 = openFileDialog.FileName;
try
{
string textA = File.ReadAllText(fileName);
string textB = File.ReadAllText(fileName2);
DiffResult diffResult = BuildDiff(textA, textB, Path.GetFileName(fileName), Path.GetFileName(fileName2));
Clipboard.SetText(diffResult.Text);
NotificationService.Notify("파일 비교 완료", $"+{diffResult.Added} -{diffResult.Removed} ={diffResult.Same} · 결과 클립보드 복사됨");
}
catch (Exception ex)
{
NotificationService.Notify("비교 실패", ex.Message);
}
}
}
});
return;
}
data = item.Data;
string text = data as string;
if (text == null || string.IsNullOrWhiteSpace(text))
{
return;
}
try
{
Application current2 = Application.Current;
if (current2 != null)
{
((DispatcherObject)current2).Dispatcher.Invoke((Action)delegate
{
Clipboard.SetText(text);
});
}
}
catch
{
}
NotificationService.Notify("비교 결과", "클립보드에 복사되었습니다");
}
private static DiffResult BuildDiff(string textA, string textB, string labelA, string labelB)
{
string[] array = (from l in textA.Split('\n')
select l.TrimEnd('\r')).ToArray();
string[] array2 = (from l in textB.Split('\n')
select l.TrimEnd('\r')).ToArray();
HashSet<string> hashSet = new HashSet<string>(array);
HashSet<string> hashSet2 = new HashSet<string>(array2);
StringBuilder stringBuilder = new StringBuilder();
StringBuilder stringBuilder2 = stringBuilder;
StringBuilder stringBuilder3 = stringBuilder2;
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(4, 1, stringBuilder2);
handler.AppendLiteral("--- ");
handler.AppendFormatted(labelA);
stringBuilder3.AppendLine(ref handler);
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder4 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(4, 1, stringBuilder2);
handler.AppendLiteral("+++ ");
handler.AppendFormatted(labelB);
stringBuilder4.AppendLine(ref handler);
stringBuilder.AppendLine();
int num = 0;
int num2 = 0;
int num3 = 0;
int num4 = Math.Max(array.Length, array2.Length);
for (int num5 = 0; num5 < num4; num5++)
{
string text = ((num5 < array.Length) ? array[num5] : null);
string text2 = ((num5 < array2.Length) ? array2[num5] : null);
if (text == text2)
{
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder5 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(2, 1, stringBuilder2);
handler.AppendLiteral(" ");
handler.AppendFormatted(text);
stringBuilder5.AppendLine(ref handler);
num3++;
continue;
}
if (text != null && !hashSet2.Contains(text))
{
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder6 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(2, 1, stringBuilder2);
handler.AppendLiteral("- ");
handler.AppendFormatted(text);
stringBuilder6.AppendLine(ref handler);
num2++;
}
if (text2 != null && !hashSet.Contains(text2))
{
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder7 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(2, 1, stringBuilder2);
handler.AppendLiteral("+ ");
handler.AppendFormatted(text2);
stringBuilder7.AppendLine(ref handler);
num++;
}
if (text != null && hashSet2.Contains(text) && text != text2)
{
stringBuilder2 = stringBuilder;
StringBuilder stringBuilder8 = stringBuilder2;
handler = new StringBuilder.AppendInterpolatedStringHandler(2, 1, stringBuilder2);
handler.AppendLiteral(" ");
handler.AppendFormatted(text);
stringBuilder8.AppendLine(ref handler);
num3++;
}
}
return new DiffResult(stringBuilder.ToString(), num, num2, num3);
}
}