Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_syntax/src/cmd.rs

3.6 KiB, 36 runs

created by r1870400018:1045, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use crate::{
2 arg::Arg,
3 core::{
4 Syntax,
5 SyntaxPrefs,
6 },
7 key::Key,
8 val::Val,
9};
10
11use oxedyne_fe2o3_core::{
12 prelude::*,
13 map::Recursive,
14};
15
16use std::{
17 collections::BTreeMap,
18 fmt,
19};
20
21#[derive(Clone, Default)]
22pub struct Cmd {
23 pub cfg: CmdConfig,
24 pub args: BTreeMap<Key, Recursive<Key, Arg>>,
25 // Binary
26 pub id: u16,
27 pub next_arg_id:u16,
28}
29
30#[derive(Clone, Default)]
31pub struct CmdConfig {
32 pub name: String,
33 pub vals: Vec<Val>, // Expected values.
34 pub rest: Option<Val>, // Words after "--", taken as they stand.
35 pub rargs: Vec<String>, // Which arguments are required?
36 pub excess: Option<String>, // The command's own sentence for a word too many.
37 // CLI
38 pub help: Option<String>, // One line, for the command table.
39 pub detail: Option<String>, // Prose for the command's own page.
40 pub see: Vec<String>, // Commands or topics named under SEE ALSO.
41 pub prefs: SyntaxPrefs,
42 pub cat: String, // Command category, a help heading.
43}
44
45impl fmt::Debug for Cmd {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 write!(f,
48 "Cmd {{ name: {}, kinds: {:?}, args: {:?} }}",
49 &self.config().name,
50 &self.config().vals,
51 &self.args,
52 )
53 }
54}
55
56impl Cmd {
57
58 pub fn new<S: Into<String>>(name: S) -> Outcome<Self> {
59 let name = name.into();
60 if name.starts_with('-') || name.contains(' ') {
61 Err(err!(
62 "Command name '{}' should not start with a hyphen or contain spaces", name;
63 Input, Invalid))
64 } else {
65 let cfg = CmdConfig {
66 name: name,
67 ..Default::default()
68 };
69 Ok(Self {
70 cfg: cfg,
71 ..Default::default()
72 })
73 }
74 }
75
76 pub fn config(&self) -> &CmdConfig { &self.cfg }
77
78 pub fn add_arg(mut self, mut a: Arg) -> Outcome<Self> {
79 a.id = self.next_arg_id;
80 self.next_arg_id = res!(Syntax::inc_counter(
81 self.next_arg_id,
82 fmt!("command '{}' arguments", self.config().name),
83 ));
84 res!(a.attach_arg(
85 &mut self.args,
86 &mut self.cfg.rargs,
87 ));
88 Ok(self)
89 }
90
91 pub fn expected_vals<V: Into<Val>>(mut self, vals: Vec<V>) -> Self {
92 self.cfg.vals = vals.into_iter().map(|v| v.into()).collect();
93 self
94 }
95
96 pub fn rest(mut self, val: Val) -> Self {
97 self.cfg.rest = Some(val);
98 self
99 }
100
101 pub fn detail<S: Into<String>>(mut self, s: S) -> Self {
102 self.cfg.detail = Some(s.into());
103 self
104 }
105
106 pub fn cat<S: Into<String>>(mut self, s: S) -> Self {
107 self.cfg.cat = s.into();
108 self
109 }
110
111 pub fn excess<S: Into<String>>(mut self, s: S) -> Self {
112 self.cfg.excess = Some(s.into());
113 self
114 }
115
116 /// The command's arguments in the order they were added.
117 pub fn args_in_order(&self) -> Vec<&Arg> {
118 self.args.iter().filter_map(|(k, v)| match (k, v) {
119 (Key::Id(_), Recursive::Val(arg)) => Some(arg),
120 _ => None,
121 }).collect()
122 }
123
124 pub fn help<S: Into<String>>(mut self, s: S) -> Self {
125 self.cfg.help = Some(s.into());
126 self
127 }
128
129 /// Collects the short form switch strings of those arguments that have one.
130 pub fn collect_short_arg_names(&self) -> Vec<String> {
131 self.args_in_order()
132 .into_iter()
133 .filter_map(|arg| arg.config().hyph1.clone())
134 .collect()
135 }
136}
137