• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Std
2 use std::collections::HashMap;
3 use std::ffi::OsString;
4 use std::mem;
5 use std::ops::Deref;
6 
7 // Internal
8 use crate::builder::{Arg, ArgPredicate, Command};
9 use crate::parser::AnyValue;
10 use crate::parser::Identifier;
11 use crate::parser::PendingArg;
12 use crate::parser::{ArgMatches, MatchedArg, SubCommand, ValueSource};
13 use crate::util::Id;
14 use crate::INTERNAL_ERROR_MSG;
15 
16 #[derive(Debug, Default)]
17 pub(crate) struct ArgMatcher {
18     matches: ArgMatches,
19     pending: Option<PendingArg>,
20 }
21 
22 impl ArgMatcher {
new(_cmd: &Command) -> Self23     pub(crate) fn new(_cmd: &Command) -> Self {
24         ArgMatcher {
25             matches: ArgMatches {
26                 #[cfg(debug_assertions)]
27                 valid_args: {
28                     let args = _cmd.get_arguments().map(|a| a.id.clone());
29                     let groups = _cmd.get_groups().map(|g| g.id.clone());
30                     args.chain(groups).collect()
31                 },
32                 #[cfg(debug_assertions)]
33                 valid_subcommands: _cmd.get_subcommands().map(|sc| sc.get_id()).collect(),
34                 // HACK: Allow an external subcommand's ArgMatches be a stand-in for any ArgMatches
35                 // since users can't detect it and avoid the asserts.
36                 //
37                 // See clap-rs/clap#3263
38                 #[cfg(debug_assertions)]
39                 #[cfg(not(feature = "unstable-v4"))]
40                 disable_asserts: _cmd.is_allow_external_subcommands_set(),
41                 #[cfg(debug_assertions)]
42                 #[cfg(feature = "unstable-v4")]
43                 disable_asserts: false,
44                 ..Default::default()
45             },
46             pending: None,
47         }
48     }
49 
into_inner(self) -> ArgMatches50     pub(crate) fn into_inner(self) -> ArgMatches {
51         self.matches
52     }
53 
propagate_globals(&mut self, global_arg_vec: &[Id])54     pub(crate) fn propagate_globals(&mut self, global_arg_vec: &[Id]) {
55         debug!(
56             "ArgMatcher::get_global_values: global_arg_vec={:?}",
57             global_arg_vec
58         );
59         let mut vals_map = HashMap::new();
60         self.fill_in_global_values(global_arg_vec, &mut vals_map);
61     }
62 
fill_in_global_values( &mut self, global_arg_vec: &[Id], vals_map: &mut HashMap<Id, MatchedArg>, )63     fn fill_in_global_values(
64         &mut self,
65         global_arg_vec: &[Id],
66         vals_map: &mut HashMap<Id, MatchedArg>,
67     ) {
68         for global_arg in global_arg_vec {
69             if let Some(ma) = self.get(global_arg) {
70                 // We have to check if the parent's global arg wasn't used but still exists
71                 // such as from a default value.
72                 //
73                 // For example, `myprog subcommand --global-arg=value` where `--global-arg` defines
74                 // a default value of `other` myprog would have an existing MatchedArg for
75                 // `--global-arg` where the value is `other`
76                 let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
77                     if parent_ma.source() > ma.source() {
78                         parent_ma
79                     } else {
80                         ma
81                     }
82                 } else {
83                     ma
84                 }
85                 .clone();
86                 vals_map.insert(global_arg.clone(), to_update);
87             }
88         }
89         if let Some(ref mut sc) = self.matches.subcommand {
90             let mut am = ArgMatcher {
91                 matches: mem::take(&mut sc.matches),
92                 pending: None,
93             };
94             am.fill_in_global_values(global_arg_vec, vals_map);
95             mem::swap(&mut am.matches, &mut sc.matches);
96         }
97 
98         for (name, matched_arg) in vals_map.iter_mut() {
99             self.matches.args.insert(name.clone(), matched_arg.clone());
100         }
101     }
102 
get(&self, arg: &Id) -> Option<&MatchedArg>103     pub(crate) fn get(&self, arg: &Id) -> Option<&MatchedArg> {
104         self.matches.args.get(arg)
105     }
106 
get_mut(&mut self, arg: &Id) -> Option<&mut MatchedArg>107     pub(crate) fn get_mut(&mut self, arg: &Id) -> Option<&mut MatchedArg> {
108         self.matches.args.get_mut(arg)
109     }
110 
remove(&mut self, arg: &Id)111     pub(crate) fn remove(&mut self, arg: &Id) {
112         self.matches.args.swap_remove(arg);
113     }
114 
contains(&self, arg: &Id) -> bool115     pub(crate) fn contains(&self, arg: &Id) -> bool {
116         self.matches.args.contains_key(arg)
117     }
118 
arg_ids(&self) -> indexmap::map::Keys<Id, MatchedArg>119     pub(crate) fn arg_ids(&self) -> indexmap::map::Keys<Id, MatchedArg> {
120         self.matches.args.keys()
121     }
122 
entry(&mut self, arg: &Id) -> indexmap::map::Entry<Id, MatchedArg>123     pub(crate) fn entry(&mut self, arg: &Id) -> indexmap::map::Entry<Id, MatchedArg> {
124         self.matches.args.entry(arg.clone())
125     }
126 
subcommand(&mut self, sc: SubCommand)127     pub(crate) fn subcommand(&mut self, sc: SubCommand) {
128         self.matches.subcommand = Some(Box::new(sc));
129     }
130 
subcommand_name(&self) -> Option<&str>131     pub(crate) fn subcommand_name(&self) -> Option<&str> {
132         self.matches.subcommand_name()
133     }
134 
iter(&self) -> indexmap::map::Iter<Id, MatchedArg>135     pub(crate) fn iter(&self) -> indexmap::map::Iter<Id, MatchedArg> {
136         self.matches.args.iter()
137     }
138 
check_explicit<'a>(&self, arg: &Id, predicate: ArgPredicate<'a>) -> bool139     pub(crate) fn check_explicit<'a>(&self, arg: &Id, predicate: ArgPredicate<'a>) -> bool {
140         self.get(arg).map_or(false, |a| a.check_explicit(predicate))
141     }
142 
start_custom_arg(&mut self, arg: &Arg, source: ValueSource)143     pub(crate) fn start_custom_arg(&mut self, arg: &Arg, source: ValueSource) {
144         let id = &arg.id;
145         debug!(
146             "ArgMatcher::start_custom_arg: id={:?}, source={:?}",
147             id, source
148         );
149         let ma = self.entry(id).or_insert(MatchedArg::new_arg(arg));
150         debug_assert_eq!(ma.type_id(), Some(arg.get_value_parser().type_id()));
151         ma.set_source(source);
152         ma.new_val_group();
153     }
154 
start_custom_group(&mut self, id: &Id, source: ValueSource)155     pub(crate) fn start_custom_group(&mut self, id: &Id, source: ValueSource) {
156         debug!(
157             "ArgMatcher::start_custom_arg: id={:?}, source={:?}",
158             id, source
159         );
160         let ma = self.entry(id).or_insert(MatchedArg::new_group());
161         debug_assert_eq!(ma.type_id(), None);
162         ma.set_source(source);
163         ma.new_val_group();
164     }
165 
start_occurrence_of_arg(&mut self, arg: &Arg)166     pub(crate) fn start_occurrence_of_arg(&mut self, arg: &Arg) {
167         let id = &arg.id;
168         debug!("ArgMatcher::start_occurrence_of_arg: id={:?}", id);
169         let ma = self.entry(id).or_insert(MatchedArg::new_arg(arg));
170         debug_assert_eq!(ma.type_id(), Some(arg.get_value_parser().type_id()));
171         ma.set_source(ValueSource::CommandLine);
172         #[allow(deprecated)]
173         ma.inc_occurrences();
174         ma.new_val_group();
175     }
176 
start_occurrence_of_group(&mut self, id: &Id)177     pub(crate) fn start_occurrence_of_group(&mut self, id: &Id) {
178         debug!("ArgMatcher::start_occurrence_of_group: id={:?}", id);
179         let ma = self.entry(id).or_insert(MatchedArg::new_group());
180         debug_assert_eq!(ma.type_id(), None);
181         ma.set_source(ValueSource::CommandLine);
182         #[allow(deprecated)]
183         ma.inc_occurrences();
184         ma.new_val_group();
185     }
186 
start_occurrence_of_external(&mut self, cmd: &crate::Command)187     pub(crate) fn start_occurrence_of_external(&mut self, cmd: &crate::Command) {
188         let id = &Id::empty_hash();
189         debug!("ArgMatcher::start_occurrence_of_external: id={:?}", id,);
190         let ma = self.entry(id).or_insert(MatchedArg::new_external(cmd));
191         debug_assert_eq!(
192             ma.type_id(),
193             Some(
194                 cmd.get_external_subcommand_value_parser()
195                     .expect(INTERNAL_ERROR_MSG)
196                     .type_id()
197             )
198         );
199         ma.set_source(ValueSource::CommandLine);
200         #[allow(deprecated)]
201         ma.inc_occurrences();
202         ma.new_val_group();
203     }
204 
add_val_to(&mut self, arg: &Id, val: AnyValue, raw_val: OsString)205     pub(crate) fn add_val_to(&mut self, arg: &Id, val: AnyValue, raw_val: OsString) {
206         let ma = self.get_mut(arg).expect(INTERNAL_ERROR_MSG);
207         ma.append_val(val, raw_val);
208     }
209 
add_index_to(&mut self, arg: &Id, idx: usize)210     pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize) {
211         let ma = self.get_mut(arg).expect(INTERNAL_ERROR_MSG);
212         ma.push_index(idx);
213     }
214 
needs_more_vals(&self, o: &Arg) -> bool215     pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool {
216         let num_resolved = self.get(&o.id).map(|ma| ma.num_vals()).unwrap_or(0);
217         let num_pending = self
218             .pending
219             .as_ref()
220             .and_then(|p| (p.id == o.id).then(|| p.raw_vals.len()))
221             .unwrap_or(0);
222         let current_num = num_resolved + num_pending;
223         debug!(
224             "ArgMatcher::needs_more_vals: o={}, resolved={}, pending={}",
225             o.name, num_resolved, num_pending
226         );
227         if current_num == 0 {
228             true
229         } else if let Some(num) = o.num_vals {
230             debug!("ArgMatcher::needs_more_vals: num_vals...{}", num);
231             #[allow(deprecated)]
232             if o.is_multiple_occurrences_set() {
233                 (current_num % num) != 0
234             } else {
235                 num != current_num
236             }
237         } else if let Some(num) = o.max_vals {
238             debug!("ArgMatcher::needs_more_vals: max_vals...{}", num);
239             current_num < num
240         } else if o.min_vals.is_some() {
241             debug!("ArgMatcher::needs_more_vals: min_vals...true");
242             true
243         } else {
244             o.is_multiple_values_set()
245         }
246     }
247 
pending_arg_id(&self) -> Option<&Id>248     pub(crate) fn pending_arg_id(&self) -> Option<&Id> {
249         self.pending.as_ref().map(|p| &p.id)
250     }
251 
pending_values_mut( &mut self, id: &Id, ident: Option<Identifier>, ) -> &mut Vec<OsString>252     pub(crate) fn pending_values_mut(
253         &mut self,
254         id: &Id,
255         ident: Option<Identifier>,
256     ) -> &mut Vec<OsString> {
257         let pending = self.pending.get_or_insert_with(|| PendingArg {
258             id: id.clone(),
259             ident,
260             raw_vals: Default::default(),
261         });
262         debug_assert_eq!(pending.id, *id, "{}", INTERNAL_ERROR_MSG);
263         if ident.is_some() {
264             debug_assert_eq!(pending.ident, ident, "{}", INTERNAL_ERROR_MSG);
265         }
266         &mut pending.raw_vals
267     }
268 
take_pending(&mut self) -> Option<PendingArg>269     pub(crate) fn take_pending(&mut self) -> Option<PendingArg> {
270         self.pending.take()
271     }
272 }
273 
274 impl Deref for ArgMatcher {
275     type Target = ArgMatches;
276 
deref(&self) -> &Self::Target277     fn deref(&self) -> &Self::Target {
278         &self.matches
279     }
280 }
281