225 lines
8.8 KiB
C#
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);
|
|
}
|
|
}
|