-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Subcommand help headings #5819
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -101,9 +101,11 @@ pub struct Command { | |
subcommands: Vec<Command>, | ||
groups: Vec<ArgGroup>, | ||
current_help_heading: Option<Str>, | ||
current_subcommand_help_heading: Option<Str>, | ||
current_disp_ord: Option<usize>, | ||
subcommand_value_name: Option<Str>, | ||
subcommand_heading: Option<Str>, | ||
subcommand_help_heading: Option<Option<Str>>, | ||
external_value_parser: Option<super::ValueParser>, | ||
long_help_exists: bool, | ||
deferred: Option<fn(Command) -> Command>, | ||
|
@@ -490,6 +492,9 @@ impl Command { | |
subcmd.disp_ord.get_or_insert(current); | ||
*current_disp_ord = current + 1; | ||
} | ||
subcmd | ||
.subcommand_help_heading | ||
.get_or_insert_with(|| self.current_subcommand_help_heading.clone()); | ||
self.subcommands.push(subcmd); | ||
self | ||
} | ||
|
@@ -2295,6 +2300,22 @@ impl Command { | |
self | ||
} | ||
|
||
/// Set the default section heading for future subcommands. | ||
/// | ||
/// This will be used for any subcommand that hasn't had [`Command::subcommand_help_heading`] called. | ||
/// | ||
/// This is useful if the default `Commands` heading is | ||
/// not specific enough for one's use case. | ||
/// | ||
/// [`Command::subcommand`]: Command::subcommand() | ||
/// [`Command::subcommand_help_heading`]: crate::Command::subcommand_help_heading() | ||
#[inline] | ||
#[must_use] | ||
pub fn next_subcommand_help_heading(mut self, heading: impl IntoResettable<Str>) -> Self { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The derive has special handling for regular help headings, so we should probably have the same for these There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we only have one There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question, that would make api simpler, but I'd rather have clear separation between subcommand and parameter heading There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you explain why? |
||
self.current_subcommand_help_heading = heading.into_resettable().into_option(); | ||
self | ||
} | ||
|
||
/// Change the starting value for assigning future display orders for args. | ||
/// | ||
/// This will be used for any arg that hasn't had [`Arg::display_order`] called. | ||
|
@@ -3753,6 +3774,14 @@ impl Command { | |
self.current_help_heading.as_deref() | ||
} | ||
|
||
/// Get the custom section heading specified via [`Command::next_subcommand_help_heading`]. | ||
/// | ||
/// [`Command::subcommand_help_heading`]: Command::subcommand_help_heading() | ||
#[inline] | ||
pub fn get_next_subcommand_help_heading(&self) -> Option<&str> { | ||
self.current_subcommand_help_heading.as_deref() | ||
} | ||
|
||
/// Iterate through the *visible* aliases for this subcommand. | ||
#[inline] | ||
pub fn get_visible_aliases(&self) -> impl Iterator<Item = &str> + '_ { | ||
|
@@ -4889,6 +4918,14 @@ impl Command { | |
.any(|sc| sc.name != "help" && !sc.is_set(AppSettings::Hidden)) | ||
} | ||
|
||
#[cfg(any(feature = "usage", feature = "help"))] | ||
pub(crate) fn needs_commands_header(&self) -> bool { | ||
self.subcommands | ||
.iter() | ||
.filter(|sc| !sc.is_set(AppSettings::Hidden)) | ||
.any(|sc| sc.subcommand_help_heading.is_none()) | ||
} | ||
|
||
/// Check if this subcommand can be referred to as `name`. In other words, | ||
/// check if `name` is the name of this subcommand or is one of its aliases. | ||
#[inline] | ||
|
@@ -5131,9 +5168,11 @@ impl Default for Command { | |
subcommands: Default::default(), | ||
groups: Default::default(), | ||
current_help_heading: Default::default(), | ||
current_subcommand_help_heading: Default::default(), | ||
current_disp_ord: Some(0), | ||
subcommand_value_name: Default::default(), | ||
subcommand_heading: Default::default(), | ||
subcommand_help_heading: Default::default(), | ||
external_value_parser: Default::default(), | ||
long_help_exists: false, | ||
deferred: None, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
use clap::{arg, error::ErrorKind, Arg, ArgAction, Command}; | ||
|
||
|
||
use super::utils; | ||
use snapbox::assert_data_eq; | ||
use snapbox::str; | ||
|
@@ -630,3 +631,86 @@ fn duplicate_subcommand_alias() { | |
.subcommand(Command::new("unique").alias("repeat")) | ||
.build(); | ||
} | ||
|
||
#[test] | ||
fn subcommand_help_header() { | ||
static VISIBLE_ALIAS_HELP: &str = "\ | ||
Usage: clap-test [COMMAND] | ||
|
||
Commands: | ||
help Print this message or the help of the given subcommand(s) | ||
Comment on lines
+640
to
+641
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Before this can move forward, we need to come to a resolution on |
||
|
||
Test commands: | ||
test Some help | ||
|
||
Options: | ||
-h, --help Print help | ||
-V, --version Print version | ||
"; | ||
|
||
let cmd = Command::new("clap-test").version("2.6").subcommand( | ||
Command::new("test") | ||
.about("Some help") | ||
.subcommand_help_heading("Test commands") | ||
); | ||
utils::assert_output(cmd, "clap-test --help", VISIBLE_ALIAS_HELP, false); | ||
} | ||
|
||
|
||
#[test] | ||
fn subcommand_help_header_hide_commands_header() { | ||
static VISIBLE_ALIAS_HELP: &str = "\ | ||
Usage: clap-test [COMMAND] | ||
|
||
Test commands: | ||
test Some help | ||
|
||
Options: | ||
-h, --help Print help | ||
-V, --version Print version | ||
"; | ||
|
||
let cmd = Command::new("clap-test") | ||
.version("2.6") | ||
.disable_help_subcommand(true) | ||
.subcommand( | ||
Command::new("test") | ||
.about("Some help") | ||
.subcommand_help_heading("Test commands") | ||
); | ||
utils::assert_output(cmd, "clap-test --help", VISIBLE_ALIAS_HELP, false); | ||
} | ||
|
||
|
||
#[test] | ||
fn subcommand_help_header_multiple_help_headers() { | ||
static VISIBLE_ALIAS_HELP: &str = "\ | ||
Usage: clap-test [COMMAND] | ||
|
||
Test commands 1: | ||
test1 Some help | ||
|
||
Test commands 2: | ||
test2 Some help | ||
|
||
Options: | ||
-h, --help Print help | ||
-V, --version Print version | ||
"; | ||
|
||
let cmd = Command::new("clap-test") | ||
.version("2.6") | ||
.disable_help_subcommand(true) | ||
.subcommand( | ||
Command::new("test1") | ||
.about("Some help") | ||
.subcommand_help_heading("Test commands 1") | ||
) | ||
.subcommand( | ||
Command::new("test2") | ||
.about("Some help") | ||
.subcommand_help_heading("Test commands 2") | ||
); | ||
|
||
utils::assert_output(cmd, "clap-test --help", VISIBLE_ALIAS_HELP, false); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will also need a way to set the help heading for the current command
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will likely run into name conflicts with
subcommand_help_heading
. We should probably deprecate that and migrate people over to settingnext_subcommand_help_heading
.