1use ratatui::{
2 crossterm::{
3 terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
4 ExecutableCommand,
5 },
6 DefaultTerminal,
7};
8use serde::{Deserialize, Deserializer};
9use std::{io::stdout, process};
10use tracing::error;
11
12use crate::{
13 app::{Message, ScrollAmount},
14 debug_log, explorer, help_modal, input, note_editor,
15 note_editor::state::Operator,
16 note_editor::Direction,
17 outline, splash_modal, theme_selector_modal, vault_selector_modal,
18};
19
20trait ReplaceVar {
21 fn replace_var(&self, variable: &str, content: &str) -> Self;
22}
23
24impl ReplaceVar for String {
25 fn replace_var(&self, variable: &str, content: &str) -> Self {
26 self.replace(variable, content)
27 }
28}
29
30#[derive(Clone, Debug, PartialEq)]
31pub(crate) enum Command {
32 Quit,
33
34 SplashUp,
35 SplashDown,
36 SplashOpen,
37
38 ExplorerUp,
39 ExplorerDown,
40 ExplorerOpen,
41 ExplorerSort,
42 ExplorerToggle,
43 ExplorerNewUntitledNote,
44 ExplorerNewUntitledFolder,
45 ExplorerToggleInputRename,
46 ExplorerToggleOutline,
47 ExplorerSwitchPaneNext,
48 ExplorerSwitchPanePrevious,
49 ExplorerHidePane,
50 ExplorerExpandPane,
51 ExplorerScrollUpOne,
52 ExplorerScrollDownOne,
53 ExplorerScrollUpHalfPage,
54 ExplorerScrollDownHalfPage,
55
56 OutlineUp,
57 OutlineDown,
58 OutlineSelect,
59 OutlineExpand,
60 OutlineToggle,
61 OutlineToggleExplorer,
62 OutlineSwitchPaneNext,
63 OutlineSwitchPanePrevious,
64
65 HelpModalScrollUpOne,
66 HelpModalScrollDownOne,
67 HelpModalScrollUpHalfPage,
68 HelpModalScrollDownHalfPage,
69 HelpModalToggle,
70 HelpModalClose,
71
72 NoteEditorScrollUpOne,
73 NoteEditorScrollDownOne,
74 NoteEditorScrollUpHalfPage,
75 NoteEditorScrollDownHalfPage,
76 NoteEditorSwitchPaneNext,
77 NoteEditorSwitchPanePrevious,
78 NoteEditorToggleExplorer,
79 NoteEditorToggleOutline,
80 NoteEditorCursorUp,
81 NoteEditorCursorDown,
82 NoteEditorScrollToTop,
83 NoteEditorScrollToBottom,
84
85 ExplorerScrollToTop,
86 ExplorerScrollToBottom,
87
88 TabNext,
89 TabPrevious,
90 TabClose,
91
92 NoteEditorExperimentalCursorWordForward,
93 NoteEditorExperimentalCursorWordBackward,
94 NoteEditorExperimentalToggleView,
95 NoteEditorExperimentalSetEditView,
96 NoteEditorExperimentalSetReadView,
97 NoteEditorExperimentalSave,
98 NoteEditorExperimentalExit,
99 NoteEditorExperimentalCursorLeft,
100 NoteEditorExperimentalCursorRight,
101 NoteEditorInsertMode,
102 NoteEditorAppend,
103 NoteEditorReplaceChar,
104 NoteEditorVisualMode,
105 NoteEditorVisualLineMode,
106 NoteEditorCursorLineStart,
107 NoteEditorCursorLineEnd,
108 NoteEditorCursorFirstNonblank,
109 NoteEditorCursorWordEnd,
110 NoteEditorCursorWordForwardBig,
111 NoteEditorCursorWordBackwardBig,
112 NoteEditorCursorWordEndBig,
113 NoteEditorParagraphForward,
114 NoteEditorParagraphBackward,
115 NoteEditorMatchingPair,
116 NoteEditorCursorDocStart,
117 NoteEditorCursorDocEnd,
118 NoteEditorFindForward,
119 NoteEditorFindBackward,
120 NoteEditorTillForward,
121 NoteEditorTillBackward,
122 NoteEditorRepeatFind,
123 NoteEditorRepeatFindReverse,
124 NoteEditorDelete,
125 NoteEditorChange,
126 NoteEditorYankOperator,
127 NoteEditorDeleteUnderCursor,
128 NoteEditorDeleteToLineEnd,
129 NoteEditorChangeToLineEnd,
130 NoteEditorSubstituteChar,
131 NoteEditorPasteAfter,
132 NoteEditorPasteBefore,
133 NoteEditorUndo,
134 NoteEditorRedo,
135
136 VaultSelectorModalUp,
137 VaultSelectorModalDown,
138 VaultSelectorModalClose,
139 VaultSelectorModalOpen,
140 VaultSelectorModalToggle,
141
142 DebugLogToggle,
143 DebugLogClose,
144 DebugLogClear,
145 DebugLogCycleLevel,
146 DebugLogScrollUpOne,
147 DebugLogScrollDownOne,
148 DebugLogScrollUpHalfPage,
149 DebugLogScrollDownHalfPage,
150
151 ThemeSelectorModalUp,
152 ThemeSelectorModalDown,
153 ThemeSelectorModalClose,
154 ThemeSelectorModalOpen,
155 ThemeSelectorModalToggle,
156
157 InputModalWordForward,
158 InputModalWordBackward,
159 InputModalLeft,
160 InputModalRight,
161 InputModalCancel,
162 InputModalAccept,
163 InputModalEditMode,
164
165 Exec(String),
166 Spawn(String),
167}
168
169fn str_to_command(s: &str) -> Option<Command> {
170 match s {
171 "quit" => Some(Command::Quit),
172
173 "splash_up" => Some(Command::SplashUp),
174 "splash_down" => Some(Command::SplashDown),
175 "splash_open" => Some(Command::SplashOpen),
176
177 "explorer_up" => Some(Command::ExplorerUp),
178 "explorer_down" => Some(Command::ExplorerDown),
179 "explorer_open" => Some(Command::ExplorerOpen),
180 "explorer_sort" => Some(Command::ExplorerSort),
181 "explorer_toggle" => Some(Command::ExplorerToggle),
182 "explorer_new_untitled_note" => Some(Command::ExplorerNewUntitledNote),
183 "explorer_new_untitled_folder" => Some(Command::ExplorerNewUntitledFolder),
184 "explorer_toggle_outline" => Some(Command::ExplorerToggleOutline),
185 "explorer_toggle_input_rename" => Some(Command::ExplorerToggleInputRename),
186 "explorer_switch_pane_next" => Some(Command::ExplorerSwitchPaneNext),
187 "explorer_hide_pane" => Some(Command::ExplorerHidePane),
188 "explorer_expand_pane" => Some(Command::ExplorerExpandPane),
189 "explorer_switch_pane_previous" => Some(Command::ExplorerSwitchPanePrevious),
190 "explorer_scroll_up_one" => Some(Command::ExplorerScrollUpOne),
191 "explorer_scroll_down_one" => Some(Command::ExplorerScrollDownOne),
192 "explorer_scroll_up_half_page" => Some(Command::ExplorerScrollUpHalfPage),
193 "explorer_scroll_down_half_page" => Some(Command::ExplorerScrollDownHalfPage),
194
195 "input_modal_word_forward" => Some(Command::InputModalWordForward),
196 "input_modal_word_backward" => Some(Command::InputModalWordBackward),
197 "input_modal_left" => Some(Command::InputModalLeft),
198 "input_modal_right" => Some(Command::InputModalRight),
199 "input_modal_cancel" => Some(Command::InputModalCancel),
200 "input_modal_accept" => Some(Command::InputModalAccept),
201 "input_modal_edit_mode" => Some(Command::InputModalEditMode),
202
203 "outline_up" => Some(Command::OutlineUp),
204 "outline_down" => Some(Command::OutlineDown),
205 "outline_select" => Some(Command::OutlineSelect),
206 "outline_expand" => Some(Command::OutlineExpand),
207 "outline_toggle" => Some(Command::OutlineToggle),
208 "outline_toggle_explorer" => Some(Command::OutlineToggleExplorer),
209 "outline_switch_pane_next" => Some(Command::OutlineSwitchPaneNext),
210 "outline_switch_pane_previous" => Some(Command::OutlineSwitchPanePrevious),
211
212 "help_modal_scroll_up_one" => Some(Command::HelpModalScrollUpOne),
213 "help_modal_scroll_down_one" => Some(Command::HelpModalScrollDownOne),
214 "help_modal_scroll_up_half_page" => Some(Command::HelpModalScrollUpHalfPage),
215 "help_modal_scroll_down_half_page" => Some(Command::HelpModalScrollDownHalfPage),
216 "help_modal_toggle" => Some(Command::HelpModalToggle),
217 "help_modal_close" => Some(Command::HelpModalClose),
218
219 "note_editor_scroll_up_one" => Some(Command::NoteEditorScrollUpOne),
220 "note_editor_scroll_down_one" => Some(Command::NoteEditorScrollDownOne),
221 "note_editor_scroll_up_half_page" => Some(Command::NoteEditorScrollUpHalfPage),
222 "note_editor_scroll_down_half_page" => Some(Command::NoteEditorScrollDownHalfPage),
223 "note_editor_switch_pane_next" => Some(Command::NoteEditorSwitchPaneNext),
224 "note_editor_switch_pane_previous" => Some(Command::NoteEditorSwitchPanePrevious),
225 "note_editor_toggle_explorer" => Some(Command::NoteEditorToggleExplorer),
226 "note_editor_toggle_outline" => Some(Command::NoteEditorToggleOutline),
227 "note_editor_cursor_up" => Some(Command::NoteEditorCursorUp),
228 "note_editor_cursor_down" => Some(Command::NoteEditorCursorDown),
229 "note_editor_scroll_to_top" => Some(Command::NoteEditorScrollToTop),
230 "note_editor_scroll_to_bottom" => Some(Command::NoteEditorScrollToBottom),
231
232 "explorer_scroll_to_top" => Some(Command::ExplorerScrollToTop),
233 "explorer_scroll_to_bottom" => Some(Command::ExplorerScrollToBottom),
234
235 "tab_next" => Some(Command::TabNext),
236 "tab_previous" => Some(Command::TabPrevious),
237 "tab_close" => Some(Command::TabClose),
238
239 "note_editor_experimental_cursor_word_forward" => {
240 Some(Command::NoteEditorExperimentalCursorWordForward)
241 }
242 "note_editor_experimental_cursor_word_backward" => {
243 Some(Command::NoteEditorExperimentalCursorWordBackward)
244 }
245 "note_editor_experimental_set_edit_view" => {
246 Some(Command::NoteEditorExperimentalSetEditView)
247 }
248 "note_editor_experimental_toggle_view" => Some(Command::NoteEditorExperimentalToggleView),
249 "note_editor_experimental_set_read_view" => {
250 Some(Command::NoteEditorExperimentalSetReadView)
251 }
252 "note_editor_experimental_save" => Some(Command::NoteEditorExperimentalSave),
253 "note_editor_experimental_exit" => Some(Command::NoteEditorExperimentalExit),
254 "note_editor_experimental_cursor_left" => Some(Command::NoteEditorExperimentalCursorLeft),
255 "note_editor_experimental_cursor_right" => Some(Command::NoteEditorExperimentalCursorRight),
256 "note_editor_insert_mode" => Some(Command::NoteEditorInsertMode),
257 "note_editor_append" => Some(Command::NoteEditorAppend),
258 "note_editor_replace_char" => Some(Command::NoteEditorReplaceChar),
259 "note_editor_visual_mode" => Some(Command::NoteEditorVisualMode),
260 "note_editor_visual_line_mode" => Some(Command::NoteEditorVisualLineMode),
261 "note_editor_delete" => Some(Command::NoteEditorDelete),
262 "note_editor_change" => Some(Command::NoteEditorChange),
263 "note_editor_yank" => Some(Command::NoteEditorYankOperator),
264 "note_editor_delete_under_cursor" => Some(Command::NoteEditorDeleteUnderCursor),
265 "note_editor_delete_to_line_end" => Some(Command::NoteEditorDeleteToLineEnd),
266 "note_editor_change_to_line_end" => Some(Command::NoteEditorChangeToLineEnd),
267 "note_editor_substitute_char" => Some(Command::NoteEditorSubstituteChar),
268 "note_editor_paste_after" => Some(Command::NoteEditorPasteAfter),
269 "note_editor_paste_before" => Some(Command::NoteEditorPasteBefore),
270 "note_editor_undo" => Some(Command::NoteEditorUndo),
271 "note_editor_redo" => Some(Command::NoteEditorRedo),
272 "note_editor_cursor_line_start" => Some(Command::NoteEditorCursorLineStart),
273 "note_editor_cursor_line_end" => Some(Command::NoteEditorCursorLineEnd),
274 "note_editor_cursor_first_non_blank" => Some(Command::NoteEditorCursorFirstNonblank),
275 "note_editor_cursor_word_end" => Some(Command::NoteEditorCursorWordEnd),
276 "note_editor_cursor_word_forward_big" => Some(Command::NoteEditorCursorWordForwardBig),
277 "note_editor_cursor_word_backward_big" => Some(Command::NoteEditorCursorWordBackwardBig),
278 "note_editor_cursor_word_end_big" => Some(Command::NoteEditorCursorWordEndBig),
279 "note_editor_paragraph_forward" => Some(Command::NoteEditorParagraphForward),
280 "note_editor_paragraph_backward" => Some(Command::NoteEditorParagraphBackward),
281 "note_editor_matching_pair" => Some(Command::NoteEditorMatchingPair),
282 "note_editor_cursor_doc_start" => Some(Command::NoteEditorCursorDocStart),
283 "note_editor_cursor_doc_end" => Some(Command::NoteEditorCursorDocEnd),
284 "note_editor_find_forward" => Some(Command::NoteEditorFindForward),
285 "note_editor_find_backward" => Some(Command::NoteEditorFindBackward),
286 "note_editor_till_forward" => Some(Command::NoteEditorTillForward),
287 "note_editor_till_backward" => Some(Command::NoteEditorTillBackward),
288 "note_editor_repeat_find" => Some(Command::NoteEditorRepeatFind),
289 "note_editor_repeat_find_reverse" => Some(Command::NoteEditorRepeatFindReverse),
290
291 "vault_selector_modal_up" => Some(Command::VaultSelectorModalUp),
292 "vault_selector_modal_down" => Some(Command::VaultSelectorModalDown),
293 "vault_selector_modal_close" => Some(Command::VaultSelectorModalClose),
294 "vault_selector_modal_open" => Some(Command::VaultSelectorModalOpen),
295 "vault_selector_modal_toggle" => Some(Command::VaultSelectorModalToggle),
296
297 "debug_log_toggle" => Some(Command::DebugLogToggle),
298 "debug_log_close" => Some(Command::DebugLogClose),
299 "debug_log_clear" => Some(Command::DebugLogClear),
300 "debug_log_cycle_level" => Some(Command::DebugLogCycleLevel),
301 "debug_log_scroll_up_one" => Some(Command::DebugLogScrollUpOne),
302 "debug_log_scroll_down_one" => Some(Command::DebugLogScrollDownOne),
303 "debug_log_scroll_up_half_page" => Some(Command::DebugLogScrollUpHalfPage),
304 "debug_log_scroll_down_half_page" => Some(Command::DebugLogScrollDownHalfPage),
305
306 "theme_selector_modal_up" => Some(Command::ThemeSelectorModalUp),
307 "theme_selector_modal_down" => Some(Command::ThemeSelectorModalDown),
308 "theme_selector_modal_close" => Some(Command::ThemeSelectorModalClose),
309 "theme_selector_modal_open" => Some(Command::ThemeSelectorModalOpen),
310 "theme_selector_modal_toggle" => Some(Command::ThemeSelectorModalToggle),
311
312 "note_editor_experimental_set_edit_mode" => {
315 Some(Command::NoteEditorExperimentalSetEditView)
316 }
317 "note_editor_experimental_set_read_mode" => {
319 Some(Command::NoteEditorExperimentalSetReadView)
320 }
321 "note_editor_experimental_exit_mode" => Some(Command::NoteEditorExperimentalExit),
323 _ => None,
324 }
325}
326
327impl<'de> Deserialize<'de> for Command {
328 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
329 where
330 D: Deserializer<'de>,
331 {
332 let s = String::deserialize(deserializer)?;
333
334 if let Some(command) = s
335 .strip_prefix("exec:")
336 .map(|command| Command::Exec(command.to_string()))
337 .or(s
338 .strip_prefix("spawn:")
339 .map(|command| Command::Spawn(command.to_string())))
340 {
341 return Ok(command);
342 }
343
344 str_to_command(&s).ok_or(serde::de::Error::custom(format!(
345 "{s} is not a valid command"
346 )))
347 }
348}
349
350impl From<Command> for Message<'_> {
351 fn from(value: Command) -> Self {
352 match value {
353 Command::Quit => Message::Quit,
354
355 Command::SplashUp => Message::Splash(splash_modal::Message::Up),
356 Command::SplashDown => Message::Splash(splash_modal::Message::Down),
357 Command::SplashOpen => Message::Splash(splash_modal::Message::Open),
358
359 Command::ExplorerUp => Message::Explorer(explorer::Message::Up),
360 Command::ExplorerDown => Message::Explorer(explorer::Message::Down),
361 Command::ExplorerOpen => Message::Explorer(explorer::Message::Select),
362 Command::ExplorerSort => Message::Explorer(explorer::Message::Sort),
363 Command::ExplorerToggle => Message::Explorer(explorer::Message::Toggle),
364 Command::ExplorerToggleOutline => Message::Explorer(explorer::Message::ToggleOutline),
365 Command::ExplorerToggleInputRename => {
366 Message::Explorer(explorer::Message::ToggleInputRename)
367 }
368 Command::ExplorerHidePane => Message::Explorer(explorer::Message::HidePane),
369 Command::ExplorerExpandPane => Message::Explorer(explorer::Message::ExpandPane),
370 Command::ExplorerSwitchPaneNext => Message::Explorer(explorer::Message::SwitchPaneNext),
371 Command::ExplorerSwitchPanePrevious => {
372 Message::Explorer(explorer::Message::SwitchPanePrevious)
373 }
374 Command::ExplorerScrollUpOne => {
375 Message::Explorer(explorer::Message::ScrollUp(ScrollAmount::One))
376 }
377 Command::ExplorerScrollDownOne => {
378 Message::Explorer(explorer::Message::ScrollDown(ScrollAmount::One))
379 }
380 Command::ExplorerScrollUpHalfPage => {
381 Message::Explorer(explorer::Message::ScrollUp(ScrollAmount::HalfPage))
382 }
383 Command::ExplorerScrollDownHalfPage => {
384 Message::Explorer(explorer::Message::ScrollDown(ScrollAmount::HalfPage))
385 }
386 Command::ExplorerNewUntitledNote => Message::CreateUntitledNote,
387 Command::ExplorerNewUntitledFolder => Message::CreateUntitledFolder,
388
389 Command::InputModalEditMode => Message::Input(input::Message::EditMode),
390 Command::InputModalAccept => Message::Input(input::Message::Accept),
391 Command::InputModalCancel => Message::Input(input::Message::Cancel),
392 Command::InputModalLeft => Message::Input(input::Message::CursorLeft),
393 Command::InputModalRight => Message::Input(input::Message::CursorRight),
394 Command::InputModalWordForward => Message::Input(input::Message::CursorWordForward),
395 Command::InputModalWordBackward => Message::Input(input::Message::CursorWordBackward),
396
397 Command::OutlineUp => Message::Outline(outline::Message::Up),
398 Command::OutlineDown => Message::Outline(outline::Message::Down),
399 Command::OutlineSelect => Message::Outline(outline::Message::Select),
400 Command::OutlineExpand => Message::Outline(outline::Message::Expand),
401 Command::OutlineToggle => Message::Outline(outline::Message::Toggle),
402 Command::OutlineToggleExplorer => Message::Outline(outline::Message::ToggleExplorer),
403 Command::OutlineSwitchPaneNext => Message::Outline(outline::Message::SwitchPaneNext),
404 Command::OutlineSwitchPanePrevious => {
405 Message::Outline(outline::Message::SwitchPanePrevious)
406 }
407
408 Command::HelpModalScrollUpOne => {
409 Message::HelpModal(help_modal::Message::ScrollUp(ScrollAmount::One))
410 }
411 Command::HelpModalScrollDownOne => {
412 Message::HelpModal(help_modal::Message::ScrollDown(ScrollAmount::One))
413 }
414 Command::HelpModalScrollUpHalfPage => {
415 Message::HelpModal(help_modal::Message::ScrollUp(ScrollAmount::HalfPage))
416 }
417 Command::HelpModalScrollDownHalfPage => {
418 Message::HelpModal(help_modal::Message::ScrollDown(ScrollAmount::HalfPage))
419 }
420 Command::HelpModalToggle => Message::HelpModal(help_modal::Message::Toggle),
421 Command::HelpModalClose => Message::HelpModal(help_modal::Message::Close),
422
423 Command::NoteEditorScrollUpOne => {
424 Message::NoteEditor(note_editor::Message::ScrollUp(ScrollAmount::One))
425 }
426 Command::NoteEditorScrollDownOne => {
427 Message::NoteEditor(note_editor::Message::ScrollDown(ScrollAmount::One))
428 }
429 Command::NoteEditorScrollUpHalfPage => {
430 Message::NoteEditor(note_editor::Message::ScrollUp(ScrollAmount::HalfPage))
431 }
432 Command::NoteEditorScrollDownHalfPage => {
433 Message::NoteEditor(note_editor::Message::ScrollDown(ScrollAmount::HalfPage))
434 }
435 Command::NoteEditorSwitchPaneNext => {
436 Message::NoteEditor(note_editor::Message::SwitchPaneNext)
437 }
438 Command::NoteEditorSwitchPanePrevious => {
439 Message::NoteEditor(note_editor::Message::SwitchPanePrevious)
440 }
441 Command::NoteEditorCursorUp => Message::NoteEditor(note_editor::Message::CursorUp),
442 Command::NoteEditorCursorDown => Message::NoteEditor(note_editor::Message::CursorDown),
443 Command::NoteEditorScrollToTop => {
444 Message::NoteEditor(note_editor::Message::ScrollToTop)
445 }
446 Command::NoteEditorScrollToBottom => {
447 Message::NoteEditor(note_editor::Message::ScrollToBottom)
448 }
449 Command::ExplorerScrollToTop => Message::Explorer(explorer::Message::ScrollToTop),
450 Command::ExplorerScrollToBottom => Message::Explorer(explorer::Message::ScrollToBottom),
451
452 Command::TabNext => Message::TabNext,
453 Command::TabPrevious => Message::TabPrevious,
454 Command::TabClose => Message::CloseTab,
455 Command::NoteEditorToggleExplorer => {
456 Message::NoteEditor(note_editor::Message::ToggleExplorer)
457 }
458 Command::NoteEditorToggleOutline => {
459 Message::NoteEditor(note_editor::Message::ToggleOutline)
460 }
461
462 Command::NoteEditorExperimentalToggleView => {
464 Message::NoteEditor(note_editor::Message::ToggleView)
465 }
466 Command::NoteEditorExperimentalSetEditView => {
467 Message::NoteEditor(note_editor::Message::EditView)
468 }
469 Command::NoteEditorExperimentalSetReadView => {
470 Message::NoteEditor(note_editor::Message::ReadView)
471 }
472 Command::NoteEditorExperimentalSave => Message::NoteEditor(note_editor::Message::Save),
473 Command::NoteEditorExperimentalExit => Message::NoteEditor(note_editor::Message::Exit),
474 Command::NoteEditorExperimentalCursorWordForward => {
475 Message::NoteEditor(note_editor::Message::CursorWordForward)
476 }
477 Command::NoteEditorExperimentalCursorWordBackward => {
478 Message::NoteEditor(note_editor::Message::CursorWordBackward)
479 }
480 Command::NoteEditorExperimentalCursorLeft => {
481 Message::NoteEditor(note_editor::Message::CursorLeft)
482 }
483 Command::NoteEditorExperimentalCursorRight => {
484 Message::NoteEditor(note_editor::Message::CursorRight)
485 }
486 Command::NoteEditorInsertMode => Message::NoteEditor(note_editor::Message::InsertMode),
487 Command::NoteEditorAppend => Message::NoteEditor(note_editor::Message::Append),
488 Command::NoteEditorReplaceChar => {
489 Message::NoteEditor(note_editor::Message::ReplaceChar)
490 }
491 Command::NoteEditorVisualMode => Message::NoteEditor(note_editor::Message::VisualMode),
492 Command::NoteEditorVisualLineMode => {
493 Message::NoteEditor(note_editor::Message::VisualLineMode)
494 }
495 Command::NoteEditorDelete => {
496 Message::NoteEditor(note_editor::Message::Operator(Operator::Delete))
497 }
498 Command::NoteEditorChange => {
499 Message::NoteEditor(note_editor::Message::Operator(Operator::Change))
500 }
501 Command::NoteEditorYankOperator => {
502 Message::NoteEditor(note_editor::Message::Operator(Operator::Yank))
503 }
504 Command::NoteEditorDeleteUnderCursor => {
505 Message::NoteEditor(note_editor::Message::DeleteUnderCursor)
506 }
507 Command::NoteEditorDeleteToLineEnd => {
508 Message::NoteEditor(note_editor::Message::DeleteToLineEnd)
509 }
510 Command::NoteEditorChangeToLineEnd => {
511 Message::NoteEditor(note_editor::Message::ChangeToLineEnd)
512 }
513 Command::NoteEditorSubstituteChar => {
514 Message::NoteEditor(note_editor::Message::SubstituteChar)
515 }
516 Command::NoteEditorPasteAfter => Message::NoteEditor(note_editor::Message::PasteAfter),
517 Command::NoteEditorPasteBefore => {
518 Message::NoteEditor(note_editor::Message::PasteBefore)
519 }
520 Command::NoteEditorUndo => Message::NoteEditor(note_editor::Message::Undo),
521 Command::NoteEditorRedo => Message::NoteEditor(note_editor::Message::Redo),
522 Command::NoteEditorCursorLineStart => {
523 Message::NoteEditor(note_editor::Message::CursorLineStart)
524 }
525 Command::NoteEditorCursorLineEnd => {
526 Message::NoteEditor(note_editor::Message::CursorLineEnd)
527 }
528 Command::NoteEditorCursorFirstNonblank => {
529 Message::NoteEditor(note_editor::Message::CursorFirstNonblank)
530 }
531 Command::NoteEditorCursorWordEnd => {
532 Message::NoteEditor(note_editor::Message::CursorWordEnd)
533 }
534 Command::NoteEditorCursorWordForwardBig => {
535 Message::NoteEditor(note_editor::Message::CursorWordForwardBig)
536 }
537 Command::NoteEditorCursorWordBackwardBig => {
538 Message::NoteEditor(note_editor::Message::CursorWordBackwardBig)
539 }
540 Command::NoteEditorCursorWordEndBig => {
541 Message::NoteEditor(note_editor::Message::CursorWordEndBig)
542 }
543 Command::NoteEditorParagraphForward => {
544 Message::NoteEditor(note_editor::Message::ParagraphForward)
545 }
546 Command::NoteEditorParagraphBackward => {
547 Message::NoteEditor(note_editor::Message::ParagraphBackward)
548 }
549 Command::NoteEditorMatchingPair => {
550 Message::NoteEditor(note_editor::Message::MatchingPair)
551 }
552 Command::NoteEditorCursorDocStart => {
553 Message::NoteEditor(note_editor::Message::CursorDocStart)
554 }
555 Command::NoteEditorCursorDocEnd => {
556 Message::NoteEditor(note_editor::Message::CursorDocEnd)
557 }
558 Command::NoteEditorFindForward => Message::NoteEditor(note_editor::Message::FindChar {
559 direction: Direction::Forward,
560 till: false,
561 }),
562 Command::NoteEditorFindBackward => {
563 Message::NoteEditor(note_editor::Message::FindChar {
564 direction: Direction::Backward,
565 till: false,
566 })
567 }
568 Command::NoteEditorTillForward => Message::NoteEditor(note_editor::Message::FindChar {
569 direction: Direction::Forward,
570 till: true,
571 }),
572 Command::NoteEditorTillBackward => {
573 Message::NoteEditor(note_editor::Message::FindChar {
574 direction: Direction::Backward,
575 till: true,
576 })
577 }
578 Command::NoteEditorRepeatFind => {
579 Message::NoteEditor(note_editor::Message::RepeatFind { reverse: false })
580 }
581 Command::NoteEditorRepeatFindReverse => {
582 Message::NoteEditor(note_editor::Message::RepeatFind { reverse: true })
583 }
584
585 Command::VaultSelectorModalClose => {
586 Message::VaultSelectorModal(vault_selector_modal::Message::Close)
587 }
588 Command::VaultSelectorModalToggle => {
589 Message::VaultSelectorModal(vault_selector_modal::Message::Toggle)
590 }
591 Command::VaultSelectorModalUp => {
592 Message::VaultSelectorModal(vault_selector_modal::Message::Up)
593 }
594 Command::VaultSelectorModalDown => {
595 Message::VaultSelectorModal(vault_selector_modal::Message::Down)
596 }
597 Command::VaultSelectorModalOpen => {
598 Message::VaultSelectorModal(vault_selector_modal::Message::Select)
599 }
600
601 Command::DebugLogToggle => Message::DebugLog(debug_log::Message::Toggle),
602 Command::DebugLogClose => Message::DebugLog(debug_log::Message::Close),
603 Command::DebugLogClear => Message::DebugLog(debug_log::Message::Clear),
604 Command::DebugLogCycleLevel => Message::DebugLog(debug_log::Message::CycleLevel),
605 Command::DebugLogScrollUpOne => {
606 Message::DebugLog(debug_log::Message::ScrollUp(ScrollAmount::One))
607 }
608 Command::DebugLogScrollDownOne => {
609 Message::DebugLog(debug_log::Message::ScrollDown(ScrollAmount::One))
610 }
611 Command::DebugLogScrollUpHalfPage => {
612 Message::DebugLog(debug_log::Message::ScrollUp(ScrollAmount::HalfPage))
613 }
614 Command::DebugLogScrollDownHalfPage => {
615 Message::DebugLog(debug_log::Message::ScrollDown(ScrollAmount::HalfPage))
616 }
617 Command::ThemeSelectorModalClose => {
618 Message::ThemeSelectorModal(theme_selector_modal::Message::Close)
619 }
620 Command::ThemeSelectorModalToggle => {
621 Message::ThemeSelectorModal(theme_selector_modal::Message::Toggle)
622 }
623 Command::ThemeSelectorModalUp => {
624 Message::ThemeSelectorModal(theme_selector_modal::Message::Up)
625 }
626 Command::ThemeSelectorModalDown => {
627 Message::ThemeSelectorModal(theme_selector_modal::Message::Down)
628 }
629 Command::ThemeSelectorModalOpen => {
630 Message::ThemeSelectorModal(theme_selector_modal::Message::Select)
631 }
632
633 Command::Exec(command) => Message::Exec(command),
634 Command::Spawn(command) => Message::Spawn(command),
635 }
636 }
637}
638
639pub fn run_command<'a>(
640 command: String,
641 vault_name: &str,
642 note_name: &str,
643 note_path: &str,
644 mut callback: impl FnMut(&str, &[&str]) -> Option<Message<'a>>,
645) -> Option<Message<'a>> {
646 let expanded = command
647 .replace_var("%vault", vault_name)
648 .replace_var("%note_path", note_path)
650 .replace_var("%note", note_name);
651
652 let args = expanded.split_whitespace().collect::<Vec<_>>();
653
654 match args.as_slice() {
655 [command, args @ ..] => callback(command, args),
656 [] => None,
657 }
658}
659
660pub fn sync_command<'a>(
661 terminal: &mut DefaultTerminal,
662 command: String,
663 vault_name: &str,
664 note_name: &str,
665 note_path: &str,
666) -> Option<Message<'a>> {
667 fn enter_alternate_screen(terminal: &mut DefaultTerminal) -> Result<(), std::io::Error> {
668 disable_raw_mode()?;
669 stdout().execute(LeaveAlternateScreen)?;
670 stdout().execute(EnterAlternateScreen)?;
671 enable_raw_mode()?;
672 terminal.clear()
673 }
674
675 run_command(
676 command,
677 vault_name,
678 note_name,
679 note_path,
680 |command, args| {
681 if let Err(error) = process::Command::new(command).arg(args.join(" ")).status() {
682 error!(?error, command, "exec command failed");
683 return None;
684 }
685 enter_alternate_screen(terminal)
686 .map(|_| Message::Explorer(explorer::Message::Select))
687 .ok()
688 },
689 )
690}
691
692pub fn spawn_command<'a>(
693 command: String,
694 vault_name: &str,
695 note_name: &str,
696 note_path: &str,
697) -> Option<Message<'a>> {
698 run_command(
699 command,
700 vault_name,
701 note_name,
702 note_path,
703 |command, args| {
704 if let Err(error) = process::Command::new(command).arg(args.join(" ")).spawn() {
705 error!(?error, command, "spawn command failed");
706 }
707 None
708 },
709 )
710}