cmder/parse/
args.rs

1use crate::ui::formatter::FormatGenerator;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub struct Argument {
5    /// Sets the name of the argument. The name is what actually gets returned in the resulting hashmaps once the arguments are parsed. It is in a rust-friendly format, that is, all the leading hyphens are removed and any other hyphens replaced with underscores
6    pub name: String,
7
8    /// Depending on whether the argument is wrapped in angle brackets or square brackets, it is marked as required or not. This field is later checked when the cmd.parse method is called and if a required arg is missing, and error is thrown and the program exits, althought this behavior can be modified by adding a listener to the `Event::OptionMissingArgument` event.
9    pub required: bool,
10
11    /// The raw literal of the argument, in the same way that it was passed, without any modifications, angle brackets and all.
12    pub literal: String,
13
14    /// An optional description about the argument
15    pub description: Option<String>,
16
17    /// Whether or not the arg is variadic or not
18    pub variadic: bool,
19}
20
21impl Argument {
22    pub fn new(val: &str) -> Self {
23        Self {
24            name: val.into(),
25            required: false,
26            description: None,
27            literal: "".into(),
28            variadic: false,
29        }
30    }
31
32    /// Takes in a string literal as input and returns a new argument instance after resolving all the struct fields of an argument by calling the `clean_arg` function.
33    pub fn generate(value: &str, description: Option<String>) -> Self {
34        let (name, required, variadic) = clean_arg(value.trim());
35
36        Self {
37            name,
38            required,
39            literal: value.to_string(),
40            description,
41            variadic,
42        }
43    }
44
45    pub fn help(mut self, val: &str) -> Self {
46        self.description = Some(val.into());
47        self
48    }
49
50    pub fn is_variadic(mut self, val: bool) -> Self {
51        self.variadic = val;
52        self
53    }
54
55    pub fn is_required(mut self, val: bool) -> Self {
56        self.required = val;
57        self
58    }
59}
60
61/// Cleans an argument by removing any brackets and determining whether the argument is required is not.
62fn clean_arg(val: &str) -> (String, bool, bool) {
63    let delimiters;
64
65    let required = if val.starts_with('<') {
66        delimiters = vec!['<', '>'];
67        true
68    } else {
69        delimiters = vec!['[', ']'];
70        false
71    };
72
73    let mut name = val
74        .replace(delimiters[0], "")
75        .replace(delimiters[1], "")
76        .replace('-', "_");
77
78    let variadic = if name.ends_with("...") {
79        name = name.replace("...", "");
80        true
81    } else {
82        false
83    };
84
85    (name, required, variadic)
86}
87
88impl FormatGenerator for Argument {
89    fn generate(&self, ptrn: crate::ui::formatter::Pattern) -> (String, String) {
90        use crate::ui::formatter::Pattern;
91        match &ptrn {
92            Pattern::Custom(ptrn) => {
93                let base = &ptrn.args_fmter;
94
95                let mut floating = String::from("");
96                let mut leading = base
97                    .replace("{{name}}", &self.name)
98                    .replace("{{literal}}", &self.literal);
99
100                if base.contains("{{description}}") {
101                    leading =
102                        leading.replace("{{description}}", &self.description.clone().unwrap());
103                } else {
104                    floating = self.description.clone().unwrap()
105                }
106
107                (leading, floating)
108            }
109            _ => (self.literal.clone(), self.description.clone().unwrap()),
110        }
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn test_arg_creation() {
120        let a = Argument::generate("<test-app>", Some("Dummy help str".into()));
121
122        assert!(a.required);
123        assert!(!a.variadic);
124        assert_eq!(a.name, "test_app");
125        assert_eq!(a.description, Some("Dummy help str".into()));
126    }
127}