1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, ts_rs::TS)]
5#[ts(export)]
6pub enum KeyContext {
7 Global,
9 Normal,
11 Prompt,
13 Popup,
15 FileExplorer,
17 Menu,
19 Terminal,
21 Settings,
23 Mode(String),
25}
26
27impl KeyContext {
28 pub fn allows_text_input(&self) -> bool {
30 matches!(self, Self::Normal | Self::Prompt)
31 }
32
33 pub fn from_when_clause(when: &str) -> Option<Self> {
35 let trimmed = when.trim();
36 if let Some(mode_name) = trimmed.strip_prefix("mode:") {
37 return Some(Self::Mode(mode_name.to_string()));
38 }
39 Some(match trimmed {
40 "global" => Self::Global,
41 "prompt" => Self::Prompt,
42 "popup" => Self::Popup,
43 "fileExplorer" | "file_explorer" => Self::FileExplorer,
44 "normal" => Self::Normal,
45 "menu" => Self::Menu,
46 "terminal" => Self::Terminal,
47 "settings" => Self::Settings,
48 _ => return None,
49 })
50 }
51
52 pub fn to_when_clause(&self) -> String {
54 match self {
55 Self::Global => "global".to_string(),
56 Self::Normal => "normal".to_string(),
57 Self::Prompt => "prompt".to_string(),
58 Self::Popup => "popup".to_string(),
59 Self::FileExplorer => "fileExplorer".to_string(),
60 Self::Menu => "menu".to_string(),
61 Self::Terminal => "terminal".to_string(),
62 Self::Settings => "settings".to_string(),
63 Self::Mode(name) => format!("mode:{}", name),
64 }
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ts_rs::TS)]
70#[ts(export)]
71pub enum Action {
72 InsertChar(char),
74 InsertNewline,
75 InsertTab,
76
77 MoveLeft,
79 MoveRight,
80 MoveUp,
81 MoveDown,
82 MoveWordLeft,
83 MoveWordRight,
84 MoveLineStart,
85 MoveLineEnd,
86 MovePageUp,
87 MovePageDown,
88 MoveDocumentStart,
89 MoveDocumentEnd,
90
91 SelectLeft,
93 SelectRight,
94 SelectUp,
95 SelectDown,
96 SelectWordLeft,
97 SelectWordRight,
98 SelectLineStart,
99 SelectLineEnd,
100 SelectDocumentStart,
101 SelectDocumentEnd,
102 SelectPageUp,
103 SelectPageDown,
104 SelectAll,
105 SelectWord,
106 SelectLine,
107 ExpandSelection,
108
109 BlockSelectLeft,
111 BlockSelectRight,
112 BlockSelectUp,
113 BlockSelectDown,
114
115 DeleteBackward,
117 DeleteForward,
118 DeleteWordBackward,
119 DeleteWordForward,
120 DeleteLine,
121 DeleteToLineEnd,
122 DeleteToLineStart,
123 TransposeChars,
124 OpenLine,
125
126 Recenter,
128
129 SetMark,
131 CancelMark,
132 ClearMark,
133
134 Copy,
136 CopyWithTheme(String),
137 Cut,
138 Paste,
139
140 YankWordForward,
142 YankWordBackward,
143 YankToLineEnd,
144 YankToLineStart,
145
146 AddCursorAbove,
148 AddCursorBelow,
149 AddCursorNextMatch,
150 RemoveSecondaryCursors,
151
152 Save,
154 SaveAs,
155 Open,
156 SwitchProject,
157 New,
158 Close,
159 CloseTab,
160 Quit,
161 Revert,
162 ToggleAutoRevert,
163 FormatBuffer,
164
165 GotoLine,
167 ScanLineIndex,
168 GoToMatchingBracket,
169 JumpToNextError,
170 JumpToPreviousError,
171
172 SmartHome,
174 DedentSelection,
175 ToggleComment,
176 DabbrevExpand,
180
181 SetBookmark(char),
183 JumpToBookmark(char),
184 ClearBookmark(char),
185 ListBookmarks,
186
187 ToggleSearchCaseSensitive,
189 ToggleSearchWholeWord,
190 ToggleSearchRegex,
191 ToggleSearchConfirmEach,
192
193 StartMacroRecording,
195 StopMacroRecording,
196 PlayMacro(char),
197 ToggleMacroRecording(char),
198 ShowMacro(char),
199 ListMacros,
200 PromptRecordMacro,
201 PromptPlayMacro,
202 PlayLastMacro,
203
204 PromptSetBookmark,
206 PromptJumpToBookmark,
207
208 Undo,
210 Redo,
211
212 ScrollUp,
214 ScrollDown,
215 ShowHelp,
216 ShowKeyboardShortcuts,
217 ShowWarnings,
218 ShowLspStatus,
219 ClearWarnings,
220 CommandPalette,
221 ToggleLineWrap,
222 ToggleReadOnly,
223 TogglePageView,
224 SetPageWidth,
225 InspectThemeAtCursor,
226 SelectTheme,
227 SelectKeybindingMap,
228 SelectCursorStyle,
229 SelectLocale,
230
231 NextBuffer,
233 PrevBuffer,
234 SwitchToPreviousTab,
235 SwitchToTabByName,
236
237 ScrollTabsLeft,
239 ScrollTabsRight,
240
241 NavigateBack,
243 NavigateForward,
244
245 SplitHorizontal,
247 SplitVertical,
248 CloseSplit,
249 NextSplit,
250 PrevSplit,
251 IncreaseSplitSize,
252 DecreaseSplitSize,
253 ToggleMaximizeSplit,
254
255 PromptConfirm,
257 PromptConfirmWithText(String),
259 PromptCancel,
260 PromptBackspace,
261 PromptDelete,
262 PromptMoveLeft,
263 PromptMoveRight,
264 PromptMoveStart,
265 PromptMoveEnd,
266 PromptSelectPrev,
267 PromptSelectNext,
268 PromptPageUp,
269 PromptPageDown,
270 PromptAcceptSuggestion,
271 PromptMoveWordLeft,
272 PromptMoveWordRight,
273 PromptDeleteWordForward,
275 PromptDeleteWordBackward,
276 PromptDeleteToLineEnd,
277 PromptCopy,
278 PromptCut,
279 PromptPaste,
280 PromptMoveLeftSelecting,
282 PromptMoveRightSelecting,
283 PromptMoveHomeSelecting,
284 PromptMoveEndSelecting,
285 PromptSelectWordLeft,
286 PromptSelectWordRight,
287 PromptSelectAll,
288
289 FileBrowserToggleHidden,
291
292 PopupSelectNext,
294 PopupSelectPrev,
295 PopupPageUp,
296 PopupPageDown,
297 PopupConfirm,
298 PopupCancel,
299
300 ToggleFileExplorer,
302 ToggleMenuBar,
304 ToggleTabBar,
306 FocusFileExplorer,
307 FocusEditor,
308 FileExplorerUp,
309 FileExplorerDown,
310 FileExplorerPageUp,
311 FileExplorerPageDown,
312 FileExplorerExpand,
313 FileExplorerCollapse,
314 FileExplorerOpen,
315 FileExplorerRefresh,
316 FileExplorerNewFile,
317 FileExplorerNewDirectory,
318 FileExplorerDelete,
319 FileExplorerRename,
320 FileExplorerToggleHidden,
321 FileExplorerToggleGitignored,
322
323 LspCompletion,
325 LspGotoDefinition,
326 LspReferences,
327 LspImplementation,
328 LspRename,
329 LspHover,
330 LspSignatureHelp,
331 LspCodeActions,
332 LspRestart,
333 LspStop,
334 ToggleInlayHints,
335 ToggleMouseHover,
336
337 ToggleLineNumbers,
339 ToggleScrollSync,
340 ToggleMouseCapture,
341 ToggleDebugHighlights, SetBackground,
343 SetBackgroundBlend,
344
345 SetTabSize,
347 SetLineEnding,
348 ToggleIndentationStyle,
349 ToggleTabIndicators,
350 ResetBufferSettings,
351
352 DumpConfig,
354
355 Search,
357 FindInSelection,
358 FindNext,
359 FindPrevious,
360 FindSelectionNext, FindSelectionPrevious, Replace,
363 QueryReplace, MenuActivate, MenuClose, MenuLeft, MenuRight, MenuUp, MenuDown, MenuExecute, MenuOpen(String), SwitchKeybindingMap(String), PluginAction(String),
380
381 LoadPluginFromBuffer,
383
384 OpenSettings, CloseSettings, SettingsSave, SettingsReset, SettingsToggleFocus, SettingsActivate, SettingsSearch, SettingsHelp, SettingsIncrement, SettingsDecrement, OpenTerminal, OpenTerminalRight, OpenTerminalBelow, CloseTerminal, FocusTerminal, TerminalEscape, ToggleKeyboardCapture, TerminalPaste, ShellCommand, ShellCommandReplace, ToUpperCase, ToLowerCase, CalibrateInput, None,
419}
420
421#[cfg(test)]
422mod tests {
423 use super::*;
424
425 #[test]
428 fn when_clause_is_a_roundtrip_for_every_variant() {
429 let variants = [
430 KeyContext::Global,
431 KeyContext::Normal,
432 KeyContext::Prompt,
433 KeyContext::Popup,
434 KeyContext::FileExplorer,
435 KeyContext::Menu,
436 KeyContext::Terminal,
437 KeyContext::Settings,
438 KeyContext::Mode("search-replace-list".into()),
439 KeyContext::Mode(String::new()),
440 ];
441 for ctx in &variants {
442 let clause = ctx.to_when_clause();
443 assert_eq!(
444 KeyContext::from_when_clause(&clause).as_ref(),
445 Some(ctx),
446 "roundtrip failed: {:?} → {:?}",
447 ctx,
448 clause
449 );
450 }
451 }
452
453 #[test]
457 fn from_when_clause_handles_aliases_whitespace_and_rejects_unknown() {
458 assert_eq!(
460 KeyContext::from_when_clause("file_explorer"),
461 Some(KeyContext::FileExplorer)
462 );
463 assert_eq!(
465 KeyContext::from_when_clause(" prompt "),
466 Some(KeyContext::Prompt)
467 );
468 assert_eq!(KeyContext::from_when_clause("nonsense"), None);
470 assert_eq!(KeyContext::from_when_clause("GLOBAL"), None);
471 assert_eq!(KeyContext::from_when_clause(""), None);
472 }
473
474 #[test]
476 fn allows_text_input_iff_normal_or_prompt() {
477 for ctx in [
478 KeyContext::Global,
479 KeyContext::Normal,
480 KeyContext::Prompt,
481 KeyContext::Popup,
482 KeyContext::FileExplorer,
483 KeyContext::Menu,
484 KeyContext::Terminal,
485 KeyContext::Settings,
486 KeyContext::Mode("foo".into()),
487 ] {
488 let expected = matches!(ctx, KeyContext::Normal | KeyContext::Prompt);
489 assert_eq!(
490 ctx.allows_text_input(),
491 expected,
492 "{:?} text-input expectation violated",
493 ctx
494 );
495 }
496 }
497}