fresh/input/
commands.rs

1//! Command palette system for executing editor actions by name
2
3use crate::input::keybindings::{Action, KeyContext};
4use rust_i18n::t;
5
6/// Source of a command (builtin or from a plugin)
7#[derive(Debug, Clone, PartialEq)]
8pub enum CommandSource {
9    /// Built-in editor command
10    Builtin,
11    /// Command registered by a plugin (contains plugin filename without extension)
12    Plugin(String),
13}
14
15/// A command that can be executed from the command palette
16#[derive(Debug, Clone)]
17pub struct Command {
18    /// Command name (e.g., "Open File")
19    pub name: String,
20    /// Command description
21    pub description: String,
22    /// The action to trigger
23    pub action: Action,
24    /// Contexts where this command is available (empty = available in all contexts)
25    pub contexts: Vec<KeyContext>,
26    /// Custom contexts required for this command (plugin-defined contexts like "config-editor")
27    /// If non-empty, all custom contexts must be active for the command to be available
28    pub custom_contexts: Vec<String>,
29    /// Source of the command (builtin or plugin)
30    pub source: CommandSource,
31}
32
33impl Command {
34    /// Get the localized name of the command
35    pub fn get_localized_name(&self) -> String {
36        if self.name.starts_with('%') {
37            if let CommandSource::Plugin(ref plugin_name) = self.source {
38                return crate::i18n::translate_plugin_string(
39                    plugin_name,
40                    &self.name[1..],
41                    &std::collections::HashMap::new(),
42                );
43            }
44        }
45        self.name.clone()
46    }
47
48    /// Get the localized description of the command
49    pub fn get_localized_description(&self) -> String {
50        if self.description.starts_with('%') {
51            if let CommandSource::Plugin(ref plugin_name) = self.source {
52                return crate::i18n::translate_plugin_string(
53                    plugin_name,
54                    &self.description[1..],
55                    &std::collections::HashMap::new(),
56                );
57            }
58        }
59        self.description.clone()
60    }
61}
62
63/// A single suggestion item for autocomplete
64#[derive(Debug, Clone, PartialEq)]
65pub struct Suggestion {
66    /// The text to display
67    pub text: String,
68    /// Optional description
69    pub description: Option<String>,
70    /// The value to use when selected (defaults to text if None)
71    pub value: Option<String>,
72    /// Whether this suggestion is disabled (greyed out)
73    pub disabled: bool,
74    /// Optional keyboard shortcut
75    pub keybinding: Option<String>,
76    /// Source of the command (for command palette)
77    pub source: Option<CommandSource>,
78}
79
80impl Suggestion {
81    pub fn new(text: String) -> Self {
82        Self {
83            text,
84            description: None,
85            value: None,
86            disabled: false,
87            keybinding: None,
88            source: None,
89        }
90    }
91
92    pub fn with_description(text: String, description: String) -> Self {
93        Self {
94            text,
95            description: Some(description),
96            value: None,
97            disabled: false,
98            keybinding: None,
99            source: None,
100        }
101    }
102
103    pub fn with_description_and_disabled(
104        text: String,
105        description: String,
106        disabled: bool,
107    ) -> Self {
108        Self {
109            text,
110            description: Some(description),
111            value: None,
112            disabled,
113            keybinding: None,
114            source: None,
115        }
116    }
117
118    pub fn with_all(
119        text: String,
120        description: Option<String>,
121        disabled: bool,
122        keybinding: Option<String>,
123    ) -> Self {
124        Self {
125            text,
126            description,
127            value: None,
128            disabled,
129            keybinding,
130            source: None,
131        }
132    }
133
134    pub fn with_source(
135        text: String,
136        description: Option<String>,
137        disabled: bool,
138        keybinding: Option<String>,
139        source: Option<CommandSource>,
140    ) -> Self {
141        Self {
142            text,
143            description,
144            value: None,
145            disabled,
146            keybinding,
147            source,
148        }
149    }
150
151    pub fn get_value(&self) -> &str {
152        self.value.as_ref().unwrap_or(&self.text)
153    }
154}
155
156/// Get all available commands for the command palette
157pub fn get_all_commands() -> Vec<Command> {
158    vec![
159        // File operations
160        Command {
161            name: t!("cmd.open_file").to_string(),
162            description: t!("cmd.open_file_desc").to_string(),
163            action: Action::Open,
164            contexts: vec![],
165            custom_contexts: vec![],
166            source: CommandSource::Builtin,
167        },
168        Command {
169            name: t!("cmd.switch_project").to_string(),
170            description: t!("cmd.switch_project_desc").to_string(),
171            action: Action::SwitchProject,
172            contexts: vec![],
173            custom_contexts: vec![],
174            source: CommandSource::Builtin,
175        },
176        Command {
177            name: t!("cmd.save_file").to_string(),
178            description: t!("cmd.save_file_desc").to_string(),
179            action: Action::Save,
180            contexts: vec![KeyContext::Normal],
181            custom_contexts: vec![],
182            source: CommandSource::Builtin,
183        },
184        Command {
185            name: t!("cmd.save_file_as").to_string(),
186            description: t!("cmd.save_file_as_desc").to_string(),
187            action: Action::SaveAs,
188            contexts: vec![KeyContext::Normal],
189            custom_contexts: vec![],
190            source: CommandSource::Builtin,
191        },
192        Command {
193            name: t!("cmd.new_file").to_string(),
194            description: t!("cmd.new_file_desc").to_string(),
195            action: Action::New,
196            contexts: vec![],
197            custom_contexts: vec![],
198            source: CommandSource::Builtin,
199        },
200        Command {
201            name: t!("cmd.close_buffer").to_string(),
202            description: t!("cmd.close_buffer_desc").to_string(),
203            action: Action::Close,
204            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
205            custom_contexts: vec![],
206            source: CommandSource::Builtin,
207        },
208        Command {
209            name: t!("cmd.close_tab").to_string(),
210            description: t!("cmd.close_tab_desc").to_string(),
211            action: Action::CloseTab,
212            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
213            custom_contexts: vec![],
214            source: CommandSource::Builtin,
215        },
216        Command {
217            name: t!("cmd.revert_file").to_string(),
218            description: t!("cmd.revert_file_desc").to_string(),
219            action: Action::Revert,
220            contexts: vec![KeyContext::Normal],
221            custom_contexts: vec![],
222            source: CommandSource::Builtin,
223        },
224        Command {
225            name: t!("cmd.toggle_auto_revert").to_string(),
226            description: t!("cmd.toggle_auto_revert_desc").to_string(),
227            action: Action::ToggleAutoRevert,
228            contexts: vec![],
229            custom_contexts: vec![],
230            source: CommandSource::Builtin,
231        },
232        Command {
233            name: t!("cmd.format_buffer").to_string(),
234            description: t!("cmd.format_buffer_desc").to_string(),
235            action: Action::FormatBuffer,
236            contexts: vec![KeyContext::Normal],
237            custom_contexts: vec![],
238            source: CommandSource::Builtin,
239        },
240        Command {
241            name: t!("cmd.quit").to_string(),
242            description: t!("cmd.quit_desc").to_string(),
243            action: Action::Quit,
244            contexts: vec![],
245            custom_contexts: vec![],
246            source: CommandSource::Builtin,
247        },
248        // Edit operations
249        Command {
250            name: t!("cmd.undo").to_string(),
251            description: t!("cmd.undo_desc").to_string(),
252            action: Action::Undo,
253            contexts: vec![KeyContext::Normal],
254            custom_contexts: vec![],
255            source: CommandSource::Builtin,
256        },
257        Command {
258            name: t!("cmd.redo").to_string(),
259            description: t!("cmd.redo_desc").to_string(),
260            action: Action::Redo,
261            contexts: vec![KeyContext::Normal],
262            custom_contexts: vec![],
263            source: CommandSource::Builtin,
264        },
265        Command {
266            name: t!("cmd.copy").to_string(),
267            description: t!("cmd.copy_desc").to_string(),
268            action: Action::Copy,
269            contexts: vec![KeyContext::Normal],
270            custom_contexts: vec![],
271            source: CommandSource::Builtin,
272        },
273        Command {
274            name: t!("cmd.copy_with_formatting").to_string(),
275            description: t!("cmd.copy_with_formatting_desc").to_string(),
276            action: Action::CopyWithTheme(String::new()),
277            contexts: vec![KeyContext::Normal],
278            custom_contexts: vec![],
279            source: CommandSource::Builtin,
280        },
281        Command {
282            name: t!("cmd.cut").to_string(),
283            description: t!("cmd.cut_desc").to_string(),
284            action: Action::Cut,
285            contexts: vec![KeyContext::Normal],
286            custom_contexts: vec![],
287            source: CommandSource::Builtin,
288        },
289        Command {
290            name: t!("cmd.paste").to_string(),
291            description: t!("cmd.paste_desc").to_string(),
292            action: Action::Paste,
293            contexts: vec![KeyContext::Normal],
294            custom_contexts: vec![],
295            source: CommandSource::Builtin,
296        },
297        Command {
298            name: t!("cmd.delete_line").to_string(),
299            description: t!("cmd.delete_line_desc").to_string(),
300            action: Action::DeleteLine,
301            contexts: vec![KeyContext::Normal],
302            custom_contexts: vec![],
303            source: CommandSource::Builtin,
304        },
305        Command {
306            name: t!("cmd.delete_word_backward").to_string(),
307            description: t!("cmd.delete_word_backward_desc").to_string(),
308            action: Action::DeleteWordBackward,
309            contexts: vec![KeyContext::Normal],
310            custom_contexts: vec![],
311            source: CommandSource::Builtin,
312        },
313        Command {
314            name: t!("cmd.delete_word_forward").to_string(),
315            description: t!("cmd.delete_word_forward_desc").to_string(),
316            action: Action::DeleteWordForward,
317            contexts: vec![KeyContext::Normal],
318            custom_contexts: vec![],
319            source: CommandSource::Builtin,
320        },
321        Command {
322            name: t!("cmd.delete_to_end_of_line").to_string(),
323            description: t!("cmd.delete_to_end_of_line_desc").to_string(),
324            action: Action::DeleteToLineEnd,
325            contexts: vec![KeyContext::Normal],
326            custom_contexts: vec![],
327            source: CommandSource::Builtin,
328        },
329        Command {
330            name: t!("cmd.transpose_characters").to_string(),
331            description: t!("cmd.transpose_characters_desc").to_string(),
332            action: Action::TransposeChars,
333            contexts: vec![KeyContext::Normal],
334            custom_contexts: vec![],
335            source: CommandSource::Builtin,
336        },
337        Command {
338            name: t!("cmd.transform_uppercase").to_string(),
339            description: t!("cmd.transform_uppercase_desc").to_string(),
340            action: Action::ToUpperCase,
341            contexts: vec![KeyContext::Normal],
342            custom_contexts: vec![],
343            source: CommandSource::Builtin,
344        },
345        Command {
346            name: t!("cmd.transform_lowercase").to_string(),
347            description: t!("cmd.transform_lowercase_desc").to_string(),
348            action: Action::ToLowerCase,
349            contexts: vec![KeyContext::Normal],
350            custom_contexts: vec![],
351            source: CommandSource::Builtin,
352        },
353        Command {
354            name: t!("cmd.open_line").to_string(),
355            description: t!("cmd.open_line_desc").to_string(),
356            action: Action::OpenLine,
357            contexts: vec![KeyContext::Normal],
358            custom_contexts: vec![],
359            source: CommandSource::Builtin,
360        },
361        Command {
362            name: t!("cmd.recenter").to_string(),
363            description: t!("cmd.recenter_desc").to_string(),
364            action: Action::Recenter,
365            contexts: vec![KeyContext::Normal],
366            custom_contexts: vec![],
367            source: CommandSource::Builtin,
368        },
369        Command {
370            name: t!("cmd.set_mark").to_string(),
371            description: t!("cmd.set_mark_desc").to_string(),
372            action: Action::SetMark,
373            contexts: vec![KeyContext::Normal],
374            custom_contexts: vec![],
375            source: CommandSource::Builtin,
376        },
377        // Selection
378        Command {
379            name: t!("cmd.select_all").to_string(),
380            description: t!("cmd.select_all_desc").to_string(),
381            action: Action::SelectAll,
382            contexts: vec![KeyContext::Normal],
383            custom_contexts: vec![],
384            source: CommandSource::Builtin,
385        },
386        Command {
387            name: t!("cmd.select_word").to_string(),
388            description: t!("cmd.select_word_desc").to_string(),
389            action: Action::SelectWord,
390            contexts: vec![KeyContext::Normal],
391            custom_contexts: vec![],
392            source: CommandSource::Builtin,
393        },
394        Command {
395            name: t!("cmd.select_line").to_string(),
396            description: t!("cmd.select_line_desc").to_string(),
397            action: Action::SelectLine,
398            contexts: vec![KeyContext::Normal],
399            custom_contexts: vec![],
400            source: CommandSource::Builtin,
401        },
402        Command {
403            name: t!("cmd.expand_selection").to_string(),
404            description: t!("cmd.expand_selection_desc").to_string(),
405            action: Action::ExpandSelection,
406            contexts: vec![KeyContext::Normal],
407            custom_contexts: vec![],
408            source: CommandSource::Builtin,
409        },
410        // Multi-cursor
411        Command {
412            name: t!("cmd.add_cursor_above").to_string(),
413            description: t!("cmd.add_cursor_above_desc").to_string(),
414            action: Action::AddCursorAbove,
415            contexts: vec![KeyContext::Normal],
416            custom_contexts: vec![],
417            source: CommandSource::Builtin,
418        },
419        Command {
420            name: t!("cmd.add_cursor_below").to_string(),
421            description: t!("cmd.add_cursor_below_desc").to_string(),
422            action: Action::AddCursorBelow,
423            contexts: vec![KeyContext::Normal],
424            custom_contexts: vec![],
425            source: CommandSource::Builtin,
426        },
427        Command {
428            name: t!("cmd.add_cursor_next_match").to_string(),
429            description: t!("cmd.add_cursor_next_match_desc").to_string(),
430            action: Action::AddCursorNextMatch,
431            contexts: vec![KeyContext::Normal],
432            custom_contexts: vec![],
433            source: CommandSource::Builtin,
434        },
435        Command {
436            name: t!("cmd.remove_secondary_cursors").to_string(),
437            description: t!("cmd.remove_secondary_cursors_desc").to_string(),
438            action: Action::RemoveSecondaryCursors,
439            contexts: vec![KeyContext::Normal],
440            custom_contexts: vec![],
441            source: CommandSource::Builtin,
442        },
443        // Buffer navigation
444        Command {
445            name: t!("cmd.next_buffer").to_string(),
446            description: t!("cmd.next_buffer_desc").to_string(),
447            action: Action::NextBuffer,
448            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
449            custom_contexts: vec![],
450            source: CommandSource::Builtin,
451        },
452        Command {
453            name: t!("cmd.previous_buffer").to_string(),
454            description: t!("cmd.previous_buffer_desc").to_string(),
455            action: Action::PrevBuffer,
456            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
457            custom_contexts: vec![],
458            source: CommandSource::Builtin,
459        },
460        Command {
461            name: t!("cmd.switch_to_previous_tab").to_string(),
462            description: t!("cmd.switch_to_previous_tab_desc").to_string(),
463            action: Action::SwitchToPreviousTab,
464            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
465            custom_contexts: vec![],
466            source: CommandSource::Builtin,
467        },
468        Command {
469            name: t!("cmd.switch_to_tab_by_name").to_string(),
470            description: t!("cmd.switch_to_tab_by_name_desc").to_string(),
471            action: Action::SwitchToTabByName,
472            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
473            custom_contexts: vec![],
474            source: CommandSource::Builtin,
475        },
476        // Split operations
477        Command {
478            name: t!("cmd.split_horizontal").to_string(),
479            description: t!("cmd.split_horizontal_desc").to_string(),
480            action: Action::SplitHorizontal,
481            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
482            custom_contexts: vec![],
483            source: CommandSource::Builtin,
484        },
485        Command {
486            name: t!("cmd.split_vertical").to_string(),
487            description: t!("cmd.split_vertical_desc").to_string(),
488            action: Action::SplitVertical,
489            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
490            custom_contexts: vec![],
491            source: CommandSource::Builtin,
492        },
493        Command {
494            name: t!("cmd.close_split").to_string(),
495            description: t!("cmd.close_split_desc").to_string(),
496            action: Action::CloseSplit,
497            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
498            custom_contexts: vec![],
499            source: CommandSource::Builtin,
500        },
501        Command {
502            name: t!("cmd.next_split").to_string(),
503            description: t!("cmd.next_split_desc").to_string(),
504            action: Action::NextSplit,
505            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
506            custom_contexts: vec![],
507            source: CommandSource::Builtin,
508        },
509        Command {
510            name: t!("cmd.previous_split").to_string(),
511            description: t!("cmd.previous_split_desc").to_string(),
512            action: Action::PrevSplit,
513            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
514            custom_contexts: vec![],
515            source: CommandSource::Builtin,
516        },
517        Command {
518            name: t!("cmd.increase_split_size").to_string(),
519            description: t!("cmd.increase_split_size_desc").to_string(),
520            action: Action::IncreaseSplitSize,
521            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
522            custom_contexts: vec![],
523            source: CommandSource::Builtin,
524        },
525        Command {
526            name: t!("cmd.decrease_split_size").to_string(),
527            description: t!("cmd.decrease_split_size_desc").to_string(),
528            action: Action::DecreaseSplitSize,
529            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
530            custom_contexts: vec![],
531            source: CommandSource::Builtin,
532        },
533        Command {
534            name: t!("cmd.toggle_maximize_split").to_string(),
535            description: t!("cmd.toggle_maximize_split_desc").to_string(),
536            action: Action::ToggleMaximizeSplit,
537            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
538            custom_contexts: vec![],
539            source: CommandSource::Builtin,
540        },
541        // View toggles
542        Command {
543            name: t!("cmd.toggle_line_numbers").to_string(),
544            description: t!("cmd.toggle_line_numbers_desc").to_string(),
545            action: Action::ToggleLineNumbers,
546            contexts: vec![KeyContext::Normal],
547            custom_contexts: vec![],
548            source: CommandSource::Builtin,
549        },
550        Command {
551            name: t!("cmd.debug_toggle_highlight").to_string(),
552            description: t!("cmd.debug_toggle_highlight_desc").to_string(),
553            action: Action::ToggleDebugHighlights,
554            contexts: vec![KeyContext::Normal],
555            custom_contexts: vec![],
556            source: CommandSource::Builtin,
557        },
558        // Buffer settings commands
559        Command {
560            name: t!("cmd.set_tab_size").to_string(),
561            description: t!("cmd.set_tab_size_desc").to_string(),
562            action: Action::SetTabSize,
563            contexts: vec![KeyContext::Normal],
564            custom_contexts: vec![],
565            source: CommandSource::Builtin,
566        },
567        Command {
568            name: t!("cmd.set_line_ending").to_string(),
569            description: t!("cmd.set_line_ending_desc").to_string(),
570            action: Action::SetLineEnding,
571            contexts: vec![KeyContext::Normal],
572            custom_contexts: vec![],
573            source: CommandSource::Builtin,
574        },
575        Command {
576            name: t!("cmd.toggle_indentation").to_string(),
577            description: t!("cmd.toggle_indentation_desc").to_string(),
578            action: Action::ToggleIndentationStyle,
579            contexts: vec![KeyContext::Normal],
580            custom_contexts: vec![],
581            source: CommandSource::Builtin,
582        },
583        Command {
584            name: t!("cmd.toggle_tab_indicators").to_string(),
585            description: t!("cmd.toggle_tab_indicators_desc").to_string(),
586            action: Action::ToggleTabIndicators,
587            contexts: vec![KeyContext::Normal],
588            custom_contexts: vec![],
589            source: CommandSource::Builtin,
590        },
591        Command {
592            name: t!("cmd.reset_buffer_settings").to_string(),
593            description: t!("cmd.reset_buffer_settings_desc").to_string(),
594            action: Action::ResetBufferSettings,
595            contexts: vec![KeyContext::Normal],
596            custom_contexts: vec![],
597            source: CommandSource::Builtin,
598        },
599        Command {
600            name: t!("cmd.scroll_up").to_string(),
601            description: t!("cmd.scroll_up_desc").to_string(),
602            action: Action::ScrollUp,
603            contexts: vec![KeyContext::Normal],
604            custom_contexts: vec![],
605            source: CommandSource::Builtin,
606        },
607        Command {
608            name: t!("cmd.scroll_down").to_string(),
609            description: t!("cmd.scroll_down_desc").to_string(),
610            action: Action::ScrollDown,
611            contexts: vec![KeyContext::Normal],
612            custom_contexts: vec![],
613            source: CommandSource::Builtin,
614        },
615        Command {
616            name: t!("cmd.scroll_tabs_left").to_string(),
617            description: t!("cmd.scroll_tabs_left_desc").to_string(),
618            action: Action::ScrollTabsLeft,
619            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
620            custom_contexts: vec![],
621            source: CommandSource::Builtin,
622        },
623        Command {
624            name: t!("cmd.scroll_tabs_right").to_string(),
625            description: t!("cmd.scroll_tabs_right_desc").to_string(),
626            action: Action::ScrollTabsRight,
627            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
628            custom_contexts: vec![],
629            source: CommandSource::Builtin,
630        },
631        Command {
632            name: t!("cmd.toggle_mouse_support").to_string(),
633            description: t!("cmd.toggle_mouse_support_desc").to_string(),
634            action: Action::ToggleMouseCapture,
635            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
636            custom_contexts: vec![],
637            source: CommandSource::Builtin,
638        },
639        // File explorer
640        Command {
641            name: t!("cmd.toggle_file_explorer").to_string(),
642            description: t!("cmd.toggle_file_explorer_desc").to_string(),
643            action: Action::ToggleFileExplorer,
644            contexts: vec![
645                KeyContext::Normal,
646                KeyContext::FileExplorer,
647                KeyContext::Terminal,
648            ],
649            custom_contexts: vec![],
650            source: CommandSource::Builtin,
651        },
652        Command {
653            name: t!("cmd.toggle_menu_bar").to_string(),
654            description: t!("cmd.toggle_menu_bar_desc").to_string(),
655            action: Action::ToggleMenuBar,
656            contexts: vec![
657                KeyContext::Normal,
658                KeyContext::FileExplorer,
659                KeyContext::Terminal,
660            ],
661            custom_contexts: vec![],
662            source: CommandSource::Builtin,
663        },
664        Command {
665            name: t!("cmd.toggle_tab_bar").to_string(),
666            description: t!("cmd.toggle_tab_bar_desc").to_string(),
667            action: Action::ToggleTabBar,
668            contexts: vec![
669                KeyContext::Normal,
670                KeyContext::FileExplorer,
671                KeyContext::Terminal,
672            ],
673            custom_contexts: vec![],
674            source: CommandSource::Builtin,
675        },
676        Command {
677            name: t!("cmd.focus_file_explorer").to_string(),
678            description: t!("cmd.focus_file_explorer_desc").to_string(),
679            action: Action::FocusFileExplorer,
680            contexts: vec![KeyContext::Normal, KeyContext::Terminal],
681            custom_contexts: vec![],
682            source: CommandSource::Builtin,
683        },
684        Command {
685            name: t!("cmd.focus_editor").to_string(),
686            description: t!("cmd.focus_editor_desc").to_string(),
687            action: Action::FocusEditor,
688            contexts: vec![KeyContext::FileExplorer],
689            custom_contexts: vec![],
690            source: CommandSource::Builtin,
691        },
692        Command {
693            name: t!("cmd.explorer_refresh").to_string(),
694            description: t!("cmd.explorer_refresh_desc").to_string(),
695            action: Action::FileExplorerRefresh,
696            contexts: vec![KeyContext::FileExplorer],
697            custom_contexts: vec![],
698            source: CommandSource::Builtin,
699        },
700        Command {
701            name: t!("cmd.explorer_new_file").to_string(),
702            description: t!("cmd.explorer_new_file_desc").to_string(),
703            action: Action::FileExplorerNewFile,
704            contexts: vec![KeyContext::FileExplorer],
705            custom_contexts: vec![],
706            source: CommandSource::Builtin,
707        },
708        Command {
709            name: t!("cmd.explorer_new_directory").to_string(),
710            description: t!("cmd.explorer_new_directory_desc").to_string(),
711            action: Action::FileExplorerNewDirectory,
712            contexts: vec![KeyContext::FileExplorer],
713            custom_contexts: vec![],
714            source: CommandSource::Builtin,
715        },
716        Command {
717            name: t!("cmd.explorer_delete").to_string(),
718            description: t!("cmd.explorer_delete_desc").to_string(),
719            action: Action::FileExplorerDelete,
720            contexts: vec![KeyContext::FileExplorer],
721            custom_contexts: vec![],
722            source: CommandSource::Builtin,
723        },
724        Command {
725            name: t!("cmd.explorer_rename").to_string(),
726            description: t!("cmd.explorer_rename_desc").to_string(),
727            action: Action::FileExplorerRename,
728            contexts: vec![KeyContext::FileExplorer],
729            custom_contexts: vec![],
730            source: CommandSource::Builtin,
731        },
732        Command {
733            name: t!("cmd.toggle_hidden_files").to_string(),
734            description: t!("cmd.toggle_hidden_files_desc").to_string(),
735            action: Action::FileExplorerToggleHidden,
736            contexts: vec![KeyContext::FileExplorer],
737            custom_contexts: vec![],
738            source: CommandSource::Builtin,
739        },
740        Command {
741            name: t!("cmd.toggle_gitignored_files").to_string(),
742            description: t!("cmd.toggle_gitignored_files_desc").to_string(),
743            action: Action::FileExplorerToggleGitignored,
744            contexts: vec![KeyContext::FileExplorer],
745            custom_contexts: vec![],
746            source: CommandSource::Builtin,
747        },
748        // View
749        Command {
750            name: t!("cmd.toggle_line_wrap").to_string(),
751            description: t!("cmd.toggle_line_wrap_desc").to_string(),
752            action: Action::ToggleLineWrap,
753            contexts: vec![KeyContext::Normal],
754            custom_contexts: vec![],
755            source: CommandSource::Builtin,
756        },
757        // Note: Compose mode commands removed - markdown_compose plugin provides these
758        Command {
759            name: t!("cmd.set_background").to_string(),
760            description: t!("cmd.set_background_desc").to_string(),
761            action: Action::SetBackground,
762            contexts: vec![KeyContext::Normal],
763            custom_contexts: vec![],
764            source: CommandSource::Builtin,
765        },
766        Command {
767            name: t!("cmd.set_background_blend").to_string(),
768            description: t!("cmd.set_background_blend_desc").to_string(),
769            action: Action::SetBackgroundBlend,
770            contexts: vec![KeyContext::Normal],
771            custom_contexts: vec![],
772            source: CommandSource::Builtin,
773        },
774        // Note: Command Palette is intentionally not in the command list
775        // to avoid confusion when it's already open (use Ctrl+P or Ctrl+/ to toggle)
776        // Search and replace
777        Command {
778            name: t!("cmd.search").to_string(),
779            description: t!("cmd.search_desc").to_string(),
780            action: Action::Search,
781            contexts: vec![KeyContext::Normal],
782            custom_contexts: vec![],
783            source: CommandSource::Builtin,
784        },
785        Command {
786            name: t!("cmd.find_in_selection").to_string(),
787            description: t!("cmd.find_in_selection_desc").to_string(),
788            action: Action::FindInSelection,
789            contexts: vec![KeyContext::Normal],
790            custom_contexts: vec![],
791            source: CommandSource::Builtin,
792        },
793        Command {
794            name: t!("cmd.find_next").to_string(),
795            description: t!("cmd.find_next_desc").to_string(),
796            action: Action::FindNext,
797            contexts: vec![KeyContext::Normal],
798            custom_contexts: vec![],
799            source: CommandSource::Builtin,
800        },
801        Command {
802            name: t!("cmd.find_previous").to_string(),
803            description: t!("cmd.find_previous_desc").to_string(),
804            action: Action::FindPrevious,
805            contexts: vec![KeyContext::Normal],
806            custom_contexts: vec![],
807            source: CommandSource::Builtin,
808        },
809        Command {
810            name: t!("cmd.find_selection_next").to_string(),
811            description: t!("cmd.find_selection_next_desc").to_string(),
812            action: Action::FindSelectionNext,
813            contexts: vec![KeyContext::Normal],
814            custom_contexts: vec![],
815            source: CommandSource::Builtin,
816        },
817        Command {
818            name: t!("cmd.find_selection_previous").to_string(),
819            description: t!("cmd.find_selection_previous_desc").to_string(),
820            action: Action::FindSelectionPrevious,
821            contexts: vec![KeyContext::Normal],
822            custom_contexts: vec![],
823            source: CommandSource::Builtin,
824        },
825        Command {
826            name: t!("cmd.replace").to_string(),
827            description: t!("cmd.replace_desc").to_string(),
828            action: Action::Replace,
829            contexts: vec![KeyContext::Normal],
830            custom_contexts: vec![],
831            source: CommandSource::Builtin,
832        },
833        Command {
834            name: t!("cmd.query_replace").to_string(),
835            description: t!("cmd.query_replace_desc").to_string(),
836            action: Action::QueryReplace,
837            contexts: vec![KeyContext::Normal],
838            custom_contexts: vec![],
839            source: CommandSource::Builtin,
840        },
841        // Navigation
842        Command {
843            name: t!("cmd.goto_line").to_string(),
844            description: t!("cmd.goto_line_desc").to_string(),
845            action: Action::GotoLine,
846            contexts: vec![KeyContext::Normal],
847            custom_contexts: vec![],
848            source: CommandSource::Builtin,
849        },
850        Command {
851            name: t!("cmd.smart_home").to_string(),
852            description: t!("cmd.smart_home_desc").to_string(),
853            action: Action::SmartHome,
854            contexts: vec![KeyContext::Normal],
855            custom_contexts: vec![],
856            source: CommandSource::Builtin,
857        },
858        Command {
859            name: t!("cmd.show_completions").to_string(),
860            description: t!("cmd.show_completions_desc").to_string(),
861            action: Action::LspCompletion,
862            contexts: vec![KeyContext::Normal],
863            custom_contexts: vec![],
864            source: CommandSource::Builtin,
865        },
866        Command {
867            name: t!("cmd.goto_definition").to_string(),
868            description: t!("cmd.goto_definition_desc").to_string(),
869            action: Action::LspGotoDefinition,
870            contexts: vec![KeyContext::Normal],
871            custom_contexts: vec![],
872            source: CommandSource::Builtin,
873        },
874        Command {
875            name: t!("cmd.show_hover_info").to_string(),
876            description: t!("cmd.show_hover_info_desc").to_string(),
877            action: Action::LspHover,
878            contexts: vec![KeyContext::Normal],
879            custom_contexts: vec![],
880            source: CommandSource::Builtin,
881        },
882        Command {
883            name: t!("cmd.find_references").to_string(),
884            description: t!("cmd.find_references_desc").to_string(),
885            action: Action::LspReferences,
886            contexts: vec![KeyContext::Normal],
887            custom_contexts: vec![],
888            source: CommandSource::Builtin,
889        },
890        Command {
891            name: t!("cmd.show_signature_help").to_string(),
892            description: t!("cmd.show_signature_help_desc").to_string(),
893            action: Action::LspSignatureHelp,
894            contexts: vec![KeyContext::Normal],
895            custom_contexts: vec![],
896            source: CommandSource::Builtin,
897        },
898        Command {
899            name: t!("cmd.code_actions").to_string(),
900            description: t!("cmd.code_actions_desc").to_string(),
901            action: Action::LspCodeActions,
902            contexts: vec![KeyContext::Normal],
903            custom_contexts: vec![],
904            source: CommandSource::Builtin,
905        },
906        Command {
907            name: t!("cmd.start_restart_lsp").to_string(),
908            description: t!("cmd.start_restart_lsp_desc").to_string(),
909            action: Action::LspRestart,
910            contexts: vec![KeyContext::Normal],
911            custom_contexts: vec![],
912            source: CommandSource::Builtin,
913        },
914        Command {
915            name: t!("cmd.stop_lsp").to_string(),
916            description: t!("cmd.stop_lsp_desc").to_string(),
917            action: Action::LspStop,
918            contexts: vec![KeyContext::Normal],
919            custom_contexts: vec![],
920            source: CommandSource::Builtin,
921        },
922        Command {
923            name: t!("cmd.toggle_mouse_hover").to_string(),
924            description: t!("cmd.toggle_mouse_hover_desc").to_string(),
925            action: Action::ToggleMouseHover,
926            contexts: vec![],
927            custom_contexts: vec![],
928            source: CommandSource::Builtin,
929        },
930        Command {
931            name: t!("cmd.navigate_back").to_string(),
932            description: t!("cmd.navigate_back_desc").to_string(),
933            action: Action::NavigateBack,
934            contexts: vec![KeyContext::Normal],
935            custom_contexts: vec![],
936            source: CommandSource::Builtin,
937        },
938        Command {
939            name: t!("cmd.navigate_forward").to_string(),
940            description: t!("cmd.navigate_forward_desc").to_string(),
941            action: Action::NavigateForward,
942            contexts: vec![KeyContext::Normal],
943            custom_contexts: vec![],
944            source: CommandSource::Builtin,
945        },
946        // Smart editing
947        Command {
948            name: t!("cmd.toggle_comment").to_string(),
949            description: t!("cmd.toggle_comment_desc").to_string(),
950            action: Action::ToggleComment,
951            contexts: vec![KeyContext::Normal],
952            custom_contexts: vec![],
953            source: CommandSource::Builtin,
954        },
955        Command {
956            name: t!("cmd.dedent_selection").to_string(),
957            description: t!("cmd.dedent_selection_desc").to_string(),
958            action: Action::DedentSelection,
959            contexts: vec![KeyContext::Normal],
960            custom_contexts: vec![],
961            source: CommandSource::Builtin,
962        },
963        Command {
964            name: t!("cmd.goto_matching_bracket").to_string(),
965            description: t!("cmd.goto_matching_bracket_desc").to_string(),
966            action: Action::GoToMatchingBracket,
967            contexts: vec![KeyContext::Normal],
968            custom_contexts: vec![],
969            source: CommandSource::Builtin,
970        },
971        // Error navigation
972        Command {
973            name: t!("cmd.jump_to_next_error").to_string(),
974            description: t!("cmd.jump_to_next_error_desc").to_string(),
975            action: Action::JumpToNextError,
976            contexts: vec![KeyContext::Normal],
977            custom_contexts: vec![],
978            source: CommandSource::Builtin,
979        },
980        Command {
981            name: t!("cmd.jump_to_previous_error").to_string(),
982            description: t!("cmd.jump_to_previous_error_desc").to_string(),
983            action: Action::JumpToPreviousError,
984            contexts: vec![KeyContext::Normal],
985            custom_contexts: vec![],
986            source: CommandSource::Builtin,
987        },
988        // LSP
989        Command {
990            name: t!("cmd.rename_symbol").to_string(),
991            description: t!("cmd.rename_symbol_desc").to_string(),
992            action: Action::LspRename,
993            contexts: vec![KeyContext::Normal],
994            custom_contexts: vec![],
995            source: CommandSource::Builtin,
996        },
997        // Bookmarks and Macros
998        Command {
999            name: t!("cmd.list_bookmarks").to_string(),
1000            description: t!("cmd.list_bookmarks_desc").to_string(),
1001            action: Action::ListBookmarks,
1002            contexts: vec![KeyContext::Normal],
1003            custom_contexts: vec![],
1004            source: CommandSource::Builtin,
1005        },
1006        Command {
1007            name: t!("cmd.list_macros").to_string(),
1008            description: t!("cmd.list_macros_desc").to_string(),
1009            action: Action::ListMacros,
1010            contexts: vec![KeyContext::Normal],
1011            custom_contexts: vec![],
1012            source: CommandSource::Builtin,
1013        },
1014        Command {
1015            name: t!("cmd.record_macro").to_string(),
1016            description: t!("cmd.record_macro_desc").to_string(),
1017            action: Action::PromptRecordMacro,
1018            contexts: vec![KeyContext::Normal],
1019            custom_contexts: vec![],
1020            source: CommandSource::Builtin,
1021        },
1022        Command {
1023            name: t!("cmd.stop_recording_macro").to_string(),
1024            description: t!("cmd.stop_recording_macro_desc").to_string(),
1025            action: Action::StopMacroRecording,
1026            contexts: vec![KeyContext::Normal],
1027            custom_contexts: vec![],
1028            source: CommandSource::Builtin,
1029        },
1030        Command {
1031            name: t!("cmd.play_macro").to_string(),
1032            description: t!("cmd.play_macro_desc").to_string(),
1033            action: Action::PromptPlayMacro,
1034            contexts: vec![KeyContext::Normal],
1035            custom_contexts: vec![],
1036            source: CommandSource::Builtin,
1037        },
1038        Command {
1039            name: t!("cmd.play_last_macro").to_string(),
1040            description: t!("cmd.play_last_macro_desc").to_string(),
1041            action: Action::PlayLastMacro,
1042            contexts: vec![KeyContext::Normal],
1043            custom_contexts: vec![],
1044            source: CommandSource::Builtin,
1045        },
1046        Command {
1047            name: t!("cmd.set_bookmark").to_string(),
1048            description: t!("cmd.set_bookmark_desc").to_string(),
1049            action: Action::PromptSetBookmark,
1050            contexts: vec![KeyContext::Normal],
1051            custom_contexts: vec![],
1052            source: CommandSource::Builtin,
1053        },
1054        Command {
1055            name: t!("cmd.jump_to_bookmark").to_string(),
1056            description: t!("cmd.jump_to_bookmark_desc").to_string(),
1057            action: Action::PromptJumpToBookmark,
1058            contexts: vec![KeyContext::Normal],
1059            custom_contexts: vec![],
1060            source: CommandSource::Builtin,
1061        },
1062        // Help
1063        Command {
1064            name: t!("cmd.show_manual").to_string(),
1065            description: t!("cmd.show_manual_desc").to_string(),
1066            action: Action::ShowHelp,
1067            contexts: vec![],
1068            custom_contexts: vec![],
1069            source: CommandSource::Builtin,
1070        },
1071        Command {
1072            name: t!("cmd.show_keyboard_shortcuts").to_string(),
1073            description: t!("cmd.show_keyboard_shortcuts_desc").to_string(),
1074            action: Action::ShowKeyboardShortcuts,
1075            contexts: vec![],
1076            custom_contexts: vec![],
1077            source: CommandSource::Builtin,
1078        },
1079        Command {
1080            name: t!("cmd.show_warnings").to_string(),
1081            description: t!("cmd.show_warnings_desc").to_string(),
1082            action: Action::ShowWarnings,
1083            contexts: vec![],
1084            custom_contexts: vec![],
1085            source: CommandSource::Builtin,
1086        },
1087        Command {
1088            name: t!("cmd.show_lsp_status").to_string(),
1089            description: t!("cmd.show_lsp_status_desc").to_string(),
1090            action: Action::ShowLspStatus,
1091            contexts: vec![],
1092            custom_contexts: vec![],
1093            source: CommandSource::Builtin,
1094        },
1095        Command {
1096            name: t!("cmd.clear_warnings").to_string(),
1097            description: t!("cmd.clear_warnings_desc").to_string(),
1098            action: Action::ClearWarnings,
1099            contexts: vec![],
1100            custom_contexts: vec![],
1101            source: CommandSource::Builtin,
1102        },
1103        // Config
1104        Command {
1105            name: t!("cmd.dump_config").to_string(),
1106            description: t!("cmd.dump_config_desc").to_string(),
1107            action: Action::DumpConfig,
1108            contexts: vec![],
1109            custom_contexts: vec![],
1110            source: CommandSource::Builtin,
1111        },
1112        Command {
1113            name: t!("cmd.toggle_inlay_hints").to_string(),
1114            description: t!("cmd.toggle_inlay_hints_desc").to_string(),
1115            action: Action::ToggleInlayHints,
1116            contexts: vec![KeyContext::Normal],
1117            custom_contexts: vec![],
1118            source: CommandSource::Builtin,
1119        },
1120        // Theme selection
1121        Command {
1122            name: t!("cmd.select_theme").to_string(),
1123            description: t!("cmd.select_theme_desc").to_string(),
1124            action: Action::SelectTheme,
1125            contexts: vec![],
1126            custom_contexts: vec![],
1127            source: CommandSource::Builtin,
1128        },
1129        // Keybinding map selection
1130        Command {
1131            name: t!("cmd.select_keybinding_map").to_string(),
1132            description: t!("cmd.select_keybinding_map_desc").to_string(),
1133            action: Action::SelectKeybindingMap,
1134            contexts: vec![],
1135            custom_contexts: vec![],
1136            source: CommandSource::Builtin,
1137        },
1138        // Cursor style selection
1139        Command {
1140            name: t!("cmd.select_cursor_style").to_string(),
1141            description: t!("cmd.select_cursor_style_desc").to_string(),
1142            action: Action::SelectCursorStyle,
1143            contexts: vec![],
1144            custom_contexts: vec![],
1145            source: CommandSource::Builtin,
1146        },
1147        // Locale selection
1148        Command {
1149            name: t!("cmd.select_locale").to_string(),
1150            description: t!("cmd.select_locale_desc").to_string(),
1151            action: Action::SelectLocale,
1152            contexts: vec![],
1153            custom_contexts: vec![],
1154            source: CommandSource::Builtin,
1155        },
1156        // Settings
1157        Command {
1158            name: t!("cmd.open_settings").to_string(),
1159            description: t!("cmd.open_settings_desc").to_string(),
1160            action: Action::OpenSettings,
1161            contexts: vec![],
1162            custom_contexts: vec![],
1163            source: CommandSource::Builtin,
1164        },
1165        // Input calibration
1166        Command {
1167            name: t!("cmd.calibrate_input").to_string(),
1168            description: t!("cmd.calibrate_input_desc").to_string(),
1169            action: Action::CalibrateInput,
1170            contexts: vec![],
1171            custom_contexts: vec![],
1172            source: CommandSource::Builtin,
1173        },
1174        // Terminal commands
1175        Command {
1176            name: t!("cmd.open_terminal").to_string(),
1177            description: t!("cmd.open_terminal_desc").to_string(),
1178            action: Action::OpenTerminal,
1179            contexts: vec![], // Available in all contexts (file explorer, normal, terminal, etc.)
1180            custom_contexts: vec![],
1181            source: CommandSource::Builtin,
1182        },
1183        Command {
1184            name: t!("cmd.focus_terminal").to_string(),
1185            description: t!("cmd.focus_terminal_desc").to_string(),
1186            action: Action::FocusTerminal,
1187            contexts: vec![KeyContext::Normal],
1188            custom_contexts: vec![],
1189            source: CommandSource::Builtin,
1190        },
1191        Command {
1192            name: t!("cmd.exit_terminal_mode").to_string(),
1193            description: t!("cmd.exit_terminal_mode_desc").to_string(),
1194            action: Action::TerminalEscape,
1195            contexts: vec![KeyContext::Terminal],
1196            custom_contexts: vec![],
1197            source: CommandSource::Builtin,
1198        },
1199        Command {
1200            name: t!("cmd.toggle_keyboard_capture").to_string(),
1201            description: t!("cmd.toggle_keyboard_capture_desc").to_string(),
1202            action: Action::ToggleKeyboardCapture,
1203            contexts: vec![KeyContext::Terminal],
1204            custom_contexts: vec![],
1205            source: CommandSource::Builtin,
1206        },
1207        // Shell command operations
1208        Command {
1209            name: t!("cmd.shell_command").to_string(),
1210            description: t!("cmd.shell_command_desc").to_string(),
1211            action: Action::ShellCommand,
1212            contexts: vec![KeyContext::Normal],
1213            custom_contexts: vec![],
1214            source: CommandSource::Builtin,
1215        },
1216        Command {
1217            name: t!("cmd.shell_command_replace").to_string(),
1218            description: t!("cmd.shell_command_replace_desc").to_string(),
1219            action: Action::ShellCommandReplace,
1220            contexts: vec![KeyContext::Normal],
1221            custom_contexts: vec![],
1222            source: CommandSource::Builtin,
1223        },
1224    ]
1225}
1226
1227/// Filter commands by fuzzy matching the query, with context awareness
1228pub fn filter_commands(
1229    query: &str,
1230    current_context: KeyContext,
1231    keybinding_resolver: &crate::input::keybindings::KeybindingResolver,
1232) -> Vec<Suggestion> {
1233    let query_lower = query.to_lowercase();
1234    let commands = get_all_commands();
1235
1236    // Helper function to check if command is available in current context
1237    let is_available = |cmd: &Command| -> bool {
1238        // Empty contexts means available in all contexts
1239        cmd.contexts.is_empty() || cmd.contexts.contains(&current_context)
1240    };
1241
1242    // Helper function for fuzzy matching
1243    let matches_query = |cmd: &Command| -> bool {
1244        if query.is_empty() {
1245            return true;
1246        }
1247
1248        let name_lower = cmd.name.to_lowercase();
1249        let mut query_chars = query_lower.chars();
1250        let mut current_char = query_chars.next();
1251
1252        for name_char in name_lower.chars() {
1253            if let Some(qc) = current_char {
1254                if qc == name_char {
1255                    current_char = query_chars.next();
1256                }
1257            } else {
1258                break;
1259            }
1260        }
1261
1262        current_char.is_none() // All query characters matched
1263    };
1264
1265    // Filter and convert to suggestions
1266    let mut suggestions: Vec<Suggestion> = commands
1267        .into_iter()
1268        .filter(|cmd| matches_query(cmd))
1269        .map(|cmd| {
1270            let available = is_available(&cmd);
1271            let keybinding =
1272                keybinding_resolver.get_keybinding_for_action(&cmd.action, current_context);
1273            Suggestion::with_all(
1274                cmd.name.clone(),
1275                Some(cmd.description),
1276                !available,
1277                keybinding,
1278            )
1279        })
1280        .collect();
1281
1282    // Sort: available commands first, then disabled ones
1283    suggestions.sort_by_key(|s| s.disabled);
1284
1285    suggestions
1286}