using System.Diagnostics;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Windows;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;
namespace AxCopilot.Handlers;
///
/// 즐겨찾기(파일/폴더/경로) 핸들러. "fav" 프리픽스로 사용합니다.
/// 자주 사용하는 로컬 파일·폴더 경로를 등록하고 빠르게 실행합니다.
/// 예: fav → 전체 즐겨찾기 목록
/// fav 보고서 → "보고서" 포함 항목 필터
/// fav add 보고서 C:\work\report.xlsx → 즐겨찾기 추가
/// fav del 보고서 → 즐겨찾기 삭제
/// Enter → 파일/폴더 열기.
///
public class FavoriteHandler : IActionHandler
{
public string? Prefix => "fav";
public PluginMetadata Metadata => new(
"Favorite",
"즐겨찾기 관리 — fav",
"1.0",
"AX");
private static readonly string FavFile = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"AxCopilot", "favorites.json");
private static readonly JsonSerializerOptions JsonOpts = new()
{
WriteIndented = true,
PropertyNameCaseInsensitive = true
};
private List _cache = new();
private bool _loaded;
public Task> GetItemsAsync(string query, CancellationToken ct)
{
EnsureLoaded();
var q = query.Trim();
// add 명령
if (q.StartsWith("add ", StringComparison.OrdinalIgnoreCase))
{
var rest = q[4..].Trim();
var spaceIdx = rest.IndexOf(' ');
if (spaceIdx > 0)
{
var name = rest[..spaceIdx].Trim();
var path = rest[(spaceIdx + 1)..].Trim();
return Task.FromResult>(
[
new LauncherItem(
$"즐겨찾기 추가: {name}",
$"경로: {path} · Enter로 추가",
null, ValueTuple.Create("__ADD__", name, path),
Symbol: Symbols.Save)
]);
}
return Task.FromResult>(
[
new LauncherItem(
"사용법: fav add [이름] [경로]",
"예: fav add 보고서 C:\\work\\report.xlsx",
null, null, Symbol: Symbols.Info)
]);
}
// del 명령
if (q.StartsWith("del ", StringComparison.OrdinalIgnoreCase))
{
var name = q[4..].Trim();
var found = _cache.FirstOrDefault(b =>
b.Name.Contains(name, StringComparison.OrdinalIgnoreCase));
if (found != null)
{
return Task.FromResult>(
[
new LauncherItem(
$"즐겨찾기 삭제: {found.Name}",
$"경로: {found.Path} · Enter로 삭제",
null, ValueTuple.Create("__DEL__", found.Name),
Symbol: Symbols.Delete)
]);
}
return Task.FromResult>(
[
new LauncherItem($"'{name}'에 해당하는 즐겨찾기 없음", "fav으로 전체 목록 확인",
null, null, Symbol: Symbols.Warning)
]);
}
// 목록/검색
var filtered = string.IsNullOrWhiteSpace(q)
? _cache
: _cache.Where(b =>
b.Name.Contains(q, StringComparison.OrdinalIgnoreCase) ||
b.Path.Contains(q, StringComparison.OrdinalIgnoreCase)).ToList();
if (!filtered.Any())
{
return Task.FromResult>(
[
new LauncherItem(
_cache.Count == 0 ? "즐겨찾기가 없습니다" : $"'{q}'에 해당하는 즐겨찾기 없음",
"fav add [이름] [경로]로 추가하세요",
null, null, Symbol: Symbols.Info)
]);
}
var items = filtered.Select(b =>
{
var isDir = Directory.Exists(b.Path);
var isFile = File.Exists(b.Path);
var symbol = isDir ? Symbols.Folder : isFile ? Symbols.File : Symbols.Warning;
var hint = isDir ? "폴더 열기" : isFile ? "파일 열기" : "경로를 찾을 수 없음";
return new LauncherItem(b.Name, $"{b.Path} · {hint}", null, b.Path, Symbol: symbol);
}).ToList();
return Task.FromResult>(items);
}
public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
{
if (item.Data is ValueTuple add && add.Item1 == "__ADD__")
{
AddFav(add.Item2, add.Item3);
NotificationService.Notify("AX Copilot", $"즐겨찾기 추가: {add.Item2}");
return Task.CompletedTask;
}
if (item.Data is ValueTuple del && del.Item1 == "__DEL__")
{
RemoveFav(del.Item2);
NotificationService.Notify("AX Copilot", $"즐겨찾기 삭제: {del.Item2}");
return Task.CompletedTask;
}
if (item.Data is string path)
{
if (Directory.Exists(path) || File.Exists(path))
{
try { Process.Start(new ProcessStartInfo(path) { UseShellExecute = true }); }
catch (Exception ex) { LogService.Warn($"즐겨찾기 열기 실패: {ex.Message}"); }
}
else
{
try { Application.Current?.Dispatcher.Invoke(() => Clipboard.SetText(path)); }
catch (Exception) { }
}
}
return Task.CompletedTask;
}
private void EnsureLoaded()
{
if (_loaded) return;
_loaded = true;
try
{
if (!File.Exists(FavFile)) return;
_cache = JsonSerializer.Deserialize>(File.ReadAllText(FavFile), JsonOpts) ?? new();
}
catch (Exception ex) { LogService.Warn($"즐겨찾기 로드 실패: {ex.Message}"); }
}
private void AddFav(string name, string path)
{
EnsureLoaded();
_cache.RemoveAll(b => b.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
_cache.Insert(0, new FavEntry { Name = name, Path = path });
Save();
}
private void RemoveFav(string name)
{
EnsureLoaded();
_cache.RemoveAll(b => b.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
Save();
}
private void Save()
{
try
{
Directory.CreateDirectory(Path.GetDirectoryName(FavFile)!);
File.WriteAllText(FavFile, JsonSerializer.Serialize(_cache, JsonOpts));
}
catch (Exception ex) { LogService.Warn($"즐겨찾기 저장 실패: {ex.Message}"); }
}
private class FavEntry
{
[JsonPropertyName("name")] public string Name { get; set; } = "";
[JsonPropertyName("path")] public string Path { get; set; } = "";
}
}