jargon_args/
jargons.rs

1use super::Error;
2use super::Key;
3use std::result::Result;
4use std::str::FromStr;
5
6/// # Jargon
7///
8/// This is the main struct in this crate. This is what is used to handle arguments,
9/// and get arguments' values.
10///
11/// # Example
12///
13/// ```
14/// use jargon_args::Jargon;
15/// let mut jargon: Jargon = Jargon::from_env();
16///
17/// if jargon.contains(["-h", "--help"]) {
18///     println!("help text");
19///     std::process::exit(0);
20/// }
21///
22/// // ...
23#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
24pub struct Jargon(pub(crate) Vec<String>);
25
26impl Jargon {
27    /// Extracts a program's arguments from the environment.
28    pub fn from_env() -> Self {
29        Self(std::env::args().collect())
30    }
31
32    /// Places provided vector into Jargon. Please have the program's name or subcommand's name at
33    /// index `0`. 0 is always ignored.
34    pub fn from_vec<T: ToString>(v: Vec<T>) -> Self {
35        Self(v.iter().map(|x| x.to_string()).collect())
36    }
37
38    /// Checks if provided key is given in arguments. Removes it.
39    pub fn contains<K: Into<Key>>(&mut self, key: K) -> bool {
40        let key: Key = key.into();
41        let len: usize = self.0.len();
42
43        match key {
44            Key::Dual {
45                char: c,
46                s_txt: s,
47                l_txt: l,
48            } => {
49                let s: Key = Key::Short { char: c, txt: s };
50                let l: Key = Key::Long { char: c, txt: l };
51                for i in 0..len {
52                    let cont: Key = self.0[i].clone().into();
53                    if cont == s || cont == l {
54                        self.0.remove(i);
55                        return true;
56                    }
57                }
58            }
59            key => {
60                for i in 0..len {
61                    let cont: Key = self.0[i].clone().into();
62                    if cont == key {
63                        self.0.remove(i);
64                        return true;
65                    }
66                }
67            }
68        }
69
70        false
71    }
72
73    #[cfg(feature = "no_mut")]
74    /// Checks if provided key is given in arguments. Dose not remove it.
75    pub fn contains_nomut<K: Into<Key>>(&self, key: K) -> bool {
76        let m = self.0.clone();
77        let mut m = Self(m);
78        m.contains(key)
79    }
80
81    /// Runs function that does not return a value if specified key exists.
82    /// Removes the program's name from provided vector.
83    pub fn on_subcommand<K: Into<Key>, F: FnMut(Vec<String>)>(&mut self, key: K, mut f: F) {
84        let key: Key = key.into();
85        for i in 0..self.0.len() {
86            let cont: Key = self.0[i].clone().into();
87            if cont.is_sub() && cont == key {
88                return f(self.clone().finish());
89            }
90        }
91    }
92
93    /// Runs function that returns Option<T> if specified key exists.
94    /// Removes the program's name from provided vector.
95    pub fn opt_on_subcommand<K: Into<Key>, F: FnMut(Vec<String>) -> Option<T>, T>(
96        &mut self,
97        key: K,
98        mut f: F,
99    ) -> Option<T> {
100        let key: Key = key.into();
101        for i in 0..self.0.len() {
102            let cont: Key = self.0[i].clone().into();
103            if cont.is_sub() && cont == key {
104                return f(self.clone().finish());
105            }
106        }
107        None
108    }
109
110    /// Runs function that returns Result<T, jargon_args::Error> if specified key exists.
111    /// Removes the program's name from provided vector.
112    pub fn res_on_subcommand<K: Into<Key>, F: FnMut(Vec<String>) -> Result<T, Error>, T>(
113        &mut self,
114        key: K,
115        mut f: F,
116    ) -> Result<T, Error> {
117        let key: Key = key.into();
118        for i in 0..self.0.len() {
119            let cont: Key = self.0[i].clone().into();
120            if cont.is_sub() && cont == key {
121                return f(self.clone().finish());
122            }
123        }
124
125        Err(Error::MissingArg(key))
126    }
127
128    /// Checks if key exists, removes it, and returns it and all remaining arguments in
129    /// Some(Vec<String>). None if key isn't in arguments.
130    pub fn subcommand<K: Into<Key>>(&mut self, key: K) -> Option<Vec<String>> {
131        let mut v: Vec<String> = Vec::new();
132        self.on_subcommand(key, |vv| v = vv);
133        if v.is_empty() {
134            None
135        } else {
136            Some(v)
137        }
138    }
139
140    #[cfg(feature = "no_mut")]
141    /// Checks if key exists, removes it without modifying your Jargon variable,
142    /// and returns it and all remaining arguments in
143    /// Some(Vec<String>). None if key isn't in arguments.
144    pub fn subcommand_nomut<K: Into<Key>>(&self, key: K) -> Option<Vec<String>> {
145        Jargon::from_vec(self.0.clone()).subcommand(key)
146    }
147
148    /// Checks for provided key in arguments, removes it, returns Some(String) with the value after it if there is one.
149    /// None is there is no value.
150    pub fn option_arg<T: FromStr, K: Into<Key>>(&mut self, key: K) -> Option<T> {
151        let key: Key = key.into();
152        let len: usize = self.0.len();
153
154        match key {
155            Key::Dual {
156                char: c,
157                s_txt: s,
158                l_txt: l,
159            } => {
160                let s: Key = Key::Short { char: c, txt: s };
161                let l: Key = Key::Long { char: c, txt: l };
162                for i in 0..len {
163                    let cont: Key = self.0[i].clone().into();
164                    if cont == s || cont == l {
165                        if i >= self.0.len() - 1 {
166                            return None;
167                        }
168                        return if !self.0[i + 1].starts_with(s.char())
169                            || !self.0[i + 1].starts_with(l.char())
170                        {
171                            self.0.remove(i);
172                            self.0.remove(i).parse().ok()
173                        } else {
174                            None
175                        };
176                    }
177                }
178            }
179            key => {
180                for i in 0..len {
181                    let cont: Key = self.0[i].clone().into();
182                    if cont == key {
183                        if i >= self.0.len() - 1 {
184                            return None;
185                        }
186                        return if !self.0[i + 1].starts_with(key.char()) {
187                            self.0.remove(i);
188                            self.0.remove(i).parse().ok()
189                        } else {
190                            None
191                        };
192                    }
193                }
194            }
195        }
196
197        None
198    }
199
200    /// Checks for provided key in arguments, removes it, returns Ok(String) with the value after it if there is one.
201    /// Err(jargon_args::Error) is there is no value.
202    pub fn result_arg<T: FromStr, K: Into<Key>>(&mut self, key: K) -> Result<T, Error> {
203        let key: Key = key.into();
204        self.option_arg(key.clone()).ok_or(Error::MissingArg(key))
205    }
206
207    /// Returns the next argument as `Some(T)` or 'None' if there is no more arguments.
208    pub fn opt_next<T: FromStr>(&mut self) -> Option<T> {
209        if self.0.len() == 0 {
210            return None;
211        }
212
213        self.0.remove(0).parse().ok()
214    }
215
216    /// Drops your jargon instance and returns all remaining arguments.
217    pub fn finish(self) -> Vec<String> {
218        self.0.iter().skip(1).map(|s| s.to_string()).collect()
219    }
220}