Skip to content

Commit

Permalink
feat: supports -aValue style options
Browse files Browse the repository at this point in the history
  • Loading branch information
kbknapp committed Oct 2, 2015
1 parent d03e3e0 commit 0e3733e
Showing 1 changed file with 98 additions and 118 deletions.
216 changes: 98 additions & 118 deletions src/app/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1336,10 +1336,10 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}

usage.push_str(&req_string[..]);

// places a '--' in the usage string if there are args and options
// supporting multiple values
if !self.positionals_idx.is_empty() &&
if !self.positionals_idx.is_empty() &&
(self.opts.values().any(|a| a.settings.is_set(&ArgSettings::Multiple)) ||
self.positionals_idx.values().any(|a| a.settings.is_set(&ArgSettings::Multiple))) &&
!self.opts.values().any(|a| a.settings.is_set(&ArgSettings::Required)) &&
Expand Down Expand Up @@ -3167,138 +3167,118 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
full_arg: &str)
-> Result<Option<&'ar str>, ClapError> {
let arg = &full_arg[..].trim_left_matches(|c| c == '-');
if arg.len() > 1 {
// Multiple flags using short i.e. -bgHlS
for c in arg.chars() {
if let Err(e) = self.check_for_help_and_version(c) {
return Err(ClapError{
error: format!("{} {}\n\terror message: {}\n",
Format::Error("error:"),
INTERNAL_ERROR_MSG, e.description()),
error_type: ClapErrorType::MissingSubcommand
});
}
match self.parse_single_short_flag(matches, c) {
Ok(b) => {
if !b {
return Err(self.report_error(format!("The argument '{}' isn't valid",
Format::Warning(format!("-{}", c))),
ClapErrorType::InvalidArgument,
Some(matches.args.keys().map(|k| *k).collect())));
}
}
Err(e) => return Err(e),
}
for c in arg.chars() {
if let Err(e) = self.check_for_help_and_version(c) {
return Err(ClapError{
error: format!("{} {}\n\terror message: {}\n",
Format::Error("error:"),
INTERNAL_ERROR_MSG, e.description()),
error_type: ClapErrorType::MissingSubcommand
});
}
return Ok(None);
}
// Short flag or opt
let arg_c = arg.chars().nth(0).unwrap();

// Ensure the arg in question isn't a help or version flag
if let Err(e) = self.check_for_help_and_version(arg_c) {
return Err(ClapError{
error: format!("{} {}\n\terror message: {}\n",
Format::Error("error:"),
INTERNAL_ERROR_MSG, e.description()),
error_type: ClapErrorType::MissingSubcommand
});
}

// Check for a matching flag, and return none if found
match self.parse_single_short_flag(matches, arg_c) {
Ok(b) => {
if b {
return Ok(None);
// Check for matching short in options, and return the name
// (only ones with shorts, of course)
if let Some(v) = self.opts.values()
.filter(|&v| v.short.is_some())
.filter(|&v| v.short == Some(c)).nth(0) {
let mut ret = Some(v.name);
// Ensure this option isn't on the master mutually excludes list
if self.blacklist.contains(&v.name) {
matches.args.remove(v.name);
return Err(self.report_error(format!("The argument '{}' cannot be used with {}",
Format::Warning(format!("-{}", arg)),
match self.blacklisted_from(v.name, matches) {
Some(name) => format!("'{}'", Format::Warning(name)),
None => "one or more of the other specified arguments".to_owned()
}),
ClapErrorType::ArgumentConflict,
Some(matches.args.keys().map(|k| *k).collect())));
}
}
Err(e) => return Err(e),
}

// Check for matching short in options, and return the name
// (only ones with shorts, of course)
if let Some(v) = self.opts.values()
.filter(|&v| v.short.is_some())
.filter(|&v| v.short.unwrap() == arg_c).nth(0) {
// Ensure this option isn't on the master mutually excludes list
if self.blacklist.contains(&v.name) {
matches.args.remove(v.name);
return Err(self.report_error(format!("The argument '{}' cannot be used with {}",
Format::Warning(format!("-{}", arg)),
match self.blacklisted_from(v.name, matches) {
Some(name) => format!("'{}'", Format::Warning(name)),
None => "one or more of the other specified arguments".to_owned()
}),
ClapErrorType::ArgumentConflict,
Some(matches.args.keys().map(|k| *k).collect())));
}
if self.overrides.contains(&v.name) {
if let Some(name) = self.overriden_from(v.name, matches) {
matches.args.remove(&*name);
remove_override!(self, &*name);
if self.overrides.contains(&v.name) {
if let Some(name) = self.overriden_from(v.name, matches) {
matches.args.remove(&*name);
remove_override!(self, &*name);
}
}
}
if let Some(ref or) = v.overrides {
for pa in or {
matches.args.remove(pa);
remove_override!(self, pa);
self.overrides.push(pa);
if let Some(ref or) = v.overrides {
for pa in or {
matches.args.remove(pa);
remove_override!(self, pa);
self.overrides.push(pa);
}
}
}

if matches.args.contains_key(v.name) {
if !v.settings.is_set(&ArgSettings::Multiple) {
return Err(self.report_error(format!("The argument '{}' was supplied more \
than once, but does not support multiple values",
Format::Warning(format!("-{}", arg))),
ClapErrorType::UnexpectedMultipleUsage,
Some(matches.args.keys().map(|k| *k).collect())));
if matches.args.contains_key(v.name) {
if !v.settings.is_set(&ArgSettings::Multiple) {
return Err(self.report_error(format!("The argument '{}' was supplied more \
than once, but does not support multiple values",
Format::Warning(format!("-{}", arg))),
ClapErrorType::UnexpectedMultipleUsage,
Some(matches.args.keys().map(|k| *k).collect())));
}
} 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()),
});
}
}
matches.args.insert(v.name, MatchedArg{
// occurrences will be incremented on getting a value
occurrences: 0,
values: Some(bm)
});
}
} else {
if let Some(ref vec) = self.groups_for(v.name) {
for grp in vec {
matches.args.insert(grp, MatchedArg{
occurrences: 1,
values: Some(BTreeMap::new()),
});
if let Some(ref bl) = v.blacklist {
for name in bl {
self.blacklist.push(name);
vec_remove!(self.overrides, name);
vec_remove!(self.required, name);
}
}
matches.args.insert(v.name, MatchedArg{
// occurrences will be incremented on getting a value
occurrences: 0,
values: Some(BTreeMap::new())
});
}
if let Some(ref bl) = v.blacklist {
for name in bl {
self.blacklist.push(name);
vec_remove!(self.overrides, name);
vec_remove!(self.required, name);

if let Some(ref reqs) = v.requires {
// Add all required args which aren't already found in matches to the
// final required list
for n in reqs {
if matches.args.contains_key(n) {
continue;
}

self.required.push(n);
}
}

parse_group_reqs!(self, v);

return Ok(ret);
}

if let Some(ref reqs) = v.requires {
// Add all required args which aren't already found in matches to the
// final required list
for n in reqs {
if matches.args.contains_key(n) {
continue;
match self.parse_single_short_flag(matches, c) {
Ok(b) => {
if !b {
return Err(self.report_error(format!("The argument '{}' isn't valid",
Format::Warning(format!("-{}", c))),
ClapErrorType::InvalidArgument,
Some(matches.args.keys().map(|k| *k).collect())));
}

self.required.push(n);
}
Err(e) => return Err(e),
}

parse_group_reqs!(self, v);

return Ok(Some(v.name))
}

// Didn't match a flag or option, must be invalid
Err(self.report_error(format!("The argument '{}' isn't valid",
Format::Warning(format!("-{}", arg_c))),
ClapErrorType::InvalidArgument,
Some(matches.args.keys().map(|k| *k).collect())))
unreachable!();
}

fn parse_single_short_flag(&mut self,
Expand Down

0 comments on commit 0e3733e

Please sign in to comment.