clap/args/arg_builder/
positional.rs

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