diff --git a/src/app/settings.rs b/src/app/settings.rs index 97b2cebc5ec..de404d7d478 100644 --- a/src/app/settings.rs +++ b/src/app/settings.rs @@ -4,33 +4,34 @@ use std::str::FromStr; bitflags! { flags Flags: u32 { - const SC_NEGATE_REQS = 0b000000000000000000000000001, - const SC_REQUIRED = 0b000000000000000000000000010, - const A_REQUIRED_ELSE_HELP = 0b000000000000000000000000100, - const GLOBAL_VERSION = 0b000000000000000000000001000, - const VERSIONLESS_SC = 0b000000000000000000000010000, - const UNIFIED_HELP = 0b000000000000000000000100000, - const WAIT_ON_ERROR = 0b000000000000000000001000000, - const SC_REQUIRED_ELSE_HELP= 0b000000000000000000010000000, - const NEEDS_LONG_HELP = 0b000000000000000000100000000, - const NEEDS_LONG_VERSION = 0b000000000000000001000000000, - const NEEDS_SC_HELP = 0b000000000000000010000000000, - const DISABLE_VERSION = 0b000000000000000100000000000, - const HIDDEN = 0b000000000000001000000000000, - const TRAILING_VARARG = 0b000000000000010000000000000, - const NO_BIN_NAME = 0b000000000000100000000000000, - const ALLOW_UNK_SC = 0b000000000001000000000000000, - const UTF8_STRICT = 0b000000000010000000000000000, - const UTF8_NONE = 0b000000000100000000000000000, - const LEADING_HYPHEN = 0b000000001000000000000000000, - const NO_POS_VALUES = 0b000000010000000000000000000, - const NEXT_LINE_HELP = 0b000000100000000000000000000, - const DERIVE_DISP_ORDER = 0b000001000000000000000000000, - const COLORED_HELP = 0b000010000000000000000000000, - const COLOR_ALWAYS = 0b000100000000000000000000000, - const COLOR_AUTO = 0b001000000000000000000000000, - const COLOR_NEVER = 0b010000000000000000000000000, - const DONT_DELIM_TRAIL = 0b100000000000000000000000000, + const SC_NEGATE_REQS = 0b0000000000000000000000000001, + const SC_REQUIRED = 0b0000000000000000000000000010, + const A_REQUIRED_ELSE_HELP = 0b0000000000000000000000000100, + const GLOBAL_VERSION = 0b0000000000000000000000001000, + const VERSIONLESS_SC = 0b0000000000000000000000010000, + const UNIFIED_HELP = 0b0000000000000000000000100000, + const WAIT_ON_ERROR = 0b0000000000000000000001000000, + const SC_REQUIRED_ELSE_HELP= 0b0000000000000000000010000000, + const NEEDS_LONG_HELP = 0b0000000000000000000100000000, + const NEEDS_LONG_VERSION = 0b0000000000000000001000000000, + const NEEDS_SC_HELP = 0b0000000000000000010000000000, + const DISABLE_VERSION = 0b0000000000000000100000000000, + const HIDDEN = 0b0000000000000001000000000000, + const TRAILING_VARARG = 0b0000000000000010000000000000, + const NO_BIN_NAME = 0b0000000000000100000000000000, + const ALLOW_UNK_SC = 0b0000000000001000000000000000, + const UTF8_STRICT = 0b0000000000010000000000000000, + const UTF8_NONE = 0b0000000000100000000000000000, + const LEADING_HYPHEN = 0b0000000001000000000000000000, + const NO_POS_VALUES = 0b0000000010000000000000000000, + const NEXT_LINE_HELP = 0b0000000100000000000000000000, + const DERIVE_DISP_ORDER = 0b0000001000000000000000000000, + const COLORED_HELP = 0b0000010000000000000000000000, + const COLOR_ALWAYS = 0b0000100000000000000000000000, + const COLOR_AUTO = 0b0001000000000000000000000000, + const COLOR_NEVER = 0b0010000000000000000000000000, + const DONT_DELIM_TRAIL = 0b0100000000000000000000000000, + const ALLOW_NEG_NUMS = 0b1000000000000000000000000000, } } @@ -56,33 +57,34 @@ impl AppFlags { } impl_settings! { AppSettings, - SubcommandsNegateReqs => SC_NEGATE_REQS, - VersionlessSubcommands => VERSIONLESS_SC, - SubcommandRequired => SC_REQUIRED, ArgRequiredElseHelp => A_REQUIRED_ELSE_HELP, - GlobalVersion => GLOBAL_VERSION, - UnifiedHelpMessage => UNIFIED_HELP, - WaitOnError => WAIT_ON_ERROR, - SubcommandRequiredElseHelp => SC_REQUIRED_ELSE_HELP, - NeedsLongHelp => NEEDS_LONG_HELP, - NeedsLongVersion => NEEDS_LONG_VERSION, - NeedsSubcommandHelp => NEEDS_SC_HELP, - DisableVersion => DISABLE_VERSION, - Hidden => HIDDEN, - TrailingVarArg => TRAILING_VARARG, - NoBinaryName => NO_BIN_NAME, AllowExternalSubcommands => ALLOW_UNK_SC, - StrictUtf8 => UTF8_STRICT, AllowInvalidUtf8 => UTF8_NONE, AllowLeadingHyphen => LEADING_HYPHEN, - HidePossibleValuesInHelp => NO_POS_VALUES, - NextLineHelp => NEXT_LINE_HELP, + AllowNegativeNumbers => ALLOW_NEG_NUMS, ColoredHelp => COLORED_HELP, - DeriveDisplayOrder => DERIVE_DISP_ORDER, ColorAlways => COLOR_ALWAYS, ColorAuto => COLOR_AUTO, ColorNever => COLOR_NEVER, - DontDelimitTrailingValues => DONT_DELIM_TRAIL + DontDelimitTrailingValues => DONT_DELIM_TRAIL, + DeriveDisplayOrder => DERIVE_DISP_ORDER, + DisableVersion => DISABLE_VERSION, + GlobalVersion => GLOBAL_VERSION, + HidePossibleValuesInHelp => NO_POS_VALUES, + Hidden => HIDDEN, + NeedsLongHelp => NEEDS_LONG_HELP, + NeedsLongVersion => NEEDS_LONG_VERSION, + NeedsSubcommandHelp => NEEDS_SC_HELP, + NoBinaryName => NO_BIN_NAME, + StrictUtf8 => UTF8_STRICT, + SubcommandsNegateReqs => SC_NEGATE_REQS, + SubcommandRequired => SC_REQUIRED, + SubcommandRequiredElseHelp => SC_REQUIRED_ELSE_HELP, + TrailingVarArg => TRAILING_VARARG, + UnifiedHelpMessage => UNIFIED_HELP, + NextLineHelp => NEXT_LINE_HELP, + VersionlessSubcommands => VERSIONLESS_SC, + WaitOnError => WAIT_ON_ERROR } } @@ -94,72 +96,130 @@ impl AppFlags { /// [`App`]: ./struct.App.html #[derive(Debug, PartialEq, Copy, Clone)] pub enum AppSettings { - /// Allows [`SubCommand`]s to override all requirements of the parent command. - /// For example if you had a subcommand or top level application with a required argument - /// that is only required as long as there is no subcommand present, - /// using this setting would allow you to set those arguments to [`Arg::required(true)`] - /// and yet receive no error so long as the user uses a valid subcommand instead. + /// Specifies that any invalid UTF-8 code points should *not* be treated as an error. + /// This is the default behavior of `clap`. /// - /// **NOTE:** This defaults to false (using subcommand does *not* negate requirements) + /// **NOTE:** Using argument values with invalid UTF-8 code points requires using + /// [`ArgMatches::os_value_of`], [`ArgMatches::os_values_of`], [`ArgMatches::lossy_value_of`], + /// or [`ArgMatches::lossy_values_of`] for those particular arguments which may contain invalid + /// UTF-8 values + /// + /// **NOTE:** This rule only applies to argument values, as flags, options, and + /// [`SubCommand`]s themselves only allow valid UTF-8 code points. + /// + /// # Platform Specific + /// + /// Non Windows systems only /// /// # Examples /// - /// This first example shows that it is an error to not use a required argument + #[cfg_attr(not(unix), doc=" ```ignore")] + #[cfg_attr( unix , doc=" ```")] + /// # use clap::{App, AppSettings}; + /// use std::ffi::OsString; + /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; + /// + /// let r = App::new("myprog") + /// //.setting(AppSettings::AllowInvalidUtf8) + /// .arg_from_usage(" 'some positional arg'") + /// .get_matches_from_safe( + /// vec![ + /// OsString::from("myprog"), + /// OsString::from_vec(vec![0xe9])]); + /// + /// assert!(r.is_ok()); + /// let m = r.unwrap(); + /// assert_eq!(m.value_of_os("arg").unwrap().as_bytes(), &[0xe9]); + /// ``` + /// [`ArgMatches::os_value_of`]: ./struct.ArgMatches.html#method.os_value_of + /// [`ArgMatches::os_values_of`]: ./struct.ArgMatches.html#method.os_values_of + /// [`ArgMatches::lossy_value_of`]: ./struct.ArgMatches.html#method.lossy_value_of + /// [`ArgMatches::lossy_values_of`]: ./struct.ArgMatches.html#method.lossy_values_of + AllowInvalidUtf8, + + /// Specifies that leading hyphens are allowed in argument *values*, such as negative numbers + /// like `-10`. (which would otherwise be parsed as another flag or option) + /// + /// **NOTE:** This can only be set application wide and not on a per argument basis. + /// + /// **NOTE:** Use this setting with caution as it silences certain circumstances which would + /// otherwise be an error (such as accidentally forgetting to specify a value for leading + /// option) + /// + /// # Examples /// /// ```rust - /// # use clap::{App, Arg, AppSettings, SubCommand, ErrorKind}; - /// let err = App::new("myprog") - /// .setting(AppSettings::SubcommandsNegateReqs) - /// .arg(Arg::with_name("opt").required(true)) - /// .subcommand(SubCommand::with_name("test")) - /// .get_matches_from_safe(vec![ - /// "myprog" + /// # use clap::{Arg, App, AppSettings}; + /// // Imagine you needed to represent negative numbers as well, such as -10 + /// let m = App::new("nums") + /// .setting(AppSettings::AllowLeadingHyphen) + /// .arg(Arg::with_name("neg").index(1)) + /// .get_matches_from(vec![ + /// "nums", "-20" /// ]); - /// assert!(err.is_err()); - /// assert_eq!(err.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// + /// assert_eq!(m.value_of("neg"), Some("-20")); /// # ; /// ``` + AllowLeadingHyphen, + + /// Allows negative numbers to pass as values. This is similar to + /// `AllowLeadingHyphen` except that it only allows numbers, all + /// other undefined leading hyphens will fail to parse. /// - /// This next example shows that it is no longer error to not use a required argument if a - /// valid subcommand is used. + /// # Examples /// /// ```rust - /// # use clap::{App, Arg, AppSettings, SubCommand, ErrorKind}; - /// let noerr = App::new("myprog") - /// .setting(AppSettings::SubcommandsNegateReqs) - /// .arg(Arg::with_name("opt").required(true)) - /// .subcommand(SubCommand::with_name("test")) + /// # use clap::{App, AppSettings, ErrorKind}; + /// let res = App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::AllowNegativeNumbers) + /// .arg(Arg::with_name("num")) /// .get_matches_from_safe(vec![ - /// "myprog", "test" + /// "myprog", "-20" /// ]); - /// assert!(noerr.is_ok()); - /// # ; + /// assert!(res.is_ok()); + /// let m = res.unwrap(); + /// assert_eq!(m.value_of("num").unwrap(), "-20"); /// ``` - /// [`Arg::required(true)`]: ./struct.Arg.html#method.required - /// [`SubCommand`]: ./struct.SubCommand.html - SubcommandsNegateReqs, + /// [`AllowLeadingHyphen`]: ./enum.AppSettings.html#variant.AllowLeadingHyphen + AllowNegativeNumbers, - /// Allows specifying that if no [`SubCommand`] is present at runtime, - /// error and exit gracefully. + /// Specifies that an unexpected positional argument, + /// which would otherwise cause a [`ErrorKind::UnknownArgument`] error, + /// should instead be treated as a [`SubCommand`] within the [`ArgMatches`] struct. /// - /// **NOTE:** This defaults to `false` (subcommands do *not* need to be present) + /// **NOTE:** Use this setting with caution, + /// as a truly unexpected argument (i.e. one that is *NOT* an external subcommand) + /// will **not** cause an error and instead be treated as a potential subcommand. + /// One should check for such cases manually and inform the user appropriately. /// /// # Examples /// /// ```rust - /// # use clap::{App, AppSettings, SubCommand, ErrorKind}; - /// let err = App::new("myprog") - /// .setting(AppSettings::SubcommandRequired) - /// .subcommand(SubCommand::with_name("test")) - /// .get_matches_from_safe(vec![ - /// "myprog", + /// # use clap::{App, AppSettings}; + /// // Assume there is an external subcommand named "subcmd" + /// let m = App::new("myprog") + /// .setting(AppSettings::AllowExternalSubcommands) + /// .get_matches_from(vec![ + /// "myprog", "subcmd", "--option", "value", "-fff", "--flag" /// ]); - /// assert!(err.is_err()); - /// assert_eq!(err.unwrap_err().kind, ErrorKind::MissingSubcommand); - /// # ; + /// + /// // All trailing arguments will be stored under the subcommand's sub-matches using an empty + /// // string argument name + /// match m.subcommand() { + /// (external, Some(ext_m)) => { + /// let ext_args: Vec<&str> = ext_m.values_of("").unwrap().collect(); + /// assert_eq!(external, "subcmd"); + /// assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]); + /// }, + /// _ => {}, + /// } /// ``` + /// [`ErrorKind::UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument /// [`SubCommand`]: ./struct.SubCommand.html - SubcommandRequired, + /// [`ArgMatches`]: ./struct.ArgMatches.html + AllowExternalSubcommands, /// Specifies that the help text should be displayed (and then exit gracefully), /// if no arguments are present at runtime (i.e. an empty run such as, `$ myprog`. @@ -177,149 +237,183 @@ pub enum AppSettings { /// [`SubCommand`]: ./struct.SubCommand.html ArgRequiredElseHelp, - /// Specifies to use the version of the current command for all child [`SubCommand`]s. - /// (Defaults to `false`; subcommands have independant version strings from their parents.) + /// Uses colorized help messages. /// - /// **NOTE:** The version for the current command **and** this setting must be set **prior** to - /// adding any child subcommands + /// **NOTE:** Must be compiled with the `color` cargo feature + /// + /// # Platform Specific + /// + /// This setting only applies to Unix, Linux, and OSX (i.e. non-Windows platforms) /// /// # Examples /// /// ```no_run /// # use clap::{App, Arg, SubCommand, AppSettings}; /// App::new("myprog") - /// .version("v1.1") - /// .setting(AppSettings::GlobalVersion) - /// .subcommand(SubCommand::with_name("test")) + /// .setting(AppSettings::ColoredHelp) /// .get_matches(); - /// // running `$ myprog test --version` will display - /// // "myprog-test v1.1" /// ``` - /// [`SubCommand`]: ./struct.SubCommand.html - GlobalVersion, + ColoredHelp, - /// Disables `-V` and `--version` for all [`SubCommand`]s - /// (Defaults to `false`; subcommands *do* have version flags.) - /// - /// **NOTE:** This setting must be set **prior** adding any subcommands + /// Enables colored output only when the output is going to a terminal or TTY. /// - /// # Examples + /// **NOTE:** This is the default behavior of `clap`. /// - /// ```rust - /// # use clap::{App, SubCommand, AppSettings, ErrorKind}; - /// let res = App::new("myprog") - /// .version("v1.1") - /// .setting(AppSettings::VersionlessSubcommands) - /// .subcommand(SubCommand::with_name("test")) - /// .get_matches_from_safe(vec![ - /// "myprog", "test", "-V" - /// ]); - /// assert!(res.is_err()); - /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); - /// ``` - /// [`SubCommand`]: ./struct.SubCommand.html - VersionlessSubcommands, - - /// Groups flags and options together, presenting a more unified help message - /// (a la `getopts` or `docopt` style). + /// **NOTE:** Must be compiled with the `color` cargo feature. /// - /// The default is that the auto-generated help message will group flags, and options - /// separately. + /// # Platform Specific /// - /// **NOTE:** This setting is cosmetic only and does not affect any functionality. + /// This setting only applies to Unix, Linux, and OSX (i.e. non-Windows platforms). /// /// # Examples /// /// ```no_run /// # use clap::{App, Arg, SubCommand, AppSettings}; /// App::new("myprog") - /// .setting(AppSettings::UnifiedHelpMessage) + /// .setting(AppSettings::ColorAuto) /// .get_matches(); - /// // running `myprog --help` will display a unified "docopt" or "getopts" style help message /// ``` - UnifiedHelpMessage, + ColorAuto, - /// Will display a message "Press [ENTER]/[RETURN] to continue..." and wait for user before - /// exiting + /// Enables colored output regardless of whether or not the output is going to a terminal/TTY. /// - /// This is most useful when writing an application which is run from a GUI shortcut, or on - /// Windows where a user tries to open the binary by double-clicking instead of using the - /// command line. + /// **NOTE:** Must be compiled with the `color` cargo feature. /// - /// **NOTE:** This setting is **not** recursive with [`SubCommand`]s, meaning if you wish this - /// behavior for all subcommands, you must set this on each command (needing this is extremely - /// rare) + /// # Platform Specific + /// + /// This setting only applies to Unix, Linux, and OSX (i.e. non-Windows platforms). /// /// # Examples /// - /// ```rust - /// # use clap::{App, Arg, AppSettings}; + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; /// App::new("myprog") - /// .setting(AppSettings::WaitOnError) - /// # ; + /// .setting(AppSettings::ColorAlways) + /// .get_matches(); /// ``` - /// [`SubCommand`]: ./struct.SubCommand.html - WaitOnError, + ColorAlways, - /// Specifies that the help text should be displayed (before exiting gracefully) if no - /// [`SubCommand`]s are present at runtime (i.e. an empty run such as `$ myprog`). + /// Disables colored output no matter if the output is going to a terminal/TTY, or not. /// - /// **NOTE:** This should *not* be used with [`AppSettings::SubcommandRequired`] as they do - /// nearly same thing; this prints the help text, and the other prints an error. + /// **NOTE:** Must be compiled with the `color` cargo feature /// - /// **NOTE:** If the user specifies arguments at runtime, but no subcommand the help text will - /// still be displayed and exit. If this is *not* the desired result, consider using - /// [`AppSettings::ArgRequiredElseHelp`] instead. + /// # Platform Specific + /// + /// This setting only applies to Unix, Linux, and OSX (i.e. non-Windows platforms) /// /// # Examples /// - /// ```rust - /// # use clap::{App, Arg, AppSettings}; + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; /// App::new("myprog") - /// .setting(AppSettings::SubcommandRequiredElseHelp) - /// # ; + /// .setting(AppSettings::ColorNever) + /// .get_matches(); /// ``` - /// [`SubCommand`]: ./struct.SubCommand.html - /// [`AppSettings::SubcommandRequired`]: ./enum.AppSettings.html#variant.SubcommandRequired - /// [`AppSettings::ArgRequiredElseHelp`]: ./enum.AppSettings.html#variant.ArgRequiredElseHelp - SubcommandRequiredElseHelp, + ColorNever, - /// Specifies that this [`SubCommand`] should be hidden from help messages + /// Disables the automatic delimiting of values when `--` or [`AppSettings::TrailingVarArg`] + /// was used. + /// + /// **NOTE:** The same thing can be done manually by setting the final positional argument to + /// [`Arg::use_delimiter(false)`]. Using this setting is safer, because it's easier to locate + /// when making changes. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::DontDelimitTrailingValues) + /// .get_matches(); + /// ``` + /// [`AppSettings::TrailingVarArg`]: ./enum.AppSettings.html#variant.TrailingVarArg + /// [`Arg::use_delimiter(false)`]: ./struct.Arg.html#method.use_delimiter + DontDelimitTrailingValues, + + /// Disables `-V` and `--version` [`App`] without affecting any of the [`SubCommand`]s + /// (Defaults to `false`; application *does* have a version flag) /// /// # Examples /// /// ```rust - /// # use clap::{App, Arg, AppSettings, SubCommand}; + /// # use clap::{App, AppSettings, ErrorKind}; + /// let res = App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::DisableVersion) + /// .get_matches_from_safe(vec![ + /// "myprog", "-V" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// + /// ```rust + /// # use clap::{App, SubCommand, AppSettings, ErrorKind}; + /// let res = App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::DisableVersion) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", "test", "-V" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::VersionDisplayed); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + DisableVersion, + + /// Displays the arguments and [`SubCommand`]s in the help message in the order that they were + /// declared in, and not alphabetically which is the default. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; /// App::new("myprog") - /// .subcommand(SubCommand::with_name("test") - /// .setting(AppSettings::Hidden)) - /// # ; + /// .setting(AppSettings::DeriveDisplayOrder) + /// .get_matches(); /// ``` /// [`SubCommand`]: ./struct.SubCommand.html - Hidden, + DeriveDisplayOrder, - /// Specifies that the final positional argument is a "VarArg" and that `clap` should not - /// attempt to parse any further args. + /// Specifies to use the version of the current command for all child [`SubCommand`]s. + /// (Defaults to `false`; subcommands have independant version strings from their parents.) /// - /// The values of the trailing positional argument will contain all args from itself on. + /// **NOTE:** The version for the current command **and** this setting must be set **prior** to + /// adding any child subcommands /// - /// **NOTE:** The final positional argument **must** have [`Arg::multiple(true)`] or the usage - /// string equivalent. + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::GlobalVersion) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches(); + /// // running `$ myprog test --version` will display + /// // "myprog-test v1.1" + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + GlobalVersion, + + /// Specifies that this [`SubCommand`] should be hidden from help messages /// /// # Examples /// /// ```rust - /// # use clap::{App, Arg, AppSettings}; - /// let m = App::new("myprog") - /// .setting(AppSettings::TrailingVarArg) - /// .arg(Arg::from_usage("... 'commands to run'")) - /// .get_matches_from(vec!["myprog", "arg1", "-r", "val1"]); - /// - /// let trail: Vec<&str> = m.values_of("cmd").unwrap().collect(); - /// assert_eq!(trail, ["arg1", "-r", "val1"]); + /// # use clap::{App, Arg, AppSettings, SubCommand}; + /// App::new("myprog") + /// .subcommand(SubCommand::with_name("test") + /// .setting(AppSettings::Hidden)) + /// # ; /// ``` - /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple - TrailingVarArg, + /// [`SubCommand`]: ./struct.SubCommand.html + Hidden, + + /// Tells `clap` *not* to print possible values when displaying help information. + /// This can be useful if there are many values, or they are explained elsewhere. + HidePossibleValuesInHelp, /// Specifies that the parser should not assume the first argument passed is the binary name. /// This is normally the case when using a "daemon" style mode, or an interactive CLI where one @@ -339,41 +433,85 @@ pub enum AppSettings { /// ``` NoBinaryName, - /// Specifies that an unexpected positional argument, - /// which would otherwise cause a [`ErrorKind::UnknownArgument`] error, - /// should instead be treated as a [`SubCommand`] within the [`ArgMatches`] struct. + /// Places the help string for all arguments on the line after the argument. /// - /// **NOTE:** Use this setting with caution, - /// as a truly unexpected argument (i.e. one that is *NOT* an external subcommand) - /// will **not** cause an error and instead be treated as a potential subcommand. - /// One should check for such cases manually and inform the user appropriately. + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::NextLineHelp) + /// .get_matches(); + /// ``` + NextLineHelp, + + /// Allows [`SubCommand`]s to override all requirements of the parent command. + /// For example if you had a subcommand or top level application with a required argument + /// that is only required as long as there is no subcommand present, + /// using this setting would allow you to set those arguments to [`Arg::required(true)`] + /// and yet receive no error so long as the user uses a valid subcommand instead. + /// + /// **NOTE:** This defaults to false (using subcommand does *not* negate requirements) /// /// # Examples /// + /// This first example shows that it is an error to not use a required argument + /// /// ```rust - /// # use clap::{App, AppSettings}; - /// // Assume there is an external subcommand named "subcmd" - /// let m = App::new("myprog") - /// .setting(AppSettings::AllowExternalSubcommands) - /// .get_matches_from(vec![ - /// "myprog", "subcmd", "--option", "value", "-fff", "--flag" + /// # use clap::{App, Arg, AppSettings, SubCommand, ErrorKind}; + /// let err = App::new("myprog") + /// .setting(AppSettings::SubcommandsNegateReqs) + /// .arg(Arg::with_name("opt").required(true)) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog" /// ]); + /// assert!(err.is_err()); + /// assert_eq!(err.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// # ; + /// ``` /// - /// // All trailing arguments will be stored under the subcommand's sub-matches using an empty - /// // string argument name - /// match m.subcommand() { - /// (external, Some(ext_m)) => { - /// let ext_args: Vec<&str> = ext_m.values_of("").unwrap().collect(); - /// assert_eq!(external, "subcmd"); - /// assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]); - /// }, - /// _ => {}, - /// } + /// This next example shows that it is no longer error to not use a required argument if a + /// valid subcommand is used. + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings, SubCommand, ErrorKind}; + /// let noerr = App::new("myprog") + /// .setting(AppSettings::SubcommandsNegateReqs) + /// .arg(Arg::with_name("opt").required(true)) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", "test" + /// ]); + /// assert!(noerr.is_ok()); + /// # ; /// ``` - /// [`ErrorKind::UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument + /// [`Arg::required(true)`]: ./struct.Arg.html#method.required /// [`SubCommand`]: ./struct.SubCommand.html - /// [`ArgMatches`]: ./struct.ArgMatches.html - AllowExternalSubcommands, + SubcommandsNegateReqs, + + /// Specifies that the help text should be displayed (before exiting gracefully) if no + /// [`SubCommand`]s are present at runtime (i.e. an empty run such as `$ myprog`). + /// + /// **NOTE:** This should *not* be used with [`AppSettings::SubcommandRequired`] as they do + /// nearly same thing; this prints the help text, and the other prints an error. + /// + /// **NOTE:** If the user specifies arguments at runtime, but no subcommand the help text will + /// still be displayed and exit. If this is *not* the desired result, consider using + /// [`AppSettings::ArgRequiredElseHelp`] instead. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::SubcommandRequiredElseHelp) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings::SubcommandRequired`]: ./enum.AppSettings.html#variant.SubcommandRequired + /// [`AppSettings::ArgRequiredElseHelp`]: ./enum.AppSettings.html#variant.ArgRequiredElseHelp + SubcommandRequiredElseHelp, /// Specifies that any invalid UTF-8 code points should be treated as an error and fail /// with a [`ErrorKind::InvalidUtf8`] error. @@ -408,195 +546,113 @@ pub enum AppSettings { /// [`ErrorKind::InvalidUtf8`]: ./enum.ErrorKind.html#variant.InvalidUtf8 StrictUtf8, - /// Specifies that any invalid UTF-8 code points should *not* be treated as an error. - /// This is the default behavior of `clap`. + /// Allows specifying that if no [`SubCommand`] is present at runtime, + /// error and exit gracefully. /// - /// **NOTE:** Using argument values with invalid UTF-8 code points requires using - /// [`ArgMatches::os_value_of`], [`ArgMatches::os_values_of`], [`ArgMatches::lossy_value_of`], - /// or [`ArgMatches::lossy_values_of`] for those particular arguments which may contain invalid - /// UTF-8 values + /// **NOTE:** This defaults to `false` (subcommands do *not* need to be present) /// - /// **NOTE:** This rule only applies to argument values, as flags, options, and - /// [`SubCommand`]s themselves only allow valid UTF-8 code points. + /// # Examples /// - /// # Platform Specific + /// ```rust + /// # use clap::{App, AppSettings, SubCommand, ErrorKind}; + /// let err = App::new("myprog") + /// .setting(AppSettings::SubcommandRequired) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", + /// ]); + /// assert!(err.is_err()); + /// assert_eq!(err.unwrap_err().kind, ErrorKind::MissingSubcommand); + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + SubcommandRequired, + + /// Specifies that the final positional argument is a "VarArg" and that `clap` should not + /// attempt to parse any further args. /// - /// Non Windows systems only - /// - /// # Examples - /// - #[cfg_attr(not(unix), doc=" ```ignore")] - #[cfg_attr( unix , doc=" ```")] - /// # use clap::{App, AppSettings}; - /// use std::ffi::OsString; - /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; - /// - /// let r = App::new("myprog") - /// //.setting(AppSettings::AllowInvalidUtf8) - /// .arg_from_usage(" 'some positional arg'") - /// .get_matches_from_safe( - /// vec![ - /// OsString::from("myprog"), - /// OsString::from_vec(vec![0xe9])]); - /// - /// assert!(r.is_ok()); - /// let m = r.unwrap(); - /// assert_eq!(m.value_of_os("arg").unwrap().as_bytes(), &[0xe9]); - /// ``` - /// [`ArgMatches::os_value_of`]: ./struct.ArgMatches.html#method.os_value_of - /// [`ArgMatches::os_values_of`]: ./struct.ArgMatches.html#method.os_values_of - /// [`ArgMatches::lossy_value_of`]: ./struct.ArgMatches.html#method.lossy_value_of - /// [`ArgMatches::lossy_values_of`]: ./struct.ArgMatches.html#method.lossy_values_of - AllowInvalidUtf8, - - /// Specifies that leading hyphens are allowed in argument *values*, such as negative numbers - /// like `-10`. (which would otherwise be parsed as another flag or option) - /// - /// **NOTE:** This can only be set application wide and not on a per argument basis. - /// - /// **NOTE:** Use this setting with caution as it silences certain circumstances which would - /// otherwise be an error (such as accidentally forgetting to specify a value for leading - /// option) + /// The values of the trailing positional argument will contain all args from itself on. + /// + /// **NOTE:** The final positional argument **must** have [`Arg::multiple(true)`] or the usage + /// string equivalent. /// /// # Examples /// /// ```rust - /// # use clap::{Arg, App, AppSettings}; - /// // Imagine you needed to represent negative numbers as well, such as -10 - /// let m = App::new("nums") - /// .setting(AppSettings::AllowLeadingHyphen) - /// .arg(Arg::with_name("neg").index(1)) - /// .get_matches_from(vec![ - /// "nums", "-20" - /// ]); - /// - /// assert_eq!(m.value_of("neg"), Some("-20")); - /// # ; - /// ``` - AllowLeadingHyphen, - - /// Tells `clap` *not* to print possible values when displaying help information. - /// This can be useful if there are many values, or they are explained elsewhere. - HidePossibleValuesInHelp, - - /// Places the help string for all arguments on the line after the argument. - /// - /// # Examples - /// - /// ```no_run - /// # use clap::{App, Arg, SubCommand, AppSettings}; - /// App::new("myprog") - /// .setting(AppSettings::NextLineHelp) - /// .get_matches(); - /// ``` - NextLineHelp, - - /// Displays the arguments and [`SubCommand`]s in the help message in the order that they were - /// declared in, and not alphabetically which is the default. - /// - /// # Examples - /// - /// ```no_run - /// # use clap::{App, Arg, SubCommand, AppSettings}; - /// App::new("myprog") - /// .setting(AppSettings::DeriveDisplayOrder) - /// .get_matches(); - /// ``` - /// [`SubCommand`]: ./struct.SubCommand.html - DeriveDisplayOrder, - - /// Uses colorized help messages. - /// - /// **NOTE:** Must be compiled with the `color` cargo feature - /// - /// # Platform Specific - /// - /// This setting only applies to Unix, Linux, and OSX (i.e. non-Windows platforms) - /// - /// # Examples + /// # use clap::{App, Arg, AppSettings}; + /// let m = App::new("myprog") + /// .setting(AppSettings::TrailingVarArg) + /// .arg(Arg::from_usage("... 'commands to run'")) + /// .get_matches_from(vec!["myprog", "arg1", "-r", "val1"]); /// - /// ```no_run - /// # use clap::{App, Arg, SubCommand, AppSettings}; - /// App::new("myprog") - /// .setting(AppSettings::ColoredHelp) - /// .get_matches(); + /// let trail: Vec<&str> = m.values_of("cmd").unwrap().collect(); + /// assert_eq!(trail, ["arg1", "-r", "val1"]); /// ``` - ColoredHelp, + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + TrailingVarArg, - /// Enables colored output only when the output is going to a terminal or TTY. - /// - /// **NOTE:** This is the default behavior of `clap`. - /// - /// **NOTE:** Must be compiled with the `color` cargo feature. + /// Groups flags and options together, presenting a more unified help message + /// (a la `getopts` or `docopt` style). /// - /// # Platform Specific + /// The default is that the auto-generated help message will group flags, and options + /// separately. /// - /// This setting only applies to Unix, Linux, and OSX (i.e. non-Windows platforms). + /// **NOTE:** This setting is cosmetic only and does not affect any functionality. /// /// # Examples /// /// ```no_run /// # use clap::{App, Arg, SubCommand, AppSettings}; /// App::new("myprog") - /// .setting(AppSettings::ColorAuto) + /// .setting(AppSettings::UnifiedHelpMessage) /// .get_matches(); + /// // running `myprog --help` will display a unified "docopt" or "getopts" style help message /// ``` - ColorAuto, + UnifiedHelpMessage, - /// Enables colored output regardless of whether or not the output is going to a terminal/TTY. - /// - /// **NOTE:** Must be compiled with the `color` cargo feature. - /// - /// # Platform Specific + /// Disables `-V` and `--version` for all [`SubCommand`]s + /// (Defaults to `false`; subcommands *do* have version flags.) /// - /// This setting only applies to Unix, Linux, and OSX (i.e. non-Windows platforms). + /// **NOTE:** This setting must be set **prior** adding any subcommands /// /// # Examples /// - /// ```no_run - /// # use clap::{App, Arg, SubCommand, AppSettings}; - /// App::new("myprog") - /// .setting(AppSettings::ColorAlways) - /// .get_matches(); + /// ```rust + /// # use clap::{App, SubCommand, AppSettings, ErrorKind}; + /// let res = App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::VersionlessSubcommands) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", "test", "-V" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); /// ``` - ColorAlways, + /// [`SubCommand`]: ./struct.SubCommand.html + VersionlessSubcommands, - /// Disables colored output no matter if the output is going to a terminal/TTY, or not. - /// - /// **NOTE:** Must be compiled with the `color` cargo feature - /// - /// # Platform Specific - /// - /// This setting only applies to Unix, Linux, and OSX (i.e. non-Windows platforms) - /// - /// # Examples + /// Will display a message "Press [ENTER]/[RETURN] to continue..." and wait for user before + /// exiting /// - /// ```no_run - /// # use clap::{App, Arg, SubCommand, AppSettings}; - /// App::new("myprog") - /// .setting(AppSettings::ColorNever) - /// .get_matches(); - /// ``` - ColorNever, - - /// Disables the automatic delimiting of values when `--` or [`AppSettings::TrailingVarArg`] - /// was used. + /// This is most useful when writing an application which is run from a GUI shortcut, or on + /// Windows where a user tries to open the binary by double-clicking instead of using the + /// command line. /// - /// **NOTE:** The same thing can be done manually by setting the final positional argument to - /// [`Arg::use_delimiter(false)`]. Using this setting is safer, because it's easier to locate - /// when making changes. + /// **NOTE:** This setting is **not** recursive with [`SubCommand`]s, meaning if you wish this + /// behavior for all subcommands, you must set this on each command (needing this is extremely + /// rare) /// /// # Examples /// - /// ```no_run - /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// ```rust + /// # use clap::{App, Arg, AppSettings}; /// App::new("myprog") - /// .setting(AppSettings::DontDelimitTrailingValues) - /// .get_matches(); + /// .setting(AppSettings::WaitOnError) + /// # ; /// ``` - /// [`AppSettings::TrailingVarArg`]: ./enum.AppSettings.html#variant.TrailingVarArg - /// [`Arg::use_delimiter(false)`]: ./struct.Arg.html#method.use_delimiter - DontDelimitTrailingValues, + /// [`SubCommand`]: ./struct.SubCommand.html + WaitOnError, #[doc(hidden)] NeedsLongVersion, @@ -607,67 +663,37 @@ pub enum AppSettings { #[doc(hidden)] NeedsSubcommandHelp, - /// Disables `-V` and `--version` [`App`] without affecting any of the [`SubCommand`]s - /// (Defaults to `false`; application *does* have a version flag) - /// - /// # Examples - /// - /// ```rust - /// # use clap::{App, AppSettings, ErrorKind}; - /// let res = App::new("myprog") - /// .version("v1.1") - /// .setting(AppSettings::DisableVersion) - /// .get_matches_from_safe(vec![ - /// "myprog", "-V" - /// ]); - /// assert!(res.is_err()); - /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); - /// ``` - /// - /// ```rust - /// # use clap::{App, SubCommand, AppSettings, ErrorKind}; - /// let res = App::new("myprog") - /// .version("v1.1") - /// .setting(AppSettings::DisableVersion) - /// .subcommand(SubCommand::with_name("test")) - /// .get_matches_from_safe(vec![ - /// "myprog", "test", "-V" - /// ]); - /// assert!(res.is_err()); - /// assert_eq!(res.unwrap_err().kind, ErrorKind::VersionDisplayed); - /// ``` - /// [`SubCommand`]: ./struct.SubCommand.html - DisableVersion, } impl FromStr for AppSettings { type Err = String; fn from_str(s: &str) -> Result::Err> { match &*s.to_ascii_lowercase() { - "subcommandsnegatereqs" => Ok(AppSettings::SubcommandsNegateReqs), - "subcommandrequired" => Ok(AppSettings::SubcommandRequired), "argrequiredelsehelp" => Ok(AppSettings::ArgRequiredElseHelp), - "globalversion" => Ok(AppSettings::GlobalVersion), - "versionlesssubcommands" => Ok(AppSettings::VersionlessSubcommands), - "unifiedhelpmessage" => Ok(AppSettings::UnifiedHelpMessage), - "waitonerror" => Ok(AppSettings::WaitOnError), - "subcommandrequiredelsehelp" => Ok(AppSettings::SubcommandRequiredElseHelp), - "hidden" => Ok(AppSettings::Hidden), - "allowexternalsubcommands" => Ok(AppSettings::AllowExternalSubcommands), - "trailingvararg" => Ok(AppSettings::TrailingVarArg), - "nobinaryname" => Ok(AppSettings::NoBinaryName), - "strictutf8" => Ok(AppSettings::StrictUtf8), "allowinvalidutf8" => Ok(AppSettings::AllowInvalidUtf8), "allowleadinghyphen" => Ok(AppSettings::AllowLeadingHyphen), - "hidepossiblevaluesinhelp" => Ok(AppSettings::HidePossibleValuesInHelp), - "nextlinehelp" => Ok(AppSettings::NextLineHelp), - "derivedisplayorder" => Ok(AppSettings::DeriveDisplayOrder), - "coloredhelp" => Ok(AppSettings::ColoredHelp), - "dontdelimittrailingvalues" => Ok(AppSettings::DontDelimitTrailingValues), + "allowexternalsubcommands" => Ok(AppSettings::AllowExternalSubcommands), + "allownegativenumbers" => Ok(AppSettings::AllowNegativeNumbers), "colorauto" => Ok(AppSettings::ColorAuto), "coloralways" => Ok(AppSettings::ColorAlways), "colornever" => Ok(AppSettings::ColorNever), + "coloredhelp" => Ok(AppSettings::ColoredHelp), + "derivedisplayorder" => Ok(AppSettings::DeriveDisplayOrder), + "dontdelimittrailingvalues" => Ok(AppSettings::DontDelimitTrailingValues), "disableversion" => Ok(AppSettings::DisableVersion), + "globalversion" => Ok(AppSettings::GlobalVersion), + "hidden" => Ok(AppSettings::Hidden), + "hidepossiblevaluesinhelp" => Ok(AppSettings::HidePossibleValuesInHelp), + "nobinaryname" => Ok(AppSettings::NoBinaryName), + "nextlinehelp" => Ok(AppSettings::NextLineHelp), + "strictutf8" => Ok(AppSettings::StrictUtf8), + "subcommandsnegatereqs" => Ok(AppSettings::SubcommandsNegateReqs), + "subcommandrequired" => Ok(AppSettings::SubcommandRequired), + "subcommandrequiredelsehelp" => Ok(AppSettings::SubcommandRequiredElseHelp), + "trailingvararg" => Ok(AppSettings::TrailingVarArg), + "unifiedhelpmessage" => Ok(AppSettings::UnifiedHelpMessage), + "versionlesssubcommands" => Ok(AppSettings::VersionlessSubcommands), + "waitonerror" => Ok(AppSettings::WaitOnError), _ => Err("unknown AppSetting, cannot convert from str".to_owned()), } } @@ -679,44 +705,56 @@ mod test { #[test] fn app_settings_fromstr() { - assert_eq!("subcommandsnegatereqs".parse::().unwrap(), - AppSettings::SubcommandsNegateReqs); - assert_eq!("subcommandrequired".parse::().unwrap(), - AppSettings::SubcommandRequired); assert_eq!("argrequiredelsehelp".parse::().unwrap(), AppSettings::ArgRequiredElseHelp); - assert_eq!("globalversion".parse::().unwrap(), - AppSettings::GlobalVersion); - assert_eq!("versionlesssubcommands".parse::().unwrap(), - AppSettings::VersionlessSubcommands); - assert_eq!("unifiedhelpmessage".parse::().unwrap(), - AppSettings::UnifiedHelpMessage); - assert_eq!("waitonerror".parse::().unwrap(), - AppSettings::WaitOnError); - assert_eq!("subcommandrequiredelsehelp".parse::().unwrap(), - AppSettings::SubcommandRequiredElseHelp); assert_eq!("allowexternalsubcommands".parse::().unwrap(), AppSettings::AllowExternalSubcommands); - assert_eq!("trailingvararg".parse::().unwrap(), - AppSettings::TrailingVarArg); - assert_eq!("nobinaryname".parse::().unwrap(), - AppSettings::NoBinaryName); - assert_eq!("strictutf8".parse::().unwrap(), - AppSettings::StrictUtf8); assert_eq!("allowinvalidutf8".parse::().unwrap(), AppSettings::AllowInvalidUtf8); assert_eq!("allowleadinghyphen".parse::().unwrap(), AppSettings::AllowLeadingHyphen); - assert_eq!("hidepossiblevaluesinhelp".parse::().unwrap(), - AppSettings::HidePossibleValuesInHelp); + assert_eq!("allownegativenumbers".parse::().unwrap(), + AppSettings::AllowNegativeNumbers); assert_eq!("coloredhelp".parse::().unwrap(), AppSettings::ColoredHelp); - assert_eq!("hidden".parse::().unwrap(), - AppSettings::Hidden); - assert_eq!("dontdelimittrailingvalues".parse::().unwrap(), - AppSettings::DontDelimitTrailingValues); + assert_eq!("colorauto".parse::().unwrap(), + AppSettings::ColorAuto); + assert_eq!("coloralways".parse::().unwrap(), + AppSettings::ColorAlways); + assert_eq!("colornever".parse::().unwrap(), + AppSettings::ColorNever); assert_eq!("disableversion".parse::().unwrap(), AppSettings::DisableVersion); + assert_eq!("dontdelimittrailingvalues".parse::().unwrap(), + AppSettings::DontDelimitTrailingValues); + assert_eq!("derivedisplayorder".parse::().unwrap(), + AppSettings::DeriveDisplayOrder); + assert_eq!("globalversion".parse::().unwrap(), + AppSettings::GlobalVersion); + assert_eq!("hidden".parse::().unwrap(), + AppSettings::Hidden); + assert_eq!("hidepossiblevaluesinhelp".parse::().unwrap(), + AppSettings::HidePossibleValuesInHelp); + assert_eq!("nobinaryname".parse::().unwrap(), + AppSettings::NoBinaryName); + assert_eq!("nextlinehelp".parse::().unwrap(), + AppSettings::NextLineHelp); + assert_eq!("subcommandsnegatereqs".parse::().unwrap(), + AppSettings::SubcommandsNegateReqs); + assert_eq!("subcommandrequired".parse::().unwrap(), + AppSettings::SubcommandRequired); + assert_eq!("subcommandrequiredelsehelp".parse::().unwrap(), + AppSettings::SubcommandRequiredElseHelp); + assert_eq!("strictutf8".parse::().unwrap(), + AppSettings::StrictUtf8); + assert_eq!("trailingvararg".parse::().unwrap(), + AppSettings::TrailingVarArg); + assert_eq!("unifiedhelpmessage".parse::().unwrap(), + AppSettings::UnifiedHelpMessage); + assert_eq!("versionlesssubcommands".parse::().unwrap(), + AppSettings::VersionlessSubcommands); + assert_eq!("waitonerror".parse::().unwrap(), + AppSettings::WaitOnError); assert!("hahahaha".parse::().is_err()); } }