1#![allow(clippy::to_string_trait_impl)]
2use 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}