clap/args/arg_builder/
option.rs

1// Std
2use std::{
3    ffi::{OsStr, OsString},
4    fmt::{Display, Formatter, Result},
5    mem,
6    rc::Rc,
7    result::Result as StdResult,
8};
9
10// Internal
11use crate::{
12    args::{AnyArg, Arg, ArgSettings, Base, DispOrder, Switched, Valued},
13    map::{self, VecMap},
14    INTERNAL_ERROR_MSG,
15};
16
17#[allow(missing_debug_implementations)]
18#[doc(hidden)]
19#[derive(Default, Clone)]
20pub struct OptBuilder<'n, 'e>
21where
22    'n: 'e,
23{
24    pub b: Base<'n, 'e>,
25    pub s: Switched<'e>,
26    pub v: Valued<'n, 'e>,
27}
28
29impl<'n, 'e> OptBuilder<'n, 'e> {
30    pub fn new(name: &'n str) -> Self {
31        OptBuilder {
32            b: Base::new(name),
33            ..Default::default()
34        }
35    }
36}
37
38impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for OptBuilder<'n, 'e> {
39    fn from(a: &'z Arg<'n, 'e>) -> Self {
40        OptBuilder {
41            b: Base::from(a),
42            s: Switched::from(a),
43            v: Valued::from(a),
44        }
45    }
46}
47
48impl<'n, 'e> From<Arg<'n, 'e>> for OptBuilder<'n, 'e> {
49    fn from(mut a: Arg<'n, 'e>) -> Self {
50        a.v.fill_in();
51        OptBuilder {
52            b: mem::take(&mut a.b),
53            s: mem::take(&mut a.s),
54            v: mem::take(&mut a.v),
55        }
56    }
57}
58
59impl<'n, 'e> Display for OptBuilder<'n, 'e> {
60    fn fmt(&self, f: &mut Formatter) -> Result {
61        debugln!("OptBuilder::fmt:{}", self.b.name);
62        let sep = if self.b.is_set(ArgSettings::RequireEquals) {
63            "="
64        } else {
65            " "
66        };
67        // Write the name such --long or -l
68        if let Some(l) = self.s.long {
69            write!(f, "--{}{}", l, sep)?;
70        } else {
71            write!(f, "-{}{}", self.s.short.unwrap(), sep)?;
72        }
73        let delim = if self.is_set(ArgSettings::RequireDelimiter) {
74            self.v.val_delim.expect(INTERNAL_ERROR_MSG)
75        } else {
76            ' '
77        };
78
79        // Write the values such as <name1> <name2>
80        if let Some(ref vec) = self.v.val_names {
81            let mut it = vec.iter().peekable();
82            while let Some((_, val)) = it.next() {
83                write!(f, "<{}>", val)?;
84                if it.peek().is_some() {
85                    write!(f, "{}", delim)?;
86                }
87            }
88            let num = vec.len();
89            if self.is_set(ArgSettings::Multiple) && num == 1 {
90                write!(f, "...")?;
91            }
92        } else if let Some(num) = self.v.num_vals {
93            let mut it = (0..num).peekable();
94            while let Some(_) = it.next() {
95                write!(f, "<{}>", self.b.name)?;
96                if it.peek().is_some() {
97                    write!(f, "{}", delim)?;
98                }
99            }
100            if self.is_set(ArgSettings::Multiple) && num == 1 {
101                write!(f, "...")?;
102            }
103        } else {
104            write!(
105                f,
106                "<{}>{}",
107                self.b.name,
108                if self.is_set(ArgSettings::Multiple) {
109                    "..."
110                } else {
111                    ""
112                }
113            )?;
114        }
115
116        Ok(())
117    }
118}
119
120impl<'n, 'e> AnyArg<'n, 'e> for OptBuilder<'n, 'e> {
121    fn name(&self) -> &'n str {
122        self.b.name
123    }
124    fn overrides(&self) -> Option<&[&'e str]> {
125        self.b.overrides.as_ref().map(|o| &o[..])
126    }
127    fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> {
128        self.b.requires.as_ref().map(|o| &o[..])
129    }
130    fn blacklist(&self) -> Option<&[&'e str]> {
131        self.b.blacklist.as_ref().map(|o| &o[..])
132    }
133    fn required_unless(&self) -> Option<&[&'e str]> {
134        self.b.r_unless.as_ref().map(|o| &o[..])
135    }
136    fn val_names(&self) -> Option<&VecMap<&'e str>> {
137        self.v.val_names.as_ref()
138    }
139    fn is_set(&self, s: ArgSettings) -> bool {
140        self.b.settings.is_set(s)
141    }
142    fn has_switch(&self) -> bool {
143        true
144    }
145    fn set(&mut self, s: ArgSettings) {
146        self.b.settings.set(s)
147    }
148    fn max_vals(&self) -> Option<u64> {
149        self.v.max_vals
150    }
151    fn val_terminator(&self) -> Option<&'e str> {
152        self.v.terminator
153    }
154    fn num_vals(&self) -> Option<u64> {
155        self.v.num_vals
156    }
157    fn possible_vals(&self) -> Option<&[&'e str]> {
158        self.v.possible_vals.as_ref().map(|o| &o[..])
159    }
160    #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))]
161    fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> {
162        self.v.validator.as_ref()
163    }
164    #[cfg_attr(feature = "cargo-clippy", allow(clippy::type_complexity))]
165    fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> StdResult<(), OsString>>> {
166        self.v.validator_os.as_ref()
167    }
168    fn min_vals(&self) -> Option<u64> {
169        self.v.min_vals
170    }
171    fn short(&self) -> Option<char> {
172        self.s.short
173    }
174    fn long(&self) -> Option<&'e str> {
175        self.s.long
176    }
177    fn val_delim(&self) -> Option<char> {
178        self.v.val_delim
179    }
180    fn takes_value(&self) -> bool {
181        true
182    }
183    fn help(&self) -> Option<&'e str> {
184        self.b.help
185    }
186    fn long_help(&self) -> Option<&'e str> {
187        self.b.long_help
188    }
189    fn default_val(&self) -> Option<&'e OsStr> {
190        self.v.default_val
191    }
192    fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
193        self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
194    }
195    fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> {
196        self.v
197            .env
198            .as_ref()
199            .map(|&(key, ref value)| (key, value.as_ref()))
200    }
201    fn longest_filter(&self) -> bool {
202        true
203    }
204    fn aliases(&self) -> Option<Vec<&'e str>> {
205        if let Some(ref aliases) = self.s.aliases {
206            let vis_aliases: Vec<_> = aliases
207                .iter()
208                .filter_map(|&(n, v)| if v { Some(n) } else { None })
209                .collect();
210            if vis_aliases.is_empty() {
211                None
212            } else {
213                Some(vis_aliases)
214            }
215        } else {
216            None
217        }
218    }
219}
220
221impl<'n, 'e> DispOrder for OptBuilder<'n, 'e> {
222    fn disp_ord(&self) -> usize {
223        self.s.disp_ord
224    }
225}
226
227impl<'n, 'e> PartialEq for OptBuilder<'n, 'e> {
228    fn eq(&self, other: &OptBuilder<'n, 'e>) -> bool {
229        self.b == other.b
230    }
231}
232
233#[cfg(test)]
234mod test {
235    use super::OptBuilder;
236    use crate::{args::settings::ArgSettings, map::VecMap};
237
238    #[test]
239    fn optbuilder_display1() {
240        let mut o = OptBuilder::new("opt");
241        o.s.long = Some("option");
242        o.b.settings.set(ArgSettings::Multiple);
243
244        assert_eq!(&*format!("{}", o), "--option <opt>...");
245    }
246
247    #[test]
248    fn optbuilder_display2() {
249        let mut v_names = VecMap::new();
250        v_names.insert(0, "file");
251        v_names.insert(1, "name");
252
253        let mut o2 = OptBuilder::new("opt");
254        o2.s.short = Some('o');
255        o2.v.val_names = Some(v_names);
256
257        assert_eq!(&*format!("{}", o2), "-o <file> <name>");
258    }
259
260    #[test]
261    fn optbuilder_display3() {
262        let mut v_names = VecMap::new();
263        v_names.insert(0, "file");
264        v_names.insert(1, "name");
265
266        let mut o2 = OptBuilder::new("opt");
267        o2.s.short = Some('o');
268        o2.v.val_names = Some(v_names);
269        o2.b.settings.set(ArgSettings::Multiple);
270
271        assert_eq!(&*format!("{}", o2), "-o <file> <name>");
272    }
273
274    #[test]
275    fn optbuilder_display_single_alias() {
276        let mut o = OptBuilder::new("opt");
277        o.s.long = Some("option");
278        o.s.aliases = Some(vec![("als", true)]);
279
280        assert_eq!(&*format!("{}", o), "--option <opt>");
281    }
282
283    #[test]
284    fn optbuilder_display_multiple_aliases() {
285        let mut o = OptBuilder::new("opt");
286        o.s.long = Some("option");
287        o.s.aliases = Some(vec![
288            ("als_not_visible", false),
289            ("als2", true),
290            ("als3", true),
291            ("als4", true),
292        ]);
293        assert_eq!(&*format!("{}", o), "--option <opt>");
294    }
295}