1 // Std 2 use std::{collections::HashMap, ffi::OsString, mem, ops::Deref}; 3 4 // Internal 5 use crate::{ 6 build::{App, Arg, ArgSettings}, 7 parse::{ArgMatches, MatchedArg, SubCommand, ValueType}, 8 util::Id, 9 }; 10 11 // Third party 12 use indexmap::map::Entry; 13 14 #[derive(Debug, Default)] 15 pub(crate) struct ArgMatcher(ArgMatches); 16 17 impl ArgMatcher { new(_app: &App) -> Self18 pub(crate) fn new(_app: &App) -> Self { 19 ArgMatcher(ArgMatches { 20 #[cfg(debug_assertions)] 21 valid_args: { 22 let args = _app.args.args().map(|a| a.id.clone()); 23 let groups = _app.groups.iter().map(|g| g.id.clone()); 24 args.chain(groups).collect() 25 }, 26 #[cfg(debug_assertions)] 27 valid_subcommands: _app.subcommands.iter().map(|sc| sc.id.clone()).collect(), 28 // HACK: Allow an external subcommand's ArgMatches be a stand-in for any ArgMatches 29 // since users can't detect it and avoid the asserts. 30 // 31 // See clap-rs/clap#3263 32 #[cfg(debug_assertions)] 33 disable_asserts: _app.is_set(crate::AppSettings::AllowExternalSubcommands), 34 ..Default::default() 35 }) 36 } 37 into_inner(self) -> ArgMatches38 pub(crate) fn into_inner(self) -> ArgMatches { 39 self.0 40 } 41 propagate_globals(&mut self, global_arg_vec: &[Id])42 pub(crate) fn propagate_globals(&mut self, global_arg_vec: &[Id]) { 43 debug!( 44 "ArgMatcher::get_global_values: global_arg_vec={:?}", 45 global_arg_vec 46 ); 47 let mut vals_map = HashMap::new(); 48 self.fill_in_global_values(global_arg_vec, &mut vals_map); 49 } 50 fill_in_global_values( &mut self, global_arg_vec: &[Id], vals_map: &mut HashMap<Id, MatchedArg>, )51 fn fill_in_global_values( 52 &mut self, 53 global_arg_vec: &[Id], 54 vals_map: &mut HashMap<Id, MatchedArg>, 55 ) { 56 for global_arg in global_arg_vec { 57 if let Some(ma) = self.get(global_arg) { 58 // We have to check if the parent's global arg wasn't used but still exists 59 // such as from a default value. 60 // 61 // For example, `myprog subcommand --global-arg=value` where --global-arg defines 62 // a default value of `other` myprog would have an existing MatchedArg for 63 // --global-arg where the value is `other`, however the occurs will be 0. 64 let to_update = if let Some(parent_ma) = vals_map.get(global_arg) { 65 if parent_ma.get_occurrences() > 0 && ma.get_occurrences() == 0 { 66 parent_ma 67 } else { 68 ma 69 } 70 } else { 71 ma 72 } 73 .clone(); 74 vals_map.insert(global_arg.clone(), to_update); 75 } 76 } 77 if let Some(ref mut sc) = self.0.subcommand { 78 let mut am = ArgMatcher(mem::take(&mut sc.matches)); 79 am.fill_in_global_values(global_arg_vec, vals_map); 80 mem::swap(&mut am.0, &mut sc.matches); 81 } 82 83 for (name, matched_arg) in vals_map.iter_mut() { 84 self.0.args.insert(name.clone(), matched_arg.clone()); 85 } 86 } 87 get_mut(&mut self, arg: &Id) -> Option<&mut MatchedArg>88 pub(crate) fn get_mut(&mut self, arg: &Id) -> Option<&mut MatchedArg> { 89 self.0.args.get_mut(arg) 90 } 91 get(&self, arg: &Id) -> Option<&MatchedArg>92 pub(crate) fn get(&self, arg: &Id) -> Option<&MatchedArg> { 93 self.0.args.get(arg) 94 } 95 remove(&mut self, arg: &Id)96 pub(crate) fn remove(&mut self, arg: &Id) { 97 self.0.args.swap_remove(arg); 98 } 99 contains(&self, arg: &Id) -> bool100 pub(crate) fn contains(&self, arg: &Id) -> bool { 101 self.0.args.contains_key(arg) 102 } 103 contains_explicit(&self, arg: &Id) -> bool104 pub(crate) fn contains_explicit(&self, arg: &Id) -> bool { 105 self.0 106 .args 107 .get(arg) 108 .map_or(false, |a| a.source() != ValueType::DefaultValue) 109 } 110 is_empty(&self) -> bool111 pub(crate) fn is_empty(&self) -> bool { 112 self.0.args.is_empty() 113 } 114 arg_names(&self) -> indexmap::map::Keys<Id, MatchedArg>115 pub(crate) fn arg_names(&self) -> indexmap::map::Keys<Id, MatchedArg> { 116 self.0.args.keys() 117 } 118 entry(&mut self, arg: &Id) -> indexmap::map::Entry<Id, MatchedArg>119 pub(crate) fn entry(&mut self, arg: &Id) -> indexmap::map::Entry<Id, MatchedArg> { 120 self.0.args.entry(arg.clone()) 121 } 122 subcommand(&mut self, sc: SubCommand)123 pub(crate) fn subcommand(&mut self, sc: SubCommand) { 124 self.0.subcommand = Some(Box::new(sc)); 125 } 126 subcommand_name(&self) -> Option<&str>127 pub(crate) fn subcommand_name(&self) -> Option<&str> { 128 self.0.subcommand_name() 129 } 130 iter(&self) -> indexmap::map::Iter<Id, MatchedArg>131 pub(crate) fn iter(&self) -> indexmap::map::Iter<Id, MatchedArg> { 132 self.0.args.iter() 133 } 134 inc_occurrence_of_arg(&mut self, arg: &Arg)135 pub(crate) fn inc_occurrence_of_arg(&mut self, arg: &Arg) { 136 let id = &arg.id; 137 debug!("ArgMatcher::inc_occurrence_of_arg: id={:?}", id); 138 let ma = self.entry(id).or_insert(MatchedArg::new()); 139 ma.update_ty(ValueType::CommandLine); 140 ma.set_ignore_case(arg.is_set(ArgSettings::IgnoreCase)); 141 ma.invalid_utf8_allowed(arg.is_set(ArgSettings::AllowInvalidUtf8)); 142 ma.inc_occurrences(); 143 } 144 inc_occurrence_of_group(&mut self, id: &Id)145 pub(crate) fn inc_occurrence_of_group(&mut self, id: &Id) { 146 debug!("ArgMatcher::inc_occurrence_of_group: id={:?}", id); 147 let ma = self.entry(id).or_insert(MatchedArg::new()); 148 ma.update_ty(ValueType::CommandLine); 149 ma.inc_occurrences(); 150 } 151 add_val_to(&mut self, arg: &Id, val: OsString, ty: ValueType, append: bool)152 pub(crate) fn add_val_to(&mut self, arg: &Id, val: OsString, ty: ValueType, append: bool) { 153 if append { 154 self.append_val_to(arg, val, ty); 155 } else { 156 self.push_val_to(arg, val, ty); 157 } 158 } 159 push_val_to(&mut self, arg: &Id, val: OsString, ty: ValueType)160 fn push_val_to(&mut self, arg: &Id, val: OsString, ty: ValueType) { 161 // We will manually inc occurrences later(for flexibility under 162 // specific circumstances, like only add one occurrence for flag 163 // when we met: `--flag=one,two`). 164 let ma = self.entry(arg).or_default(); 165 ma.update_ty(ty); 166 ma.push_val(val); 167 } 168 append_val_to(&mut self, arg: &Id, val: OsString, ty: ValueType)169 fn append_val_to(&mut self, arg: &Id, val: OsString, ty: ValueType) { 170 let ma = self.entry(arg).or_default(); 171 ma.update_ty(ty); 172 ma.append_val(val); 173 } 174 new_val_group(&mut self, arg: &Id)175 pub(crate) fn new_val_group(&mut self, arg: &Id) { 176 let ma = self.entry(arg).or_default(); 177 ma.new_val_group(); 178 } 179 add_index_to(&mut self, arg: &Id, idx: usize, ty: ValueType)180 pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize, ty: ValueType) { 181 let ma = self.entry(arg).or_default(); 182 ma.update_ty(ty); 183 ma.push_index(idx); 184 } 185 has_val_groups(&mut self, arg: &Id) -> bool186 pub(crate) fn has_val_groups(&mut self, arg: &Id) -> bool { 187 match self.entry(arg) { 188 Entry::Occupied(e) => e.get().has_val_groups(), 189 Entry::Vacant(_) => false, 190 } 191 } 192 needs_more_vals(&self, o: &Arg) -> bool193 pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool { 194 debug!("ArgMatcher::needs_more_vals: o={}", o.name); 195 if let Some(ma) = self.get(&o.id) { 196 let current_num = ma.num_vals(); 197 if let Some(num) = o.num_vals { 198 debug!("ArgMatcher::needs_more_vals: num_vals...{}", num); 199 return if o.is_set(ArgSettings::MultipleOccurrences) { 200 (current_num % num) != 0 201 } else { 202 num != current_num 203 }; 204 } else if let Some(num) = o.max_vals { 205 debug!("ArgMatcher::needs_more_vals: max_vals...{}", num); 206 return current_num < num; 207 } else if o.min_vals.is_some() { 208 debug!("ArgMatcher::needs_more_vals: min_vals...true"); 209 return true; 210 } 211 return o.is_set(ArgSettings::MultipleValues); 212 } 213 true 214 } 215 } 216 217 impl Deref for ArgMatcher { 218 type Target = ArgMatches; 219 deref(&self) -> &Self::Target220 fn deref(&self) -> &Self::Target { 221 &self.0 222 } 223 } 224