diff --git a/src/app/help.rs b/src/app/help.rs index aed333033b2..df1d034c0a0 100644 --- a/src/app/help.rs +++ b/src/app/help.rs @@ -296,6 +296,8 @@ impl<'w> Help<'w> { /// Writes argument's possible values to the wrapped stream. fn val<'b, 'c>(&mut self, arg: &Arg<'b, 'c>) -> Result { debugln!("Help::val: arg={}", arg.name); + let mult = + arg.is_set(ArgSettings::MultipleValues) || arg.is_set(ArgSettings::MultipleOccurrences); if arg.is_set(ArgSettings::TakesValue) { let delim = if arg.is_set(ArgSettings::RequireDelimiter) { arg.val_delim.expect(INTERNAL_ERROR_MSG) @@ -311,7 +313,7 @@ impl<'w> Help<'w> { } } let num = vec.len(); - if arg.is_set(ArgSettings::Multiple) && num == 1 { + if mult && num == 1 { color!(self, "...", good)?; } } else if let Some(num) = arg.num_vals { @@ -322,12 +324,12 @@ impl<'w> Help<'w> { write!(self.writer, "{}", delim)?; } } - if arg.is_set(ArgSettings::Multiple) && num == 1 { + if mult && num == 1 { color!(self, "...", good)?; } } else if arg.has_switch() { color!(self, "<{}>", arg.name, good)?; - if arg.is_set(ArgSettings::Multiple) { + if mult { color!(self, "...", good)?; } } else { diff --git a/src/app/mod.rs b/src/app/mod.rs index b4647af7816..9bbed4cc95c 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1564,8 +1564,8 @@ impl<'a, 'b> App<'a, 'b> { assert!( positionals!(self).fold(0, |acc, p| if p.index == Some(idx as u64){acc+1}else{acc}) < 2, "Argument '{}' has the same index as another positional \ - argument\n\n\tUse Arg::multiple(true) to allow one positional argument \ - to take multiple values", + argument\n\n\tUse Arg::setting(ArgSettings::MultipleValues) to allow one \ + positional argument to take multiple values", a.name ); } diff --git a/src/app/parser.rs b/src/app/parser.rs index f2d8e3569ac..4b528b3c9db 100644 --- a/src/app/parser.rs +++ b/src/app/parser.rs @@ -128,7 +128,7 @@ where // Next we verify that only the highest index has a .multiple(true) (if any) if positionals!(self.app).any(|a| { - a.is_set(ArgSettings::Multiple) && (a.index.unwrap_or(0) != highest_idx as u64) + a.is_set(ArgSettings::MultipleValues) && (a.index.unwrap_or(0) != highest_idx as u64) }) { // First we make sure if there is a positional that allows multiple values // the one before it (second to last) has one of these: @@ -157,7 +157,8 @@ where ); // We make sure if the second to last is Multiple the last is ArgSettings::Last - let ok = second_to_last.is_set(ArgSettings::Multiple) || last.is_set(ArgSettings::Last); + let ok = second_to_last.is_set(ArgSettings::MultipleValues) + || last.is_set(ArgSettings::Last); assert!( ok, "Only the last positional argument, or second to last positional \ @@ -166,15 +167,15 @@ where // Next we check how many have both Multiple and not a specific number of values set let count = positionals!(self.app).fold(0, |acc, p| { - if p.settings.is_set(ArgSettings::Multiple) && p.num_vals.is_none() { + if p.settings.is_set(ArgSettings::MultipleValues) && p.num_vals.is_none() { acc + 1 } else { acc } }); let ok = count <= 1 - || (last.is_set(ArgSettings::Last) && last.is_set(ArgSettings::Multiple) - && second_to_last.is_set(ArgSettings::Multiple) + || (last.is_set(ArgSettings::Last) && last.is_set(ArgSettings::MultipleValues) + && second_to_last.is_set(ArgSettings::MultipleValues) && count == 2); assert!( ok, @@ -307,7 +308,7 @@ where debug_assert!(self._verify_positionals()); // Set the LowIndexMultiple flag if required if positionals!(self.app).any(|a| { - a.is_set(ArgSettings::Multiple) + a.is_set(ArgSettings::MultipleValues) && (a.index.unwrap_or(0) as usize != self.positionals.len()) }) && self.positionals.values().last().map_or(false, |p_name| { !find!(self.app, p_name) @@ -535,7 +536,7 @@ where self.app.settings.set(AS::ValidArgFound); // Only increment the positional counter if it doesn't allow multiples - if !p.settings.is_set(ArgSettings::Multiple) { + if !p.settings.is_set(ArgSettings::MultipleValues) { pos_counter += 1; } self.app.settings.set(AS::ValidArgFound); @@ -721,7 +722,7 @@ where if help_help { let mut pb = Arg::with_name("subcommand") .index(1) - .set(ArgSettings::Multiple) + .setting(ArgSettings::MultipleValues) .help("The subcommand whose help message to display"); pb._build(); parser.positionals.insert(1, pb.name); @@ -754,11 +755,11 @@ where let arg_allows_tac = match needs_val_of { ParseResult::Opt(name) => { let o = find!(self.app, &name).expect(INTERNAL_ERROR_MSG); - (o.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings) + (o.is_set(ArgSettings::AllowHyphenValues) || app_wide_settings) } ParseResult::Pos(name) => { let p = find!(self.app, &name).expect(INTERNAL_ERROR_MSG); - (p.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings) + (p.is_set(ArgSettings::AllowHyphenValues) || app_wide_settings) } ParseResult::ValuesDone => return true, _ => false, @@ -1061,7 +1062,7 @@ where debugln!("Parser::parse_opt; opt.settings={:?}", opt.settings); let mut has_eq = false; let no_val = val.is_none(); - let empty_vals = opt.is_set(ArgSettings::EmptyValues); + let empty_vals = opt.is_set(ArgSettings::AllowEmptyValues); let min_vals_zero = opt.min_vals.unwrap_or(1) == 0; let needs_eq = opt.is_set(ArgSettings::RequireEquals); @@ -1101,7 +1102,8 @@ where .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec))); let needs_delim = opt.is_set(ArgSettings::RequireDelimiter); - let mult = opt.is_set(ArgSettings::Multiple); + let mult = opt.is_set(ArgSettings::MultipleValues); + // @TODO @soundness: if doesn't have an equal, but requires equal is ValuesDone?! if no_val && min_vals_zero && !has_eq && needs_eq { debugln!("Parser::parse_opt: More arg vals not required..."); return Ok(ParseResult::ValuesDone); diff --git a/src/app/usage.rs b/src/app/usage.rs index 07a24ac4a4b..c2f66ea534b 100644 --- a/src/app/usage.rs +++ b/src/app/usage.rs @@ -96,7 +96,7 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> { let has_last = positionals!(self.0.app).any(|p| p.is_set(ArgSettings::Last)); // places a '--' in the usage string if there are args and options // supporting multiple values - if opts!(self.0.app).any(|o| o.is_set(ArgSettings::Multiple)) + if opts!(self.0.app).any(|o| o.is_set(ArgSettings::MultipleValues)) && positionals!(self.0.app).any(|p| !p.is_set(ArgSettings::Required)) && !(self.0.app.has_visible_subcommands() || self.0.is_set(AS::AllowExternalSubcommands)) && !has_last diff --git a/src/app/validator.rs b/src/app/validator.rs index 40101d0baff..0b897e567e8 100644 --- a/src/app/validator.rs +++ b/src/app/validator.rs @@ -95,7 +95,7 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> { if let Some(ref p_vals) = arg.possible_vals { debugln!("Validator::validate_arg_values: possible_vals={:?}", p_vals); let val_str = val.to_string_lossy(); - let ok = if arg.is_set(ArgSettings::CaseInsensitive) { + let ok = if arg.is_set(ArgSettings::IgnoreCase) { p_vals.iter().any(|pv| pv.eq_ignore_ascii_case(&*val_str)) } else { p_vals.contains(&&*val_str) @@ -110,7 +110,7 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> { )); } } - if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty_() + if !arg.is_set(ArgSettings::AllowEmptyValues) && val.is_empty_() && matcher.contains(&*arg.name) { debugln!("Validator::validate_arg_values: illegal empty val found"); @@ -292,7 +292,7 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> { matcher: &ArgMatcher<'a>, ) -> ClapResult<()> { debugln!("Validator::validate_arg_num_occurs: a={};", a.name); - if ma.occurs > 1 && !a.is_set(ArgSettings::Multiple) { + if ma.occurs > 1 && !a.is_set(ArgSettings::MultipleOccurrences) { // Not the first time, and we don't allow multiples return Err(Error::unexpected_multiple_usage( a, @@ -312,7 +312,7 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> { debugln!("Validator::validate_arg_num_vals;"); if let Some(num) = a.num_vals { debugln!("Validator::validate_arg_num_vals: num_vals set...{}", num); - let should_err = if a.is_set(ArgSettings::Multiple) { + let should_err = if a.is_set(ArgSettings::MultipleValues) { ((ma.vals.len() as u64) % num) != 0 } else { num != (ma.vals.len() as u64) @@ -322,13 +322,14 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> { return Err(Error::wrong_number_of_values( a, num, - if a.is_set(ArgSettings::Multiple) { + if a.is_set(ArgSettings::MultipleValues) { (ma.vals.len() % num as usize) } else { ma.vals.len() }, if ma.vals.len() == 1 - || (a.is_set(ArgSettings::Multiple) && (ma.vals.len() % num as usize) == 1) + || (a.is_set(ArgSettings::MultipleValues) + && (ma.vals.len() % num as usize) == 1) { "as" } else { diff --git a/src/args/arg.rs b/src/args/arg.rs index e016f226e77..cdf9fa78f8b 100644 --- a/src/args/arg.rs +++ b/src/args/arg.rs @@ -210,142 +210,6 @@ impl<'a, 'b> Arg<'a, 'b> { a } - /// Creates a new instance of [`Arg`] from a usage string. Allows creation of basic settings - /// for the [`Arg`]. The syntax is flexible, but there are some rules to follow. - /// - /// **NOTE**: Not all settings may be set using the usage string method. Some properties are - /// only available via the builder pattern. - /// - /// **NOTE**: Only ASCII values are officially supported in [`Arg::from_usage`] strings. Some - /// UTF-8 codepoints may work just fine, but this is not guaranteed. - /// - /// # Syntax - /// - /// Usage strings typically following the form: - /// - /// ```notrust - /// [explicit name] [short] [long] [value names] [help string] - /// ``` - /// - /// This is not a hard rule as the attributes can appear in other orders. There are also - /// several additional sigils which denote additional settings. Below are the details of each - /// portion of the string. - /// - /// ### Explicit Name - /// - /// This is an optional field, if it's omitted the argument will use one of the additional - /// fields as the name using the following priority order: - /// - /// * Explicit Name (This always takes precedence when present) - /// * Long - /// * Short - /// * Value Name - /// - /// `clap` determines explicit names as the first string of characters between either `[]` or - /// `<>` where `[]` has the dual notation of meaning the argument is optional, and `<>` meaning - /// the argument is required. - /// - /// Explicit names may be followed by: - /// * The multiple denotation `...` - /// - /// Example explicit names as follows (`ename` for an optional argument, and `rname` for a - /// required argument): - /// - /// ```notrust - /// [ename] -s, --long 'some flag' - /// -r, --longer 'some other flag' - /// ``` - /// - /// ### Short - /// - /// This is set by placing a single character after a leading `-`. - /// - /// Shorts may be followed by - /// * The multiple denotation `...` - /// * An optional comma `,` which is cosmetic only - /// * Value notation - /// - /// Example shorts are as follows (`-s`, and `-r`): - /// - /// ```notrust - /// -s, --long 'some flag' - /// -r [val], --longer 'some option' - /// ``` - /// - /// ### Long - /// - /// This is set by placing a word (no spaces) after a leading `--`. - /// - /// Shorts may be followed by - /// * The multiple denotation `...` - /// * Value notation - /// - /// Example longs are as follows (`--some`, and `--rapid`): - /// - /// ```notrust - /// -s, --some 'some flag' - /// --rapid=[FILE] 'some option' - /// ``` - /// - /// ### Values (Value Notation) - /// - /// This is set by placing a word(s) between `[]` or `<>` optionally after `=` (although this - /// is cosmetic only and does not affect functionality). If an explicit name has **not** been - /// set, using `<>` will denote a required argument, and `[]` will denote an optional argument - /// - /// Values may be followed by - /// * The multiple denotation `...` - /// * More Value notation - /// - /// More than one value will also implicitly set the arguments number of values, i.e. having - /// two values, `--option [val1] [val2]` specifies that in order for option to be satisified it - /// must receive exactly two values - /// - /// Example values are as follows (`FILE`, and `SPEED`): - /// - /// ```notrust - /// -s, --some [FILE] 'some option' - /// --rapid=... 'some required multiple option' - /// ``` - /// - /// ### Help String - /// - /// The help string is denoted between a pair of single quotes `''` and may contain any - /// characters. - /// - /// Example help strings are as follows: - /// - /// ```notrust - /// -s, --some [FILE] 'some option' - /// --rapid=... 'some required multiple option' - /// ``` - /// - /// ### Additional Sigils - /// - /// Multiple notation `...` (three consecutive dots/periods) specifies that this argument may - /// be used multiple times. Do not confuse multiple occurrences (`...`) with multiple values. - /// `--option val1 val2` is a single occurrence with multiple values. `--flag --flag` is - /// multiple occurrences (and then you can obviously have instances of both as well) - /// - /// # Examples - /// - /// ```rust - /// # use clap::{App, Arg}; - /// App::new("prog") - /// .args(&[ - /// Arg::from_usage("--config 'a required file for the configuration and no short'"), - /// Arg::from_usage("-d, --debug... 'turns on debugging information and allows multiples'"), - /// Arg::from_usage("[input] 'an optional input file to use'") - /// ]) - /// # ; - /// ``` - /// [`Arg`]: ./struct.Arg.html - /// [`Arg::from_usage`]: ./struct.Arg.html#method.from_usage - pub fn from_usage(u: &'a str) -> Self { - let parser = UsageParser::from_usage(u); - parser.parse() - } - /// Sets the short version of the argument without the preceding `-`. /// /// By default `clap` automatically assigns `V` and `h` to the auto-generated `version` and @@ -673,271 +537,6 @@ impl<'a, 'b> Arg<'a, 'b> { self } - /// Specifies that this arg is the last, or final, positional argument (i.e. has the highest - /// index) and is *only* able to be accessed via the `--` syntax (i.e. `$ prog args -- - /// last_arg`). Even, if no other arguments are left to parse, if the user omits the `--` syntax - /// they will receive an [`UnknownArgument`] error. Setting an argument to `.last(true)` also - /// allows one to access this arg early using the `--` syntax. Accessing an arg early, even with - /// the `--` syntax is otherwise not possible. - /// - /// **NOTE:** This will change the usage string to look like `$ prog [FLAGS] [-- ]` if - /// `ARG` is marked as `.last(true)`. - /// - /// **NOTE:** This setting will imply [`AppSettings::DontCollapseArgsInUsage`] because failing - /// to set this can make the usage string very confusing. - /// - /// **NOTE**: This setting only applies to positional arguments, and has no affect on FLAGS / - /// OPTIONS - /// - /// **CAUTION:** Setting an argument to `.last(true)` *and* having child subcommands is not - /// recommended with the exception of *also* using [`AppSettings::ArgsNegateSubcommands`] - /// (or [`AppSettings::SubcommandsNegateReqs`] if the argument marked `.last(true)` is also - /// marked [`.required(true)`]) - /// - /// # Examples - /// - /// ```rust - /// # use clap::Arg; - /// Arg::with_name("args") - /// .last(true) - /// # ; - /// ``` - /// - /// Setting [`Arg::last(true)`] ensures the arg has the highest [index] of all positional args - /// and requires that the `--` syntax be used to access it early. - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let res = App::new("prog") - /// .arg(Arg::with_name("first")) - /// .arg(Arg::with_name("second")) - /// .arg(Arg::with_name("third").last(true)) - /// .get_matches_from_safe(vec![ - /// "prog", "one", "--", "three" - /// ]); - /// - /// assert!(res.is_ok()); - /// let m = res.unwrap(); - /// assert_eq!(m.value_of("third"), Some("three")); - /// assert!(m.value_of("second").is_none()); - /// ``` - /// - /// Even if the positional argument marked `.last(true)` is the only argument left to parse, - /// failing to use the `--` syntax results in an error. - /// - /// ```rust - /// # use clap::{App, Arg, ErrorKind}; - /// let res = App::new("prog") - /// .arg(Arg::with_name("first")) - /// .arg(Arg::with_name("second")) - /// .arg(Arg::with_name("third").last(true)) - /// .get_matches_from_safe(vec![ - /// "prog", "one", "two", "three" - /// ]); - /// - /// assert!(res.is_err()); - /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); - /// ``` - /// [`Arg::last(true)`]: ./struct.Arg.html#method.last - /// [index]: ./struct.Arg.html#method.index - /// [`AppSettings::DontCollapseArgsInUsage`]: ./enum.AppSettings.html#variant.DontCollapseArgsInUsage - /// [`AppSettings::ArgsNegateSubcommands`]: ./enum.AppSettings.html#variant.ArgsNegateSubcommands - /// [`AppSettings::SubcommandsNegateReqs`]: ./enum.AppSettings.html#variant.SubcommandsNegateReqs - /// [`.required(true)`]: ./struct.Arg.html#method.required - /// [`UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument - pub fn last(self, l: bool) -> Self { - if l { - self.set(ArgSettings::Last) - } else { - self.unset(ArgSettings::Last) - } - } - - /// Sets whether or not the argument is required by default. Required by default means it is - /// required, when no other conflicting rules have been evaluated. Conflicting rules take - /// precedence over being required. **Default:** `false` - /// - /// **NOTE:** Flags (i.e. not positional, or arguments that take values) cannot be required by - /// default. This is simply because if a flag should be required, it should simply be implied - /// as no additional information is required from user. Flags by their very nature are simply - /// yes/no, or true/false. - /// - /// # Examples - /// - /// ```rust - /// # use clap::Arg; - /// Arg::with_name("config") - /// .required(true) - /// # ; - /// ``` - /// - /// Setting [`Arg::required(true)`] requires that the argument be used at runtime. - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let res = App::new("prog") - /// .arg(Arg::with_name("cfg") - /// .required(true) - /// .takes_value(true) - /// .long("config")) - /// .get_matches_from_safe(vec![ - /// "prog", "--config", "file.conf" - /// ]); - /// - /// assert!(res.is_ok()); - /// ``` - /// - /// Setting [`Arg::required(true)`] and *not* supplying that argument is an error. - /// - /// ```rust - /// # use clap::{App, Arg, ErrorKind}; - /// let res = App::new("prog") - /// .arg(Arg::with_name("cfg") - /// .required(true) - /// .takes_value(true) - /// .long("config")) - /// .get_matches_from_safe(vec![ - /// "prog" - /// ]); - /// - /// assert!(res.is_err()); - /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); - /// ``` - /// [`Arg::required(true)`]: ./struct.Arg.html#method.required - pub fn required(self, r: bool) -> Self { - if r { - self.set(ArgSettings::Required) - } else { - self.unset(ArgSettings::Required) - } - } - - /// Requires that options use the `--option=val` syntax (i.e. an equals between the option and - /// associated value) **Default:** `false` - /// - /// **NOTE:** This setting also removes the default of allowing empty values and implies - /// [`Arg::empty_values(false)`]. - /// - /// # Examples - /// - /// ```rust - /// # use clap::Arg; - /// Arg::with_name("config") - /// .long("config") - /// .takes_value(true) - /// .require_equals(true) - /// # ; - /// ``` - /// - /// Setting [`Arg::require_equals(true)`] requires that the option have an equals sign between - /// it and the associated value. - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let res = App::new("prog") - /// .arg(Arg::with_name("cfg") - /// .require_equals(true) - /// .takes_value(true) - /// .long("config")) - /// .get_matches_from_safe(vec![ - /// "prog", "--config=file.conf" - /// ]); - /// - /// assert!(res.is_ok()); - /// ``` - /// - /// Setting [`Arg::require_equals(true)`] and *not* supplying the equals will cause an error - /// unless [`Arg::empty_values(true)`] is set. - /// - /// ```rust - /// # use clap::{App, Arg, ErrorKind}; - /// let res = App::new("prog") - /// .arg(Arg::with_name("cfg") - /// .require_equals(true) - /// .takes_value(true) - /// .long("config")) - /// .get_matches_from_safe(vec![ - /// "prog", "--config", "file.conf" - /// ]); - /// - /// assert!(res.is_err()); - /// assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); - /// ``` - /// [`Arg::require_equals(true)`]: ./struct.Arg.html#method.require_equals - /// [`Arg::empty_values(true)`]: ./struct.Arg.html#method.empty_values - /// [`Arg::empty_values(false)`]: ./struct.Arg.html#method.empty_values - pub fn require_equals(mut self, r: bool) -> Self { - if r { - self.unsetb(ArgSettings::EmptyValues); - self.set(ArgSettings::RequireEquals) - } else { - self.unset(ArgSettings::RequireEquals) - } - } - - /// Allows values which start with a leading hyphen (`-`) - /// - /// **WARNING**: Take caution when using this setting combined with [`Arg::multiple(true)`], as - /// this becomes ambiguous `$ prog --arg -- -- val`. All three `--, --, val` will be values - /// when the user may have thought the second `--` would constitute the normal, "Only - /// positional args follow" idiom. To fix this, consider using [`Arg::number_of_values(1)`] - /// - /// **WARNING**: When building your CLIs, consider the effects of allowing leading hyphens and - /// the user passing in a value that matches a valid short. For example `prog -opt -F` where - /// `-F` is supposed to be a value, yet `-F` is *also* a valid short for another arg. Care should - /// should be taken when designing these args. This is compounded by the ability to "stack" - /// short args. I.e. if `-val` is supposed to be a value, but `-v`, `-a`, and `-l` are all valid - /// shorts. - /// - /// # Examples - /// - /// ```rust - /// # use clap::Arg; - /// Arg::with_name("pattern") - /// .allow_hyphen_values(true) - /// # ; - /// ``` - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let m = App::new("prog") - /// .arg(Arg::with_name("pat") - /// .allow_hyphen_values(true) - /// .takes_value(true) - /// .long("pattern")) - /// .get_matches_from(vec![ - /// "prog", "--pattern", "-file" - /// ]); - /// - /// assert_eq!(m.value_of("pat"), Some("-file")); - /// ``` - /// - /// Not setting [`Arg::allow_hyphen_values(true)`] and supplying a value which starts with a - /// hyphen is an error. - /// - /// ```rust - /// # use clap::{App, Arg, ErrorKind}; - /// let res = App::new("prog") - /// .arg(Arg::with_name("pat") - /// .takes_value(true) - /// .long("pattern")) - /// .get_matches_from_safe(vec![ - /// "prog", "--pattern", "-file" - /// ]); - /// - /// assert!(res.is_err()); - /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); - /// ``` - /// [`Arg::allow_hyphen_values(true)`]: ./struct.Arg.html#method.allow_hyphen_values - /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple - /// [`Arg::number_of_values(1)`]: ./struct.Arg.html#method.number_of_values - pub fn allow_hyphen_values(self, a: bool) -> Self { - if a { - self.set(ArgSettings::AllowLeadingHyphen) - } else { - self.unset(ArgSettings::AllowLeadingHyphen) - } - } /// Sets an arg that override this arg's required setting. (i.e. this arg will be required /// unless this other argument is present). /// @@ -1768,25 +1367,30 @@ impl<'a, 'b> Arg<'a, 'b> { self } - /// Specifies that the argument takes a value at run time. + /// Specifies the index of a positional argument **starting at** 1. + /// + /// **NOTE:** The index refers to position according to **other positional argument**. It does + /// not define position in the argument list as a whole. + /// + /// **NOTE:** If no [`Arg::short`], or [`Arg::long`] have been defined, you can optionally + /// leave off the `index` method, and the index will be assigned in order of evaluation. + /// Utilizing the `index` method allows for setting indexes out of order /// - /// **NOTE:** values for arguments may be specified in any of the following methods + /// **NOTE:** When utilized with [`Arg::multiple(true)`], only the **last** positional argument + /// may be defined as multiple (i.e. with the highest index) /// - /// * Using a space such as `-o value` or `--option value` - /// * Using an equals and no space such as `-o=value` or `--option=value` - /// * Use a short and no space such as `-ovalue` + /// # Panics /// - /// **NOTE:** By default, args which allow [multiple values] are delimited by commas, meaning - /// `--option=val1,val2,val3` is three values for the `--option` argument. If you wish to - /// change the delimiter to another character you can use [`Arg::value_delimiter(char)`], - /// alternatively you can turn delimiting values **OFF** by using [`Arg::use_delimiter(false)`] + /// Although not in this method directly, [`App`] will [`panic!`] if indexes are skipped (such + /// as defining `index(1)` and `index(3)` but not `index(2)`, or a positional argument is + /// defined as multiple and is not the highest index /// /// # Examples /// /// ```rust /// # use clap::{App, Arg}; /// Arg::with_name("config") - /// .takes_value(true) + /// .index(1) /// # ; /// ``` /// @@ -1794,137 +1398,16 @@ impl<'a, 'b> Arg<'a, 'b> { /// # use clap::{App, Arg}; /// let m = App::new("prog") /// .arg(Arg::with_name("mode") - /// .long("mode") - /// .takes_value(true)) + /// .index(1)) + /// .arg(Arg::with_name("debug") + /// .long("debug")) /// .get_matches_from(vec![ - /// "prog", "--mode", "fast" + /// "prog", "--debug", "fast" /// ]); /// /// assert!(m.is_present("mode")); - /// assert_eq!(m.value_of("mode"), Some("fast")); - /// ``` - /// [`Arg::value_delimiter(char)`]: ./struct.Arg.html#method.value_delimiter - /// [`Arg::use_delimiter(false)`]: ./struct.Arg.html#method.use_delimiter - /// [multiple values]: ./struct.Arg.html#method.multiple - pub fn takes_value(self, tv: bool) -> Self { - if tv { - self.set(ArgSettings::TakesValue) - } else { - self.unset(ArgSettings::TakesValue) - } - } - - /// Specifies if the possible values of an argument should be displayed in the help text or - /// not. Defaults to `false` (i.e. show possible values) - /// - /// This is useful for args with many values, or ones which are explained elsewhere in the - /// help text. - /// - /// # Examples - /// - /// ```rust - /// # use clap::{App, Arg}; - /// Arg::with_name("config") - /// .hide_possible_values(true) - /// # ; - /// ``` - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let m = App::new("prog") - /// .arg(Arg::with_name("mode") - /// .long("mode") - /// .possible_values(&["fast", "slow"]) - /// .takes_value(true) - /// .hide_possible_values(true)); - /// - /// ``` - /// - /// If we were to run the above program with `--help` the `[values: fast, slow]` portion of - /// the help text would be omitted. - pub fn hide_possible_values(self, hide: bool) -> Self { - if hide { - self.set(ArgSettings::HidePossibleValues) - } else { - self.unset(ArgSettings::HidePossibleValues) - } - } - - /// Specifies if the default value of an argument should be displayed in the help text or - /// not. Defaults to `false` (i.e. show default value) - /// - /// This is useful when default behavior of an arg is explained elsewhere in the help text. - /// - /// # Examples - /// - /// ```rust - /// # use clap::{App, Arg}; - /// Arg::with_name("config") - /// .hide_default_value(true) - /// # ; - /// ``` - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let m = App::new("connect") - /// .arg(Arg::with_name("host") - /// .long("host") - /// .default_value("localhost") - /// .hide_default_value(true)); - /// - /// ``` - /// - /// If we were to run the above program with `--help` the `[default: localhost]` portion of - /// the help text would be omitted. - pub fn hide_default_value(self, hide: bool) -> Self { - if hide { - self.set(ArgSettings::HideDefaultValue) - } else { - self.unset(ArgSettings::HideDefaultValue) - } - } - - /// Specifies the index of a positional argument **starting at** 1. - /// - /// **NOTE:** The index refers to position according to **other positional argument**. It does - /// not define position in the argument list as a whole. - /// - /// **NOTE:** If no [`Arg::short`], or [`Arg::long`] have been defined, you can optionally - /// leave off the `index` method, and the index will be assigned in order of evaluation. - /// Utilizing the `index` method allows for setting indexes out of order - /// - /// **NOTE:** When utilized with [`Arg::multiple(true)`], only the **last** positional argument - /// may be defined as multiple (i.e. with the highest index) - /// - /// # Panics - /// - /// Although not in this method directly, [`App`] will [`panic!`] if indexes are skipped (such - /// as defining `index(1)` and `index(3)` but not `index(2)`, or a positional argument is - /// defined as multiple and is not the highest index - /// - /// # Examples - /// - /// ```rust - /// # use clap::{App, Arg}; - /// Arg::with_name("config") - /// .index(1) - /// # ; - /// ``` - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let m = App::new("prog") - /// .arg(Arg::with_name("mode") - /// .index(1)) - /// .arg(Arg::with_name("debug") - /// .long("debug")) - /// .get_matches_from(vec![ - /// "prog", "--debug", "fast" - /// ]); - /// - /// assert!(m.is_present("mode")); - /// assert_eq!(m.value_of("mode"), Some("fast")); // notice index(1) means "first positional" - /// // *not* first argument + /// assert_eq!(m.value_of("mode"), Some("fast")); // notice index(1) means "first positional" + /// // *not* first argument /// ``` /// [`Arg::short`]: ./struct.Arg.html#method.short /// [`Arg::long`]: ./struct.Arg.html#method.long @@ -2127,13 +1610,6 @@ impl<'a, 'b> Arg<'a, 'b> { /// [positionals]: ./struct.Arg.html#method.index /// [`Arg::number_of_values(1)`]: ./struct.Arg.html#method.number_of_values /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple - pub fn multiple(self, multi: bool) -> Self { - if multi { - self.set(ArgSettings::Multiple) - } else { - self.unset(ArgSettings::Multiple) - } - } /// Specifies a value that *stops* parsing multiple values of a give argument. By default when /// one sets [`multiple(true)`] on an argument, clap will continue parsing values for that @@ -2186,146 +1662,6 @@ impl<'a, 'b> Arg<'a, 'b> { self } - /// Specifies that an argument can be matched to all child [`SubCommand`]s. - /// - /// **NOTE:** Global arguments *only* propagate down, **not** up (to parent commands), however - /// their values once a user uses them will be propagated back up to parents. In effect, this - /// means one should *define* all global arguments at the top level, however it doesn't matter - /// where the user *uses* the global argument. - /// - /// # Examples - /// - /// ```rust - /// # use clap::{App, Arg}; - /// Arg::with_name("debug") - /// .short("d") - /// .global(true) - /// # ; - /// ``` - /// - /// For example, assume an appliction with two subcommands, and you'd like to define a - /// `--verbose` flag that can be called on any of the subcommands and parent, but you don't - /// want to clutter the source with three duplicate [`Arg`] definitions. - /// - /// ```rust - /// # use clap::{App, Arg, SubCommand}; - /// let m = App::new("prog") - /// .arg(Arg::with_name("verb") - /// .long("verbose") - /// .short("v") - /// .global(true)) - /// .subcommand(SubCommand::with_name("test")) - /// .subcommand(SubCommand::with_name("do-stuff")) - /// .get_matches_from(vec![ - /// "prog", "do-stuff", "--verbose" - /// ]); - /// - /// assert_eq!(m.subcommand_name(), Some("do-stuff")); - /// let sub_m = m.subcommand_matches("do-stuff").unwrap(); - /// assert!(sub_m.is_present("verb")); - /// ``` - /// [`SubCommand`]: ./struct.SubCommand.html - /// [required]: ./struct.Arg.html#method.required - /// [`ArgMatches`]: ./struct.ArgMatches.html - /// [`ArgMatches::is_present("flag")`]: ./struct.ArgMatches.html#method.is_present - /// [`Arg`]: ./struct.Arg.html - pub fn global(self, g: bool) -> Self { - if g { - self.set(ArgSettings::Global) - } else { - self.unset(ArgSettings::Global) - } - } - - /// Allows an argument to accept explicitly empty values. An empty value must be specified at - /// the command line with an explicit `""`, or `''` - /// - /// **NOTE:** Defaults to `true` (Explicitly empty values are allowed) - /// - /// **NOTE:** Implicitly sets [`Arg::takes_value(true)`] when set to `false` - /// - /// # Examples - /// - /// ```rust - /// # use clap::{App, Arg}; - /// Arg::with_name("file") - /// .long("file") - /// .empty_values(false) - /// # ; - /// ``` - /// The default is to allow empty values, such as `--option ""` would be an empty value. But - /// we can change to make empty values become an error. - /// - /// ```rust - /// # use clap::{App, Arg, ErrorKind}; - /// let res = App::new("prog") - /// .arg(Arg::with_name("cfg") - /// .long("config") - /// .short("v") - /// .empty_values(false)) - /// .get_matches_from_safe(vec![ - /// "prog", "--config=" - /// ]); - /// - /// assert!(res.is_err()); - /// assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); - /// ``` - /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value - pub fn empty_values(mut self, ev: bool) -> Self { - if ev { - self.set(ArgSettings::EmptyValues) - } else { - self = self.set(ArgSettings::TakesValue); - self.unset(ArgSettings::EmptyValues) - } - } - - /// Hides an argument from help message output. - /// - /// **NOTE:** This does **not** hide the argument from usage strings on error - /// - /// # Examples - /// - /// ```rust - /// # use clap::{App, Arg}; - /// Arg::with_name("debug") - /// .hidden(true) - /// # ; - /// ``` - /// Setting `hidden(true)` will hide the argument when displaying help text - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let m = App::new("prog") - /// .arg(Arg::with_name("cfg") - /// .long("config") - /// .hidden(true) - /// .help("Some help text describing the --config arg")) - /// .get_matches_from(vec![ - /// "prog", "--help" - /// ]); - /// ``` - /// - /// The above example displays - /// - /// ```notrust - /// helptest - /// - /// USAGE: - /// helptest [FLAGS] - /// - /// FLAGS: - /// -h, --help Prints help information - /// -V, --version Prints version information - /// ``` - pub fn hidden(self, h: bool) -> Self { - if h { - self.set(ArgSettings::Hidden) - } else { - self.unset(ArgSettings::Hidden) - } - } - /// Specifies a list of possible values for this argument. At runtime, `clap` verifies that /// only one of the specified values was used, or fails with an error message. /// @@ -2374,6 +1710,7 @@ impl<'a, 'b> Arg<'a, 'b> { /// [options]: ./struct.Arg.html#method.takes_value /// [positional arguments]: ./struct.Arg.html#method.index pub fn possible_values(mut self, names: &[&'b str]) -> Self { + self.setb(ArgSettings::TakesValue); if let Some(ref mut vec) = self.possible_vals { for s in names { vec.push(s); @@ -2438,6 +1775,7 @@ impl<'a, 'b> Arg<'a, 'b> { /// [options]: ./struct.Arg.html#method.takes_value /// [positional arguments]: ./struct.Arg.html#method.index pub fn possible_value(mut self, name: &'b str) -> Self { + self.setb(ArgSettings::TakesValue); if let Some(ref mut vec) = self.possible_vals { vec.push(name); } else { @@ -2446,59 +1784,6 @@ impl<'a, 'b> Arg<'a, 'b> { self } - /// When used with [`Arg::possible_values`] it allows the argument value to pass validation even if - /// the case differs from that of the specified `possible_value`. - /// - /// **Pro Tip:** Use this setting with [`arg_enum!`] - /// - /// # Examples - /// - /// ```rust - /// # use clap::{App, Arg}; - /// # use std::ascii::AsciiExt; - /// let m = App::new("pv") - /// .arg(Arg::with_name("option") - /// .long("--option") - /// .takes_value(true) - /// .possible_value("test123") - /// .case_insensitive(true)) - /// .get_matches_from(vec![ - /// "pv", "--option", "TeSt123", - /// ]); - /// - /// assert!(m.value_of("option").unwrap().eq_ignore_ascii_case("test123")); - /// ``` - /// - /// This setting also works when multiple values can be defined: - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let m = App::new("pv") - /// .arg(Arg::with_name("option") - /// .short("-o") - /// .long("--option") - /// .takes_value(true) - /// .possible_value("test123") - /// .possible_value("test321") - /// .multiple(true) - /// .case_insensitive(true)) - /// .get_matches_from(vec![ - /// "pv", "--option", "TeSt123", "teST123", "tESt321" - /// ]); - /// - /// let matched_vals = m.values_of("option").unwrap().collect::>(); - /// assert_eq!(&*matched_vals, &["TeSt123", "teST123", "tESt321"]); - /// ``` - /// [`Arg::case_insensitive(true)`]: ./struct.Arg.html#method.possible_values - /// [`arg_enum!`]: ./macro.arg_enum.html - pub fn case_insensitive(self, ci: bool) -> Self { - if ci { - self.set(ArgSettings::CaseInsensitive) - } else { - self.unset(ArgSettings::CaseInsensitive) - } - } - /// Specifies the name of the [`ArgGroup`] the argument belongs to. /// /// # Examples @@ -2762,6 +2047,7 @@ impl<'a, 'b> Arg<'a, 'b> { /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple pub fn max_values(mut self, qty: u64) -> Self { self.setb(ArgSettings::TakesValue); + self.setb(ArgSettings::MultipleValues); self.max_vals = Some(qty); self } @@ -2825,153 +2111,7 @@ impl<'a, 'b> Arg<'a, 'b> { /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple pub fn min_values(mut self, qty: u64) -> Self { self.min_vals = Some(qty); - self.set(ArgSettings::TakesValue) - } - - /// Specifies whether or not an argument should allow grouping of multiple values via a - /// delimiter. I.e. should `--option=val1,val2,val3` be parsed as three values (`val1`, `val2`, - /// and `val3`) or as a single value (`val1,val2,val3`). Defaults to using `,` (comma) as the - /// value delimiter for all arguments that accept values (options and positional arguments) - /// - /// **NOTE:** The default is `false`. When set to `true` the default [`Arg::value_delimiter`] - /// is the comma `,`. - /// - /// # Examples - /// - /// The following example shows the default behavior. - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let delims = App::new("prog") - /// .arg(Arg::with_name("option") - /// .long("option") - /// .use_delimiter(true) - /// .takes_value(true)) - /// .get_matches_from(vec![ - /// "prog", "--option=val1,val2,val3", - /// ]); - /// - /// assert!(delims.is_present("option")); - /// assert_eq!(delims.occurrences_of("option"), 1); - /// assert_eq!(delims.values_of("option").unwrap().collect::>(), ["val1", "val2", "val3"]); - /// ``` - /// The next example shows the difference when turning delimiters off. This is the default - /// behavior - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let nodelims = App::new("prog") - /// .arg(Arg::with_name("option") - /// .long("option") - /// .use_delimiter(false) - /// .takes_value(true)) - /// .get_matches_from(vec![ - /// "prog", "--option=val1,val2,val3", - /// ]); - /// - /// assert!(nodelims.is_present("option")); - /// assert_eq!(nodelims.occurrences_of("option"), 1); - /// assert_eq!(nodelims.value_of("option").unwrap(), "val1,val2,val3"); - /// ``` - /// [`Arg::value_delimiter`]: ./struct.Arg.html#method.value_delimiter - pub fn use_delimiter(mut self, d: bool) -> Self { - if d { - if self.val_delim.is_none() { - self.val_delim = Some(','); - } - self.setb(ArgSettings::TakesValue); - self.setb(ArgSettings::UseValueDelimiter); - self.unset(ArgSettings::ValueDelimiterNotSet) - } else { - self.val_delim = None; - self.unsetb(ArgSettings::UseValueDelimiter); - self.unset(ArgSettings::ValueDelimiterNotSet) - } - } - - /// Specifies that *multiple values* may only be set using the delimiter. This means if an - /// if an option is encountered, and no delimiter is found, it automatically assumed that no - /// additional values for that option follow. This is unlike the default, where it is generally - /// assumed that more values will follow regardless of whether or not a delimiter is used. - /// - /// **NOTE:** The default is `false`. - /// - /// **NOTE:** Setting this to true implies [`Arg::use_delimiter(true)`] - /// - /// **NOTE:** It's a good idea to inform the user that use of a delimiter is required, either - /// through help text or other means. - /// - /// # Examples - /// - /// These examples demonstrate what happens when `require_delimiter(true)` is used. Notice - /// everything works in this first example, as we use a delimiter, as expected. - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let delims = App::new("prog") - /// .arg(Arg::with_name("opt") - /// .short("o") - /// .takes_value(true) - /// .multiple(true) - /// .require_delimiter(true)) - /// .get_matches_from(vec![ - /// "prog", "-o", "val1,val2,val3", - /// ]); - /// - /// assert!(delims.is_present("opt")); - /// assert_eq!(delims.values_of("opt").unwrap().collect::>(), ["val1", "val2", "val3"]); - /// ``` - /// In this next example, we will *not* use a delimiter. Notice it's now an error. - /// - /// ```rust - /// # use clap::{App, Arg, ErrorKind}; - /// let res = App::new("prog") - /// .arg(Arg::with_name("opt") - /// .short("o") - /// .takes_value(true) - /// .multiple(true) - /// .require_delimiter(true)) - /// .get_matches_from_safe(vec![ - /// "prog", "-o", "val1", "val2", "val3", - /// ]); - /// - /// assert!(res.is_err()); - /// let err = res.unwrap_err(); - /// assert_eq!(err.kind, ErrorKind::UnknownArgument); - /// ``` - /// What's happening is `-o` is getting `val1`, and because delimiters are required yet none - /// were present, it stops parsing `-o`. At this point it reaches `val2` and because no - /// positional arguments have been defined, it's an error of an unexpected argument. - /// - /// In this final example, we contrast the above with `clap`'s default behavior where the above - /// is *not* an error. - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let delims = App::new("prog") - /// .arg(Arg::with_name("opt") - /// .short("o") - /// .takes_value(true) - /// .multiple(true)) - /// .get_matches_from(vec![ - /// "prog", "-o", "val1", "val2", "val3", - /// ]); - /// - /// assert!(delims.is_present("opt")); - /// assert_eq!(delims.values_of("opt").unwrap().collect::>(), ["val1", "val2", "val3"]); - /// ``` - /// [`Arg::use_delimiter(true)`]: ./struct.Arg.html#method.use_delimiter - pub fn require_delimiter(mut self, d: bool) -> Self { - if d { - self = self.use_delimiter(true); - self.unsetb(ArgSettings::ValueDelimiterNotSet); - self.setb(ArgSettings::UseValueDelimiter); - self.set(ArgSettings::RequireDelimiter) - } else { - self = self.use_delimiter(false); - self.unsetb(ArgSettings::UseValueDelimiter); - self.unset(ArgSettings::RequireDelimiter) - } + self.setting(ArgSettings::TakesValue) } /// Specifies the separator to use when values are clumped together, defaults to `,` (comma). @@ -3570,69 +2710,6 @@ impl<'a, 'b> Arg<'a, 'b> { self } - /// @TODO @p2 @docs @release: write docs - pub fn hide_env_values(self, hide: bool) -> Self { - if hide { - self.set(ArgSettings::HideEnvValues) - } else { - self.unset(ArgSettings::HideEnvValues) - } - } - - /// When set to `true` the help string will be displayed on the line after the argument and - /// indented once. This can be helpful for arguments with very long or complex help messages. - /// This can also be helpful for arguments with very long flag names, or many/long value names. - /// - /// **NOTE:** To apply this setting to all arguments consider using - /// [`AppSettings::NextLineHelp`] - /// - /// # Examples - /// - /// ```rust - /// # use clap::{App, Arg}; - /// let m = App::new("prog") - /// .arg(Arg::with_name("opt") - /// .long("long-option-flag") - /// .short("o") - /// .takes_value(true) - /// .value_names(&["value1", "value2"]) - /// .help("Some really long help and complex\n\ - /// help that makes more sense to be\n\ - /// on a line after the option") - /// .next_line_help(true)) - /// .get_matches_from(vec![ - /// "prog", "--help" - /// ]); - /// ``` - /// - /// The above example displays the following help message - /// - /// ```notrust - /// nlh - /// - /// USAGE: - /// nlh [FLAGS] [OPTIONS] - /// - /// FLAGS: - /// -h, --help Prints help information - /// -V, --version Prints version information - /// - /// OPTIONS: - /// -o, --long-option-flag - /// Some really long help and complex - /// help that makes more sense to be - /// on a line after the option - /// ``` - /// [`AppSettings::NextLineHelp`]: ./enum.AppSettings.html#variant.NextLineHelp - pub fn next_line_help(mut self, nlh: bool) -> Self { - if nlh { - self.setb(ArgSettings::NextLineHelp); - } else { - self.unsetb(ArgSettings::NextLineHelp); - } - self - } - /// Allows custom ordering of args within the help message. Args with a lower value will be /// displayed first in the help message. This is helpful when one would like to emphasise /// frequently used args, or prioritize those towards the top of the list. Duplicate values @@ -3693,31 +2770,47 @@ impl<'a, 'b> Arg<'a, 'b> { self } - /// Checks if one of the [`ArgSettings`] settings is set for the argument + // @TODO @docs @v3-beta: write better docs as ArgSettings is now critical + /// Checks if one of the [`ArgSettings`] is set for the argument /// [`ArgSettings`]: ./enum.ArgSettings.html pub fn is_set(&self, s: ArgSettings) -> bool { self.settings.is_set(s) } /// Sets one of the [`ArgSettings`] settings for the argument /// [`ArgSettings`]: ./enum.ArgSettings.html - pub fn set(mut self, s: ArgSettings) -> Self { + pub fn setting(mut self, s: ArgSettings) -> Self { self.setb(s); self } - /// Unsets one of the [`ArgSettings`] settings for the argument + // @TODO @docs @v3-beta: write better docs as ArgSettings is now critical + /// Sets multiple [`ArgSettings`] for the argument /// [`ArgSettings`]: ./enum.ArgSettings.html - pub fn unset(mut self, s: ArgSettings) -> Self { + pub fn settings(mut self, settings: &[ArgSettings]) -> Self { + for s in settings { + self.settings.set(*s); + } + self + } + + /// Unsets one of the [`ArgSettings`] for the argument + /// [`ArgSettings`]: ./enum.ArgSettings.html + pub fn unset_setting(mut self, s: ArgSettings) -> Self { self.unsetb(s); self } #[doc(hidden)] pub fn _build(&mut self) { + if (self.is_set(ArgSettings::UseValueDelimiter) + || self.is_set(ArgSettings::RequireDelimiter)) && self.val_delim.is_none() { + self.val_delim = Some(','); + } if self.index.is_some() || (self.short.is_none() && self.long.is_none()) { if self.max_vals.is_some() || self.min_vals.is_some() || (self.num_vals.is_some() && self.num_vals.unwrap() > 1) { - self.setb(ArgSettings::Multiple); + self.setb(ArgSettings::MultipleValues); + self.setb(ArgSettings::MultipleOccurrences); } } else if self.is_set(ArgSettings::TakesValue) { if let Some(ref vec) = self.val_names { @@ -3728,9 +2821,11 @@ impl<'a, 'b> Arg<'a, 'b> { } } + // @TODO @p6 @naming @internal: rename to set_mut #[doc(hidden)] pub fn setb(&mut self, s: ArgSettings) { self.settings.set(s); } + // @TODO @p6 @naming @internal: rename to unset_mut #[doc(hidden)] pub fn unsetb(&mut self, s: ArgSettings) { self.settings.unset(s); } @@ -3748,7 +2843,8 @@ impl<'a, 'b> Arg<'a, 'b> { let mult_vals = self.val_names .as_ref() .map_or(true, |names| names.len() < 2); - if self.is_set(ArgSettings::Multiple) && mult_vals { + if (self.is_set(ArgSettings::MultipleValues) || self.is_set(ArgSettings::MultipleOccurrences)) + && mult_vals { "..." } else { "" @@ -3785,6 +2881,212 @@ impl<'a, 'b> Arg<'a, 'b> { } } +// Deprecations +// @TODO @v3-beta: remove +impl<'a, 'b> Arg<'a, 'b> { + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Renamed to `Arg::setting`. Will be removed in v3.0-beta")] + pub fn set(mut self, s: ArgSettings) -> Self { + self.setb(s); + self + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Renamed to `Arg::unset_setting`. Will be removed in v3.0-beta")] + pub fn unset(mut self, s: ArgSettings) -> Self { + self.unsetb(s); + self + } + + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::from` instead. Will be removed in v3.0-beta")] + pub fn from_usage(u: &'a str) -> Self { + let parser = UsageParser::from_usage(u); + parser.parse() + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::Last)` instead. Will be removed in v3.0-beta")] + pub fn last(self, l: bool) -> Self { + if l { + self.setting(ArgSettings::Last) + } else { + self.unset_setting(ArgSettings::Last) + } + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::Required)` instead. Will be removed in v3.0-beta")] + pub fn required(self, r: bool) -> Self { + if r { + self.setting(ArgSettings::Required) + } else { + self.unset_setting(ArgSettings::Required) + } + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::TakesValue)` instead. Will be removed in v3.0-beta")] + pub fn takes_value(self, tv: bool) -> Self { + if tv { + self.setting(ArgSettings::TakesValue) + } else { + self.unset_setting(ArgSettings::TakesValue) + } + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::AllowHyphenValues)` instead. Will be removed in v3.0-beta")] + pub fn allow_hyphen_values(self, a: bool) -> Self { + if a { + self.setting(ArgSettings::AllowHyphenValues) + } else { + self.unset_setting(ArgSettings::AllowHyphenValues) + } + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::RequireEquals)` instead. Will be removed in v3.0-beta")] + pub fn require_equals(mut self, r: bool) -> Self { + if r { + self.unsetb(ArgSettings::AllowEmptyValues); + self.setting(ArgSettings::RequireEquals) + } else { + self.unset_setting(ArgSettings::RequireEquals) + } + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::Global)` instead. Will be removed in v3.0-beta")] + pub fn global(self, g: bool) -> Self { + if g { + self.setting(ArgSettings::Global) + } else { + self.unset_setting(ArgSettings::Global) + } + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::RequireDelimiter)` instead. Will be removed in v3.0-beta")] + pub fn require_delimiter(mut self, d: bool) -> Self { + if d { + self.setb(ArgSettings::UseValueDelimiter); + self.unsetb(ArgSettings::ValueDelimiterNotSet); + self.setb(ArgSettings::UseValueDelimiter); + self.setting(ArgSettings::RequireDelimiter) + } else { + self.unsetb(ArgSettings::UseValueDelimiter); + self.unsetb(ArgSettings::UseValueDelimiter); + self.unset_setting(ArgSettings::RequireDelimiter) + } + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::HidePossibleValues)` instead. Will be removed in v3.0-beta")] + pub fn hide_possible_values(self, hide: bool) -> Self { + if hide { + self.setting(ArgSettings::HidePossibleValues) + } else { + self.unset_setting(ArgSettings::HidePossibleValues) + } + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::HideDefaultValue)` instead. Will be removed in v3.0-beta")] + pub fn hide_default_value(self, hide: bool) -> Self { + if hide { + self.setting(ArgSettings::HideDefaultValue) + } else { + self.unset_setting(ArgSettings::HideDefaultValue) + } + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::AllowEmptyValues)` instead. Will be removed in v3.0-beta")] + pub fn empty_values(mut self, ev: bool) -> Self { + if ev { + self.setting(ArgSettings::AllowEmptyValues) + } else { + self = self.setting(ArgSettings::TakesValue); + self.unset_setting(ArgSettings::AllowEmptyValues) + } + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::Hidden)` instead. Will be removed in v3.0-beta")] + pub fn hidden(self, h: bool) -> Self { + if h { + self.setting(ArgSettings::Hidden) + } else { + self.unset_setting(ArgSettings::Hidden) + } + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::IgnoreCase)` instead. Will be removed in v3.0-beta")] + pub fn case_insensitive(self, ci: bool) -> Self { + if ci { + self.setting(ArgSettings::IgnoreCase) + } else { + self.unset_setting(ArgSettings::IgnoreCase) + } + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::UseValueDelimiter)` instead. Will be removed in v3.0-beta")] + pub fn use_delimiter(mut self, d: bool) -> Self { + if d { + if self.val_delim.is_none() { + self.val_delim = Some(','); + } + self.setb(ArgSettings::TakesValue); + self.setb(ArgSettings::UseValueDelimiter); + self.unset_setting(ArgSettings::ValueDelimiterNotSet) + } else { + self.val_delim = None; + self.unsetb(ArgSettings::UseValueDelimiter); + self.unset_setting(ArgSettings::ValueDelimiterNotSet) + } + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::HideEnvValues)` instead. Will be removed in v3.0-beta")] + pub fn hide_env_values(self, hide: bool) -> Self { + if hide { + self.setting(ArgSettings::HideEnvValues) + } else { + self.unset_setting(ArgSettings::HideEnvValues) + } + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::NextLineHelp)` instead. Will be removed in v3.0-beta")] + pub fn next_line_help(mut self, nlh: bool) -> Self { + if nlh { + self.setb(ArgSettings::NextLineHelp); + } else { + self.unsetb(ArgSettings::NextLineHelp); + } + self + } + + /// **Deprecated** + #[deprecated(since="2.30.0", note="Use `Arg::setting(ArgSettings::Multiple)` instead. Also note `ArgSettings::MultipleValues` and `ArgSettings::MultipleOccurrences` have been added which may be more appropriate. Will be removed in v3.0-beta")] + pub fn multiple(mut self, multi: bool) -> Self { + if multi { + self.setb(ArgSettings::MultipleOccurrences); + self.setting(ArgSettings::MultipleValues) + } else { + self.unsetb(ArgSettings::MultipleOccurrences); + self.unset_setting(ArgSettings::MultipleValues) + } + } + + +} + impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for Arg<'a, 'b> { fn from(a: &'z Arg<'a, 'b>) -> Self { a.clone() } } @@ -3816,7 +3118,7 @@ impl<'n, 'e> Display for Arg<'n, 'e> { } else { write!(f, "<{}>", self.name)?; } - if self.settings.is_set(ArgSettings::Multiple) + if self.settings.is_set(ArgSettings::MultipleValues) && (self.val_names.is_none() || (self.val_names.is_some() && self.val_names.as_ref().unwrap().len() == 1)) @@ -3861,7 +3163,7 @@ impl<'n, 'e> Display for Arg<'n, 'e> { } } let num = vec.len(); - if self.is_set(ArgSettings::Multiple) && num == 1 { + if self.is_set(ArgSettings::MultipleValues) && num == 1 { write!(f, "...")?; } } else if let Some(num) = self.num_vals { @@ -3872,7 +3174,7 @@ impl<'n, 'e> Display for Arg<'n, 'e> { write!(f, "{}", delim)?; } } - if self.is_set(ArgSettings::Multiple) && num == 1 { + if self.is_set(ArgSettings::MultipleValues) && num == 1 { write!(f, "...")?; } } else { @@ -3880,7 +3182,7 @@ impl<'n, 'e> Display for Arg<'n, 'e> { f, "<{}>{}", self.name, - if self.is_set(ArgSettings::Multiple) { + if self.is_set(ArgSettings::MultipleOccurrences) { "..." } else { "" @@ -3956,7 +3258,7 @@ mod test { #[test] fn flag_display() { let mut f = Arg::with_name("flg"); - f.settings.set(ArgSettings::Multiple); + f.settings.set(ArgSettings::MultipleOccurrences); f.long = Some("flag"); assert_eq!(&*format!("{}", f), "--flag"); @@ -4046,7 +3348,7 @@ mod test { #[test] fn positiona_display_mult() { let mut p = Arg::with_name("pos").index(1); - p.settings.set(ArgSettings::Multiple); + p.setb(ArgSettings::MultipleValues); assert_eq!(&*format!("{}", p), "..."); } diff --git a/src/args/arg_matcher.rs b/src/args/arg_matcher.rs index a189215fb04..a73205bee99 100644 --- a/src/args/arg_matcher.rs +++ b/src/args/arg_matcher.rs @@ -132,7 +132,7 @@ impl<'a> ArgMatcher<'a> { if let Some(ma) = self.get(o.name) { if let Some(num) = o.num_vals { debugln!("ArgMatcher::needs_more_vals: num_vals...{}", num); - return if o.is_set(ArgSettings::Multiple) { + return if o.is_set(ArgSettings::MultipleValues) { ((ma.vals.len() as u64) % num) != 0 } else { num != (ma.vals.len() as u64) @@ -144,7 +144,7 @@ impl<'a> ArgMatcher<'a> { debugln!("ArgMatcher::needs_more_vals: min_vals...true"); return true; } - return o.is_set(ArgSettings::Multiple); + return o.is_set(ArgSettings::MultipleValues); } true } diff --git a/src/args/arg_matches.rs b/src/args/arg_matches.rs index 653cd1702ce..074311e1cf0 100644 --- a/src/args/arg_matches.rs +++ b/src/args/arg_matches.rs @@ -336,11 +336,11 @@ impl<'a> ArgMatches<'a> { /// # Examples /// /// ```rust - /// # use clap::{App, Arg}; + /// # use clap::{App, Arg, ArgSettings}; /// let m = App::new("myprog") /// .arg(Arg::with_name("debug") /// .short("d") - /// .multiple(true)) + /// .setting(ArgSettings::MultipleOccurrences)) /// .get_matches_from(vec![ /// "myprog", "-d", "-d", "-d" /// ]); @@ -351,11 +351,11 @@ impl<'a> ArgMatches<'a> { /// This next example shows that counts actual uses of the argument, not just `-`'s /// /// ```rust - /// # use clap::{App, Arg}; + /// # use clap::{App, Arg, ArgSettings}; /// let m = App::new("myprog") /// .arg(Arg::with_name("debug") /// .short("d") - /// .multiple(true)) + /// .setting(ArgSettings::MultipleOccurrences)) /// .arg(Arg::with_name("flag") /// .short("f")) /// .get_matches_from(vec![ diff --git a/src/args/settings.rs b/src/args/settings.rs index 9de94d69579..729d2158a56 100644 --- a/src/args/settings.rs +++ b/src/args/settings.rs @@ -6,23 +6,24 @@ use std::str::FromStr; bitflags! { struct Flags: u32 { const REQUIRED = 1; - const MULTIPLE = 1 << 1; - const EMPTY_VALS = 1 << 2; + const MULTIPLE_OCC = 1 << 1; + const EMPTY_VALS = 1 << 2 | Self::TAKES_VAL.bits; const GLOBAL = 1 << 3; const HIDDEN = 1 << 4; const TAKES_VAL = 1 << 5; const USE_DELIM = 1 << 6; const NEXT_LINE_HELP = 1 << 7; const R_UNLESS_ALL = 1 << 8; - const REQ_DELIM = 1 << 9; + const REQ_DELIM = 1 << 9 | Self::TAKES_VAL.bits | Self::USE_DELIM.bits; const DELIM_NOT_SET = 1 << 10; - const HIDE_POS_VALS = 1 << 11; - const ALLOW_TAC_VALS = 1 << 12; - const REQUIRE_EQUALS = 1 << 13; - const LAST = 1 << 14; - const HIDE_DEFAULT_VAL = 1 << 15; + const HIDE_POS_VALS = 1 << 11 | Self::TAKES_VAL.bits; + const ALLOW_TAC_VALS = 1 << 12 | Self::TAKES_VAL.bits; + const REQUIRE_EQUALS = 1 << 13 | Self::TAKES_VAL.bits; + const LAST = 1 << 14 | Self::TAKES_VAL.bits; + const HIDE_DEFAULT_VAL = 1 << 15 | Self::TAKES_VAL.bits; const CASE_INSENSITIVE = 1 << 16; const HIDE_ENV_VALS = 1 << 17; + const MULTIPLE_VALS = 1 << 18 | Self::TAKES_VAL.bits; } } @@ -33,10 +34,12 @@ pub struct ArgFlags(Flags); impl ArgFlags { pub fn new() -> Self { ArgFlags::default() } + // @TODO @p6 @internal: Reorder alphabetically impl_settings!{ArgSettings, Required => Flags::REQUIRED, - Multiple => Flags::MULTIPLE, - EmptyValues => Flags::EMPTY_VALS, + MultipleOccurrences => Flags::MULTIPLE_OCC, + MultipleValues => Flags::MULTIPLE_VALS, + AllowEmptyValues => Flags::EMPTY_VALS, Global => Flags::GLOBAL, Hidden => Flags::HIDDEN, TakesValue => Flags::TAKES_VAL, @@ -46,17 +49,17 @@ impl ArgFlags { RequireDelimiter => Flags::REQ_DELIM, ValueDelimiterNotSet => Flags::DELIM_NOT_SET, HidePossibleValues => Flags::HIDE_POS_VALS, - AllowLeadingHyphen => Flags::ALLOW_TAC_VALS, + AllowHyphenValues => Flags::ALLOW_TAC_VALS, RequireEquals => Flags::REQUIRE_EQUALS, Last => Flags::LAST, - CaseInsensitive => Flags::CASE_INSENSITIVE, + IgnoreCase => Flags::CASE_INSENSITIVE, HideEnvValues => Flags::HIDE_ENV_VALS, HideDefaultValue => Flags::HIDE_DEFAULT_VAL } } impl Default for ArgFlags { - fn default() -> Self { ArgFlags(Flags::EMPTY_VALS | Flags::DELIM_NOT_SET) } + fn default() -> Self { ArgFlags(Flags::DELIM_NOT_SET) } } /// Various settings that apply to arguments and may be set, unset, and checked via getter/setter @@ -66,39 +69,951 @@ impl Default for ArgFlags { /// [`Arg::is_set`]: ./struct.Arg.html#method.is_set #[derive(Debug, PartialEq, Copy, Clone)] pub enum ArgSettings { - /// The argument must be used + /// Specifies that the argument is required by default. Required by default means it is + /// required, when no other conflicting rules or overrides have been evaluated. Conflicting + /// rules take precedence over being required. + /// + /// **Pro tip:** Flags (i.e. not positional, or arguments that take values) shouldn't be + /// required by default. This is because if a flag were to be required, it should simply be + /// implied. No additional information is required from user. Flags by their very nature are + /// simply boolean on/off switches. The only time a user *should* be required to use a flag + /// is if the operation is destructive in nature, and the user is essentially proving to you, + /// "Yes, I know what I'm doing." + /// + /// # Examples + /// + /// ```rust + /// # use clap::{Arg, ArgSettings}; + /// Arg::with_name("config") + /// .setting(ArgSettings::Required) + /// # ; + /// ``` + /// + /// Setting [`Required`] requires that the argument be used at runtime. + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .settings(&[ArgSettings::Required, ArgSettings::TakesValue]) + /// .long("config")) + /// .try_get_matches_from(vec![ + /// "prog", "--config", "file.conf" + /// ]); + /// + /// assert!(res.is_ok()); + /// ``` + /// + /// Not setting [`Required`] and then *not* supplying that argument at runtime is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .settings(&[ArgSettings::Required, ArgSettings::TakesValue]) + /// .long("config")) + /// .try_get_matches_from(vec![ + /// "prog" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Required`]: ./enum.ArgSettings.html#variant.Required Required, - /// The argument may be used multiple times such as `--flag --flag` - Multiple, - /// The argument allows empty values such as `--option ""` - EmptyValues, - /// The argument should be propagated down through all child [`SubCommands`] - /// [`SubCommand`]: ./struct.SubCommand.html + /// Specifies that the argument may have an unknown number of multiple values. Without any other + /// settings, this argument may appear only *once*. + /// + /// For example, `--opt val1 val2` is allowed, but `--opt val1 val2 --opt val3` is not. + /// + /// **NOTE:** Implicitly sets [`ArgSettings::TakesValue`] + /// + /// **WARNING:** + /// + /// Setting `MultipleValues` for an argument that takes a value, but with no other details can + /// be dangerous in some circumstances. Because multiple values are allowed, + /// `--option val1 val2 val3` is perfectly valid. Be careful when designing a CLI where + /// positional arguments are *also* expected as `clap` will continue parsing *values* until one + /// of the following happens: + /// + /// * It reaches the [maximum number of values] + /// * It reaches a [specific number of values] + /// * It finds another flag or option (i.e. something that starts with a `-`) + /// + /// **WARNING:** + /// + /// When using args with `MultipleValues` and [subcommands], one needs to consider the + /// posibility of an argument value being the same as a valid subcommand. By default `clap` will + /// parse the argument in question as a value *only if* a value is possible at that moment. + /// Otherwise it will be parsed as a subcommand. In effect, this means using `Multiple` with no + /// additional parameters and a value that coincides with a subcommand name, the subcommand + /// cannot be called unless another argument is passed between them. + /// + /// As an example, consider a CLI with an option `--ui-paths=...` and subcommand `signer` + /// + /// The following would be parsed as values to `--ui-paths`. + /// + /// ```notrust + /// $ program --ui-paths path1 path2 signer + /// ``` + /// + /// This is because `--ui-paths` accepts multiple values. `clap` will continue parsing values + /// until another argument is reached and it knows `--ui-paths` is done parsing. + /// + /// By adding additional parameters to `--ui-paths` we can solve this issue. Consider adding + /// [`Arg::number_of_values(1)`] or using *only* [`MultipleOccurrences`]. The following are all + /// valid, and `signer` is parsed as a subcommand in the first case, but a value in the second + /// case. + /// + /// ```notrust + /// $ program --ui-paths path1 signer + /// $ program --ui-paths path1 --ui-paths signer signer + /// ``` + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// Arg::with_name("debug") + /// .short("d") + /// .setting(ArgSettings::MultipleValues) + /// # ; + /// ``` + /// An example with flags + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("verbose") + /// .setting(ArgSettings::MultipleValues) + /// .short("v")) + /// .get_matches_from(vec![ + /// "prog", "-v", "-v", "-v" // note, -vvv would have same result + /// ]); + /// + /// assert!(m.is_present("verbose")); + /// assert_eq!(m.occurrences_of("verbose"), 3); + /// ``` + /// + /// An example with options + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("file") + /// .setting(ArgSettings::MultipleValues) // implies TakesValue + /// .short("F")) + /// .get_matches_from(vec![ + /// "prog", "-F", "file1", "file2", "file3" + /// ]); + /// + /// assert!(m.is_present("file")); + /// assert_eq!(m.occurrences_of("file"), 1); // notice only one occurrence + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3"]); + /// ``` + /// Although `MultipleVlaues` has been specified, we cannot use the argument more than once. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind, ArgSettings}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .setting(ArgSettings::MultipleValues) // implies TakesValue + /// .short("F")) + /// .try_get_matches_from(vec![ + /// "prog", "-F", "file1", "-F", "file2", "-F", "file3" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnexpectedMultipleUsage) + /// ``` + /// + /// A common mistake is to define an option which allows multiple values, and a positional + /// argument. + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("file") + /// .setting(ArgSettings::MultipleValues) // implies TakesValue + /// .short("F")) + /// .arg(Arg::with_name("word") + /// .index(1)) + /// .get_matches_from(vec![ + /// "prog", "-F", "file1", "file2", "file3", "word" + /// ]); + /// + /// assert!(m.is_present("file")); + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3", "word"]); // wait...what?! + /// assert!(!m.is_present("word")); // but we clearly used word! + /// ``` + /// The problem is `clap` doesn't know when to stop parsing values for "files". This is further + /// compounded by if we'd said `word -F file1 file2` it would have worked fine, so it would + /// appear to only fail sometimes...not good! + /// + /// A solution for the example above is to limit how many values with a [maxium], or [specific] + /// number, or to say [`MultipleOccurrences`] is ok, but multiple values is not. + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("file") + /// .settings(&[ArgSettings::MultipleOccurrences, ArgSettings::TakesValue]) + /// .short("F")) + /// .arg(Arg::with_name("word") + /// .index(1)) + /// .get_matches_from(vec![ + /// "prog", "-F", "file1", "-F", "file2", "-F", "file3", "word" + /// ]); + /// + /// assert!(m.is_present("file")); + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3"]); + /// assert!(m.is_present("word")); + /// assert_eq!(m.value_of("word"), Some("word")); + /// ``` + /// As a final example, let's fix the above error and get a pretty message to the user :) + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind, ArgSettings}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .settings(&[ArgSettings::MultipleOccurrences, ArgSettings::TakesValue]) + /// .short("F")) + /// .arg(Arg::with_name("word") + /// .index(1)) + /// .try_get_matches_from(vec![ + /// "prog", "-F", "file1", "file2", "file3", "word" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// [option]: ./enum.ArgSettings.html#variant.TakesValue + /// [options]: ./enum.ArgSettings.html#variant.TakesValue + /// [subcommands]: ./struct.App.html#method.subcommand + /// [positionals]: ./struct.Arg.html#method.index + /// [`Arg::number_of_values(1)`]: ./struct.Arg.html#method.number_of_values + /// [`MultipleOccurrences`]: ./enum.ArgSettings.html#variant.MultipleOccurrences + /// [`MultipleValues`]: ./enum.ArgSettings.html#variant.MultipleValues + /// [maximum number of values]: ./struct.Arg.html#method.max_values + /// [specific number of values]: ./struct.Arg.html#method.number_of_values + /// [maximum]: ./struct.Arg.html#method.max_values + /// [specific]: ./struct.Arg.html#method.number_of_values + MultipleValues, + /// Specifies that the argument may appear more than once. + /// For flags, this results + /// in the number of occurrences of the flag being recorded. For example `-ddd` or `-d -d -d` + /// would count as three occurrences. For options or arguments that take a value, this + /// *does not* affect how many values they can accept. (i.e. only one at a time is allowed) + /// + /// For example, `--opt val1 --opt val2` is allowed, but `--opt val1 val2` is not. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// Arg::with_name("debug") + /// .short("d") + /// .setting(ArgSettings::MultipleOccurrences) + /// # ; + /// ``` + /// An example with flags + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("verbose") + /// .setting(ArgSettings::MultipleOccurrences) + /// .short("v")) + /// .get_matches_from(vec![ + /// "prog", "-v", "-v", "-v" // note, -vvv would have same result + /// ]); + /// + /// assert!(m.is_present("verbose")); + /// assert_eq!(m.occurrences_of("verbose"), 3); + /// ``` + /// + /// An example with options + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("file") + /// .settings(&[ArgSettings::MultipleOccurrences, ArgSettings::TakesValue]) + /// .short("F")) + /// .get_matches_from(vec![ + /// "prog", "-F", "file1", "-F", file2", "-F", "file3" + /// ]); + /// + /// assert!(m.is_present("file")); + /// assert_eq!(m.occurrences_of("file"), 1); // notice only one occurrence + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3"]); + /// ``` + /// [option]: ./enum.ArgSettings.html#variant.TakesValue + /// [options]: ./enum.ArgSettings.html#variant.TakesValue + /// [subcommands]: ./struct.App.html#method.subcommand + /// [positionals]: ./struct.Arg.html#method.index + /// [`Arg::number_of_values(1)`]: ./struct.Arg.html#method.number_of_values + /// [`MultipleOccurrences`]: ./enum.ArgSettings.html#variant.MultipleOccurrences + /// [`MultipleValues`]: ./enum.ArgSettings.html#variant.MultipleValues + /// [maximum number of values]: ./struct.Arg.html#method.max_values + /// [specific number of values]: ./struct.Arg.html#method.number_of_values + /// [maximum]: ./struct.Arg.html#method.max_values + /// [specific]: ./struct.Arg.html#method.number_of_values + MultipleOccurrences, + /// Allows an argument to accept explicitly empty values. An empty value must be specified at + /// the command line with an explicit `""`, `''`, or `--option=` + /// + /// **NOTE:** By default empty values are *not* allowed + /// + /// **NOTE:** Implicitly sets [`ArgSettings::TakesValue`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// Arg::with_name("file") + /// .long("file") + /// .setting(ArgSettings::AllowEmptyValues) + /// # ; + /// ``` + /// The default is to *not* allow empty values. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind, ArgSettings}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .short("v") + /// .setting(ArgSettings::TakesValue)) + /// .try_get_matches_from(vec![ + /// "prog", "--config=" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); + /// ``` + /// By adding this setting, we can allow empty values + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .short("v") + /// .setting(ArgSettings::AllowEmptyValues)) // implies TakesValue + /// .try_get_matches_from(vec![ + /// "prog", "--config=" + /// ]); + /// + /// assert!(res.is_ok()); + /// assert_eq!(res.unwrap().value_of("config"), None); + /// ``` + /// [`ArgSettings::TakesValue`]: ./enum.ArgSettings.html#variant.TakesValue + AllowEmptyValues, + /// Specifies that an argument can be matched to all child [`SubCommand`]s. + /// + /// **NOTE:** Global arguments *only* propagate down, **not** up (to parent commands), however + /// their values once a user uses them will be propagated back up to parents. In effect, this + /// means one should *define* all global arguments at the top level, however it doesn't matter + /// where the user *uses* the global argument. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// Arg::with_name("debug") + /// .short("d") + /// .setting(ArgSettings::Global) + /// # ; + /// ``` + /// + /// For example, assume an appliction with two subcommands, and you'd like to define a + /// `--verbose` flag that can be called on any of the subcommands and parent, but you don't + /// want to clutter the source with three duplicate [`Arg`] definitions. + /// + /// ```rust + /// # use clap::{App, Arg, SubCommand, ArgSettings}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("verb") + /// .long("verbose") + /// .short("v") + /// .setting(ArgSettings::Global)) + /// .subcommand(SubCommand::with_name("test")) + /// .subcommand(SubCommand::with_name("do-stuff")) + /// .get_matches_from(vec![ + /// "prog", "do-stuff", "--verbose" + /// ]); + /// + /// assert_eq!(m.subcommand_name(), Some("do-stuff")); + /// let sub_m = m.subcommand_matches("do-stuff").unwrap(); + /// assert!(sub_m.is_present("verb")); + /// ``` + /// [`SubCommand`]: ./struct.App.html#method.subcommand + /// [required]: ./enum.ArgSettings.html#variant.Required + /// [`ArgMatches`]: ./struct.ArgMatches.html + /// [`ArgMatches::is_present("flag")`]: ./struct.ArgMatches.html#method.is_present + /// [`Arg`]: ./struct.Arg.html Global, - /// The argument should **not** be shown in help text + /// Hides an argument from help message output. + /// + /// **NOTE:** This does **not** hide the argument from usage strings on error + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// Arg::with_name("debug") + /// .setting(ArgSettings::Hidden) + /// # ; + /// ``` + /// Setting `Hidden` will hide the argument when displaying help text + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .setting(ArgSettings::Hidden) + /// .help("Some help text describing the --config arg")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// The above example displays + /// + /// ```notrust + /// helptest + /// + /// USAGE: + /// helptest [FLAGS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// ``` Hidden, - /// The argument accepts a value, such as `--option ` + /// Specifies that the argument takes a value at run time. + /// + /// **NOTE:** values for arguments may be specified in any of the following methods + /// + /// * Using a space such as `-o value` or `--option value` + /// * Using an equals and no space such as `-o=value` or `--option=value` + /// * Use a short and no space such as `-ovalue` + /// + /// **NOTE:** By default, args which allow [multiple values] are delimited by commas, meaning + /// `--option=val1,val2,val3` is three values for the `--option` argument. If you wish to + /// change the delimiter to another character you can use [`Arg::value_delimiter(char)`], + /// alternatively you can turn delimiting values **OFF** by using + /// [`Arg::unset_setting(ArgSettings::UseValueDelimiter`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// Arg::with_name("config") + /// .setting(ArgSettings::TakesValue) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .long("mode") + /// .setting(ArgSettings::TakesValue)) + /// .get_matches_from(vec![ + /// "prog", "--mode", "fast" + /// ]); + /// + /// assert!(m.is_present("mode")); + /// assert_eq!(m.value_of("mode"), Some("fast")); + /// ``` + /// [`Arg::value_delimiter(char)`]: ./struct.Arg.html#method.value_delimiter + /// [`Arg::unset_setting(ArgSettings::UseValueDelimiter`]: ./enum.ArgSettings.html#variant.UseValueDelimiter + /// [multiple values]: ./enum.ArgSettings.html#variant.MultipleValues TakesValue, - /// Determines if the argument allows values to be grouped via a delimter + /// Specifies that an argument should allow grouping of multiple values via a + /// delimiter. I.e. should `--option=val1,val2,val3` be parsed as three values (`val1`, `val2`, + /// and `val3`) or as a single value (`val1,val2,val3`). Defaults to using `,` (comma) as the + /// value delimiter for all arguments that accept values (options and positional arguments) + /// + /// **NOTE:** When this setting is used, it will default [`Arg::value_delimiter`] + /// to the comma `,`. + /// + /// **NOTE:** Implicitly sets [`ArgSettings::TakesValue`] + /// + /// # Examples + /// + /// The following example shows the default behavior. + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let delims = App::new("prog") + /// .arg(Arg::with_name("option") + /// .long("option") + /// .setting(ArgSettings::UseValueDelimiter) + /// .takes_value(true)) + /// .get_matches_from(vec![ + /// "prog", "--option=val1,val2,val3", + /// ]); + /// + /// assert!(delims.is_present("option")); + /// assert_eq!(delims.occurrences_of("option"), 1); + /// assert_eq!(delims.values_of("option").unwrap().collect::>(), ["val1", "val2", "val3"]); + /// ``` + /// The next example shows the difference when turning delimiters off. This is the default + /// behavior + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let nodelims = App::new("prog") + /// .arg(Arg::with_name("option") + /// .long("option") + /// .setting(ArgSettings::TakesValue)) + /// .get_matches_from(vec![ + /// "prog", "--option=val1,val2,val3", + /// ]); + /// + /// assert!(nodelims.is_present("option")); + /// assert_eq!(nodelims.occurrences_of("option"), 1); + /// assert_eq!(nodelims.value_of("option").unwrap(), "val1,val2,val3"); + /// ``` + /// [`Arg::value_delimiter`]: ./struct.Arg.html#method.value_delimiter UseValueDelimiter, - /// Prints the help text on the line after the argument + /// When set to `true` the help string will be displayed on the line after the argument and + /// indented once. This can be helpful for arguments with very long or complex help messages. + /// This can also be helpful for arguments with very long flag names, or many/long value names. + /// + /// **NOTE:** To apply this setting to all arguments consider using + /// [`AppSettings::NextLineHelp`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .long("long-option-flag") + /// .short("o") + /// .settings(&[ArgSettings::TakesValue, ArgSettings::NextLineHelp]) + /// .value_names(&["value1", "value2"]) + /// .help("Some really long help and complex\n\ + /// help that makes more sense to be\n\ + /// on a line after the option")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// The above example displays the following help message + /// + /// ```notrust + /// nlh + /// + /// USAGE: + /// nlh [FLAGS] [OPTIONS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// + /// OPTIONS: + /// -o, --long-option-flag + /// Some really long help and complex + /// help that makes more sense to be + /// on a line after the option + /// ``` + /// [`AppSettings::NextLineHelp`]: ./enum.AppSettings.html#variant.NextLineHelp NextLineHelp, - /// Requires the use of a value delimiter for all multiple values + /// Specifies that *multiple values* may only be set using the delimiter. This means if an + /// if an option is encountered, and no delimiter is found, it automatically assumed that no + /// additional values for that option follow. This is unlike the default, where it is generally + /// assumed that more values will follow regardless of whether or not a delimiter is used. + /// + /// **NOTE:** The default is `false`. + /// + /// **NOTE:** Setting this implies [`ArgSettings::UseValueDelimiter`] and + /// [`ArgSettings::TakesValue`] + /// + /// **NOTE:** It's a good idea to inform the user that use of a delimiter is required, either + /// through help text or other means. + /// + /// # Examples + /// + /// These examples demonstrate what happens when `require_delimiter(true)` is used. Notice + /// everything works in this first example, as we use a delimiter, as expected. + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let delims = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .short("o") + /// .settings(&[ArgSettings::RequireDelimiter, ArgSettings::MultipleValues])) + /// .get_matches_from(vec![ + /// "prog", "-o", "val1,val2,val3", + /// ]); + /// + /// assert!(delims.is_present("opt")); + /// assert_eq!(delims.values_of("opt").unwrap().collect::>(), ["val1", "val2", "val3"]); + /// ``` + /// In this next example, we will *not* use a delimiter. Notice it's now an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind, ArgSettings}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .short("o") + /// .setting(ArgSettings::RequireDelimiter)) + /// .try_get_matches_from(vec![ + /// "prog", "-o", "val1", "val2", "val3", + /// ]); + /// + /// assert!(res.is_err()); + /// let err = res.unwrap_err(); + /// assert_eq!(err.kind, ErrorKind::UnknownArgument); + /// ``` + /// What's happening is `-o` is getting `val1`, and because delimiters are required yet none + /// were present, it stops parsing `-o`. At this point it reaches `val2` and because no + /// positional arguments have been defined, it's an error of an unexpected argument. + /// + /// In this final example, we contrast the above with `clap`'s default behavior where the above + /// is *not* an error. + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let delims = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .short("o") + /// .setting(ArgSettings::MultipleValues)) + /// .get_matches_from(vec![ + /// "prog", "-o", "val1", "val2", "val3", + /// ]); + /// + /// assert!(delims.is_present("opt")); + /// assert_eq!(delims.values_of("opt").unwrap().collect::>(), ["val1", "val2", "val3"]); + /// ``` + /// [`ArgSettings::UseValueDelimiter`]: ./enum.ArgSettings.html#variant.UseValueDelimiter + /// [`ArgSettings::TakesValue`]: ./enum.ArgSettings.html#variant.TakesValue RequireDelimiter, - /// Hides the possible values from the help string + /// Specifies if the possible values of an argument should be displayed in the help text or + /// not. Defaults to `false` (i.e. show possible values) + /// + /// This is useful for args with many values, or ones which are explained elsewhere in the + /// help text. + /// + /// **NOTE:** Setting this implies [`ArgSettings::TakesValue`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// Arg::with_name("config") + /// .setting(ArgSettings::HidePossibleValues) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .long("mode") + /// .possible_values(&["fast", "slow"]) + /// .setting(ArgSettings::HidePossibleValues)); + /// ``` + /// If we were to run the above program with `--help` the `[values: fast, slow]` portion of + /// the help text would be omitted. HidePossibleValues, - /// Allows vals that start with a '-' - AllowLeadingHyphen, - /// Require options use `--option=val` syntax + /// Allows values which start with a leading hyphen (`-`) + /// + /// **NOTE:** Setting this implies [`ArgSettings::TakesValue`] + /// + /// **WARNING**: Take caution when using this setting combined with + /// [`ArgSettings::MultipleValues`], as this becomes ambiguous `$ prog --arg -- -- val`. All + /// three `--, --, val` will be values when the user may have thought the second `--` would + /// constitute the normal, "Only positional args follow" idiom. To fix this, consider using + /// [`ArgSettings::MultipleOccurrences`] which only allows a single value at a time. + /// + /// **WARNING**: When building your CLIs, consider the effects of allowing leading hyphens and + /// the user passing in a value that matches a valid short. For example `prog -opt -F` where + /// `-F` is supposed to be a value, yet `-F` is *also* a valid short for another arg. Care should + /// should be taken when designing these args. This is compounded by the ability to "stack" + /// short args. I.e. if `-val` is supposed to be a value, but `-v`, `-a`, and `-l` are all valid + /// shorts. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{Arg, ArgSettings}; + /// Arg::with_name("pattern") + /// .setting(ArgSettings::AllowHyphenValues) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("pat") + /// .setting(ArgSettings::AllowHyphenValues) + /// .long("pattern")) + /// .get_matches_from(vec![ + /// "prog", "--pattern", "-file" + /// ]); + /// + /// assert_eq!(m.value_of("pat"), Some("-file")); + /// ``` + /// + /// Not setting [`Arg::allow_hyphen_values(true)`] and supplying a value which starts with a + /// hyphen is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind, ArgSettings}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("pat") + /// .setting(ArgSettings::TakesValue) + /// .long("pattern")) + /// .try_get_matches_from(vec![ + /// "prog", "--pattern", "-file" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// [`ArgSettings::AllowHyphenValues`]: ./enum.ArgSettings.html#variant.AllowHyphenValues + /// [`ArgSettings::MultipleValues`]: ./enum.ArgSettings.html#variant.MultipleValues + /// [`ArgSettings::MultipleOccurrences`]: ./enum.ArgSettings.html#variant.MultipleOccurrences + /// [`Arg::number_of_values(1)`]: ./struct.Arg.html#method.number_of_values + AllowHyphenValues, + /// Requires that options use the `--option=val` syntax (i.e. an equals between the option and + /// associated value) **Default:** `false` + /// + /// **NOTE:** Setting this implies [`ArgSettings::TakesValue`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{Arg, ArgSettings}; + /// Arg::with_name("config") + /// .long("config") + /// .setting(ArgSettings::RequireEquals) + /// # ; + /// ``` + /// + /// Setting [`RequireEquals`] requires that the option have an equals sign between + /// it and the associated value. + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .setting(ArgSettings::RequireEquals) + /// .long("config")) + /// .try_get_matches_from(vec![ + /// "prog", "--config=file.conf" + /// ]); + /// + /// assert!(res.is_ok()); + /// ``` + /// + /// Setting [`RequireEquals`] and *not* supplying the equals will cause an error + /// unless [`ArgSettings::EmptyValues`] is set. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind, ArgSettings}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .setting(ArgSettings::RequireEquals) + /// .long("config")) + /// .try_get_matches_from(vec![ + /// "prog", "--config", "file.conf" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); + /// ``` + /// [`RequireEquals`]: ./enum.ArgSettings.html#variant.RequireEquals + /// [`ArgSettings::EmptyValues`]: ./enum.ArgSettings.html#variant.EmptyValues + /// [`ArgSettings::EmptyValues`]: ./enum.ArgSettings.html#variant.TakesValue RequireEquals, - /// Specifies that the arg is the last positional argument and may be accessed early via `--` - /// syntax + /// Specifies that this arg is the last, or final, positional argument (i.e. has the highest + /// index) and is *only* able to be accessed via the `--` syntax (i.e. `$ prog args -- + /// last_arg`). Even, if no other arguments are left to parse, if the user omits the `--` syntax + /// they will receive an [`UnknownArgument`] error. Setting an argument to `.last(true)` also + /// allows one to access this arg early using the `--` syntax. Accessing an arg early, even with + /// the `--` syntax is otherwise not possible. + /// + /// **NOTE:** This will change the usage string to look like `$ prog [FLAGS] [-- ]` if + /// `ARG` is marked as `.last(true)`. + /// + /// **NOTE:** This setting will imply [`AppSettings::DontCollapseArgsInUsage`] because failing + /// to set this can make the usage string very confusing. + /// + /// **NOTE**: This setting only applies to positional arguments, and has no affect on FLAGS / + /// OPTIONS + /// + /// **NOTE:** Setting this implies [`ArgSettings::TakesValue`] + /// + /// **CAUTION:** Using this setting *and* having child subcommands is not + /// recommended with the exception of *also* using [`AppSettings::ArgsNegateSubcommands`] + /// (or [`AppSettings::SubcommandsNegateReqs`] if the argument marked `Last` is also + /// marked [`ArgSettings::Required`]) + /// + /// # Examples + /// + /// ```rust + /// # use clap::{Arg, ArgSettings}; + /// Arg::with_name("args") + /// .setting(ArgSettings::Last) + /// # ; + /// ``` + /// + /// Setting [`Last`] ensures the arg has the highest [index] of all positional args + /// and requires that the `--` syntax be used to access it early. + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("first")) + /// .arg(Arg::with_name("second")) + /// .arg(Arg::with_name("third") + /// .setting(ArgSettings::Last)) + /// .try_get_matches_from(vec![ + /// "prog", "one", "--", "three" + /// ]); + /// + /// assert!(res.is_ok()); + /// let m = res.unwrap(); + /// assert_eq!(m.value_of("third"), Some("three")); + /// assert!(m.value_of("second").is_none()); + /// ``` + /// + /// Even if the positional argument marked `Last` is the only argument left to parse, + /// failing to use the `--` syntax results in an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind, ArgSettings}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("first")) + /// .arg(Arg::with_name("second")) + /// .arg(Arg::with_name("third") + /// .setting(ArgSettings::Last)) + /// .try_get_matches_from(vec![ + /// "prog", "one", "two", "three" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// [index]: ./struct.Arg.html#method.index + /// [`AppSettings::DontCollapseArgsInUsage`]: ./enum.AppSettings.html#variant.DontCollapseArgsInUsage + /// [`AppSettings::ArgsNegateSubcommands`]: ./enum.AppSettings.html#variant.ArgsNegateSubcommands + /// [`AppSettings::SubcommandsNegateReqs`]: ./enum.AppSettings.html#variant.SubcommandsNegateReqs + /// [`ArgSettings::Required`]: ./enum.ArgSetings.html#variant.Required + /// [`UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument Last, - /// Hides the default value from the help string + /// Specifies that the default value of an argument should not be displayed in the help text. + /// + /// This is useful when default behavior of an arg is explained elsewhere in the help text. + /// + /// **NOTE:** Setting this implies [`ArgSettings::TakesValue`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// Arg::with_name("config") + /// .setting(ArgSettings::HideDefaultValue) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let m = App::new("connect") + /// .arg(Arg::with_name("host") + /// .long("host") + /// .default_value("localhost") + /// .setting(ArgSettings::HideDefaultValue)); + /// + /// ``` + /// + /// If we were to run the above program with `--help` the `[default: localhost]` portion of + /// the help text would be omitted. HideDefaultValue, - /// Makes `Arg::possible_values` case insensitive - CaseInsensitive, - /// Hides ENV values in the help message + /// When used with [`Arg::possible_values`] it allows the argument value to pass validation even + /// if the case differs from that of the specified `possible_value`. + /// + /// **Pro Tip:** Use this setting with [`arg_enum!`] + /// + /// **NOTE:** Setting this implies [`ArgSettings::TakesValue`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// # use std::ascii::AsciiExt; + /// let m = App::new("pv") + /// .arg(Arg::with_name("option") + /// .long("--option") + /// .setting(ArgSettings::IgnoreCase) + /// .possible_value("test123")) + /// .get_matches_from(vec![ + /// "pv", "--option", "TeSt123", + /// ]); + /// + /// assert!(m.value_of("option").unwrap().eq_ignore_ascii_case("test123")); + /// ``` + /// + /// This setting also works when multiple values can be defined: + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let m = App::new("pv") + /// .arg(Arg::with_name("option") + /// .short("-o") + /// .long("--option") + /// .settings(&[ArgSettings::IgnoreCase, ArgSettings::MultipleValues]) + /// .possible_value("test123") + /// .possible_value("test321")) + /// .get_matches_from(vec![ + /// "pv", "--option", "TeSt123", "teST123", "tESt321" + /// ]); + /// + /// let matched_vals = m.values_of("option").unwrap().collect::>(); + /// assert_eq!(&*matched_vals, &["TeSt123", "teST123", "tESt321"]); + /// ``` + /// [`arg_enum!`]: ./macro.arg_enum.html + IgnoreCase, + /// Specifies that any values inside the associated ENV variables of an argument should not be + /// displayed in the help text. + /// + /// This is useful when ENV vars contain sensitive values. + /// + /// **NOTE:** Setting this implies [`ArgSettings::TakesValue`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// Arg::with_name("config") + /// .setting(ArgSettings::HideDefaultValue) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg, ArgSettings}; + /// let m = App::new("connect") + /// .arg(Arg::with_name("host") + /// .long("host") + /// .env("CONNECT") + /// .setting(ArgSettings::HideEnvValues)); + /// + /// ``` + /// + /// If we were to run the above program with `$ CONNECT=super_secret connect --help` the + /// `[default: CONNECT=super_secret]` portion of the help text would be omitted. HideEnvValues, #[doc(hidden)] RequiredUnlessAll, #[doc(hidden)] ValueDelimiterNotSet, @@ -109,9 +1024,8 @@ impl FromStr for ArgSettings { fn from_str(s: &str) -> Result::Err> { match &*s.to_ascii_lowercase() { "required" => Ok(ArgSettings::Required), - "multiple" => Ok(ArgSettings::Multiple), "global" => Ok(ArgSettings::Global), - "emptyvalues" => Ok(ArgSettings::EmptyValues), + "allowemptyvalues" => Ok(ArgSettings::AllowEmptyValues), "hidden" => Ok(ArgSettings::Hidden), "takesvalue" => Ok(ArgSettings::TakesValue), "usevaluedelimiter" => Ok(ArgSettings::UseValueDelimiter), @@ -120,11 +1034,11 @@ impl FromStr for ArgSettings { "requiredelimiter" => Ok(ArgSettings::RequireDelimiter), "valuedelimiternotset" => Ok(ArgSettings::ValueDelimiterNotSet), "hidepossiblevalues" => Ok(ArgSettings::HidePossibleValues), - "allowleadinghyphen" => Ok(ArgSettings::AllowLeadingHyphen), + "allowhyphenvalues" => Ok(ArgSettings::AllowHyphenValues), "requireequals" => Ok(ArgSettings::RequireEquals), "last" => Ok(ArgSettings::Last), "hidedefaultvalue" => Ok(ArgSettings::HideDefaultValue), - "caseinsensitive" => Ok(ArgSettings::CaseInsensitive), + "ignorecase" => Ok(ArgSettings::IgnoreCase), "hideenvvalues" => Ok(ArgSettings::HideEnvValues), _ => Err("unknown ArgSetting, cannot convert from str".to_owned()), } @@ -138,12 +1052,12 @@ mod test { #[test] fn arg_settings_fromstr() { assert_eq!( - "allowleadinghyphen".parse::().unwrap(), - ArgSettings::AllowLeadingHyphen + "allowhyphenvalues".parse::().unwrap(), + ArgSettings::AllowHyphenValues ); assert_eq!( - "emptyvalues".parse::().unwrap(), - ArgSettings::EmptyValues + "allowemptyvalues".parse::().unwrap(), + ArgSettings::AllowEmptyValues ); assert_eq!( "global".parse::().unwrap(), @@ -157,10 +1071,6 @@ mod test { "hidden".parse::().unwrap(), ArgSettings::Hidden ); - assert_eq!( - "multiple".parse::().unwrap(), - ArgSettings::Multiple - ); assert_eq!( "nextlinehelp".parse::().unwrap(), ArgSettings::NextLineHelp @@ -199,8 +1109,8 @@ mod test { ArgSettings::HideDefaultValue ); assert_eq!( - "caseinsensitive".parse::().unwrap(), - ArgSettings::CaseInsensitive + "ignorecase".parse::().unwrap(), + ArgSettings::IgnoreCase ); assert_eq!( "hideenvvalues".parse::().unwrap(), diff --git a/src/completions/bash.rs b/src/completions/bash.rs index 6d83ac2634a..0eca9cf8c72 100644 --- a/src/completions/bash.rs +++ b/src/completions/bash.rs @@ -179,7 +179,9 @@ complete -F _{name} -o bashdefault -o default {name} ); } let num = vec.len(); - if o.is_set(ArgSettings::Multiple) && num == 1 { + if (o.is_set(ArgSettings::MultipleValues) || o.is_set(ArgSettings::MultipleOccurrences)) + && num == 1 + { ret = format!("{}...", ret); } } else if let Some(num) = o.num_vals { @@ -192,12 +194,14 @@ complete -F _{name} -o bashdefault -o default {name} if it.peek().is_some() { " " } else { "" } ); } - if o.is_set(ArgSettings::Multiple) && num == 1 { + if (o.is_set(ArgSettings::MultipleValues) || o.is_set(ArgSettings::MultipleOccurrences)) + && num == 1 + { ret = format!("{}...", ret); } } else { ret = format!("<{}>", o.name); - if o.is_set(ArgSettings::Multiple) { + if o.is_set(ArgSettings::MultipleValues) || o.is_set(ArgSettings::MultipleOccurrences) { ret = format!("{}...", ret); } } diff --git a/src/completions/zsh.rs b/src/completions/zsh.rs index a97f9760de5..89e13e1d54f 100644 --- a/src/completions/zsh.rs +++ b/src/completions/zsh.rs @@ -346,7 +346,11 @@ fn write_opts_of(p: &App) -> String { format!("({})", conflicts) }; - let multiple = if o.is_set(ArgSettings::Multiple) { + // @TODO @soundness should probably be either multiple occurrences or multiple values and + // not both + let multiple = if o.is_set(ArgSettings::MultipleOccurrences) + || o.is_set(ArgSettings::MultipleValues) + { "*" } else { "" @@ -407,7 +411,7 @@ fn write_flags_of(p: &App) -> String { format!("({})", conflicts) }; - let multiple = if f.is_set(ArgSettings::Multiple) { + let multiple = if f.is_set(ArgSettings::MultipleOccurrences) { "*" } else { "" diff --git a/src/errors.rs b/src/errors.rs index 89c9dc2307b..51e14ea9e44 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -108,12 +108,12 @@ pub enum ErrorKind { /// # Examples /// /// ```rust - /// # use clap::{App, Arg, ErrorKind}; + /// # use clap::{App, Arg, ErrorKind, ArgSettings}; /// let res = App::new("prog") /// .arg(Arg::with_name("color") - /// .long("color") - /// .empty_values(false)) - /// .get_matches_from_safe(vec!["prog", "--color="]); + /// .setting(ArgSettings::TakesValue) + /// .long("color")) + /// .try_get_matches_from(vec!["prog", "--color="]); /// assert!(res.is_err()); /// assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); /// ``` @@ -136,7 +136,7 @@ pub enum ErrorKind { /// let result = App::new("prog") /// .arg(Arg::with_name("num") /// .validator(is_numeric)) - /// .get_matches_from_safe(vec!["prog", "NotANumber"]); + /// .try_get_matches_from(vec!["prog", "NotANumber"]); /// assert!(result.is_err()); /// assert_eq!(result.unwrap_err().kind, ErrorKind::ValueValidation); /// ``` @@ -153,7 +153,7 @@ pub enum ErrorKind { /// .arg(Arg::with_name("arg") /// .multiple(true) /// .max_values(2)) - /// .get_matches_from_safe(vec!["prog", "too", "many", "values"]); + /// .try_get_matches_from(vec!["prog", "too", "many", "values"]); /// assert!(result.is_err()); /// assert_eq!(result.unwrap_err().kind, ErrorKind::TooManyValues); /// ``` @@ -171,7 +171,7 @@ pub enum ErrorKind { /// .arg(Arg::with_name("some_opt") /// .long("opt") /// .min_values(3)) - /// .get_matches_from_safe(vec!["prog", "--opt", "too", "few"]); + /// .try_get_matches_from(vec!["prog", "--opt", "too", "few"]); /// assert!(result.is_err()); /// assert_eq!(result.unwrap_err().kind, ErrorKind::TooFewValues); /// ``` @@ -191,7 +191,7 @@ pub enum ErrorKind { /// .long("opt") /// .takes_value(true) /// .number_of_values(2)) - /// .get_matches_from_safe(vec!["prog", "--opt", "wrong"]); + /// .try_get_matches_from(vec!["prog", "--opt", "wrong"]); /// assert!(result.is_err()); /// assert_eq!(result.unwrap_err().kind, ErrorKind::WrongNumberOfValues); /// ``` @@ -213,7 +213,7 @@ pub enum ErrorKind { /// .conflicts_with("color")) /// .arg(Arg::with_name("color") /// .long("color")) - /// .get_matches_from_safe(vec!["prog", "--debug", "--color"]); + /// .try_get_matches_from(vec!["prog", "--debug", "--color"]); /// assert!(result.is_err()); /// assert_eq!(result.unwrap_err().kind, ErrorKind::ArgumentConflict); /// ``` diff --git a/src/lib.rs b/src/lib.rs index ef340e66b3a..88314ce5c91 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -516,6 +516,8 @@ #![doc(html_root_url = "https://docs.rs/clap/2.29.2")] #![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts, unused_import_braces, unused_allocation)] +// @TODO @v3-beta: remove me! +#![allow(deprecated)] // Lints we'd like to deny but are currently failing for upstream crates // unused_qualifications (bitflags, clippy) // trivial_numeric_casts (bitflags) diff --git a/src/usage_parser.rs b/src/usage_parser.rs index 1f5dfd970f5..31e5958e9bf 100644 --- a/src/usage_parser.rs +++ b/src/usage_parser.rs @@ -61,17 +61,14 @@ impl<'a> UsageParser<'a> { break; } } - debug_assert!( - !arg.name.is_empty(), - format!( - "No name found for Arg when parsing usage string: {}", - self.usage - ) - ); arg.num_vals = match arg.val_names { Some(ref v) if v.len() >= 2 => Some(v.len() as u64), _ => None, }; + if !arg.has_switch() && arg.is_set(ArgSettings::MultipleOccurrences) { + // We had a positional and need to set mult vals too + arg.setb(ArgSettings::MultipleValues); + } debugln!("UsageParser::parse: vals...{:?}", arg.val_names); arg } @@ -177,14 +174,10 @@ impl<'a> UsageParser<'a> { self.pos += 1; if dot_counter == 3 { debugln!("UsageParser::multiple: setting multiple"); - arg.setb(ArgSettings::Multiple); if arg.is_set(ArgSettings::TakesValue) { - arg.setb(ArgSettings::UseValueDelimiter); - arg.unsetb(ArgSettings::ValueDelimiterNotSet); - if arg.val_delim.is_none() { - arg.val_delim = Some(','); - } + arg.setb(ArgSettings::MultipleValues); } + arg.setb(ArgSettings::MultipleOccurrences); self.prev = UsageToken::Multiple; self.pos += 1; break; @@ -233,111 +226,111 @@ mod test { assert_eq!(a.short.unwrap(), 'f'); assert!(a.long.is_none()); assert_eq!(a.help.unwrap(), "some help info"); - assert!(!a.is_set(ArgSettings::Multiple)); + assert!(!a.is_set(ArgSettings::MultipleOccurrences)); + assert!(a.val_names.is_none()); + assert!(a.num_vals.is_none()); + + let a = Arg::from_usage("[flag] --flag 'some help info'"); + assert_eq!(a.name, "flag"); + assert_eq!(a.long.unwrap(), "flag"); + assert!(a.short.is_none()); + assert_eq!(a.help.unwrap(), "some help info"); + assert!(!a.is_set(ArgSettings::MultipleOccurrences)); + assert!(a.val_names.is_none()); + assert!(a.num_vals.is_none()); + + let a = Arg::from_usage("--flag 'some help info'"); + assert_eq!(a.name, "flag"); + assert_eq!(a.long.unwrap(), "flag"); + assert!(a.short.is_none()); + assert_eq!(a.help.unwrap(), "some help info"); + assert!(!a.is_set(ArgSettings::MultipleOccurrences)); + assert!(a.val_names.is_none()); + assert!(a.num_vals.is_none()); + + let a = Arg::from_usage("[flag] -f --flag 'some help info'"); + assert_eq!(a.name, "flag"); + assert_eq!(a.short.unwrap(), 'f'); + assert_eq!(a.long.unwrap(), "flag"); + assert_eq!(a.help.unwrap(), "some help info"); + assert!(!a.is_set(ArgSettings::MultipleOccurrences)); assert!(a.val_names.is_none()); assert!(a.num_vals.is_none()); - let b = Arg::from_usage("[flag] --flag 'some help info'"); - assert_eq!(b.name, "flag"); - assert_eq!(b.long.unwrap(), "flag"); - assert!(b.short.is_none()); - assert_eq!(b.help.unwrap(), "some help info"); - assert!(!b.is_set(ArgSettings::Multiple)); + let a = Arg::from_usage("[flag] -f... 'some help info'"); + assert_eq!(a.name, "flag"); + assert_eq!(a.short.unwrap(), 'f'); + assert!(a.long.is_none()); + assert_eq!(a.help.unwrap(), "some help info"); + assert!(a.is_set(ArgSettings::MultipleOccurrences)); assert!(a.val_names.is_none()); assert!(a.num_vals.is_none()); - let b = Arg::from_usage("--flag 'some help info'"); - assert_eq!(b.name, "flag"); - assert_eq!(b.long.unwrap(), "flag"); - assert!(b.short.is_none()); - assert_eq!(b.help.unwrap(), "some help info"); - assert!(!b.is_set(ArgSettings::Multiple)); - assert!(b.val_names.is_none()); - assert!(b.num_vals.is_none()); - - let c = Arg::from_usage("[flag] -f --flag 'some help info'"); - assert_eq!(c.name, "flag"); - assert_eq!(c.short.unwrap(), 'f'); - assert_eq!(c.long.unwrap(), "flag"); - assert_eq!(c.help.unwrap(), "some help info"); - assert!(!c.is_set(ArgSettings::Multiple)); - assert!(c.val_names.is_none()); - assert!(c.num_vals.is_none()); - - let d = Arg::from_usage("[flag] -f... 'some help info'"); - assert_eq!(d.name, "flag"); - assert_eq!(d.short.unwrap(), 'f'); - assert!(d.long.is_none()); - assert_eq!(d.help.unwrap(), "some help info"); - assert!(d.is_set(ArgSettings::Multiple)); - assert!(d.val_names.is_none()); - assert!(d.num_vals.is_none()); - - let e = Arg::from_usage("[flag] -f --flag... 'some help info'"); - assert_eq!(e.name, "flag"); - assert_eq!(e.long.unwrap(), "flag"); - assert_eq!(e.short.unwrap(), 'f'); - assert_eq!(e.help.unwrap(), "some help info"); - assert!(e.is_set(ArgSettings::Multiple)); - assert!(e.val_names.is_none()); - assert!(e.num_vals.is_none()); - - let e = Arg::from_usage("-f --flag... 'some help info'"); - assert_eq!(e.name, "flag"); - assert_eq!(e.long.unwrap(), "flag"); - assert_eq!(e.short.unwrap(), 'f'); - assert_eq!(e.help.unwrap(), "some help info"); - assert!(e.is_set(ArgSettings::Multiple)); - assert!(e.val_names.is_none()); - assert!(e.num_vals.is_none()); - - let e = Arg::from_usage("--flags"); - assert_eq!(e.name, "flags"); - assert_eq!(e.long.unwrap(), "flags"); - assert!(e.val_names.is_none()); - assert!(e.num_vals.is_none()); - - let e = Arg::from_usage("--flags..."); - assert_eq!(e.name, "flags"); - assert_eq!(e.long.unwrap(), "flags"); - assert!(e.is_set(ArgSettings::Multiple)); - assert!(e.val_names.is_none()); - assert!(e.num_vals.is_none()); - - let e = Arg::from_usage("[flags] -f"); - assert_eq!(e.name, "flags"); - assert_eq!(e.short.unwrap(), 'f'); - assert!(e.val_names.is_none()); - assert!(e.num_vals.is_none()); - - let e = Arg::from_usage("[flags] -f..."); - assert_eq!(e.name, "flags"); - assert_eq!(e.short.unwrap(), 'f'); - assert!(e.is_set(ArgSettings::Multiple)); - assert!(e.val_names.is_none()); - assert!(e.num_vals.is_none()); + let a = Arg::from_usage("[flag] -f --flag... 'some help info'"); + assert_eq!(a.name, "flag"); + assert_eq!(a.long.unwrap(), "flag"); + assert_eq!(a.short.unwrap(), 'f'); + assert_eq!(a.help.unwrap(), "some help info"); + assert!(a.is_set(ArgSettings::MultipleOccurrences)); + assert!(a.val_names.is_none()); + assert!(a.num_vals.is_none()); + + let a = Arg::from_usage("-f --flag... 'some help info'"); + assert_eq!(a.name, "flag"); + assert_eq!(a.long.unwrap(), "flag"); + assert_eq!(a.short.unwrap(), 'f'); + assert_eq!(a.help.unwrap(), "some help info"); + assert!(a.is_set(ArgSettings::MultipleOccurrences)); + assert!(a.val_names.is_none()); + assert!(a.num_vals.is_none()); + + let a = Arg::from_usage("--flags"); + assert_eq!(a.name, "flags"); + assert_eq!(a.long.unwrap(), "flags"); + assert!(a.val_names.is_none()); + assert!(a.num_vals.is_none()); + + let a = Arg::from_usage("--flags..."); + assert_eq!(a.name, "flags"); + assert_eq!(a.long.unwrap(), "flags"); + assert!(a.is_set(ArgSettings::MultipleOccurrences)); + assert!(a.val_names.is_none()); + assert!(a.num_vals.is_none()); + + let a = Arg::from_usage("[flags] -f"); + assert_eq!(a.name, "flags"); + assert_eq!(a.short.unwrap(), 'f'); + assert!(a.val_names.is_none()); + assert!(a.num_vals.is_none()); + + let a = Arg::from_usage("[flags] -f..."); + assert_eq!(a.name, "flags"); + assert_eq!(a.short.unwrap(), 'f'); + assert!(a.is_set(ArgSettings::MultipleOccurrences)); + assert!(a.val_names.is_none()); + assert!(a.num_vals.is_none()); let a = Arg::from_usage("-f 'some help info'"); assert_eq!(a.name, "f"); assert_eq!(a.short.unwrap(), 'f'); assert!(a.long.is_none()); assert_eq!(a.help.unwrap(), "some help info"); - assert!(!a.is_set(ArgSettings::Multiple)); + assert!(!a.is_set(ArgSettings::MultipleOccurrences)); assert!(a.val_names.is_none()); assert!(a.num_vals.is_none()); - let e = Arg::from_usage("-f"); - assert_eq!(e.name, "f"); - assert_eq!(e.short.unwrap(), 'f'); - assert!(e.val_names.is_none()); - assert!(e.num_vals.is_none()); + let a = Arg::from_usage("-f"); + assert_eq!(a.name, "f"); + assert_eq!(a.short.unwrap(), 'f'); + assert!(a.val_names.is_none()); + assert!(a.num_vals.is_none()); - let e = Arg::from_usage("-f..."); - assert_eq!(e.name, "f"); - assert_eq!(e.short.unwrap(), 'f'); - assert!(e.is_set(ArgSettings::Multiple)); - assert!(e.val_names.is_none()); - assert!(e.num_vals.is_none()); + let a = Arg::from_usage("-f..."); + assert_eq!(a.name, "f"); + assert_eq!(a.short.unwrap(), 'f'); + assert!(a.is_set(ArgSettings::MultipleOccurrences)); + assert!(a.val_names.is_none()); + assert!(a.num_vals.is_none()); } #[test] @@ -348,7 +341,8 @@ mod test { assert_eq!(a.short.unwrap(), 'o'); assert!(a.long.is_none()); assert_eq!(a.help.unwrap(), "some help info"); - assert!(!a.is_set(ArgSettings::Multiple)); + assert!(!a.is_set(ArgSettings::MultipleOccurrences)); + assert!(!a.is_set(ArgSettings::MultipleValues)); assert!(a.is_set(ArgSettings::TakesValue)); assert!(!a.is_set(ArgSettings::Required)); assert_eq!(a.val_names.unwrap().values().collect::>(), [&"opt"]); @@ -357,44 +351,47 @@ mod test { #[test] fn create_option_usage1() { - let b = Arg::from_usage("-o [opt] 'some help info'"); - assert_eq!(b.name, "o"); - assert_eq!(b.short.unwrap(), 'o'); - assert!(b.long.is_none()); - assert_eq!(b.help.unwrap(), "some help info"); - assert!(!b.is_set(ArgSettings::Multiple)); - assert!(b.is_set(ArgSettings::TakesValue)); - assert!(!b.is_set(ArgSettings::Required)); - assert_eq!(b.val_names.unwrap().values().collect::>(), [&"opt"]); - assert!(b.num_vals.is_none()); + let a = Arg::from_usage("-o [opt] 'some help info'"); + assert_eq!(a.name, "o"); + assert_eq!(a.short.unwrap(), 'o'); + assert!(a.long.is_none()); + assert_eq!(a.help.unwrap(), "some help info"); + assert!(!a.is_set(ArgSettings::MultipleOccurrences)); + assert!(!a.is_set(ArgSettings::MultipleValues)); + assert!(a.is_set(ArgSettings::TakesValue)); + assert!(!a.is_set(ArgSettings::Required)); + assert_eq!(a.val_names.unwrap().values().collect::>(), [&"opt"]); + assert!(a.num_vals.is_none()); } #[test] fn create_option_usage2() { - let c = Arg::from_usage("