diff --git a/src/build/app/settings.rs b/src/build/app/settings.rs index 0807f1b8c15..7a0aa407365 100644 --- a/src/build/app/settings.rs +++ b/src/build/app/settings.rs @@ -6,47 +6,48 @@ use std::str::FromStr; bitflags! { struct Flags: u64 { - const SC_NEGATE_REQS = 1; - const SC_REQUIRED = 1 << 1; - const A_REQUIRED_ELSE_HELP = 1 << 2; - const GLOBAL_VERSION = 1 << 3; - const VERSIONLESS_SC = 1 << 4; - const UNIFIED_HELP = 1 << 5; - const WAIT_ON_ERROR = 1 << 6; - const SC_REQUIRED_ELSE_HELP= 1 << 7; - const NO_AUTO_HELP = 1 << 8; - const NO_AUTO_VERSION = 1 << 9; - const DISABLE_VERSION = 1 << 10; - const HIDDEN = 1 << 11; - const TRAILING_VARARG = 1 << 12; - const NO_BIN_NAME = 1 << 13; - const ALLOW_UNK_SC = 1 << 14; - const UTF8_STRICT = 1 << 15; - const UTF8_NONE = 1 << 16; - const LEADING_HYPHEN = 1 << 17; - const NO_POS_VALUES = 1 << 18; - const NEXT_LINE_HELP = 1 << 19; - const DERIVE_DISP_ORDER = 1 << 20; - const COLORED_HELP = 1 << 21; - const COLOR_ALWAYS = 1 << 22; - const COLOR_AUTO = 1 << 23; - const COLOR_NEVER = 1 << 24; - const DONT_DELIM_TRAIL = 1 << 25; - const ALLOW_NEG_NUMS = 1 << 26; - const LOW_INDEX_MUL_POS = 1 << 27; - const DISABLE_HELP_SC = 1 << 28; - const DONT_COLLAPSE_ARGS = 1 << 29; - const ARGS_NEGATE_SCS = 1 << 30; - const PROPAGATE_VALS_DOWN = 1 << 31; - const ALLOW_MISSING_POS = 1 << 32; - const TRAILING_VALUES = 1 << 33; - const VALID_NEG_NUM_FOUND = 1 << 34; - const BUILT = 1 << 35; - const VALID_ARG_FOUND = 1 << 36; - const INFER_SUBCOMMANDS = 1 << 37; - const CONTAINS_LAST = 1 << 38; - const ARGS_OVERRIDE_SELF = 1 << 39; - const HELP_REQUIRED = 1 << 40; + const SC_NEGATE_REQS = 1; + const SC_REQUIRED = 1 << 1; + const A_REQUIRED_ELSE_HELP = 1 << 2; + const GLOBAL_VERSION = 1 << 3; + const VERSIONLESS_SC = 1 << 4; + const UNIFIED_HELP = 1 << 5; + const WAIT_ON_ERROR = 1 << 6; + const SC_REQUIRED_ELSE_HELP = 1 << 7; + const NO_AUTO_HELP = 1 << 8; + const NO_AUTO_VERSION = 1 << 9; + const DISABLE_VERSION = 1 << 10; + const HIDDEN = 1 << 11; + const TRAILING_VARARG = 1 << 12; + const NO_BIN_NAME = 1 << 13; + const ALLOW_UNK_SC = 1 << 14; + const UTF8_STRICT = 1 << 15; + const UTF8_NONE = 1 << 16; + const LEADING_HYPHEN = 1 << 17; + const NO_POS_VALUES = 1 << 18; + const NEXT_LINE_HELP = 1 << 19; + const DERIVE_DISP_ORDER = 1 << 20; + const COLORED_HELP = 1 << 21; + const COLOR_ALWAYS = 1 << 22; + const COLOR_AUTO = 1 << 23; + const COLOR_NEVER = 1 << 24; + const DONT_DELIM_TRAIL = 1 << 25; + const ALLOW_NEG_NUMS = 1 << 26; + const LOW_INDEX_MUL_POS = 1 << 27; + const DISABLE_HELP_SC = 1 << 28; + const DONT_COLLAPSE_ARGS = 1 << 29; + const ARGS_NEGATE_SCS = 1 << 30; + const PROPAGATE_VALS_DOWN = 1 << 31; + const ALLOW_MISSING_POS = 1 << 32; + const TRAILING_VALUES = 1 << 33; + const VALID_NEG_NUM_FOUND = 1 << 34; + const BUILT = 1 << 35; + const VALID_ARG_FOUND = 1 << 36; + const INFER_SUBCOMMANDS = 1 << 37; + const CONTAINS_LAST = 1 << 38; + const ARGS_OVERRIDE_SELF = 1 << 39; + const HELP_REQUIRED = 1 << 40; + const SUBCOMMAND_PRECEDENCE_OVER_ARG = 1 << 41; } } @@ -69,6 +70,8 @@ impl Default for AppFlags { impl_settings! { AppSettings, AppFlags, ArgRequiredElseHelp("argrequiredelsehelp") => Flags::A_REQUIRED_ELSE_HELP, + SubcommandPrecedenceOverArg("subcommandprecedenceoverarg") + => Flags::SUBCOMMAND_PRECEDENCE_OVER_ARG, ArgsNegateSubcommands("argsnegatesubcommands") => Flags::ARGS_NEGATE_SCS, AllowExternalSubcommands("allowexternalsubcommands") @@ -436,6 +439,63 @@ pub enum AppSettings { /// [`Arg::default_value`]: ./struct.Arg.html#method.default_value ArgRequiredElseHelp, + /// Instructs the parser to stop when encountering a subcommand instead of greedily consuming + /// args. + /// + /// By default, if an option taking multiple values is followed by a subcommand, the + /// subcommand will be parsed as another value. + /// + /// ```text + /// app --foo val1 val2 subcommand + /// --------- ---------- + /// values another value + /// ``` + /// + /// This setting instructs the parser to stop when encountering a subcommand instead of + /// greedily consuming arguments. + /// + /// ```text + /// app --foo val1 val2 subcommand + /// --------- ---------- + /// values subcommand + /// ``` + /// + /// **Note:** Make sure you apply it as `global_setting` if you want it to be propagated to + /// sub-sub commands! + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings, Arg}; + /// let app = App::new("app").subcommand(App::new("sub")).arg( + /// Arg::with_name("arg") + /// .long("arg") + /// .multiple(true) + /// .takes_value(true), + /// ); + /// + /// let matches = app + /// .clone() + /// .try_get_matches_from(&["app", "--arg", "1", "2", "3", "sub"]) + /// .unwrap(); + /// assert_eq!( + /// matches.values_of("arg").unwrap().collect::>(), + /// &["1", "2", "3", "sub"] + /// ); + /// assert!(matches.subcommand_matches("sub").is_none()); + /// + /// let app = app.setting(AppSettings::SubcommandPrecedenceOverArg); + /// let matches = app + /// .try_get_matches_from(&["app", "--arg", "1", "2", "3", "sub"]) + /// .unwrap(); + /// assert_eq!( + /// matches.values_of("arg").unwrap().collect::>(), + /// &["1", "2", "3"] + /// ); + /// assert!(matches.subcommand_matches("sub").is_some()); + /// ``` + SubcommandPrecedenceOverArg, + /// Uses colorized help messages. /// /// **NOTE:** Must be compiled with the `color` cargo feature @@ -988,6 +1048,12 @@ mod test { "argrequiredelsehelp".parse::().unwrap(), AppSettings::ArgRequiredElseHelp ); + assert_eq!( + "subcommandprecedenceoverarg" + .parse::() + .unwrap(), + AppSettings::SubcommandPrecedenceOverArg + ); assert_eq!( "allowexternalsubcommands".parse::().unwrap(), AppSettings::AllowExternalSubcommands diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 864e1daab73..4681ae4c695 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -469,7 +469,8 @@ where if !self.is_set(AS::TrailingValues) { // Does the arg match a subcommand name, or any of it's aliases (if defined) match needs_val_of { - ParseResult::Opt(_) | ParseResult::Pos(_) => (), + ParseResult::Opt(_) | ParseResult::Pos(_) + if !self.is_set(AS::SubcommandPrecedenceOverArg) => {} _ => { let sc_name = self.possible_subcommand(arg_os); debugln!(