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