fix(Option Args): fixes bug with args and multiple values

Closes #323
This commit is contained in:
Kevin K 2015-10-28 04:54:24 -04:00
parent 40ed2b50c3
commit c9a9548a8f
2 changed files with 92 additions and 89 deletions

View file

@ -2257,7 +2257,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
}
if arg_slice.starts_with("--") && !pos_only {
if arg_slice.len() == 2 {
// The user has passed '--' which means only positional args follow no matter
@ -2370,13 +2369,13 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
if self.overrides.contains(&p.name) {
if let Some(name) = self.overriden_from(p.name, matches) {
matches.args.remove(&*name);
remove_override!(self, &*name);
remove_overriden!(self, &*name);
}
}
if let Some(ref or) = p.overrides {
for pa in or {
matches.args.remove(pa);
remove_override!(self, pa);
remove_overriden!(self, pa);
self.overrides.push(pa);
}
}
@ -2424,6 +2423,12 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
}
if p.settings.is_set(&ArgSettings::Required) {
// for macro call
let name = &p.name;
vec_remove!(self.required, name);
}
parse_group_reqs!(self, p);
}
} else {
@ -2456,6 +2461,8 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
ClapErrorType::EmptyValue,
matches));
} else {
debugln!("Remaining Required Arg...");
debugln!("required={:#?}", self.required);
return Err(
self.create_error(
&[""],
@ -2640,7 +2647,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
fn create_help_and_version(&mut self) {
// name is "hclap_help" because flags are sorted by name
if self.settings.is_set(&AppSettings::NeedsLongHelp) {
if !self.flags.values().any(|a| a.long.is_some() && a.long.unwrap() == "help") {
if self.help_short.is_none() && !self.short_list.contains(&'h') {
self.help_short = Some('h');
}
@ -2656,12 +2663,12 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
};
self.long_list.push("help");
self.flags.insert("hclap_help", arg);
self.settings.unset(&AppSettings::NeedsLongHelp);
// self.settings.unset(&AppSettings::NeedsLongHelp);
}
if self.settings.is_set(&AppSettings::NeedsLongVersion) &&
!self.settings.is_set(&AppSettings::VersionlessSubcommands) ||
if !self.settings.is_set(&AppSettings::VersionlessSubcommands) ||
(self.settings.is_set(&AppSettings::VersionlessSubcommands) &&
self.settings.is_set(&AppSettings::DisableVersion)) {
self.settings.is_set(&AppSettings::DisableVersion)) &&
!self.flags.values().any(|a| a.long.is_some() && a.long.unwrap() == "version") {
if self.version_short.is_none() && !self.short_list.contains(&'V') {
self.version_short = Some('V');
}
@ -2678,12 +2685,12 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
};
self.long_list.push("version");
self.flags.insert("vclap_version", arg);
self.settings.unset(&AppSettings::NeedsLongVersion);
// self.settings.unset(&AppSettings::NeedsLongVersion);
}
if self.settings.is_set(&AppSettings::NeedsSubcommandHelp) && !self.subcommands.is_empty() {
if !self.subcommands.is_empty() && !self.subcommands.keys().any(|a| a == "help") {
self.subcommands.insert("help".to_owned(), App::new("help")
.about("Prints this message"));
self.settings.unset(&AppSettings::NeedsSubcommandHelp);
// self.settings.unset(&AppSettings::NeedsSubcommandHelp);
}
}
@ -2793,7 +2800,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
}
matches.args.remove(name);
remove_override!(self, name);
remove_overriden!(self, name);
}
}
if let Some(ref or) = v.overrides {
@ -2804,7 +2811,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
}
matches.args.remove(pa);
remove_override!(self, pa);
remove_overriden!(self, pa);
self.overrides.push(pa);
}
}
@ -2928,13 +2935,13 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
if let Some(name) = self.overriden_from(v.name, matches) {
debugln!("found {}", name);
matches.args.remove(name);
remove_override!(self, name);
remove_overriden!(self, name);
}
}
if let Some(ref or) = v.overrides {
for pa in or {
matches.args.remove(pa);
remove_override!(self, pa);
remove_overriden!(self, pa);
self.overrides.push(pa);
}
}
@ -3123,49 +3130,63 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
if self.overrides.contains(&v.name) {
if let Some(name) = self.overriden_from(v.name, matches) {
matches.args.remove(&*name);
remove_override!(self, &*name);
remove_overriden!(self, &*name);
}
}
if let Some(ref or) = v.overrides {
for pa in or {
matches.args.remove(pa);
remove_override!(self, pa);
remove_overriden!(self, pa);
self.overrides.push(pa);
}
}
if matches.args.contains_key(v.name) {
if !v.settings.is_set(&ArgSettings::Multiple) {
return Err(
self.create_error(
&[&*format!("-{}", arg)],
ClapErrorType::UnexpectedMultipleUsage,
matches));
}
} else {
let val: Vec<&str> = arg.splitn(2, c).collect();
let bm = if val[1].is_empty() {
BTreeMap::new()
} else {
ret = None;
let mut bm = BTreeMap::new();
bm.insert(0, val[1].to_owned());
bm
};
if let Some(ref vec) = self.groups_for(v.name) {
for grp in vec {
matches.args.insert(grp, MatchedArg{
occurrences: 1,
values: Some(bm.clone()),
if matches.args.contains_key(v.name) &&
!v.settings.is_set(&ArgSettings::Multiple) {
return Err(
self.create_error(
&[&*format!("-{}", arg)],
ClapErrorType::UnexpectedMultipleUsage,
matches));
}
// New scope for lifetimes
let val: Vec<&str> = arg.splitn(2, c).collect();
{
let ma = matches.args.entry(v.name).or_insert(
MatchedArg{
// occurrences will be incremented on getting a value
occurrences: 0,
values: Some(BTreeMap::new())
});
if !val[1].is_empty() {
if !v.settings.is_set(&ArgSettings::Multiple) {
ret = None;
}
if let Some(ref mut vals) = ma.values {
let len = vals.len() as u8 + 1;
vals.insert(len, val[1].to_owned());
}
ma.occurrences += 1;
}
}
if let Some(ref vec) = self.groups_for(v.name) {
for grp in vec {
let ma_g = matches.args.entry(grp).or_insert(MatchedArg{
occurrences: 0,
values: Some(BTreeMap::new()),
});
if !val[1].is_empty() {
if let Some(ref mut vals) = ma_g.values {
let len = vals.len() as u8 + 1;
vals.insert(len, val[1].to_owned());
}
ma_g.occurrences += 1;
}
}
matches.args.insert(v.name, MatchedArg{
// occurrences will be incremented on getting a value
occurrences: 0,
values: Some(bm)
});
}
if let Some(ref bl) = v.blacklist {
for name in bl {
self.blacklist.push(name);
@ -3229,13 +3250,13 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
if let Some(name) = self.overriden_from(v.name, matches) {
debugln!("found {}", name);
matches.args.remove(name);
remove_override!(self, name);
remove_overriden!(self, name);
}
}
if let Some(ref or) = v.overrides {
for pa in or {
matches.args.remove(pa);
remove_override!(self, pa);
remove_overriden!(self, pa);
self.overrides.push(pa);
}
}

View file

@ -57,6 +57,7 @@ macro_rules! vec_remove {
($vec:expr, $to_rem:ident) => {
{
let mut ix = None;
$vec.dedup();
for (i, val) in $vec.iter().enumerate() {
if val == $to_rem {
ix = Some(i);
@ -64,14 +65,13 @@ macro_rules! vec_remove {
}
}
if let Some(i) = ix {
$vec.dedup();
$vec.remove(i);
}
}
}
}
macro_rules! remove_override {
macro_rules! remove_overriden {
($me:ident, $name:expr) => ({
if let Some(ref o) = $me.opts.get($name) {
if let Some(ref ora) = o.requires {
@ -162,16 +162,7 @@ macro_rules! parse_group_reqs {
let mut found = false;
for name in ag.args.iter() {
if name == &$arg.name {
let mut ix = None;
for (i, val) in $me.required.iter().enumerate() {
if val == &ag.name {
ix = Some(i);
break;
}
}
if let Some(i) = ix {
$me.required.remove(i);
}
vec_remove!($me.required, name);
if let Some(ref reqs) = ag.requires {
for r in reqs {
$me.required.push(r);
@ -189,16 +180,7 @@ macro_rules! parse_group_reqs {
if found {
for name in ag.args.iter() {
if name == &$arg.name { continue }
let mut ix = None;
for (i, val) in $me.required.iter().enumerate() {
if val == name {
ix = Some(i);
break;
}
}
if let Some(i) = ix {
$me.required.remove(i);
}
vec_remove!($me.required, name);
$me.blacklist.push(name);
}
@ -208,26 +190,26 @@ macro_rules! parse_group_reqs {
}
// De-duplication macro used in src/app.rs
macro_rules! validate_reqs {
($me:ident, $t:ident, $m:ident, $n:ident) => {
if let Some(a) = $me.$t.get($n) {
if let Some(ref bl) = a.blacklist {
for n in bl.iter() {
if $m.args.contains_key(n) {
return false
} else if $me.groups.contains_key(n) {
let grp = $me.groups.get(n).unwrap();
for an in grp.args.iter() {
if $m.args.contains_key(an) {
return false
}
}
}
}
}
}
};
}
// macro_rules! validate_reqs {
// ($me:ident, $t:ident, $m:ident, $n:ident) => {
// if let Some(a) = $me.$t.get($n) {
// if let Some(ref bl) = a.blacklist {
// for n in bl.iter() {
// if $m.args.contains_key(n) {
// return false
// } else if $me.groups.contains_key(n) {
// let grp = $me.groups.get(n).unwrap();
// for an in grp.args.iter() {
// if $m.args.contains_key(an) {
// return false
// }
// }
// }
// }
// }
// }
// };
// }
// Thanks to bluss and flan3002 in #rust IRC
//