Skip to content

Commit

Permalink
feat(Settings): adds new setting to stop delimiting values with -- or…
Browse files Browse the repository at this point in the history
… TrailingVarArg

One can now use `AppSettings::DontDelimitTrailingValues` to stop clap's default behavior of
delimiting values, even when `--` or `TrailingVarArg` is used. This is useful when passing other
flags and commands through to another program.

Closes #511
  • Loading branch information
kbknapp committed Jun 8, 2016
1 parent 7db45f7 commit fc3e0f5
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 44 deletions.
13 changes: 6 additions & 7 deletions src/app/macros.rs
Expand Up @@ -112,27 +112,26 @@ macro_rules! parse_positional {
$_self:ident,
$p:ident,
$arg_os:ident,
$pos_only:ident,
$pos_counter:ident,
$matcher:ident
) => {
debugln!("macro=parse_positional!;");
validate_multiples!($_self, $p, $matcher);

if let Err(e) = $_self.add_val_to_arg($p, &$arg_os, $matcher) {
return Err(e);
}
if !$pos_only &&
if !$_self.trailing_vals &&
($_self.settings.is_set(AppSettings::TrailingVarArg) &&
$pos_counter == $_self.positionals.len()) {
$pos_only = true;
$_self.trailing_vals = true;
}
if let Err(e) = $_self.add_val_to_arg($p, &$arg_os, $matcher) {
return Err(e);
}

$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
// Only increment the positional counter if it doesn't allow multiples
if !$p.settings.is_set(ArgSettings::Multiple) {
$pos_counter += 1;
}
Expand Down
26 changes: 16 additions & 10 deletions src/app/parser.rs
Expand Up @@ -51,6 +51,7 @@ pub struct Parser<'a, 'b>
settings: AppFlags,
pub g_settings: Vec<AppSettings>,
pub meta: AppMeta<'b>,
trailing_vals: bool,
}

impl<'a, 'b> Default for Parser<'a, 'b> {
Expand All @@ -72,6 +73,7 @@ impl<'a, 'b> Default for Parser<'a, 'b> {
g_settings: vec![],
settings: AppFlags::new(),
meta: AppMeta::new(),
trailing_vals: false,
}
}
}
Expand Down Expand Up @@ -456,7 +458,6 @@ impl<'a, 'b> Parser<'a, 'b>
// necessary
self.create_help_and_version();

let mut pos_only = false;
let mut subcmd_name: Option<String> = None;
let mut needs_val_of: Option<&str> = None;
let mut pos_counter = 1;
Expand All @@ -475,7 +476,7 @@ impl<'a, 'b> Parser<'a, 'b>
};

