diff --git a/src/args/arg.rs b/src/args/arg.rs index 0561517e..a42cc79a 100644 --- a/src/args/arg.rs +++ b/src/args/arg.rs @@ -2654,6 +2654,1098 @@ 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 + /// + /// **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 + pub fn last(self, l: bool) -> Self { + if l { + self.setting(ArgSettings::Last) + } else { + self.unset_setting(ArgSettings::Last) + } + } + + /// 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 + pub fn required(self, r: bool) -> Self { + if r { + self.setting(ArgSettings::Required) + } else { + self.unset_setting(ArgSettings::Required) + } + } + + /// 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 + pub fn takes_value(self, tv: bool) -> Self { + if tv { + self.setting(ArgSettings::TakesValue) + } else { + self.unset_setting(ArgSettings::TakesValue) + } + } + + /// 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 + pub fn allow_hyphen_values(self, a: bool) -> Self { + if a { + self.setting(ArgSettings::AllowHyphenValues) + } else { + self.unset_setting(ArgSettings::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 + 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) + } + } + + /// 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 + pub fn global(self, g: bool) -> Self { + if g { + self.setting(ArgSettings::Global) + } else { + self.unset_setting(ArgSettings::Global) + } + } + + /// 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 + 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) + } + } + + /// 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. + pub fn hide_possible_values(self, hide: bool) -> Self { + if hide { + self.setting(ArgSettings::HidePossibleValues) + } else { + self.unset_setting(ArgSettings::HidePossibleValues) + } + } + + /// 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. + 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) + } + } + + /// 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 + /// ``` + pub fn hidden(self, h: bool) -> Self { + if h { + self.setting(ArgSettings::Hidden) + } else { + self.unset_setting(ArgSettings::Hidden) + } + } + + /// 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 + pub fn case_insensitive(self, ci: bool) -> Self { + if ci { + self.setting(ArgSettings::IgnoreCase) + } else { + self.unset_setting(ArgSettings::IgnoreCase) + } + } + + /// 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 + 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) + } + } + + /// 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. + pub fn hide_env_values(self, hide: bool) -> Self { + if hide { + self.setting(ArgSettings::HideEnvValues) + } else { + self.unset_setting(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, 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 + pub fn next_line_help(mut self, nlh: bool) -> Self { + if nlh { + self.setb(ArgSettings::NextLineHelp); + } else { + self.unsetb(ArgSettings::NextLineHelp); + } + self + } + + /// 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 `MultipleValues` 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::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") + /// .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 + 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) + } + } + + /// 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 + pub fn multiple_values(mut self, multi: bool) -> Self { + if multi { + self.setting(ArgSettings::MultipleValues) + } else { + self.unset_setting(ArgSettings::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"), 3); + /// 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 + pub fn multiple_occurrences(mut self, multi: bool) -> Self { + if multi { + self.setting(ArgSettings::MultipleOccurrences) + } else { + self.unset_setting(ArgSettings::MultipleOccurrences) + } + } + // @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 @@ -2685,7 +3777,7 @@ impl<'a, 'b> Arg<'a, 'b> { #[doc(hidden)] pub fn _build(&mut self) { - if (self.is_set(ArgSettings::UseValueDelimiter) + if (self.is_set(ArgSettings::UseValueDelimiter) || self.is_set(ArgSettings::RequireDelimiter)) && self.val_delim.is_none() { self.val_delim = Some(','); } @@ -2727,7 +3819,7 @@ 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::MultipleValues) || self.is_set(ArgSettings::MultipleOccurrences)) + if (self.is_set(ArgSettings::MultipleValues) || self.is_set(ArgSettings::MultipleOccurrences)) && mult_vals { "..." } else { @@ -2791,184 +3883,6 @@ impl<'a, 'b> Arg<'a, 'b> { 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> { @@ -3003,8 +3917,8 @@ impl<'n, 'e> Display for Arg<'n, 'e> { write!(f, "<{}>", self.name)?; } if self.settings.is_set(ArgSettings::MultipleValues) - && (self.val_names.is_none() - || (self.val_names.is_some() + && (self.val_names.is_none() + || (self.val_names.is_some() && self.val_names.as_ref().unwrap().len() == 1)) { write!(f, "...")?; diff --git a/src/args/settings.rs b/src/args/settings.rs index 21806f71..f2b11456 100644 --- a/src/args/settings.rs +++ b/src/args/settings.rs @@ -63,957 +63,53 @@ impl Default for ArgFlags { } /// Various settings that apply to arguments and may be set, unset, and checked via getter/setter -/// methods [`Arg::set`], [`Arg::unset`], and [`Arg::is_set`] -/// [`Arg::set`]: ./struct.Arg.html#method.set -/// [`Arg::unset`]: ./struct.Arg.html#method.unset +/// methods [`Arg::setting`], [`Arg::unset_setting`], and [`Arg::is_set`]. This is what the +/// [`Arg`] methods which accept a `bool` use internally. +/// +/// [`Arg`]: ./struct.Arg.html +/// [`Arg::setting`]: ./struct.Arg.html#method.setting +/// [`Arg::unset_setting`]: ./struct.Arg.html#method.unset_setting /// [`Arg::is_set`]: ./struct.Arg.html#method.is_set #[derive(Debug, PartialEq, Copy, Clone)] pub enum ArgSettings { - /// 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 + /// Specifies that an arg must be used Required, - /// 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 `MultipleValues` 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::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") - /// .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 + /// Allows an arg to accept multiple 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"), 3); - /// 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 + /// Allows an arg to appear multiple times 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 + /// Allows an arg accept empty values such as `""` 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 + /// Sets an arg to be global (i.e. exist in all subcommands) + /// **DEPRECATED** + #[deprecated(since="2.32.0", note="Use `App::global_arg` instead")] Global, - /// 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 - /// ``` + /// Hides an arg from the help message Hidden, - /// 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 + /// Allows an argument to take a value (such as `--option value`) TakesValue, - /// 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 + /// Enables a delimiter to break up arguments `--option val1,val2,val3` becomes three values + /// (`val1`, `val2`, and `val3`) instead of the default one (`val1,val2,val3`) UseValueDelimiter, - /// 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 + /// Tells an arg to display it's help on the line below the arg itself in the help message NextLineHelp, - /// 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 + /// Says that arg *must* use a delimiter to separate values RequireDelimiter, - /// 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. + /// Hides the possible values from the help message HidePossibleValues, - /// 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 + /// Allows values that start with a hyphen 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 + /// Requires that an equals be used to provide a value to an option such as `--option=value` RequireEquals, - /// 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 + /// Says that a positional arg will be the last positional, and reuqires `--` to be accessed. + /// It can also be accessed early (i.e. before other positionals) by providing `--` Last, - /// 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. + /// Hides the default value from the help message HideDefaultValue, - /// 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 + /// Possible values become case insensitive 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. + /// Hides any values currently assigned to ENV variables in the help message (good for sensitive + /// information) HideEnvValues, #[doc(hidden)] RequiredUnlessAll, #[doc(hidden)] ValueDelimiterNotSet, diff --git a/v3_changes.md b/v3_changes.md index f0ed204b..41e4a29b 100644 --- a/v3_changes.md +++ b/v3_changes.md @@ -4,7 +4,6 @@ * Lazy requirement validation * `App::write_help` takes `&mut self` now * `App::override_usage` No longer implies `\t` which allows multi lined usages -* `Arg::setting` instead of `bool` methods * In usage parser, for options `[name]... --option [val]` results in `ArgSettings::MultipleOccurrences` but `--option [val]...` results in `ArgSettings::MultipleValues` *and* `ArgSettings::MultipleOccurrences`. Before both resulted in the same thing * Allow empty values no longer default * UseValueDelimiter no longer the default @@ -24,26 +23,8 @@ - `Arg::set` -> `Arg::setting` -## Arg Bool Methods +## App Methods -- `Arg::last` -> `ArgSettings::Last` -- `Arg::required` -> `ArgSettings::Required` -- `Arg::require_equals` -> `ArgSettings::RequireEquals` -- `Arg::allow_hyphen_values` -> `ArgSettings::AllowHyphenValues` -- `Arg::takes_value` -> `ArgSettings::TakesValue` -- `Arg::hide_possible_values` -> `ArgSettings::HidePossibleValues` -- `Arg::hide_default_value` -> `ArgSettings::HideDefaultValue` -- `Arg::multiple` -> `ArgSettings::MultipleValues` -- `Arg::multiple` -> `ArgSettings::MultipleOccurrences` -- `Arg::multiple` -> `ArgSettings::Multiple` -- `Arg::global` -> `ArgSettings::Global` -- `Arg::empty_values` -> `ArgSettings::AllowEmptyValues` -- `Arg::hidden` -> `ArgSettings::Hidden` -- `Arg::case_insensitive` -> `ArgSettings::IgnoreCase` -- `Arg::use_delimiter` -> `ArgSettings::UseDelimiter` -- `Arg::require_delimiter` -> `ArgSettings::RequireDelimiter` -- `Arg::hide_env_values` -> `ArgSettings::HideEnvValues` -- `Arg::next_line_help` -> `ArgSettings::NextLineHelp` - `App::version_message` -> `App::mut_arg` - `App::version_short` -> `App::mut_arg`