using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using AxCopilot.SDK; using AxCopilot.Services; namespace AxCopilot.Core; public class CommandResolver { private readonly FuzzyEngine _fuzzy; private readonly SettingsService _settings; private readonly Dictionary _handlers = new Dictionary(); private readonly List _fuzzyHandlers = new List(); public IReadOnlyDictionary RegisteredHandlers => _handlers; public CommandResolver(FuzzyEngine fuzzy, SettingsService settings) { _fuzzy = fuzzy; _settings = settings; } public void RegisterHandler(IActionHandler handler) { if (handler.Prefix == null) { _fuzzyHandlers.Add(handler); LogService.Info("FuzzyHandler 등록: name='" + handler.Metadata.Name + "'"); return; } if (_handlers.ContainsKey(handler.Prefix)) { LogService.Warn($"Prefix '{handler.Prefix}' 중복 등록: '{handler.Metadata.Name}'이 기존 핸들러를 덮어씁니다."); } _handlers[handler.Prefix] = handler; LogService.Info($"Handler 등록: prefix='{handler.Prefix}', name='{handler.Metadata.Name}'"); } public async Task> ResolveAsync(string input, CancellationToken ct) { if (string.IsNullOrWhiteSpace(input)) { return Enumerable.Empty(); } foreach (var (prefix, handler) in _handlers) { if (input.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { object obj; if (input.Length <= prefix.Length) { obj = ""; } else { string text2 = input; int length = prefix.Length; obj = text2.Substring(length, text2.Length - length).Trim(); } string query = (string)obj; try { return await handler.GetItemsAsync(query, ct); } catch (OperationCanceledException) { throw; } catch (Exception ex2) { LogService.Error("Handler '" + handler.Metadata.Name + "' 오류: " + ex2.Message); return new _003C_003Ez__ReadOnlySingleElementList(new LauncherItem("오류: " + ex2.Message, handler.Metadata.Name, null, null)); } } } int maxResults = _settings.Settings.Launcher.MaxResults; HashSet seenPaths = new HashSet(StringComparer.OrdinalIgnoreCase); List fuzzyItems = UsageRankingService.SortByUsage((from r in _fuzzy.Search(input, maxResults * 2) where seenPaths.Add(r.Entry.Path) select r).Take(maxResults).Select(delegate(FuzzyResult r) { string displayName = r.Entry.DisplayName; string subtitle; if (r.Entry.Type == IndexEntryType.Alias) { string aliasType = r.Entry.AliasType; if (1 == 0) { } string text3 = ((aliasType == "url") ? "URL 단축키" : ((!(aliasType == "batch")) ? r.Entry.Path : "명령 단축키")); if (1 == 0) { } subtitle = text3; } else { subtitle = r.Entry.Path + " ⇧ Shift+Enter: 폴더 열기"; } object entry = r.Entry; IndexEntryType type = r.Entry.Type; if (1 == 0) { } string symbol; switch (type) { case IndexEntryType.App: symbol = "\uecaa"; break; case IndexEntryType.Folder: symbol = "\ue8b7"; break; case IndexEntryType.Alias: { string aliasType2 = r.Entry.AliasType; if (1 == 0) { } string text3 = ((aliasType2 == "url") ? "\ue774" : ((!(aliasType2 == "batch")) ? "\uecca" : "\ue756")); if (1 == 0) { } symbol = text3; break; } default: symbol = "\ue8a5"; break; } if (1 == 0) { } return new LauncherItem(displayName, subtitle, null, entry, null, symbol); }), (LauncherItem item) => (item.Data as IndexEntry)?.Path).ToList(); if (_fuzzyHandlers.Count > 0) { List>> extraTasks = _fuzzyHandlers.Select((IActionHandler h) => SafeGetItemsAsync(h, input, ct)).ToList(); await Task.WhenAll(extraTasks); foreach (Task> task in extraTasks) { if (task.IsCompletedSuccessfully) { fuzzyItems.AddRange(task.Result.Take(3)); } } } return fuzzyItems; } public async Task ExecuteAsync(LauncherItem item, string lastInput, CancellationToken ct) { foreach (var (prefix, handler) in _handlers) { if (lastInput.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { object obj; if (lastInput.Length <= prefix.Length) { obj = ""; } else { int length = prefix.Length; obj = lastInput.Substring(length, lastInput.Length - length).Trim().Split(' ')[0]; } string q = (string)obj; string cmdKey = (string.IsNullOrEmpty(q) ? prefix : (prefix + q)); UsageStatisticsService.RecordCommandUsage(cmdKey); await handler.ExecuteAsync(item, ct); return; } } object data = item.Data; if (data is string urlData && urlData.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { await ExecuteNullPrefixAsync(item, ct); return; } data = item.Data; IndexEntry entry = data as IndexEntry; if (entry == null) { return; } string expanded = Environment.ExpandEnvironmentVariables(entry.Path); try { await Task.Run(() => Process.Start(new ProcessStartInfo(expanded) { UseShellExecute = true })); } catch (Exception ex) { Exception ex2 = ex; LogService.Error("실행 실패: " + expanded + " - " + ex2.Message); } Task.Run(delegate { UsageRankingService.RecordExecution(entry.Path); }); } public async Task ExecuteNullPrefixAsync(LauncherItem item, CancellationToken ct) { foreach (IActionHandler handler in _fuzzyHandlers) { try { await handler.ExecuteAsync(item, ct); return; } catch (OperationCanceledException) { throw; } catch (Exception ex2) { LogService.Error("FuzzyHandler '" + handler.Metadata.Name + "' 실행 오류: " + ex2.Message); } } } private static async Task> SafeGetItemsAsync(IActionHandler handler, string query, CancellationToken ct) { try { return await handler.GetItemsAsync(query, ct); } catch (OperationCanceledException) { throw; } catch (Exception ex2) { Exception ex3 = ex2; LogService.Error("FuzzyHandler '" + handler.Metadata.Name + "' 오류: " + ex3.Message); return Enumerable.Empty(); } } }