Skip to content

Generate help subcommands for child commands #6227

@twilight-flower

Description

@twilight-flower

Please complete the following tasks

Clap Version

4.5.54

Describe your use case

As discussed in #6226: currently, for code like this:

use clap::{Parser, Subcommand};

#[derive(Subcommand)]
enum ExampleParserSubcommand {
	One,
	Two,
}

#[derive(Parser)]
struct ExampleParser {
	#[command(subcommand)]
	subcommand: ExampleParserSubcommand,
}

fn main() {
    ExampleParser::parse();
}

A help subcommand will be generated for the root-level parser—running cargo run -- help with this source code will print the help menu—but won't be generated for the individual subcommands, so if you run e.g. cargo run -- one help this will fail with an 'unrecognized argument' error and tell you to try again with --help. Because the current default is that help subcommands are generated only for commands with defined non-help subcommands, which the root parser has—it has subcommands one and two—but which one and two themselves don't have.

This presents an inconveniently-inconsistent interface, discouraging users from ever using the help subcommand in place of --help, because the former will only sometimes work while the latter always will. It would be more consistent, and therefore a better user experience, if one and two could be forced to generate help subcommands as well, even in the absence of other subcommands.

Describe the solution you'd like

For a solution, I propose that a new method be defined, Command::enable_help_subcommand, which does the inverse of the existing Command::disable_help_subcommand: if set to true, it causes a command to generate with a help subcommand even if it otherwise wouldn't, along with all its children. This would then allow changing the parser's source code to look like this:

#[derive(Parser)]
#[command(enable_help_subcommand = true)]
struct ExampleParser {
	#[command(subcommand)]
	subcommand: ExampleParserSubcommand,
}

...which would then propagate help-subcommand-generation to ExampleParserSubcommand::One and ExampleParserSubcommand::Two, producing the desired sort of consistent interface for users.

(Or the same could be set on the ExampleParserSubcommand struct for the same practical effect, or—likely unwisely—on either of its individual fields if one wanted for some reason to be more precisely-discriminating at the cost of keeping the interface inconsistent.)

Alternatives, if applicable

There's some argument to be made that, rather than needing to be explicitly requested on the user end, help-subcommand-generation should be automatically propagated to child commands from their parents, as a default if disable_help_subcommand isn't explicitly called to block it, such that my original example code would generate a help subcommand for one even absent any explicit specification of enable_help_subcommand = true as a result of one being a child of a command with a help subcommand. I would personally find that default convenient, and suspect it would generally be an improvement for users of new applications obeying that default; but it would be a larger API-change, compared with merely providing it as an opt-in option, and correspondingly potentially more costly and thus not my primary suggestion.

There's also some argument to be made that enable_help_subcommand should apply only to the command it's called on directly, and not to any of its children. I'd find that inconvenient—it would, for any codebase I'm likely to develop, lead to more boilerplate being needed on net—but I can at least theoretically conceive of some codebase-shapes—ones involving mixes of enable_help_subcommand and disable_help_subcommand on different branches—where it could lead to the codebase's boilerplate-requirements ending up smaller in total.

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-helpArea: documentation, including docs.rs, readme, examples, etc...C-enhancementCategory: Raise on the bar on expectationsE-help-wantedCall for participation: Help is requested to fix this issue.M-breaking-changeMeta: Implementing or merging this will introduce a breaking change.S-triageStatus: New; needs maintainer attention.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions