Skip to content

Commit

Permalink
feat(Trailing VarArg): adds opt-in setting for final arg being vararg
Browse files Browse the repository at this point in the history
Closes #278
  • Loading branch information
kbknapp committed Oct 1, 2015
1 parent 05414a4 commit 27018b1
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 30 deletions.
22 changes: 5 additions & 17 deletions src/app/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2354,9 +2354,7 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
Some(matches.args.keys().map(|k| *k).collect())));
}


if let Some(ref p_vals) = p.possible_vals {

if !p_vals.contains(&arg_slice) {
return Err(self.possible_values_error(arg_slice, &p.to_string(),
p_vals, matches));
Expand All @@ -2380,14 +2378,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
}
}
if !p.settings.is_set(&ArgSettings::EmptyValues) && matches.args.contains_key(p.name) &&
arg_slice.is_empty() {
return Err(self.report_error(format!("The argument '{}' does not \
allow empty values, but one was found.",
Format::Warning(p.to_string())),
ClapErrorType::EmptyValue,
Some(matches.args.keys().map(|k| *k).collect())));
}
// Check if it's already existing and update if so...
if let Some(ref mut pos) = matches.args.get_mut(p.name) {
done = true;
Expand All @@ -2397,6 +2387,11 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
vals.insert(len, arg_slice.to_owned());
}
}

if !pos_only && (self.settings.is_set(&AppSettings::TrailingVarArg) &&
pos_counter == self.positionals_idx.len() as u8) {
pos_only = true;
}
} else {
// Only increment the positional counter if it doesn't allow multiples
pos_counter += 1;
Expand All @@ -2417,13 +2412,6 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
}
let mut bm = BTreeMap::new();
if !p.settings.is_set(&ArgSettings::EmptyValues) && arg_slice.is_empty() {
return Err(self.report_error(format!("The argument '{}' does not \
allow empty values, but one was found.",
Format::Warning(p.to_string())),
ClapErrorType::EmptyValue,
Some(matches.args.keys().map(|k| *k).collect())));
}
if let Some(ref vtor) = p.validator {
let f = &*vtor;
if let Err(ref e) = f(arg_slice.to_owned()) {
Expand Down
50 changes: 37 additions & 13 deletions src/app/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ use std::ascii::AsciiExt;

bitflags! {
flags Flags: u32 {
const SC_NEGATE_REQS = 0b0000000000001,
const SC_REQUIRED = 0b0000000000010,
const A_REQUIRED_ELSE_HELP = 0b0000000000100,
const GLOBAL_VERSION = 0b0000000001000,
const VERSIONLESS_SC = 0b0000000010000,
const UNIFIED_HELP = 0b0000000100000,
const WAIT_ON_ERROR = 0b0000001000000,
const SC_REQUIRED_ELSE_HELP= 0b0000010000000,
const NEEDS_LONG_HELP = 0b0000100000000,
const NEEDS_LONG_VERSION = 0b0001000000000,
const NEEDS_SC_HELP = 0b0010000000000,
const DISABLE_VERSION = 0b0100000000000,
const HIDDEN = 0b1000000000000,
const SC_NEGATE_REQS = 0b00000000000001,
const SC_REQUIRED = 0b00000000000010,
const A_REQUIRED_ELSE_HELP = 0b00000000000100,
const GLOBAL_VERSION = 0b00000000001000,
const VERSIONLESS_SC = 0b00000000010000,
const UNIFIED_HELP = 0b00000000100000,
const WAIT_ON_ERROR = 0b00000001000000,
const SC_REQUIRED_ELSE_HELP= 0b00000010000000,
const NEEDS_LONG_HELP = 0b00000100000000,
const NEEDS_LONG_VERSION = 0b00001000000000,
const NEEDS_SC_HELP = 0b00010000000000,
const DISABLE_VERSION = 0b00100000000000,
const HIDDEN = 0b01000000000000,
const TRAILING_VARARG = 0b10000000000000,
}
}

Expand All @@ -41,6 +42,7 @@ impl AppFlags {
AppSettings::NeedsSubcommandHelp => self.0.insert(NEEDS_SC_HELP),
AppSettings::DisableVersion => self.0.insert(DISABLE_VERSION),
AppSettings::Hidden => self.0.insert(HIDDEN),
AppSettings::TrailingVarArg => self.0.insert(TRAILING_VARARG),
}
}

Expand All @@ -59,6 +61,7 @@ impl AppFlags {
AppSettings::NeedsSubcommandHelp => self.0.remove(NEEDS_SC_HELP),
AppSettings::DisableVersion => self.0.remove(DISABLE_VERSION),
AppSettings::Hidden => self.0.remove(HIDDEN),
AppSettings::TrailingVarArg => self.0.remove(TRAILING_VARARG),
}
}

Expand All @@ -77,6 +80,7 @@ impl AppFlags {
AppSettings::NeedsSubcommandHelp => self.0.contains(NEEDS_SC_HELP),
AppSettings::DisableVersion => self.0.contains(DISABLE_VERSION),
AppSettings::Hidden => self.0.contains(HIDDEN),
AppSettings::TrailingVarArg => self.0.contains(TRAILING_VARARG),
}
}
}
Expand Down Expand Up @@ -232,6 +236,26 @@ pub enum AppSettings {
/// # ;
/// ```
Hidden,
/// Specifies that the final positional argument is a vararg and that `clap` should not attempt
/// to parse any further args.
///
/// The values of the trailing positional argument will contain all args from itself on.
///
/// **NOTE:** The final positional argument **must** have `.multiple(true)` or usage token
/// equivilant.
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg, AppSettings};
/// let m = App::new("myprog")
/// .setting(AppSettings::TrailingVarArg)
/// .arg(Arg::from_usage("<cmd>... 'commands to run'"))
/// .get_matches_from(vec!["myprog", "some_command", "-r", "set"]);
///
/// assert_eq!(m.values_of("cmd").unwrap(), &["some_command", "-r", "set"]);
/// ```
TrailingVarArg,
#[doc(hidden)]
NeedsLongVersion,
#[doc(hidden)]
Expand Down

0 comments on commit 27018b1

Please sign in to comment.