Skip to main content

novem_tui/
cmd.rs

1#![allow(clippy::to_string_trait_impl)]
2// TODO: rewrite ToString to Display, or macro! it
3
4use std::str::FromStr;
5
6#[derive(Clone, Debug, PartialEq)]
7pub enum UICmd {
8    Noop,
9    Repaint,
10    Config(UIConfig),
11    Content(UIContent),
12    Help(UIHelp),
13    Focus(UIFocus),
14    History(UIHistory),
15    Input(UIInput),
16    Log(UILog),
17    Navigate(UINav),
18    Search(UISearch),
19    Selection(UISelection),
20    Tree(UITree),
21    Quit,
22    Restart,
23}
24
25#[derive(Clone, Debug, PartialEq)]
26pub enum UIConfig {
27    Edit,
28    NewProfile,
29    SwitchProfile,
30}
31
32#[derive(Clone, Debug, PartialEq)]
33pub enum UIContent {
34    Focus,
35    Clear,
36}
37
38#[derive(Clone, Debug, PartialEq)]
39pub enum UIFocus {
40    Next,
41    Prev,
42}
43
44#[derive(Clone, Debug, PartialEq)]
45pub enum UIInput {
46    Abort,
47    Append,
48    Backspace,
49    Select,
50    MoveCursorLeft,
51    MoveCursorRight,
52    MoveCursorWordLeft,
53    MoveCursorWordRight,
54    MoveCursorStart,
55    MoveCursorEnd,
56    DeleteWordBackward,
57    DeleteChar,
58    DeleteCharForward,
59    KillLine,
60}
61
62#[derive(Clone, Debug, PartialEq)]
63pub enum UILog {
64    CycleTimeFmt,
65    Focus,
66    Toggle,
67}
68
69#[derive(Clone, Debug, PartialEq)]
70pub enum UITree {
71    Focus,
72    Toggle,
73    ToggleSystem,
74}
75
76#[derive(Clone, Debug, PartialEq)]
77pub enum UIHelp {
78    Show,
79}
80
81#[derive(Clone, Debug, PartialEq)]
82pub enum UIHistory {
83    Show,
84    Close,
85    SelectRevision,
86    RestoreRevision,
87}
88
89#[derive(Clone, Debug, PartialEq)]
90pub enum UINav {
91    Up,
92    Down,
93    In,
94    Out,
95    First,
96    Last,
97    PageUp,
98    PageDown,
99    MouseClick,
100    MouseScrollUp,
101    MouseScrollDown,
102}
103
104#[derive(Clone, Debug, PartialEq)]
105pub enum UISearch {
106    Start,
107    Next,
108    Prev,
109}
110
111#[derive(Clone, Debug, PartialEq)]
112pub enum UISelection {
113    Abort,
114    Copy,
115    Create,
116    Delete,
117    Edit,
118    Options,
119    Refresh,
120    Rename,
121    Toggle,
122    Mail(MailAction),
123    View(ViewOpenType),
124}
125
126#[derive(Clone, Debug, PartialEq)]
127pub enum MailAction {
128    Send,
129    Test,
130}
131
132#[derive(Clone, Debug, PartialEq)]
133pub enum ViewOpenType {
134    Browser,
135    Ansi,
136    Text,
137}
138
139fn parse_arg<T>(cmd: &str, arg: Option<&str>) -> Result<T, String>
140where
141    T: FromStr<Err = String>,
142{
143    arg.ok_or(format!("Missing argument to {}", cmd))?
144        .parse::<T>()
145}
146
147impl FromStr for UICmd {
148    type Err = String;
149
150    fn from_str(s: &str) -> Result<Self, Self::Err> {
151        let mut parts = s.splitn(2, "::");
152        let cmd = parts.next().ok_or("Empty command")?;
153        let arg = parts.next();
154
155        Ok(match cmd {
156            "quit" => UICmd::Quit,
157            "restart" => UICmd::Restart,
158            "config" => UICmd::Config(parse_arg(cmd, arg)?),
159            "content" => UICmd::Content(parse_arg(cmd, arg)?),
160            "help" => UICmd::Help(parse_arg(cmd, arg)?),
161            "focus" => UICmd::Focus(parse_arg(cmd, arg)?),
162            "history" => UICmd::History(parse_arg(cmd, arg)?),
163            "input" => UICmd::Input(parse_arg(cmd, arg)?),
164            "log" => UICmd::Log(parse_arg(cmd, arg)?),
165            "navigate" => UICmd::Navigate(parse_arg(cmd, arg)?),
166            "search" => UICmd::Search(parse_arg(cmd, arg)?),
167            "selection" => UICmd::Selection(parse_arg(cmd, arg)?),
168            "tree" => UICmd::Tree(parse_arg(cmd, arg)?),
169            _ => return Err(format!("Unknown command: {}", cmd)),
170        })
171    }
172}
173
174impl FromStr for UIConfig {
175    type Err = String;
176
177    fn from_str(s: &str) -> Result<Self, Self::Err> {
178        Ok(match s {
179            "edit" => UIConfig::Edit,
180            "newProfile" => UIConfig::NewProfile,
181            "switchProfile" => UIConfig::SwitchProfile,
182            _ => return Err(format!("Unknown config action: {}", s)),
183        })
184    }
185}
186
187impl FromStr for UIContent {
188    type Err = String;
189
190    fn from_str(s: &str) -> Result<Self, Self::Err> {
191        Ok(match s {
192            "clear" => UIContent::Clear,
193            "focus" => UIContent::Focus,
194            _ => return Err(format!("Unknown content action: {}", s)),
195        })
196    }
197}
198
199impl FromStr for UIFocus {
200    type Err = String;
201
202    fn from_str(s: &str) -> Result<Self, Self::Err> {
203        Ok(match s {
204            "next" => UIFocus::Next,
205            "prev" => UIFocus::Prev,
206            _ => return Err(format!("Unknown content action: {}", s)),
207        })
208    }
209}
210
211impl FromStr for UILog {
212    type Err = String;
213
214    fn from_str(s: &str) -> Result<Self, Self::Err> {
215        Ok(match s {
216            "cycle_time_fmt" => UILog::CycleTimeFmt,
217            "focus" => UILog::Focus,
218            "toggle" => UILog::Toggle,
219            _ => return Err(format!("Unknown log action: {}", s)),
220        })
221    }
222}
223
224impl FromStr for UITree {
225    type Err = String;
226
227    fn from_str(s: &str) -> Result<Self, Self::Err> {
228        Ok(match s {
229            "focus" => UITree::Focus,
230            "toggle" => UITree::Toggle,
231            "toggleSystem" => UITree::ToggleSystem,
232            _ => return Err(format!("Unknown tree action: {}", s)),
233        })
234    }
235}
236
237impl FromStr for UIHelp {
238    type Err = String;
239
240    fn from_str(s: &str) -> Result<Self, Self::Err> {
241        Ok(match s {
242            "show" => UIHelp::Show,
243            _ => return Err(format!("Unknown navigation action: {}", s)),
244        })
245    }
246}
247
248impl FromStr for UIHistory {
249    type Err = String;
250
251    fn from_str(s: &str) -> Result<Self, Self::Err> {
252        Ok(match s {
253            "show" => UIHistory::Show,
254            "close" => UIHistory::Close,
255            "selectRevision" => UIHistory::SelectRevision,
256            "restoreRevision" => UIHistory::RestoreRevision,
257            _ => return Err(format!("Unknown history action: {}", s)),
258        })
259    }
260}
261
262impl FromStr for UINav {
263    type Err = String;
264
265    fn from_str(s: &str) -> Result<Self, Self::Err> {
266        Ok(match s {
267            "up" => UINav::Up,
268            "down" => UINav::Down,
269            "in" => UINav::In,
270            "out" => UINav::Out,
271            "first" => UINav::First,
272            "last" => UINav::Last,
273            "pageUp" => UINav::PageUp,
274            "pageDown" => UINav::PageDown,
275            "mouseClick" => UINav::MouseClick,
276            "mouseScrollUp" => UINav::MouseScrollUp,
277            "mouseScrollDown" => UINav::MouseScrollDown,
278            _ => return Err(format!("Unknown navigation action: {}", s)),
279        })
280    }
281}
282
283impl FromStr for UIInput {
284    type Err = String;
285
286    fn from_str(s: &str) -> Result<Self, Self::Err> {
287        Ok(match s {
288            "abort" => UIInput::Abort,
289            "append" => UIInput::Append,
290            "backspace" => UIInput::Backspace,
291            "select" => UIInput::Select,
292            "cursor_left" => UIInput::MoveCursorLeft,
293            "cursor_right" => UIInput::MoveCursorRight,
294            "cursor_word_left" => UIInput::MoveCursorWordLeft,
295            "cursor_word_right" => UIInput::MoveCursorWordRight,
296            "cursor_start" => UIInput::MoveCursorStart,
297            "cursor_end" => UIInput::MoveCursorEnd,
298            "delete_word_backward" => UIInput::DeleteWordBackward,
299            "delete_char" => UIInput::DeleteChar,
300            "delete_char_forward" => UIInput::DeleteCharForward,
301            "kill_line" => UIInput::KillLine,
302            _ => return Err(format!("Unknown input action: {}", s)),
303        })
304    }
305}
306
307impl FromStr for UISearch {
308    type Err = String;
309
310    fn from_str(s: &str) -> Result<Self, Self::Err> {
311        Ok(match s {
312            "start" => UISearch::Start,
313            "next" => UISearch::Next,
314            "prev" => UISearch::Prev,
315            _ => return Err(format!("Unknown search action: {}", s)),
316        })
317    }
318}
319
320impl FromStr for UISelection {
321    type Err = String;
322
323    fn from_str(s: &str) -> Result<Self, Self::Err> {
324        let mut parts = s.splitn(2, "::");
325        let cmd = parts.next().ok_or("Empty command")?;
326        let arg = parts.next();
327
328        Ok(match cmd {
329            "abort" => UISelection::Abort,
330            "copy" => UISelection::Copy,
331            "toggle" => UISelection::Toggle,
332            "create" => UISelection::Create,
333            "delete" => UISelection::Delete,
334            "refresh" => UISelection::Refresh,
335            "options" => UISelection::Options,
336            "rename" => UISelection::Rename,
337            "edit" => UISelection::Edit,
338            "mail" => UISelection::Mail(parse_arg(cmd, arg)?),
339            "view" => UISelection::View(parse_arg(cmd, arg)?),
340            _ => return Err(format!("Unknown selection action: {}", cmd)),
341        })
342    }
343}
344
345impl FromStr for MailAction {
346    type Err = String;
347
348    fn from_str(s: &str) -> Result<Self, Self::Err> {
349        Ok(match s {
350            "send" => MailAction::Send,
351            "test" => MailAction::Test,
352            _ => return Err(format!("Unknown mail action: {}", s)),
353        })
354    }
355}
356
357impl FromStr for ViewOpenType {
358    type Err = String;
359
360    fn from_str(s: &str) -> Result<Self, Self::Err> {
361        Ok(match s {
362            "browser" => ViewOpenType::Browser,
363            "ansi" => ViewOpenType::Ansi,
364            "text" => ViewOpenType::Text,
365            _ => return Err(format!("Unknown open type: {}", s)),
366        })
367    }
368}
369
370impl ToString for UICmd {
371    fn to_string(&self) -> String {
372        match self {
373            UICmd::Quit => "quit".to_string(),
374            UICmd::Restart => "restart".to_string(),
375            UICmd::Config(action) => format!("config::{}", action.to_string()),
376            UICmd::Content(action) => format!("content::{}", action.to_string()),
377            UICmd::Help(action) => format!("help::{}", action.to_string()),
378            UICmd::Focus(action) => format!("focus::{}", action.to_string()),
379            UICmd::Input(action) => format!("input::{}", action.to_string()),
380            UICmd::Log(action) => format!("log::{}", action.to_string()),
381            UICmd::Navigate(action) => format!("navigate::{}", action.to_string()),
382            UICmd::Search(action) => format!("search::{}", action.to_string()),
383            UICmd::Selection(action) => format!("selection::{}", action.to_string()),
384            UICmd::Tree(action) => format!("tree::{}", action.to_string()),
385            _ => "noop".to_string(),
386        }
387    }
388}
389
390impl ToString for UIConfig {
391    fn to_string(&self) -> String {
392        match self {
393            UIConfig::Edit => "edit".to_string(),
394            UIConfig::NewProfile => "newProfile".to_string(),
395            UIConfig::SwitchProfile => "switchProfile".to_string(),
396        }
397    }
398}
399
400impl ToString for UIContent {
401    fn to_string(&self) -> String {
402        match self {
403            UIContent::Focus => "focus".to_string(),
404            UIContent::Clear => "clear".to_string(),
405        }
406    }
407}
408
409impl ToString for UIFocus {
410    fn to_string(&self) -> String {
411        match self {
412            UIFocus::Next => "next".to_string(),
413            UIFocus::Prev => "prev".to_string(),
414        }
415    }
416}
417
418impl ToString for UILog {
419    fn to_string(&self) -> String {
420        match self {
421            UILog::CycleTimeFmt => "cycle_time_fmt".to_string(),
422            UILog::Focus => "focus".to_string(),
423            UILog::Toggle => "toggle".to_string(),
424        }
425    }
426}
427
428impl ToString for UITree {
429    fn to_string(&self) -> String {
430        match self {
431            UITree::Focus => "focus".to_string(),
432            UITree::Toggle => "toggle".to_string(),
433            UITree::ToggleSystem => "toggleSystem".to_string(),
434        }
435    }
436}
437
438impl ToString for UIHelp {
439    fn to_string(&self) -> String {
440        match self {
441            UIHelp::Show => "show".to_string(),
442        }
443    }
444}
445
446impl ToString for UINav {
447    fn to_string(&self) -> String {
448        match self {
449            UINav::Up => "up".to_string(),
450            UINav::Down => "down".to_string(),
451            UINav::In => "in".to_string(),
452            UINav::Out => "out".to_string(),
453            UINav::First => "first".to_string(),
454            UINav::Last => "last".to_string(),
455            UINav::PageUp => "pageUp".to_string(),
456            UINav::PageDown => "pageDown".to_string(),
457            UINav::MouseClick => "mouseClick".to_string(),
458            UINav::MouseScrollUp => "mouseScrollUp".to_string(),
459            UINav::MouseScrollDown => "mouseScrollDown".to_string(),
460        }
461    }
462}
463
464impl ToString for UIInput {
465    fn to_string(&self) -> String {
466        match self {
467            UIInput::Abort => "abort".to_string(),
468            UIInput::Append => "append".to_string(),
469            UIInput::Backspace => "backspace".to_string(),
470            UIInput::Select => "select".to_string(),
471            UIInput::MoveCursorLeft => "cursor_left".to_string(),
472            UIInput::MoveCursorRight => "cursor_right".to_string(),
473            UIInput::MoveCursorWordLeft => "cursor_word_left".to_string(),
474            UIInput::MoveCursorWordRight => "cursor_word_right".to_string(),
475            UIInput::MoveCursorStart => "cursor_start".to_string(),
476            UIInput::MoveCursorEnd => "cursor_end".to_string(),
477            UIInput::DeleteWordBackward => "delete_word_backward".to_string(),
478            UIInput::DeleteChar => "delete_char".to_string(),
479            UIInput::DeleteCharForward => "delete_char_forward".to_string(),
480            UIInput::KillLine => "kill_line".to_string(),
481        }
482    }
483}
484
485impl ToString for UISearch {
486    fn to_string(&self) -> String {
487        match self {
488            UISearch::Start => "start".to_string(),
489            UISearch::Next => "next".to_string(),
490            UISearch::Prev => "prev".to_string(),
491        }
492    }
493}
494
495impl ToString for UISelection {
496    fn to_string(&self) -> String {
497        match self {
498            UISelection::Abort => "abort".to_string(),
499            UISelection::Copy => "copy".to_string(),
500            UISelection::Toggle => "toggle".to_string(),
501            UISelection::Create => "create".to_string(),
502            UISelection::Delete => "delete".to_string(),
503            UISelection::Refresh => "refresh".to_string(),
504            UISelection::Rename => "rename".to_string(),
505            UISelection::Options => "options".to_string(),
506            UISelection::Edit => "edit".to_string(),
507            UISelection::Mail(action) => format!("mail::{}", action.to_string()),
508            UISelection::View(action) => format!("view::{}", action.to_string()),
509        }
510    }
511}
512
513impl ToString for MailAction {
514    fn to_string(&self) -> String {
515        match self {
516            MailAction::Send => "send".to_string(),
517            MailAction::Test => "test".to_string(),
518        }
519    }
520}
521
522impl ToString for ViewOpenType {
523    fn to_string(&self) -> String {
524        match self {
525            ViewOpenType::Browser => "browser".to_string(),
526            ViewOpenType::Ansi => "ansi".to_string(),
527            ViewOpenType::Text => "text".to_string(),
528        }
529    }
530}
531
532#[cfg(test)]
533mod test {
534    use crate::cmd::{UICmd, UINav};
535
536    #[test]
537    fn test_parse_command() -> Result<(), String> {
538        assert_eq!("navigate::up".parse::<UICmd>()?, UICmd::Navigate(UINav::Up),);
539        Ok(())
540    }
541}