diff --git a/src/app/parser.rs b/src/app/parser.rs index 861a4b01..31775d02 100644 --- a/src/app/parser.rs +++ b/src/app/parser.rs @@ -82,6 +82,9 @@ macro_rules! parse_positional { $pos_counter == $_self.positionals.len()) { $pos_only = true; } + + $matcher.inc_occurrence_of($p.name); + let _ = $_self.groups_for_arg($p.name).and_then(|vec| Some($matcher.inc_occurrences_of(&*vec))); arg_post_processing!($_self, $p, $matcher); // Only increment the positional counter if it doesn't allow multiples if !$p.settings.is_set(ArgSettings::Multiple) { @@ -156,7 +159,6 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { a.name); } let pb = PosBuilder::from_arg(&a, i as u8, &mut self.required); - // self.positionals_name.insert(pb.name, i); self.positionals.insert(i, pb); } else if a.takes_value { let ob = OptBuilder::from_arg(&a, &mut self.required); @@ -555,7 +557,7 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { try!(self.validate_required(matcher)); reqs_validated = true; let should_err = if let Some(ref v) = matcher.0.args.get(&*o.name) { - v.vals.is_empty() + v.vals.is_empty() && !(o.min_vals.is_some() && o.min_vals.unwrap() == 0) } else { true }; @@ -1037,6 +1039,10 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { try!(self.add_val_to_arg(opt, v, matcher)); } else { sdebugln!("None"); } + matcher.inc_occurrence_of(opt.name); + // Increment or create the group "args" + self.groups_for_arg(opt.name).and_then(|vec| Some(matcher.inc_occurrences_of(&*vec))); + if (opt.is_set(ArgSettings::Multiple) || opt.num_vals().is_some()) || val.is_none() { return Ok(Some(opt.name)); @@ -1124,8 +1130,7 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { debugln!("fn=parse_flag;"); validate_multiples!(self, flag, matcher); - matcher.inc_occurrence_of(&*flag.name.clone()); - + matcher.inc_occurrence_of(flag.name); // Increment or create the group "args" self.groups_for_arg(flag.name).and_then(|vec| Some(matcher.inc_occurrences_of(&*vec))); @@ -1295,11 +1300,9 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b { } if let Some(a) = self.flags.iter().filter(|f| &f.name == name).next() { if self._validate_blacklist_required(a, matcher) { continue 'outer; } - } - if let Some(a) = self.opts.iter().filter(|o| &o.name == name).next() { + } else if let Some(a) = self.opts.iter().filter(|o| &o.name == name).next() { if self._validate_blacklist_required(a, matcher) { continue 'outer; } - } - if let Some(a) = self.positionals.values().filter(|p| &p.name == name).next() { + } else if let Some(a) = self.positionals.values().filter(|p| &p.name == name).next() { if self._validate_blacklist_required(a, matcher) { continue 'outer; } } let err = if self.settings.is_set(AppSettings::ArgRequiredElseHelp) && matcher.is_empty() { diff --git a/src/args/arg.rs b/src/args/arg.rs index cce4bc78..239e267b 100644 --- a/src/args/arg.rs +++ b/src/args/arg.rs @@ -878,9 +878,10 @@ impl<'a, 'b> Arg<'a, 'b> { /// `.max_values(3)`, and this argument would be satisfied if the user provided, 1, 2, or 3 /// values. /// - /// **NOTE:** `qty` must be > 1 - /// - /// **NOTE:** This implicitly sets `.multiple(true)` + /// **NOTE:** For positional arguments this implicitly sets `multiple(true)` but does *not* + /// for options. This is because `-o val -o val` is multiples occurrences but a single value + /// and `-o val1 val2` is a single occurence with multple values. For positional arguments + /// there is no way to determine the diffrence between multiple occureces and multiple values. /// /// # Examples /// @@ -892,13 +893,7 @@ impl<'a, 'b> Arg<'a, 'b> { /// .max_values(3) /// # ).get_matches(); pub fn max_values(mut self, qty: u8) -> Self { - if qty < 2 { - panic!("Arguments with max_values(qty) qty must be > 1. Prefer \ - takes_value(true) for arguments with only one value, or flags for arguments \ - with 0 values."); - } self.max_vals = Some(qty); - self.multiple = true; self } @@ -907,12 +902,11 @@ impl<'a, 'b> Arg<'a, 'b> { /// `.min_values(2)`, and this argument would be satisfied if the user provided, 2 or more /// values. /// - /// **NOTE:** This implicitly sets `.multiple(true)` + /// **NOTE:** For positional arguments this implicitly sets `multiple(true)` but does *not* + /// for options. This is because `-o val -o val` is multiples occurrences but a single value + /// and `-o val1 val2` is a single occurence with multple values. For positional arguments + /// there is no way to determine the diffrence between multiple occureces and multiple values. /// - /// **NOTE:** `qty` must be > 0 - /// - /// **NOTE:** `qty` *must* be > 0. If you wish to have an argument with 0 or more values prefer - /// two separate arguments (a flag, and an option with multiple values). /// /// # Examples /// @@ -925,7 +919,6 @@ impl<'a, 'b> Arg<'a, 'b> { /// # ).get_matches(); pub fn min_values(mut self, qty: u8) -> Self { self.min_vals = Some(qty); - self.multiple = true; self } diff --git a/src/args/arg_builder/positional.rs b/src/args/arg_builder/positional.rs index dfdf8bd0..547a08a7 100644 --- a/src/args/arg_builder/positional.rs +++ b/src/args/arg_builder/positional.rs @@ -91,7 +91,7 @@ impl<'n, 'e> PosBuilder<'n, 'e> { help: a.help, ..Default::default() }; - if a.multiple { + if a.multiple || a.num_vals.is_some() || a.max_vals.is_some() || a.min_vals.is_some() { pb.settings.set(ArgSettings::Multiple); } if a.required { diff --git a/src/args/arg_matcher.rs b/src/args/arg_matcher.rs index 25a8e83d..7dc1a5ca 100644 --- a/src/args/arg_matcher.rs +++ b/src/args/arg_matcher.rs @@ -37,14 +37,6 @@ impl<'a> ArgMatcher<'a> { self.0.args.is_empty() } - // pub fn values_of(&'a self, arg: &str) -> Values<'a> { - // self.0.values_of(arg) - // } - - // pub fn os_values_of(&'a self, arg: &str) -> OsValues<'a> { - // self.0.os_values_of(arg) - // } - pub fn usage(&mut self, usage: String) { self.0.usage = Some(usage); } @@ -71,6 +63,7 @@ impl<'a> ArgMatcher<'a> { pub fn inc_occurrence_of(&mut self, arg: &'a str) { if let Some(a) = self.get_mut(arg) { + debugln!("+1 to {}'s occurrences", arg); a.occurs += 1; return; } @@ -85,13 +78,11 @@ impl<'a> ArgMatcher<'a> { pub fn add_val_to(&mut self, arg: &'a str, val: &OsStr) { let ma = self.entry(arg).or_insert(MatchedArg { - // occurrences will be incremented on getting a value occurs: 0, vals: VecMap::new(), }); let len = ma.vals.len() + 1; ma.vals.insert(len, val.to_owned()); - ma.occurs += 1; } } diff --git a/src/errors.rs b/src/errors.rs index d8cc8ada..f05946e7 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -596,7 +596,7 @@ impl Error { { let a = arg.into(); Error { - message: format!("{} The argument '{}' wasn't recognized, or isn't valid{}\n\ + message: format!("{} The argument '{}' wasn't recognized, or isn't valid in this context{}\n\ {}\n\n\ For more information try {}", Format::Error("error:"),