using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Markup; using System.Windows.Media; using AxCopilot.Core; namespace AxCopilot.Views; public class CommandPaletteWindow : Window, IComponentConnector { private record CommandEntry(string Label, string Category, string Icon, string CommandId); private readonly Action? _onExecute; private readonly List _commands = new List(); internal TextBox SearchBox; internal StackPanel ResultPanel; private bool _contentLoaded; public string? SelectedCommand { get; private set; } public CommandPaletteWindow(Action? onExecute = null) { InitializeComponent(); _onExecute = onExecute; RegisterCommands(); RenderItems(""); base.Loaded += delegate { SearchBox.Focus(); }; } private void RegisterCommands() { _commands.Add(new CommandEntry("Chat 탭으로 전환", "탭 전환", "\ue8bd", "tab:chat")); _commands.Add(new CommandEntry("Cowork 탭으로 전환", "탭 전환", "\ue8bd", "tab:cowork")); _commands.Add(new CommandEntry("Code 탭으로 전환", "탭 전환", "\ue8bd", "tab:code")); _commands.Add(new CommandEntry("새 대화 시작", "대화", "\ue710", "new_conversation")); _commands.Add(new CommandEntry("대화 검색", "대화", "\ue721", "search_conversation")); _commands.Add(new CommandEntry("모델 변경", "설정", "\uea86", "change_model")); _commands.Add(new CommandEntry("프리셋 선택", "프리셋", "\ue71d", "select_preset")); _commands.Add(new CommandEntry("설정 열기", "앱", "\ue713", "open_settings")); _commands.Add(new CommandEntry("테마 변경", "앱", "\ue790", "change_theme")); _commands.Add(new CommandEntry("통계 보기", "앱", "\ue9f9", "open_statistics")); _commands.Add(new CommandEntry("작업 폴더 변경", "파일", "\ued25", "change_folder")); _commands.Add(new CommandEntry("파일 탐색기 열기", "파일", "\ue8b7", "open_file_explorer")); _commands.Add(new CommandEntry("개발자 모드 토글", "에이전트", "\ue71c", "toggle_devmode")); _commands.Add(new CommandEntry("감사 로그 보기", "에이전트", "\ue9d9", "open_audit_log")); _commands.Add(new CommandEntry("클립보드에서 붙여넣기", "도구", "\ue77f", "paste_clipboard")); _commands.Add(new CommandEntry("대화 내보내기", "도구", "\ue78c", "export_conversation")); } private void RenderItems(string query) { ResultPanel.Children.Clear(); List list = (string.IsNullOrWhiteSpace(query) ? _commands : _commands.Where((CommandEntry c) => c.Label.Contains(query, StringComparison.OrdinalIgnoreCase) || c.Category.Contains(query, StringComparison.OrdinalIgnoreCase) || (FuzzyEngine.IsChosung(query) && FuzzyEngine.ContainsChosung(c.Label, query))).ToList()); for (int num = 0; num < list.Count; num++) { CommandEntry cmd = list[num]; int num2 = num; StackPanel stackPanel = new StackPanel { Orientation = Orientation.Horizontal }; stackPanel.Children.Add(new TextBlock { Text = cmd.Icon, FontFamily = new FontFamily("Segoe MDL2 Assets"), FontSize = 14.0, Foreground = ((FindResource("AccentColor") as Brush) ?? Brushes.CornflowerBlue), VerticalAlignment = VerticalAlignment.Center, Margin = new Thickness(0.0, 0.0, 10.0, 0.0) }); StackPanel stackPanel2 = new StackPanel(); stackPanel2.Children.Add(new TextBlock { Text = cmd.Label, FontSize = 13.0, Foreground = ((FindResource("PrimaryText") as Brush) ?? Brushes.White) }); stackPanel2.Children.Add(new TextBlock { Text = cmd.Category, FontSize = 10.5, Foreground = ((FindResource("SecondaryText") as Brush) ?? Brushes.Gray) }); stackPanel.Children.Add(stackPanel2); Border border = new Border { Child = stackPanel, Background = Brushes.Transparent, CornerRadius = new CornerRadius(8.0), Cursor = Cursors.Hand, Padding = new Thickness(10.0, 8.0, 14.0, 8.0), Margin = new Thickness(0.0, 1.0, 0.0, 1.0) }; Brush hoverBg = (FindResource("HintBackground") as Brush) ?? new SolidColorBrush(Color.FromArgb(24, byte.MaxValue, byte.MaxValue, byte.MaxValue)); border.MouseEnter += delegate(object s, MouseEventArgs _) { if (s is Border border2) { border2.Background = hoverBg; } }; border.MouseLeave += delegate(object s, MouseEventArgs _) { if (s is Border border2) { border2.Background = Brushes.Transparent; } }; border.MouseLeftButtonUp += delegate { ExecuteCommand(cmd.CommandId); }; ResultPanel.Children.Add(border); } } private void ExecuteCommand(string commandId) { SelectedCommand = commandId; _onExecute?.Invoke(commandId); Close(); } private void SearchBox_TextChanged(object sender, TextChangedEventArgs e) { RenderItems(SearchBox.Text); } private void Window_PreviewKeyDown(object sender, KeyEventArgs e) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 if ((int)e.Key == 13) { Close(); e.Handled = true; } else if ((int)e.Key == 6 && ResultPanel.Children.Count > 0) { List list = (string.IsNullOrWhiteSpace(SearchBox.Text) ? _commands : _commands.Where((CommandEntry c) => c.Label.Contains(SearchBox.Text, StringComparison.OrdinalIgnoreCase) || c.Category.Contains(SearchBox.Text, StringComparison.OrdinalIgnoreCase)).ToList()); if (list.Count > 0) { ExecuteCommand(list[0].CommandId); } e.Handled = true; } } private void Window_Deactivated(object sender, EventArgs e) { Close(); } [DebuggerNonUserCode] [GeneratedCode("PresentationBuildTasks", "10.0.5.0")] public void InitializeComponent() { if (!_contentLoaded) { _contentLoaded = true; Uri resourceLocator = new Uri("/AxCopilot;component/views/commandpalettewindow.xaml", UriKind.Relative); Application.LoadComponent(this, resourceLocator); } } [DebuggerNonUserCode] [GeneratedCode("PresentationBuildTasks", "10.0.5.0")] [EditorBrowsable(EditorBrowsableState.Never)] void IComponentConnector.Connect(int connectionId, object target) { switch (connectionId) { case 1: ((CommandPaletteWindow)target).PreviewKeyDown += Window_PreviewKeyDown; ((CommandPaletteWindow)target).Deactivated += Window_Deactivated; break; case 2: SearchBox = (TextBox)target; SearchBox.TextChanged += SearchBox_TextChanged; break; case 3: ResultPanel = (StackPanel)target; break; default: _contentLoaded = true; break; } } }