From cc3c67bcd7d7d2d8b14466ef6765479e12575686 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 11 Oct 2021 17:01:33 -0500 Subject: [PATCH] fix(help)!: Merge OPTIONS / FLAGS default groups For those that want the original behavior, you can usxe `arg.help_heading(Some("FLAGS"))` on your flags. Limitations: - This will not give you a special sort order - This will not get a `[FLAGS]` added to usage For templates, we removed `{unified}` and `{flags}`. To help people catch these, a debug_assert was added. I'm unsure but I think there might be a change in behavior in calcuating when to show `[OPTION]` in usage. The old code only looked at `required` while flags looked only at arg groups. We now look at both. Ideally we'd add these in `_build` and remove special casing for no-groups except in the sort order of groups. I feel like thats best left for later. This also reduced the scope of `App`s public API. `get_*_with_no_heading` seemed a bit specialized to be in the public API. #2853 looks at splitting it out into its own PR. BREAKING CHANGE: Multiple - `UnifiedHelpMessage` removed - `{flags}` and `{unified}` are removed and will assert when present. - `get_*_with_no_heading` removed Fixes #2807 --- README.md | 10 +- benches/04_new_help.rs | 2 +- benches/05_ripgrep.rs | 5 +- clap_derive/README.md | 14 +- clap_derive/tests/non_literal_attributes.rs | 2 +- site/content/_index.md | 6 +- src/build/app/debug_asserts.rs | 13 + src/build/app/mod.rs | 49 ++- src/build/app/settings.rs | 26 -- src/build/app/tests.rs | 8 +- src/build/arg/mod.rs | 63 ++-- src/output/help.rs | 101 ++---- src/output/usage.rs | 42 +-- tests/app_from_crate.rs | 2 +- tests/app_settings.rs | 67 +--- tests/arg_aliases.rs | 20 +- tests/arg_aliases_short.rs | 20 +- tests/cargo.rs | 4 +- tests/derive_order.rs | 182 +--------- tests/display_order.rs | 2 +- tests/double_require.rs | 8 +- tests/flag_subcommands.rs | 12 +- tests/flags.rs | 2 +- tests/groups.rs | 2 +- tests/help.rs | 367 ++++++-------------- tests/help_env.rs | 40 +-- tests/hidden_args.rs | 105 +----- tests/macros.rs | 14 +- tests/subcommands.rs | 8 +- tests/template_help.rs | 21 +- tests/utils.rs | 8 +- tests/version.rs | 2 +- tests/yaml.rs | 3 +- 33 files changed, 338 insertions(+), 892 deletions(-) diff --git a/README.md b/README.md index c5109dcb9f72..49fcec015528 100644 --- a/README.md +++ b/README.md @@ -385,15 +385,13 @@ ARGS: INPUT The input file to use USAGE: - MyApp [FLAGS] [OPTIONS] [SUBCOMMAND] - -FLAGS: - -h, --help Print help information - -v Sets the level of verbosity - -V, --version Print version information + MyApp [OPTIONS] [SUBCOMMAND] OPTIONS: -c, --config Sets a custom config file + -h, --help Print help information + -v Sets the level of verbosity + -V, --version Print version information SUBCOMMANDS: help Print this message or the help of the given subcommand(s) diff --git a/benches/04_new_help.rs b/benches/04_new_help.rs index 83c9e001c38e..077ac30cf2f6 100644 --- a/benches/04_new_help.rs +++ b/benches/04_new_help.rs @@ -196,7 +196,7 @@ pub fn example10(c: &mut Criterion) { } pub fn example4_template(c: &mut Criterion) { - let mut app = app_example4().help_template("{bin} {version}\n{author}\n{about}\n\nUSAGE:\n {usage}\n\nFLAGS:\n{flags}\n\nARGS:\n{args}\n"); + let mut app = app_example4().help_template("{bin} {version}\n{author}\n{about}\n\nUSAGE:\n {usage}\n\nOPTIONS:\n{options}\n\nARGS:\n{args}\n"); c.bench_function("example4_template", |b| b.iter(|| build_help(&mut app))); } diff --git a/benches/05_ripgrep.rs b/benches/05_ripgrep.rs index 5a33745915ee..d8386293708c 100644 --- a/benches/05_ripgrep.rs +++ b/benches/05_ripgrep.rs @@ -3,7 +3,7 @@ // // CLI used is adapted from ripgrep 48a8a3a691220f9e5b2b08f4051abe8655ea7e8a -use clap::{App, AppSettings, Arg, ArgSettings}; +use clap::{App, Arg, ArgSettings}; use criterion::{criterion_group, criterion_main, Criterion}; use std::collections::HashMap; use std::io::Cursor; @@ -267,7 +267,7 @@ ARGS: {positionals} OPTIONS: -{unified}"; +{options}"; /// Build a clap application with short help strings. fn app_short() -> App<'static> { @@ -306,7 +306,6 @@ where .version("0.4.0") // Simulating .about(ABOUT) .max_term_width(100) - .setting(AppSettings::UnifiedHelpMessage) .override_usage(USAGE) .help_template(TEMPLATE) // Handle help/version manually to make their output formatting diff --git a/clap_derive/README.md b/clap_derive/README.md index 710cb648e19c..0367163e3318 100644 --- a/clap_derive/README.md +++ b/clap_derive/README.md @@ -82,22 +82,20 @@ Guillaume Pinot , others A basic example USAGE: - basic [FLAGS] [OPTIONS] --output [--] [file]... + basic [OPTIONS] --output [--] [file]... ARGS: ... Files to process -FLAGS: - -d, --debug Activate debug mode - -h, --help Print help information - -V, --version Print version information - -v, --verbose Verbose mode (-v, -vv, -vvv, etc.) - OPTIONS: - -l, --level ... admin_level to consider -c, --nb-cars Number of cars + -d, --debug Activate debug mode + -h, --help Print help information + -l, --level ... admin_level to consider -o, --output Output file -s, --speed Set speed [default: 42] + -V, --version Print version information + -v, --verbose Verbose mode (-v, -vv, -vvv, etc.) ARGS: ... Files to process diff --git a/clap_derive/tests/non_literal_attributes.rs b/clap_derive/tests/non_literal_attributes.rs index 51d003315146..5e05bb4bfd20 100644 --- a/clap_derive/tests/non_literal_attributes.rs +++ b/clap_derive/tests/non_literal_attributes.rs @@ -19,7 +19,7 @@ pub const DISPLAY_ORDER: usize = 2; // Check if the global settings compile #[derive(Parser, Debug, PartialEq, Eq)] -#[clap(global_setting = AppSettings::UnifiedHelpMessage)] +#[clap(global_setting = AppSettings::AllowLeadingHyphen)] struct Opt { #[clap( long = "x", diff --git a/site/content/_index.md b/site/content/_index.md index b06e29121a1b..3ba3ca0612f7 100644 --- a/site/content/_index.md +++ b/site/content/_index.md @@ -50,11 +50,9 @@ Simple program to greet a person USAGE: hello [OPTIONS] --name -FLAGS: - -h, --help Print help information - -V, --version Print version information - OPTIONS: -c, --count Number of times to greet [default: 1] + -h, --help Print help information -n, --name Name of the person to greet + -V, --version Print version information ``` diff --git a/src/build/app/debug_asserts.rs b/src/build/app/debug_asserts.rs index b451f66af9ff..dbe5dcab4ddf 100644 --- a/src/build/app/debug_asserts.rs +++ b/src/build/app/debug_asserts.rs @@ -283,6 +283,19 @@ pub(crate) fn assert_app(app: &App) { detect_duplicate_flags(&long_flags, "long"); detect_duplicate_flags(&short_flags, "short"); + if let Some(help_template) = app.template { + assert!( + !help_template.contains("{flags}"), + "{}", + "`{flags}` template variable was removed in clap3, they are now included in `{options}`" + ); + assert!( + !help_template.contains("{unified}"), + "{}", + "`{unified}` template variable was removed in clap3, use `{options}` instead" + ); + } + app._panic_on_missing_help(app.g_settings.is_set(AppSettings::HelpRequired)); assert_app_flags(app); } diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs index 6ba45b095f87..5e237604bf29 100644 --- a/src/build/app/mod.rs +++ b/src/build/app/mod.rs @@ -205,7 +205,7 @@ impl<'help> App<'help> { self.args.args() } - /// Iterate through the *positionals*. + /// Iterate through the *positionals* arguments. #[inline] pub fn get_positionals(&self) -> impl Iterator> { self.get_arguments().filter(|a| a.is_positional()) @@ -223,22 +223,6 @@ impl<'help> App<'help> { .filter(|a| a.is_set(ArgSettings::TakesValue) && a.get_index().is_none()) } - /// Iterate through the *positionals* that don't have custom heading. - pub fn get_positionals_with_no_heading(&self) -> impl Iterator> { - self.get_positionals() - .filter(|a| a.get_help_heading().is_none()) - } - - /// Iterate through the *flags* that don't have custom heading. - pub fn get_flags_with_no_heading(&self) -> impl Iterator> { - self.get_flags().filter(|a| a.get_help_heading().is_none()) - } - - /// Iterate through the *options* that don't have custom heading. - pub fn get_opts_with_no_heading(&self) -> impl Iterator> { - self.get_opts().filter(|a| a.get_help_heading().is_none()) - } - // Get a list of subcommands which contain the provided Argument // // This command will only include subcommands in its list for which the subcommands @@ -862,10 +846,6 @@ impl<'help> App<'help> { /// * `{usage}` - Automatically generated or given usage string. /// * `{all-args}` - Help for all arguments (options, flags, positional /// arguments, and subcommands) including titles. - /// * `{unified}` - Unified help for options and flags. Note, you must *also* - /// set [`AppSettings::UnifiedHelpMessage`] to fully merge both - /// options and flags, otherwise the ordering is "best effort". - /// * `{flags}` - Help for flags. /// * `{options}` - Help for options. /// * `{positionals}` - Help for positional arguments. /// * `{subcommands}` - Help for subcommands. @@ -1093,7 +1073,7 @@ impl<'help> App<'help> { /// header for the specified argument type) until a subsequent call to /// [`App::help_heading`] or [`App::stop_custom_headings`]. /// - /// This is useful if the default `FLAGS`, `OPTIONS`, or `ARGS` headings are + /// This is useful if the default `OPTIONS` or `ARGS` headings are /// not specific enough for one's use case. /// /// [`App::arg`]: App::arg() @@ -1709,9 +1689,9 @@ impl<'help> App<'help> { /// cust-ord /// /// USAGE: - /// cust-ord [FLAGS] [OPTIONS] + /// cust-ord [OPTIONS] /// - /// FLAGS: + /// OPTIONS: /// -h, --help Print help information /// -V, --version Print version information /// @@ -2177,7 +2157,7 @@ impl<'help> App<'help> { /// USAGE: /// myprog [SUBCOMMAND] /// - /// FLAGS: + /// OPTIONS: /// -h, --help Print help information /// -V, --version Print version information /// @@ -2205,7 +2185,7 @@ impl<'help> App<'help> { /// USAGE: /// myprog [THING] /// - /// FLAGS: + /// OPTIONS: /// -h, --help Print help information /// -V, --version Print version information /// @@ -2651,6 +2631,23 @@ impl<'a, T> Captures<'a> for T {} // Internal Query Methods impl<'help> App<'help> { + /// Iterate through the *named* arguments. + pub(crate) fn get_non_positional(&self) -> impl Iterator> { + self.get_arguments().filter(|a| !a.is_positional()) + } + + /// Iterate through the *positionals* that don't have custom heading. + pub(crate) fn get_positionals_with_no_heading(&self) -> impl Iterator> { + self.get_positionals() + .filter(|a| a.get_help_heading().is_none()) + } + + /// Iterate through the *named* that don't have custom heading. + pub(crate) fn get_non_positional_with_no_heading(&self) -> impl Iterator> { + self.get_non_positional() + .filter(|a| a.get_help_heading().is_none()) + } + pub(crate) fn find(&self, arg_id: &Id) -> Option<&Arg<'help>> { self.args.args().find(|a| a.id == *arg_id) } diff --git a/src/build/app/settings.rs b/src/build/app/settings.rs index c462626d7080..421cc916d500 100644 --- a/src/build/app/settings.rs +++ b/src/build/app/settings.rs @@ -11,7 +11,6 @@ bitflags! { const ARG_REQUIRED_ELSE_HELP = 1 << 2; const PROPAGATE_VERSION = 1 << 3; const DISABLE_VERSION_FOR_SC = 1 << 4; - const UNIFIED_HELP = 1 << 5; const WAIT_ON_ERROR = 1 << 6; const SC_REQUIRED_ELSE_HELP = 1 << 7; const NO_AUTO_HELP = 1 << 8; @@ -122,8 +121,6 @@ impl_settings! { AppSettings, AppFlags, => Flags::USE_LONG_FORMAT_FOR_HELP_SC, TrailingVarArg("trailingvararg") => Flags::TRAILING_VARARG, - UnifiedHelpMessage("unifiedhelpmessage") - => Flags::UNIFIED_HELP, NextLineHelp("nextlinehelp") => Flags::NEXT_LINE_HELP, IgnoreErrors("ignoreerrors") @@ -958,25 +955,6 @@ pub enum AppSettings { /// [`Arg::multiple_values(true)`]: crate::Arg::multiple_values() TrailingVarArg, - /// Groups flags and options together, presenting a more unified help message - /// (a la `getopts` or `docopt` style). - /// - /// The default is that the auto-generated help message will group flags, and options - /// separately. - /// - /// **NOTE:** This setting is cosmetic only and does not affect any functionality. - /// - /// # Examples - /// - /// ```rust - /// # use clap::{App, Arg, AppSettings}; - /// App::new("myprog") - /// .setting(AppSettings::UnifiedHelpMessage) - /// .get_matches(); - /// // running `myprog --help` will display a unified "docopt" or "getopts" style help message - /// ``` - UnifiedHelpMessage, - /// Will display a message "Press \[ENTER\]/\[RETURN\] to continue..." and wait for user before /// exiting /// @@ -1164,10 +1142,6 @@ mod test { "trailingvararg".parse::().unwrap(), AppSettings::TrailingVarArg ); - assert_eq!( - "unifiedhelpmessage".parse::().unwrap(), - AppSettings::UnifiedHelpMessage - ); assert_eq!( "waitonerror".parse::().unwrap(), AppSettings::WaitOnError diff --git a/src/build/app/tests.rs b/src/build/app/tests.rs index ddc14737ad83..7440e33cbeca 100644 --- a/src/build/app/tests.rs +++ b/src/build/app/tests.rs @@ -13,7 +13,7 @@ fn propagate_version() { #[test] fn global_setting() { let mut app = App::new("test") - .global_setting(AppSettings::UnifiedHelpMessage) + .global_setting(AppSettings::AllowLeadingHyphen) .subcommand(App::new("subcmd")); app._propagate(); assert!(app @@ -21,13 +21,13 @@ fn global_setting() { .iter() .find(|s| s.name == "subcmd") .unwrap() - .is_set(AppSettings::UnifiedHelpMessage)); + .is_set(AppSettings::AllowLeadingHyphen)); } #[test] fn global_settings() { let mut app = App::new("test") - .global_setting(AppSettings::UnifiedHelpMessage) + .global_setting(AppSettings::AllowLeadingHyphen) .global_setting(AppSettings::TrailingVarArg) .subcommand(App::new("subcmd")); app._propagate(); @@ -36,7 +36,7 @@ fn global_settings() { .iter() .find(|s| s.name == "subcmd") .unwrap() - .is_set(AppSettings::UnifiedHelpMessage)); + .is_set(AppSettings::AllowLeadingHyphen)); assert!(app .subcommands .iter() diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs index 1142182962a1..65aa7c54f963 100644 --- a/src/build/arg/mod.rs +++ b/src/build/arg/mod.rs @@ -659,9 +659,9 @@ impl<'help> Arg<'help> { /// helptest /// /// USAGE: - /// helptest [FLAGS] + /// helptest [OPTIONS] /// - /// FLAGS: + /// OPTIONS: /// --config Some help text describing the --config arg /// -h, --help Print help information /// -V, --version Print version information @@ -723,9 +723,9 @@ impl<'help> Arg<'help> { /// prog /// /// USAGE: - /// prog [FLAGS] + /// prog [OPTIONS] /// - /// FLAGS: + /// OPTIONS: /// --config /// The config file used by the myprog must be in JSON format /// with only valid keys and may not contain other nonsense @@ -2575,14 +2575,12 @@ impl<'help> Arg<'help> { /// valnames /// /// USAGE: - /// valnames [FLAGS] [OPTIONS] - /// - /// FLAGS: - /// -h, --help Print help information - /// -V, --version Print version information + /// valnames [OPTIONS] /// /// OPTIONS: + /// -h, --help Print help information /// --io-files Some help text + /// -V, --version Print version information /// ``` /// [`Arg::next_line_help(true)`]: Arg::next_line_help() /// [`Arg::number_of_values`]: Arg::number_of_values() @@ -2628,14 +2626,12 @@ impl<'help> Arg<'help> { /// valnames /// /// USAGE: - /// valnames [FLAGS] [OPTIONS] - /// - /// FLAGS: - /// -h, --help Print help information - /// -V, --version Print version information + /// valnames [OPTIONS] /// /// OPTIONS: /// --config Some help text + /// -h, --help Print help information + /// -V, --version Print version information /// ``` /// [option]: Arg::takes_value() /// [positional]: Arg::index() @@ -3293,13 +3289,11 @@ impl<'help> Arg<'help> { /// cust-ord /// /// USAGE: - /// cust-ord [FLAGS] [OPTIONS] - /// - /// FLAGS: - /// -h, --help Print help information - /// -V, --version Print version information + /// cust-ord [OPTIONS] /// /// OPTIONS: + /// -h, --help Print help information + /// -V, --version Print version information /// -O, --other-option I should be first! /// -o, --long-option Some help and text /// ``` @@ -3318,14 +3312,13 @@ impl<'help> Arg<'help> { /// 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 + /// **NOTE:** This will change the usage string to look like `$ prog [OPTIONS] [-- ]` if /// `ARG` is marked as `.last(true)`. /// /// **NOTE:** This setting will imply [`crate::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**: This setting only applies to positional arguments, and has no affect on OPTIONS /// /// **NOTE:** Setting this requires [`crate::ArgSettings::TakesValue`] /// @@ -3873,9 +3866,9 @@ impl<'help> Arg<'help> { /// helptest /// /// USAGE: - /// helptest [FLAGS] + /// helptest [OPTIONS] /// - /// FLAGS: + /// OPTIONS: /// -h, --help Print help information /// -V, --version Print version information /// ``` @@ -4114,13 +4107,11 @@ impl<'help> Arg<'help> { /// nlh /// /// USAGE: - /// nlh [FLAGS] [OPTIONS] + /// nlh [OPTIONS] /// - /// FLAGS: + /// OPTIONS: /// -h, --help Print help information /// -V, --version Print version information - /// - /// OPTIONS: /// -o, --long-option-flag /// Some really long help and complex /// help that makes more sense to be @@ -4499,9 +4490,9 @@ impl<'help> Arg<'help> { /// helptest /// /// USAGE: - /// helptest [FLAGS] + /// helptest [OPTIONS] /// - /// FLAGS: + /// OPTIONS: /// -h, --help Print help information /// -V, --version Print version information /// ``` @@ -4526,9 +4517,9 @@ impl<'help> Arg<'help> { /// helptest /// /// USAGE: - /// helptest [FLAGS] + /// helptest [OPTIONS] /// - /// FLAGS: + /// OPTIONS: /// --config Some help text describing the --config arg /// -h, --help Print help information /// -V, --version Print version information @@ -4577,9 +4568,9 @@ impl<'help> Arg<'help> { /// helptest /// /// USAGE: - /// helptest [FLAGS] + /// helptest [OPTIONS] /// - /// FLAGS: + /// OPTIONS: /// -h, --help Print help information /// -V, --version Print version information /// ``` @@ -4604,9 +4595,9 @@ impl<'help> Arg<'help> { /// helptest /// /// USAGE: - /// helptest [FLAGS] + /// helptest [OPTIONS] /// - /// FLAGS: + /// OPTIONS: /// --config Some help text describing the --config arg /// -h, --help Print help information /// -V, --version Print version information diff --git a/src/output/help.rs b/src/output/help.rs index 5a1fc080cb3d..eadd65721ea6 100644 --- a/src/output/help.rs +++ b/src/output/help.rs @@ -747,16 +747,10 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> { .get_positionals_with_no_heading() .filter(|arg| should_show_arg(self.use_long, arg)) .collect::>(); - let flags = self + let non_pos = self .parser .app - .get_flags_with_no_heading() - .filter(|arg| should_show_arg(self.use_long, arg)) - .collect::>(); - let opts = self - .parser - .app - .get_opts_with_no_heading() + .get_non_positional_with_no_heading() .filter(|arg| should_show_arg(self.use_long, arg)) .collect::>(); let subcmds = self.parser.app.has_visible_subcommands(); @@ -778,63 +772,37 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> { true }; - let unified_help = self.parser.is_set(AppSettings::UnifiedHelpMessage); - - if unified_help && (!flags.is_empty() || !opts.is_empty()) { - let opts_flags = self - .parser - .app - .args - .args() - .filter(|a| !a.is_positional()) - .collect::>(); + if !non_pos.is_empty() { if !first { self.none("\n\n")?; } self.warning("OPTIONS:\n")?; - self.write_args(&*opts_flags)?; + self.write_args(&non_pos)?; first = false; - } else { - if !flags.is_empty() { - if !first { - self.none("\n\n")?; - } - self.warning("FLAGS:\n")?; - self.write_args(&flags)?; - first = false; - } - if !opts.is_empty() { - if !first { - self.none("\n\n")?; - } - self.warning("OPTIONS:\n")?; - self.write_args(&opts)?; - first = false; - } - if !custom_headings.is_empty() { - for heading in custom_headings { - let args = self - .parser - .app - .args - .args() - .filter(|a| { - if let Some(help_heading) = a.help_heading { - return help_heading == heading; - } - false - }) - .filter(|arg| should_show_arg(self.use_long, arg)) - .collect::>(); - - if !args.is_empty() { - if !first { - self.none("\n\n")?; + } + if !custom_headings.is_empty() { + for heading in custom_headings { + let args = self + .parser + .app + .args + .args() + .filter(|a| { + if let Some(help_heading) = a.help_heading { + return help_heading == heading; } - self.warning(&*format!("{}:\n", heading))?; - self.write_args(&*args)?; - first = false + false + }) + .filter(|arg| should_show_arg(self.use_long, arg)) + .collect::>(); + + if !args.is_empty() { + if !first { + self.none("\n\n")?; } + self.warning(&*format!("{}:\n", heading))?; + self.write_args(&*args)?; + first = false } } } @@ -1012,21 +980,10 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> { "all-args" => { self.write_all_args()?; } - "unified" => { - let opts_flags = self - .parser - .app - .args - .args() - .filter(|a| !a.is_positional()) - .collect::>(); - self.write_args(&opts_flags)?; - } - "flags" => { - self.write_args(&self.parser.app.get_flags().collect::>())?; - } "options" => { - self.write_args(&self.parser.app.get_opts().collect::>())?; + // Include even those with a heading as we don't have a good way of + // handling help_heading in the template. + self.write_args(&self.parser.app.get_non_positional().collect::>())?; } "positionals" => { self.write_args(&self.parser.app.get_positionals().collect::>())?; diff --git a/src/output/usage.rs b/src/output/usage.rs index fd058b5a478a..d0f335ff8d01 100644 --- a/src/output/usage.rs +++ b/src/output/usage.rs @@ -62,19 +62,7 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> { String::new() }; - let flags = self.needs_flags_tag(); - if flags && !self.p.is_set(AS::UnifiedHelpMessage) { - usage.push_str(" [FLAGS]"); - } else if flags { - usage.push_str(" [OPTIONS]"); - } - if !self.p.is_set(AS::UnifiedHelpMessage) - && self - .p - .app - .get_opts() - .any(|o| !o.is_set(ArgSettings::Required) && !o.is_set(ArgSettings::Hidden)) - { + if self.needs_options_tag() { usage.push_str(" [OPTIONS]"); } @@ -93,7 +81,7 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> { if self .p .app - .get_opts() + .get_non_positional() .any(|o| o.is_set(ArgSettings::MultipleValues)) && self .p @@ -328,22 +316,28 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> { } } - // Determines if we need the `[FLAGS]` tag in the usage string - fn needs_flags_tag(&self) -> bool { - debug!("Usage::needs_flags_tag"); - 'outer: for f in self.p.app.get_flags() { - debug!("Usage::needs_flags_tag:iter: f={}", f.name); + // Determines if we need the `[OPTIONS]` tag in the usage string + fn needs_options_tag(&self) -> bool { + debug!("Usage::needs_options_tag"); + 'outer: for f in self.p.app.get_non_positional() { + debug!("Usage::needs_options_tag:iter: f={}", f.name); - // Don't print `[FLAGS]` just for help or version + // Don't print `[OPTIONS]` just for help or version if f.long == Some("help") || f.long == Some("version") { + debug!("Usage::needs_options_tag:iter Option is built-in"); continue; } if f.is_set(ArgSettings::Hidden) { + debug!("Usage::needs_options_tag:iter Option is hidden"); + continue; + } + if f.is_set(ArgSettings::Required) { + debug!("Usage::needs_options_tag:iter Option is required"); continue; } for grp_s in self.p.app.groups_for_arg(&f.id) { - debug!("Usage::needs_flags_tag:iter:iter: grp_s={:?}", grp_s); + debug!("Usage::needs_options_tag:iter:iter: grp_s={:?}", grp_s); if self .p .app @@ -351,16 +345,16 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> { .iter() .any(|g| g.id == grp_s && g.required) { - debug!("Usage::needs_flags_tag:iter:iter: Group is required"); + debug!("Usage::needs_options_tag:iter:iter: Group is required"); continue 'outer; } } - debug!("Usage::needs_flags_tag:iter: [FLAGS] required"); + debug!("Usage::needs_options_tag:iter: [OPTIONS] required"); return true; } - debug!("Usage::needs_flags_tag: [FLAGS] not required"); + debug!("Usage::needs_options_tag: [OPTIONS] not required"); false } diff --git a/tests/app_from_crate.rs b/tests/app_from_crate.rs index f7b59e9b0c3c..1003ee569f60 100644 --- a/tests/app_from_crate.rs +++ b/tests/app_from_crate.rs @@ -9,7 +9,7 @@ A simple to use, efficient, and full-featured Command Line Argument Parser USAGE: clap -FLAGS: +OPTIONS: -h, --help Print help information -V, --version Print version information "; diff --git a/tests/app_settings.rs b/tests/app_settings.rs index 655e8bffe419..e86c24680214 100644 --- a/tests/app_settings.rs +++ b/tests/app_settings.rs @@ -7,7 +7,7 @@ static ALLOW_EXT_SC: &str = "clap-test v1.4.8 USAGE: clap-test [SUBCOMMAND] -FLAGS: +OPTIONS: -h, --help Print help information -V, --version Print version information "; @@ -22,7 +22,7 @@ ARGS: some some -FLAGS: +OPTIONS: -h, --help Print help information -V, --version Print version information "; @@ -32,31 +32,10 @@ static REQUIRE_EQUALS: &str = "clap-test v1.4.8 USAGE: clap-test --opt= -FLAGS: - -h, --help Print help information - -V, --version Print version information - OPTIONS: + -h, --help Print help information -o, --opt= some -"; - -static UNIFIED_HELP: &str = "test 1.3 - -Kevin K. - -tests stuff - -USAGE: - test [OPTIONS] [arg1] - -ARGS: - some pos arg - -OPTIONS: - -f, --flag some flag - -h, --help Print help information - --option some option - -V, --version Print version information + -V, --version Print version information "; static SKIP_POS_VALS: &str = "test 1.3 @@ -71,20 +50,18 @@ USAGE: ARGS: some pos arg -FLAGS: - -h, --help Print help information - -V, --version Print version information - OPTIONS: + -h, --help Print help information -o, --opt some option + -V, --version Print version information "; static ARG_REQUIRED_ELSE_HELP: &str = "test 1.0 USAGE: - test [FLAGS] + test [OPTIONS] -FLAGS: +OPTIONS: -h, --help Print help information -i, --info Provides more info -V, --version Print version information @@ -95,7 +72,7 @@ static SUBCOMMAND_REQUIRED_ELSE_HELP: &str = "test 1.0 USAGE: test -FLAGS: +OPTIONS: -h, --help Print help information -V, --version Print version information @@ -113,7 +90,7 @@ ARGS: long form about message -FLAGS: +OPTIONS: -h, --help Print help information "; @@ -125,7 +102,7 @@ long form about message USAGE: myprog test nested -FLAGS: +OPTIONS: -h, --help Print help information "; @@ -139,7 +116,7 @@ ARGS: long form about message -FLAGS: +OPTIONS: -h, --help Print help information @@ -445,26 +422,6 @@ fn no_bin_name() { assert_eq!(matches.value_of("test").unwrap(), "testing"); } -#[test] -fn unified_help() { - let app = App::new("myTest") - .name("test") - .author("Kevin K.") - .about("tests stuff") - .version("1.3") - .setting(AppSettings::UnifiedHelpMessage) - .arg("-f, --flag 'some flag'") - .arg("[arg1] 'some pos arg'") - .arg("--option [opt] 'some option'"); - - assert!(utils::compare_output( - app, - "test --help", - UNIFIED_HELP, - false - )); -} - #[test] fn skip_possible_values() { let app = App::new("test") diff --git a/tests/arg_aliases.rs b/tests/arg_aliases.rs index ab0fb78db018..9428b4233c3c 100644 --- a/tests/arg_aliases.rs +++ b/tests/arg_aliases.rs @@ -7,15 +7,13 @@ static SC_VISIBLE_ALIAS_HELP: &str = "ct-test 1.2 Some help USAGE: - ct test [FLAGS] [OPTIONS] - -FLAGS: - -f, --flag [aliases: v_flg, flag2, flg3] - -h, --help Print help information - -V, --version Print version information + ct test [OPTIONS] OPTIONS: + -f, --flag [aliases: v_flg, flag2, flg3] + -h, --help Print help information -o, --opt [aliases: visible] + -V, --version Print version information "; static SC_INVISIBLE_ALIAS_HELP: &str = "ct-test 1.2 @@ -23,15 +21,13 @@ static SC_INVISIBLE_ALIAS_HELP: &str = "ct-test 1.2 Some help USAGE: - ct test [FLAGS] [OPTIONS] - -FLAGS: - -f, --flag - -h, --help Print help information - -V, --version Print version information + ct test [OPTIONS] OPTIONS: + -f, --flag + -h, --help Print help information -o, --opt + -V, --version Print version information "; #[test] diff --git a/tests/arg_aliases_short.rs b/tests/arg_aliases_short.rs index 7aa9c2b28531..f5c891e465d9 100644 --- a/tests/arg_aliases_short.rs +++ b/tests/arg_aliases_short.rs @@ -7,15 +7,13 @@ static SC_VISIBLE_ALIAS_HELP: &str = "ct-test 1.2 Some help USAGE: - ct test [FLAGS] [OPTIONS] - -FLAGS: - -f, --flag [aliases: flag1] [short aliases: a, b, 🦆] - -h, --help Print help information - -V, --version Print version information + ct test [OPTIONS] OPTIONS: + -f, --flag [aliases: flag1] [short aliases: a, b, 🦆] + -h, --help Print help information -o, --opt [short aliases: v] + -V, --version Print version information "; static SC_INVISIBLE_ALIAS_HELP: &str = "ct-test 1.2 @@ -23,15 +21,13 @@ static SC_INVISIBLE_ALIAS_HELP: &str = "ct-test 1.2 Some help USAGE: - ct test [FLAGS] [OPTIONS] - -FLAGS: - -f, --flag - -h, --help Print help information - -V, --version Print version information + ct test [OPTIONS] OPTIONS: + -f, --flag + -h, --help Print help information -o, --opt + -V, --version Print version information "; #[test] diff --git a/tests/cargo.rs b/tests/cargo.rs index 1b50eab100b8..8d5a973c5202 100644 --- a/tests/cargo.rs +++ b/tests/cargo.rs @@ -7,7 +7,7 @@ A simple to use, efficient, and full-featured Command Line Argument Parser USAGE: prog -FLAGS: +OPTIONS: -h, --help Print help information -V, --version Print version information "; @@ -19,7 +19,7 @@ Kevin K. :Clap Maintainers USAGE: prog -FLAGS: +OPTIONS: -h, --help Print help information -V, --version Print version information "; diff --git a/tests/derive_order.rs b/tests/derive_order.rs index 9f9220b5185a..5d4eb7548de1 100644 --- a/tests/derive_order.rs +++ b/tests/derive_order.rs @@ -6,38 +6,6 @@ use clap::{App, AppSettings, Arg}; static NO_DERIVE_ORDER: &str = "test 1.2 -USAGE: - test [FLAGS] [OPTIONS] - -FLAGS: - --flag_a second flag - --flag_b first flag - -h, --help Print help information - -V, --version Print version information - -OPTIONS: - --option_a second option - --option_b first option -"; - -static DERIVE_ORDER: &str = "test 1.2 - -USAGE: - test [FLAGS] [OPTIONS] - -FLAGS: - --flag_b first flag - --flag_a second flag - -h, --help Print help information - -V, --version Print version information - -OPTIONS: - --option_b first option - --option_a second option -"; - -static UNIFIED_HELP: &str = "test 1.2 - USAGE: test [OPTIONS] @@ -64,36 +32,6 @@ OPTIONS: -V, --version Print version information "; -static DERIVE_ORDER_SC_PROP: &str = "test-sub 1.2 - -USAGE: - test sub [FLAGS] [OPTIONS] - -FLAGS: - --flag_b first flag - --flag_a second flag - -h, --help Print help information - -V, --version Print version information - -OPTIONS: - --option_b first option - --option_a second option -"; - -static UNIFIED_SC_PROP: &str = "test-sub 1.2 - -USAGE: - test sub [OPTIONS] - -OPTIONS: - --flag_a second flag - --flag_b first flag - -h, --help Print help information - --option_a second option - --option_b first option - -V, --version Print version information -"; - static UNIFIED_DERIVE_SC_PROP: &str = "test-sub 1.2 USAGE: @@ -125,9 +63,9 @@ OPTIONS: static PREFER_USER_HELP_DERIVE_ORDER: &str = "test 1.2 USAGE: - test [FLAGS] + test [OPTIONS] -FLAGS: +OPTIONS: -h, --help Print help message --flag_b first flag --flag_a second flag @@ -137,9 +75,9 @@ FLAGS: static PREFER_USER_HELP_SUBCMD_DERIVE_ORDER: &str = "test-sub 1.2 USAGE: - test sub [FLAGS] + test sub [OPTIONS] -FLAGS: +OPTIONS: -h, --help Print help message --flag_b first flag --flag_a second flag @@ -187,59 +125,6 @@ fn derive_order() { .about("second option"), ]); - assert!(utils::compare_output( - app, - "test --help", - DERIVE_ORDER, - false - )); -} - -#[test] -fn unified_help() { - let app = App::new("test") - .setting(AppSettings::UnifiedHelpMessage) - .version("1.2") - .args(&[ - Arg::new("flag_b").long("flag_b").about("first flag"), - Arg::new("option_b") - .long("option_b") - .takes_value(true) - .about("first option"), - Arg::new("flag_a").long("flag_a").about("second flag"), - Arg::new("option_a") - .long("option_a") - .takes_value(true) - .about("second option"), - ]); - - assert!(utils::compare_output( - app, - "test --help", - UNIFIED_HELP, - false - )); -} - -#[test] -fn unified_help_and_derive_order() { - let app = App::new("test") - .setting(AppSettings::DeriveDisplayOrder) - .setting(AppSettings::UnifiedHelpMessage) - .version("1.2") - .args(&[ - Arg::new("flag_b").long("flag_b").about("first flag"), - Arg::new("option_b") - .long("option_b") - .takes_value(true) - .about("first option"), - Arg::new("flag_a").long("flag_a").about("second flag"), - Arg::new("option_a") - .long("option_a") - .takes_value(true) - .about("second option"), - ]); - assert!(utils::compare_output( app, "test --help", @@ -252,62 +137,6 @@ fn unified_help_and_derive_order() { fn derive_order_subcommand_propagate() { let app = App::new("test") .global_setting(AppSettings::DeriveDisplayOrder) - .version("1.2") - .subcommand( - App::new("sub").version("1.2").args(&[ - Arg::new("flag_b").long("flag_b").about("first flag"), - Arg::new("option_b") - .long("option_b") - .takes_value(true) - .about("first option"), - Arg::new("flag_a").long("flag_a").about("second flag"), - Arg::new("option_a") - .long("option_a") - .takes_value(true) - .about("second option"), - ]), - ); - - assert!(utils::compare_output( - app, - "test sub --help", - DERIVE_ORDER_SC_PROP, - false - )); -} - -#[test] -fn unified_help_subcommand_propagate() { - let app = App::new("test") - .global_setting(AppSettings::UnifiedHelpMessage) - .subcommand( - App::new("sub").version("1.2").args(&[ - Arg::new("flag_b").long("flag_b").about("first flag"), - Arg::new("option_b") - .long("option_b") - .takes_value(true) - .about("first option"), - Arg::new("flag_a").long("flag_a").about("second flag"), - Arg::new("option_a") - .long("option_a") - .takes_value(true) - .about("second option"), - ]), - ); - - assert!(utils::compare_output( - app, - "test sub --help", - UNIFIED_SC_PROP, - false - )); -} - -#[test] -fn unified_help_and_derive_order_subcommand_propagate() { - let app = App::new("test") - .global_setting(AppSettings::DeriveDisplayOrder) - .global_setting(AppSettings::UnifiedHelpMessage) .subcommand( App::new("sub").version("1.2").args(&[ Arg::new("flag_b").long("flag_b").about("first flag"), @@ -332,10 +161,9 @@ fn unified_help_and_derive_order_subcommand_propagate() { } #[test] -fn unified_help_and_derive_order_subcommand_propagate_with_explicit_display_order() { +fn derive_order_subcommand_propagate_with_explicit_display_order() { let app = App::new("test") .global_setting(AppSettings::DeriveDisplayOrder) - .global_setting(AppSettings::UnifiedHelpMessage) .subcommand( App::new("sub").version("1.2").args(&[ Arg::new("flag_b").long("flag_b").about("first flag"), diff --git a/tests/display_order.rs b/tests/display_order.rs index 001d1cf2658a..f538d5fcb532 100644 --- a/tests/display_order.rs +++ b/tests/display_order.rs @@ -14,7 +14,7 @@ fn very_large_display_order() { USAGE: test [SUBCOMMAND] -FLAGS: +OPTIONS: -h, --help Print help information SUBCOMMANDS: diff --git a/tests/double_require.rs b/tests/double_require.rs index eecba34656ec..cccf2dd2a0d5 100644 --- a/tests/double_require.rs +++ b/tests/double_require.rs @@ -3,9 +3,9 @@ use clap::{App, Arg, ErrorKind}; static HELP: &str = "prog USAGE: - prog [FLAGS] + prog [OPTIONS] -FLAGS: +OPTIONS: -a -b -c @@ -16,7 +16,7 @@ static ONLY_B_ERROR: &str = "error: The following required arguments were not pr -c USAGE: - prog [FLAGS] -c -b + prog [OPTIONS] -c -b For more information try --help "; @@ -25,7 +25,7 @@ static ONLY_C_ERROR: &str = "error: The following required arguments were not pr -b USAGE: - prog [FLAGS] -b -c + prog [OPTIONS] -b -c For more information try --help "; diff --git a/tests/flag_subcommands.rs b/tests/flag_subcommands.rs index 8c6b694f573b..a0ba2c0db280 100644 --- a/tests/flag_subcommands.rs +++ b/tests/flag_subcommands.rs @@ -430,10 +430,8 @@ Query the package database. USAGE: pacman {query, --query, -Q} [OPTIONS] -FLAGS: - -h, --help Print help information - OPTIONS: + -h, --help Print help information -i, --info ... view package information -s, --search ... search locally installed packages for matching strings "; @@ -487,10 +485,8 @@ Query the package database. USAGE: pacman {query, --query} [OPTIONS] -FLAGS: - -h, --help Print help information - OPTIONS: + -h, --help Print help information -i, --info ... view package information -s, --search ... search locally installed packages for matching strings "; @@ -543,10 +539,8 @@ Query the package database. USAGE: pacman {query, -Q} [OPTIONS] -FLAGS: - -h, --help Print help information - OPTIONS: + -h, --help Print help information -i, --info ... view package information -s, --search ... search locally installed packages for matching strings "; diff --git a/tests/flags.rs b/tests/flags.rs index 13fc6d6d2083..b9d368e867f7 100644 --- a/tests/flags.rs +++ b/tests/flags.rs @@ -7,7 +7,7 @@ const USE_FLAG_AS_ARGUMENT: &str = \tIf you tried to supply `--another-flag` as a value rather than a flag, use `-- --another-flag` USAGE: - mycat [FLAGS] [filename] + mycat [OPTIONS] [filename] For more information try --help "; diff --git a/tests/groups.rs b/tests/groups.rs index d2854124a3ec..b235d1466cfa 100644 --- a/tests/groups.rs +++ b/tests/groups.rs @@ -265,7 +265,7 @@ USAGE: ARGS: -FLAGS: +OPTIONS: -h, --help Print help information "; let app = App::new("prog") diff --git a/tests/help.rs b/tests/help.rs index dbc3244879e3..445920d3d7c0 100644 --- a/tests/help.rs +++ b/tests/help.rs @@ -11,12 +11,10 @@ tests stuff USAGE: test --fake : -FLAGS: - -h, --help Print help information - -V, --version Print version information - OPTIONS: -f, --fake : some help + -h, --help Print help information + -V, --version Print version information "; static HELP: &str = "clap-test v1.4.8 @@ -26,20 +24,17 @@ Kevin K. tests clap library USAGE: - clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND] + clap-test [OPTIONS] [ARGS] [SUBCOMMAND] ARGS: tests positionals tests positionals with exclusions ... tests specific values [possible values: vi, emacs] -FLAGS: - -f, --flag tests flags - -F tests flags with exclusions - -h, --help Print help information - -V, --version Print version information - OPTIONS: + -f, --flag tests flags + -F tests flags with exclusions + -h, --help Print help information --long-option-2 tests long options with exclusions --maxvals3 ... Tests 3 max vals --minvals2 ... Tests 2 min vals @@ -47,6 +42,7 @@ OPTIONS: --multvalsmo Tests multiple values, and mult occs -o, --option ... tests options -O, --Option specific vals [possible values: fast, slow] + -V, --version Print version information SUBCOMMANDS: help Print this message or the help of the given subcommand(s) @@ -62,12 +58,10 @@ USAGE: ARGS: help -FLAGS: - -h, --help Print help information - -V, --version Print version information - OPTIONS: + -h, --help Print help information -o, --opt tests options + -V, --version Print version information SUBCOMMANDS: help Print this message or the help of the given subcommand(s) @@ -77,19 +71,17 @@ SUBCOMMANDS: static ARGS_NEGATE_SC: &str = "prog 1.0 USAGE: - prog [FLAGS] [OPTIONS] [PATH] + prog [OPTIONS] [PATH] prog ARGS: help -FLAGS: - -f, --flag testing flags - -h, --help Print help information - -V, --version Print version information - OPTIONS: + -f, --flag testing flags + -h, --help Print help information -o, --opt tests options + -V, --version Print version information SUBCOMMANDS: help Print this message or the help of the given subcommand(s) @@ -105,7 +97,7 @@ tests clap library USAGE: clap-test -FLAGS: +OPTIONS: -h, --help Print help information -V, --version Print version information @@ -121,7 +113,7 @@ tests clap library USAGE: clap-test -FLAGS: +OPTIONS: -h, --help Print help information @@ -134,15 +126,13 @@ some longer text that comes after the help static HIDDEN_ARGS: &str = "prog 1.0 USAGE: - prog [FLAGS] [OPTIONS] - -FLAGS: - -f, --flag testing flags - -h, --help Print help information - -V, --version Print version information + prog [OPTIONS] OPTIONS: + -f, --flag testing flags + -h, --help Print help information -o, --opt tests options + -V, --version Print version information "; static SC_HELP: &str = "clap-test-subcmd 0.1 @@ -152,36 +142,32 @@ Kevin K. tests subcommands USAGE: - clap-test subcmd [FLAGS] [OPTIONS] [--] [scpositional] + clap-test subcmd [OPTIONS] [--] [scpositional] ARGS: tests positionals -FLAGS: - -f, --flag tests flags - -h, --help Print help information - -V, --version Print version information - OPTIONS: + -f, --flag tests flags + -h, --help Print help information -o, --option ... tests options -s, --subcmdarg tests other args + -V, --version Print version information "; static ISSUE_1046_HIDDEN_SCS: &str = "prog 1.0 USAGE: - prog [FLAGS] [OPTIONS] [PATH] + prog [OPTIONS] [PATH] ARGS: some -FLAGS: - -f, --flag testing flags - -h, --help Print help information - -V, --version Print version information - OPTIONS: + -f, --flag testing flags + -h, --help Print help information -o, --opt tests options + -V, --version Print version information "; // Using number_of_values(1) with multiple_values(true) misaligns help message @@ -190,13 +176,11 @@ static ISSUE_760: &str = "ctest 0.1 USAGE: ctest [OPTIONS] -FLAGS: - -h, --help Print help information - -V, --version Print version information - OPTIONS: + -h, --help Print help information -o, --option