// Has the user already passed '--'?
if !pos_only {
if !self.trailing_vals {
// Does the arg match a subcommand name, or any of it's aliases (if defined)
let pos_sc = self.subcommands
.iter()
Expand All @@ -501,7 +502,7 @@ impl<'a, 'b> Parser<'a, 'b>
if arg_os.len_() == 2 {
// The user has passed '--' which means only positional args follow no
// matter what they start with
pos_only = true;
self.trailing_vals = true;
continue;
}

Expand Down Expand Up @@ -564,7 +565,7 @@ impl<'a, 'b> Parser<'a, 'b>
}

if let Some(p) = self.positionals.get(pos_counter) {
parse_positional!(self, p, arg_os, pos_only, pos_counter, matcher);
parse_positional!(self, p, arg_os, pos_counter, matcher);
} else {
if self.settings.is_set(AppSettings::AllowExternalSubcommands) {
let mut sc_m = ArgMatcher::new();
Expand Down Expand Up @@ -1131,13 +1132,17 @@ impl<'a, 'b> Parser<'a, 'b>
{
debugln!("fn=add_val_to_arg;");
let mut ret = None;
if let Some(delim) = arg.val_delim() {
if val.is_empty_() {
ret = try!(self.add_single_val_to_arg(arg, val, matcher));
} else {
for v in val.split(delim as u32 as u8) {
ret = try!(self.add_single_val_to_arg(arg, v, matcher));
if !(self.trailing_vals && self.is_set(AppSettings::DontDelimitTrailingValues)) {
if let Some(delim) = arg.val_delim() {
if val.is_empty_() {
ret = try!(self.add_single_val_to_arg(arg, val, matcher));
} else {
for v in val.split(delim as u32 as u8) {
ret = try!(self.add_single_val_to_arg(arg, v, matcher));
}
}
} else {
ret = try!(self.add_single_val_to_arg(arg, val, matcher));
}
} else {
ret = try!(self.add_single_val_to_arg(arg, val, matcher));
Expand Down Expand Up @@ -1679,6 +1684,7 @@ impl<'a, 'b> Clone for Parser<'a, 'b>
settings: self.settings.clone(),
g_settings: self.g_settings.clone(),
meta: self.meta.clone(),
trailing_vals: self.trailing_vals,
}
}
}
76 changes: 49 additions & 27 deletions src/app/settings.rs
Expand Up @@ -3,32 +3,33 @@ use std::ascii::AsciiExt;

bitflags! {
flags Flags: u32 {
const SC_NEGATE_REQS = 0b00000000000000000000000001,
const SC_REQUIRED = 0b00000000000000000000000010,
const A_REQUIRED_ELSE_HELP = 0b00000000000000000000000100,
const GLOBAL_VERSION = 0b00000000000000000000001000,
const VERSIONLESS_SC = 0b00000000000000000000010000,
const UNIFIED_HELP = 0b00000000000000000000100000,
const WAIT_ON_ERROR = 0b00000000000000000001000000,
const SC_REQUIRED_ELSE_HELP= 0b00000000000000000010000000,
const NEEDS_LONG_HELP = 0b00000000000000000100000000,
const NEEDS_LONG_VERSION = 0b00000000000000001000000000,
const NEEDS_SC_HELP = 0b00000000000000010000000000,
const DISABLE_VERSION = 0b00000000000000100000000000,
const HIDDEN = 0b00000000000001000000000000,
const TRAILING_VARARG = 0b00000000000010000000000000,
const NO_BIN_NAME = 0b00000000000100000000000000,
const ALLOW_UNK_SC = 0b00000000001000000000000000,
const UTF8_STRICT = 0b00000000010000000000000000,
const UTF8_NONE = 0b00000000100000000000000000,
const LEADING_HYPHEN = 0b00000001000000000000000000,
const NO_POS_VALUES = 0b00000010000000000000000000,
const NEXT_LINE_HELP = 0b00000100000000000000000000,
const DERIVE_DISP_ORDER = 0b00001000000000000000000000,
const COLORED_HELP = 0b00010000000000000000000000,
const COLOR_ALWAYS = 0b00100000000000000000000000,
const COLOR_AUTO = 0b01000000000000000000000000,
const COLOR_NEVER = 0b10000000000000000000000000,
const SC_NEGATE_REQS = 0b000000000000000000000000001,
const SC_REQUIRED = 0b000000000000000000000000010,
const A_REQUIRED_ELSE_HELP = 0b000000000000000000000000100,
const GLOBAL_VERSION = 0b000000000000000000000001000,
const VERSIONLESS_SC = 0b000000000000000000000010000,
const UNIFIED_HELP = 0b000000000000000000000100000,
const WAIT_ON_ERROR = 0b000000000000000000001000000,
const SC_REQUIRED_ELSE_HELP= 0b000000000000000000010000000,
const NEEDS_LONG_HELP = 0b000000000000000000100000000,
const NEEDS_LONG_VERSION = 0b000000000000000001000000000,
const NEEDS_SC_HELP = 0b000000000000000010000000000,
const DISABLE_VERSION = 0b000000000000000100000000000,
const HIDDEN = 0b000000000000001000000000000,
const TRAILING_VARARG = 0b000000000000010000000000000,
const NO_BIN_NAME = 0b000000000000100000000000000,
const ALLOW_UNK_SC = 0b000000000001000000000000000,
const UTF8_STRICT = 0b000000000010000000000000000,
const UTF8_NONE = 0b000000000100000000000000000,
const LEADING_HYPHEN = 0b000000001000000000000000000,
const NO_POS_VALUES = 0b000000010000000000000000000,
const NEXT_LINE_HELP = 0b000000100000000000000000000,
const DERIVE_DISP_ORDER = 0b000001000000000000000000000,
const COLORED_HELP = 0b000010000000000000000000000,
const COLOR_ALWAYS = 0b000100000000000000000000000,
const COLOR_AUTO = 0b001000000000000000000000000,
const COLOR_NEVER = 0b010000000000000000000000000,
const DONT_DELIM_TRAIL = 0b100000000000000000000000000,
}
}

Expand Down Expand Up @@ -79,7 +80,8 @@ impl AppFlags {
DeriveDisplayOrder => DERIVE_DISP_ORDER,
ColorAlways => COLOR_ALWAYS,
ColorAuto => COLOR_AUTO,
ColorNever => COLOR_NEVER
ColorNever => COLOR_NEVER,
DontDelimitTrailingValues => DONT_DELIM_TRAIL
}
}

Expand Down Expand Up @@ -551,6 +553,24 @@ pub enum AppSettings {
/// .get_matches();
/// ```
ColorNever,
/// Disables the automatic delimiting of values when `--` or [`AppSettings::TrailingVarArg`]
/// was used.
///
/// **NOTE:** The same thing can be done manually by setting the final positional argument to
/// [`Arg::use_delimiter(false)`]. Using this setting is safer, because it's easier to locate
/// when making changes.
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg, SubCommand, AppSettings};
/// App::new("myprog")
/// .setting(AppSettings::DontDelimitTrailingValues)
/// .get_matches();
/// ```
/// [`AppSettings::TrailingVarArg`]: ./enum.AppSettings.html#variant.TrailingVarArg
/// [`Arg::use_delimiter(false)`]: ./struct.Arg.html#method.use_delimiter
DontDelimitTrailingValues,
#[doc(hidden)]
NeedsLongVersion,
#[doc(hidden)]
Expand Down Expand Up @@ -633,6 +653,8 @@ mod test {
AppSettings::ColoredHelp);
assert_eq!("hidden".parse::<AppSettings>().unwrap(),
AppSettings::Hidden);
assert_eq!("dontdelimittrailingvalues".parse::<AppSettings>().unwrap(),
AppSettings::DontDelimitTrailingValues);
assert!("hahahaha".parse::<AppSettings>().is_err());
}
}

0 comments on commit fc3e0f5

Please sign in to comment.