From 83d6add9aadfa07b66ef076cc0a5f6498ba6e03d Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 26 Aug 2022 10:59:27 -0500 Subject: [PATCH] fix(help): Shift focus to subcommands, when present In surveying various tools and CLI parsers, I noticed they list the subcommands first. This puts an emphasis on them which makes sense because that is most likely what an end user is supposed to pass in next. Listing them last aligns with the usage order but it probably doesn't outweigh the value of getting a user moving forward. --- CHANGELOG.md | 1 + examples/cargo-example-derive.md | 6 +-- examples/cargo-example.md | 6 +-- examples/derive_ref/interop_tests.md | 8 +-- examples/git-derive.md | 20 ++++---- examples/git.md | 20 ++++---- examples/multicall-busybox.md | 8 +-- examples/pacman.md | 8 +-- examples/tutorial_builder/01_quick.md | 8 +-- .../tutorial_builder/03_04_subcommands.md | 16 +++--- examples/tutorial_derive/01_quick.md | 8 +-- examples/tutorial_derive/03_04_subcommands.md | 16 +++--- src/output/help.rs | 49 ++++++++++--------- tests/builder/derive_order.rs | 16 +++--- tests/builder/display_order.rs | 6 +-- tests/builder/help.rs | 46 ++++++++--------- tests/builder/subcommands.rs | 16 +++--- tests/builder/template_help.rs | 8 +-- tests/ui/arg_required_else_help_stderr.toml | 8 +-- tests/ui/h_flag_stdout.toml | 8 +-- tests/ui/help_cmd_stdout.toml | 12 ++--- tests/ui/help_flag_stdout.toml | 12 ++--- 22 files changed, 155 insertions(+), 151 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6516b5d9..3b7871c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -85,6 +85,7 @@ MSRV is now 1.60.0 - *(help)* Show when a flag is `ArgAction::Count` by adding an `...` - *(help)* Use a more neutral palette for coloring - *(help)* Don't rely on ALL CAPS for help headers +- *(help)* List subcommands first, focusing the emphasis on them - *(version)* Use `Command::display_name` rather than `Command::bin_name` - *(parser)* Assert on unknown args when using external subcommands (#3703) - *(parser)* Always fill in `""` argument for external subcommands (#3263) diff --git a/examples/cargo-example-derive.md b/examples/cargo-example-derive.md index 98cf2f6c..7f430e7b 100644 --- a/examples/cargo-example-derive.md +++ b/examples/cargo-example-derive.md @@ -11,13 +11,13 @@ cargo Usage: cargo -Options: - -h, --help Print help information - Subcommands: example-derive A simple to use, efficient, and full-featured Command Line Argument Parser help Print this message or the help of the given subcommand(s) +Options: + -h, --help Print help information + $ cargo-example-derive example-derive --help cargo-example-derive [..] A simple to use, efficient, and full-featured Command Line Argument Parser diff --git a/examples/cargo-example.md b/examples/cargo-example.md index 98cd01b4..600c6528 100644 --- a/examples/cargo-example.md +++ b/examples/cargo-example.md @@ -11,13 +11,13 @@ cargo Usage: cargo -Options: - -h, --help Print help information - Subcommands: example A simple to use, efficient, and full-featured Command Line Argument Parser help Print this message or the help of the given subcommand(s) +Options: + -h, --help Print help information + $ cargo-example example --help cargo-example [..] A simple to use, efficient, and full-featured Command Line Argument Parser diff --git a/examples/derive_ref/interop_tests.md b/examples/derive_ref/interop_tests.md index ee3facee..41945770 100644 --- a/examples/derive_ref/interop_tests.md +++ b/examples/derive_ref/interop_tests.md @@ -106,15 +106,15 @@ clap Usage: interop_hand_subcommand[EXE] [OPTIONS] -Options: - -t, --top-level - -h, --help Print help information - Subcommands: add remove help Print this message or the help of the given subcommand(s) +Options: + -t, --top-level + -h, --help Print help information + ``` ```console diff --git a/examples/git-derive.md b/examples/git-derive.md index 248254a0..bf875083 100644 --- a/examples/git-derive.md +++ b/examples/git-derive.md @@ -12,9 +12,6 @@ A fictional versioning CLI Usage: git-derive[EXE] -Options: - -h, --help Print help information - Subcommands: clone Clones repos push pushes things @@ -22,6 +19,9 @@ Subcommands: stash help Print this message or the help of the given subcommand(s) +Options: + -h, --help Print help information + $ git-derive help git A fictional versioning CLI @@ -29,9 +29,6 @@ A fictional versioning CLI Usage: git-derive[EXE] -Options: - -h, --help Print help information - Subcommands: clone Clones repos push pushes things @@ -39,6 +36,9 @@ Subcommands: stash help Print this message or the help of the given subcommand(s) +Options: + -h, --help Print help information + $ git-derive help add git-add adds things @@ -84,16 +84,16 @@ Usage: git-derive[EXE] stash [OPTIONS] git-derive[EXE] stash -Options: - -m, --message - -h, --help Print help information - Subcommands: push pop apply help Print this message or the help of the given subcommand(s) +Options: + -m, --message + -h, --help Print help information + $ git-derive stash push -h git-stash-push diff --git a/examples/git.md b/examples/git.md index 24cd41de..95d58079 100644 --- a/examples/git.md +++ b/examples/git.md @@ -10,9 +10,6 @@ A fictional versioning CLI Usage: git[EXE] -Options: - -h, --help Print help information - Subcommands: clone Clones repos push pushes things @@ -20,6 +17,9 @@ Subcommands: stash help Print this message or the help of the given subcommand(s) +Options: + -h, --help Print help information + $ git help git A fictional versioning CLI @@ -27,9 +27,6 @@ A fictional versioning CLI Usage: git[EXE] -Options: - -h, --help Print help information - Subcommands: clone Clones repos push pushes things @@ -37,6 +34,9 @@ Subcommands: stash help Print this message or the help of the given subcommand(s) +Options: + -h, --help Print help information + $ git help add git-add adds things @@ -82,16 +82,16 @@ Usage: git[EXE] stash [OPTIONS] git[EXE] stash -Options: - -m, --message - -h, --help Print help information - Subcommands: push pop apply help Print this message or the help of the given subcommand(s) +Options: + -m, --message + -h, --help Print help information + $ git stash push -h git-stash-push diff --git a/examples/multicall-busybox.md b/examples/multicall-busybox.md index 9140edea..6b0f6864 100644 --- a/examples/multicall-busybox.md +++ b/examples/multicall-busybox.md @@ -30,13 +30,13 @@ busybox Usage: busybox [OPTIONS] [APPLET] -Options: - --install Install hardlinks for all subcommands in path - -h, --help Print help information - APPLETS: true does nothing successfully false does nothing unsuccessfully help Print this message or the help of the given subcommand(s) +Options: + --install Install hardlinks for all subcommands in path + -h, --help Print help information + ``` diff --git a/examples/pacman.md b/examples/pacman.md index 81653e14..51642c62 100644 --- a/examples/pacman.md +++ b/examples/pacman.md @@ -42,15 +42,15 @@ package manager utility Usage: pacman[EXE] -Options: - -h, --help Print help information - -V, --version Print version information - Subcommands: query -Q --query Query the package database. sync -S --sync Synchronize packages. help Print this message or the help of the given subcommand(s) +Options: + -h, --help Print help information + -V, --version Print version information + $ pacman -S -h pacman-sync Synchronize packages. diff --git a/examples/tutorial_builder/01_quick.md b/examples/tutorial_builder/01_quick.md index 74b83d76..c7f2d23f 100644 --- a/examples/tutorial_builder/01_quick.md +++ b/examples/tutorial_builder/01_quick.md @@ -6,6 +6,10 @@ A simple to use, efficient, and full-featured Command Line Argument Parser Usage: 01_quick[EXE] [OPTIONS] [name] [SUBCOMMAND] +Subcommands: + test does testing things + help Print this message or the help of the given subcommand(s) + Arguments: Optional name to operate on @@ -15,10 +19,6 @@ Options: -h, --help Print help information -V, --version Print version information -Subcommands: - test does testing things - help Print this message or the help of the given subcommand(s) - ``` By default, the program does nothing: diff --git a/examples/tutorial_builder/03_04_subcommands.md b/examples/tutorial_builder/03_04_subcommands.md index 30f0318a..0afa755f 100644 --- a/examples/tutorial_builder/03_04_subcommands.md +++ b/examples/tutorial_builder/03_04_subcommands.md @@ -6,14 +6,14 @@ A simple to use, efficient, and full-featured Command Line Argument Parser Usage: 03_04_subcommands[EXE] -Options: - -h, --help Print help information - -V, --version Print version information - Subcommands: add Adds files to myapp help Print this message or the help of the given subcommand(s) +Options: + -h, --help Print help information + -V, --version Print version information + $ 03_04_subcommands help add clap-add [..] Adds files to myapp @@ -43,14 +43,14 @@ A simple to use, efficient, and full-featured Command Line Argument Parser Usage: 03_04_subcommands[EXE] -Options: - -h, --help Print help information - -V, --version Print version information - Subcommands: add Adds files to myapp help Print this message or the help of the given subcommand(s) +Options: + -h, --help Print help information + -V, --version Print version information + ``` Because we set [`Command::propagate_version`][crate::Command::propagate_version]: diff --git a/examples/tutorial_derive/01_quick.md b/examples/tutorial_derive/01_quick.md index 1e58db5f..61e9bd3f 100644 --- a/examples/tutorial_derive/01_quick.md +++ b/examples/tutorial_derive/01_quick.md @@ -6,6 +6,10 @@ A simple to use, efficient, and full-featured Command Line Argument Parser Usage: 01_quick_derive[EXE] [OPTIONS] [NAME] [SUBCOMMAND] +Subcommands: + test does testing things + help Print this message or the help of the given subcommand(s) + Arguments: Optional name to operate on @@ -15,10 +19,6 @@ Options: -h, --help Print help information -V, --version Print version information -Subcommands: - test does testing things - help Print this message or the help of the given subcommand(s) - ``` By default, the program does nothing: diff --git a/examples/tutorial_derive/03_04_subcommands.md b/examples/tutorial_derive/03_04_subcommands.md index ec264223..87f56f8b 100644 --- a/examples/tutorial_derive/03_04_subcommands.md +++ b/examples/tutorial_derive/03_04_subcommands.md @@ -6,14 +6,14 @@ A simple to use, efficient, and full-featured Command Line Argument Parser Usage: 03_04_subcommands_derive[EXE] -Options: - -h, --help Print help information - -V, --version Print version information - Subcommands: add Adds files to myapp help Print this message or the help of the given subcommand(s) +Options: + -h, --help Print help information + -V, --version Print version information + $ 03_04_subcommands_derive help add clap-add [..] Adds files to myapp @@ -43,14 +43,14 @@ A simple to use, efficient, and full-featured Command Line Argument Parser Usage: 03_04_subcommands_derive[EXE] -Options: - -h, --help Print help information - -V, --version Print version information - Subcommands: add Adds files to myapp help Print this message or the help of the given subcommand(s) +Options: + -h, --help Print help information + -V, --version Print version information + ``` Because we added `#[clap(propagate_version = true)]`: diff --git a/src/output/help.rs b/src/output/help.rs index f7a7f2de..d0eae613 100644 --- a/src/output/help.rs +++ b/src/output/help.rs @@ -338,22 +338,41 @@ impl<'cmd, 'writer> Help<'cmd, 'writer> { .filter_map(|arg| arg.get_help_heading()) .collect::>(); - let mut first = if !pos.is_empty() { + let mut first = true; + + if subcmds { + if !first { + self.none("\n\n"); + } + first = false; + let default_help_heading = Str::from("Subcommands"); + self.header( + self.cmd + .get_subcommand_help_heading() + .unwrap_or(&default_help_heading), + ); + self.header(":\n"); + + self.write_subcommands(self.cmd); + } + + if !pos.is_empty() { + if !first { + self.none("\n\n"); + } + first = false; // Write positional args if any self.header("Arguments:\n"); self.write_args(&pos, "Arguments", positional_sort_key); - false - } else { - true - }; + } if !non_pos.is_empty() { if !first { self.none("\n\n"); } + first = false; self.header("Options:\n"); self.write_args(&non_pos, "Options", option_sort_key); - first = false; } if !custom_headings.is_empty() { for heading in custom_headings { @@ -373,28 +392,12 @@ impl<'cmd, 'writer> Help<'cmd, 'writer> { if !first { self.none("\n\n"); } + first = false; self.header(format!("{}:\n", heading)); self.write_args(&args, heading, option_sort_key); - first = false } } } - - if subcmds { - if !first { - self.none("\n\n"); - } - - let default_help_heading = Str::from("Subcommands"); - self.header( - self.cmd - .get_subcommand_help_heading() - .unwrap_or(&default_help_heading), - ); - self.header(":\n"); - - self.write_subcommands(self.cmd); - } } /// Sorts arguments by length and display order and write their help to the wrapped stream. fn write_args(&mut self, args: &[&Arg], _category: &str, sort_key: ArgSortKey) { diff --git a/tests/builder/derive_order.rs b/tests/builder/derive_order.rs index 3c6180b5..ccce2ed0 100644 --- a/tests/builder/derive_order.rs +++ b/tests/builder/derive_order.rs @@ -271,14 +271,14 @@ fn subcommand_sorted_display_order() { Usage: test [SUBCOMMAND] -Options: - -h, --help Print help information - -V, --version Print version information - Subcommands: a1 blah a1 b1 blah b1 help Print this message or the help of the given subcommand(s) + +Options: + -h, --help Print help information + -V, --version Print version information "; let app_subcmd_alpha_order = Command::new("test") @@ -308,14 +308,14 @@ fn subcommand_derived_display_order() { Usage: test [SUBCOMMAND] -Options: - -h, --help Print help information - -V, --version Print version information - Subcommands: b1 blah b1 a1 blah a1 help Print this message or the help of the given subcommand(s) + +Options: + -h, --help Print help information + -V, --version Print version information "; let app_subcmd_decl_order = Command::new("test").version("1").subcommands(vec![ diff --git a/tests/builder/display_order.rs b/tests/builder/display_order.rs index 52b5fa10..c2898704 100644 --- a/tests/builder/display_order.rs +++ b/tests/builder/display_order.rs @@ -14,12 +14,12 @@ fn very_large_display_order() { Usage: test [SUBCOMMAND] -Options: - -h, --help Print help information - Subcommands: help Print this message or the help of the given subcommand(s) sub + +Options: + -h, --help Print help information ", false, ); diff --git a/tests/builder/help.rs b/tests/builder/help.rs index c43cd55d..3224321c 100644 --- a/tests/builder/help.rs +++ b/tests/builder/help.rs @@ -207,6 +207,10 @@ tests clap library Usage: clap-test [OPTIONS] [ARGS] [SUBCOMMAND] +Subcommands: + subcmd tests subcommands + help Print this message or the help of the given subcommand(s) + Arguments: tests positionals tests positionals with exclusions @@ -226,10 +230,6 @@ Options: --optvalnoeq [] Tests optional value -h, --help Print help information -V, --version Print version information - -Subcommands: - subcmd tests subcommands - help Print this message or the help of the given subcommand(s) "; utils::assert_output(utils::complex_app(), "clap-test --help", HELP, false); @@ -1103,6 +1103,10 @@ Usage: prog --opt [PATH] prog [PATH] +Subcommands: + test + help Print this message or the help of the given subcommand(s) + Arguments: help @@ -1110,10 +1114,6 @@ Options: -o, --opt tests options -h, --help Print help information -V, --version Print version information - -Subcommands: - test - help Print this message or the help of the given subcommand(s) "; let cmd = Command::new("prog") @@ -1155,6 +1155,10 @@ Usage: prog [OPTIONS] [PATH] prog +Subcommands: + test + help Print this message or the help of the given subcommand(s) + Arguments: help @@ -1163,10 +1167,6 @@ Options: -o, --opt tests options -h, --help Print help information -V, --version Print version information - -Subcommands: - test - help Print this message or the help of the given subcommand(s) "; let cmd = Command::new("prog") @@ -1399,6 +1399,10 @@ Usage: last [CORPUS] -- ... last +Subcommands: + test some + help Print this message or the help of the given subcommand(s) + Arguments: some some @@ -1407,10 +1411,6 @@ Arguments: Options: -h, --help Print help information -V, --version Print version information - -Subcommands: - test some - help Print this message or the help of the given subcommand(s) "; let cmd = Command::new("last") @@ -1438,6 +1438,10 @@ Usage: last [CORPUS] [-- ...] last +Subcommands: + test some + help Print this message or the help of the given subcommand(s) + Arguments: some some @@ -1446,10 +1450,6 @@ Arguments: Options: -h, --help Print help information -V, --version Print version information - -Subcommands: - test some - help Print this message or the help of the given subcommand(s) "; let cmd = Command::new("last") @@ -2139,12 +2139,12 @@ fn prefer_about_over_long_about_in_subcommands_list() { Usage: about-in-subcommands-list [SUBCOMMAND] -Options: - -h, --help Print help information - Subcommands: sub short about sub help Print this message or the help of the given subcommand(s) + +Options: + -h, --help Print help information "; let cmd = Command::new("about-in-subcommands-list").subcommand( diff --git a/tests/builder/subcommands.rs b/tests/builder/subcommands.rs index 31c828a2..876d30be 100644 --- a/tests/builder/subcommands.rs +++ b/tests/builder/subcommands.rs @@ -7,13 +7,13 @@ static VISIBLE_ALIAS_HELP: &str = "clap-test 2.6 Usage: clap-test [SUBCOMMAND] -Options: - -h, --help Print help information - -V, --version Print version information - Subcommands: test Some help [aliases: dongle, done] help Print this message or the help of the given subcommand(s) + +Options: + -h, --help Print help information + -V, --version Print version information "; static INVISIBLE_ALIAS_HELP: &str = "clap-test 2.6 @@ -21,13 +21,13 @@ static INVISIBLE_ALIAS_HELP: &str = "clap-test 2.6 Usage: clap-test [SUBCOMMAND] -Options: - -h, --help Print help information - -V, --version Print version information - Subcommands: test Some help help Print this message or the help of the given subcommand(s) + +Options: + -h, --help Print help information + -V, --version Print version information "; #[cfg(feature = "suggestions")] diff --git a/tests/builder/template_help.rs b/tests/builder/template_help.rs index a4a55451..e80abaf5 100644 --- a/tests/builder/template_help.rs +++ b/tests/builder/template_help.rs @@ -51,6 +51,10 @@ Does awesome things Usage: MyApp [OPTIONS] [SUBCOMMAND] +Subcommands: + test does testing things + help Print this message or the help of the given subcommand(s) + Arguments: Sets an optional output file @@ -59,10 +63,6 @@ Options: -d... Turn debugging information on -h, --help Print help information -V, --version Print version information - -Subcommands: - test does testing things - help Print this message or the help of the given subcommand(s) "; #[test] diff --git a/tests/ui/arg_required_else_help_stderr.toml b/tests/ui/arg_required_else_help_stderr.toml index 9062ab7b..21192793 100644 --- a/tests/ui/arg_required_else_help_stderr.toml +++ b/tests/ui/arg_required_else_help_stderr.toml @@ -8,12 +8,12 @@ stdio-fixture 1.0 Usage: stdio-fixture[EXE] [OPTIONS] [SUBCOMMAND] +Subcommands: + more + help Print this message or the help of the given subcommand(s) + Options: --verbose log -h, --help Print help information -V, --version Print version information - -Subcommands: - more - help Print this message or the help of the given subcommand(s) """ diff --git a/tests/ui/h_flag_stdout.toml b/tests/ui/h_flag_stdout.toml index f987d564..d0371c3a 100644 --- a/tests/ui/h_flag_stdout.toml +++ b/tests/ui/h_flag_stdout.toml @@ -7,13 +7,13 @@ stdio-fixture 1.0 Usage: stdio-fixture[EXE] [OPTIONS] [SUBCOMMAND] +Subcommands: + more + help Print this message or the help of the given subcommand(s) + Options: --verbose log -h, --help Print help information -V, --version Print version information - -Subcommands: - more - help Print this message or the help of the given subcommand(s) """ stderr = "" diff --git a/tests/ui/help_cmd_stdout.toml b/tests/ui/help_cmd_stdout.toml index 00737352..ea78b06d 100644 --- a/tests/ui/help_cmd_stdout.toml +++ b/tests/ui/help_cmd_stdout.toml @@ -7,6 +7,12 @@ stdio-fixture 1.0 Usage: stdio-fixture[EXE] [OPTIONS] [SUBCOMMAND] +Subcommands: + more + + help + Print this message or the help of the given subcommand(s) + Options: --verbose more log @@ -16,11 +22,5 @@ Options: -V, --version Print version information - -Subcommands: - more - - help - Print this message or the help of the given subcommand(s) """ stderr = "" diff --git a/tests/ui/help_flag_stdout.toml b/tests/ui/help_flag_stdout.toml index 85335fdc..63e07980 100644 --- a/tests/ui/help_flag_stdout.toml +++ b/tests/ui/help_flag_stdout.toml @@ -7,6 +7,12 @@ stdio-fixture 1.0 Usage: stdio-fixture[EXE] [OPTIONS] [SUBCOMMAND] +Subcommands: + more + + help + Print this message or the help of the given subcommand(s) + Options: --verbose more log @@ -16,11 +22,5 @@ Options: -V, --version Print version information - -Subcommands: - more - - help - Print this message or the help of the given subcommand(s) """ stderr = ""