250 lines
6.3 KiB
C#
250 lines
6.3 KiB
C#
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<string, IActionHandler> _handlers = new Dictionary<string, IActionHandler>();
|
|
|
|
private readonly List<IActionHandler> _fuzzyHandlers = new List<IActionHandler>();
|
|
|
|
public IReadOnlyDictionary<string, IActionHandler> 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<IEnumerable<LauncherItem>> ResolveAsync(string input, CancellationToken ct)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(input))
|
|
{
|
|
return Enumerable.Empty<LauncherItem>();
|
|
}
|
|
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<LauncherItem>(new LauncherItem("오류: " + ex2.Message, handler.Metadata.Name, null, null));
|
|
}
|
|
}
|
|
}
|
|
int maxResults = _settings.Settings.Launcher.MaxResults;
|
|
HashSet<string> seenPaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
List<LauncherItem> 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<Task<IEnumerable<LauncherItem>>> extraTasks = _fuzzyHandlers.Select((IActionHandler h) => SafeGetItemsAsync(h, input, ct)).ToList();
|
|
await Task.WhenAll(extraTasks);
|
|
foreach (Task<IEnumerable<LauncherItem>> 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<IEnumerable<LauncherItem>> 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<LauncherItem>();
|
|
}
|
|
}
|
|
}
|