feat: add Command::help_subcommand builder method (#6227)#6395
Closed
SMC17 wants to merge 1 commit into
Closed
Conversation
Adds an opt-in tri-state `Command::help_subcommand(impl IntoResettable<bool>)` gated on `unstable-v5`, addressing clap-rs#6227 where the auto-generated `help` subcommand is absent on leaf subcommands so `cmd one help` fails while `cmd help` succeeds. The implementation follows epage's design comment verbatim: a new `Option<bool>` field on `Command`, propagation via `get_or_insert` in `_propagate_subcommand`, and a carve-out in `_build_self` so an explicit `true` keeps the `help` subcommand on leaves. The existing `disable_help_subcommand(bool)` API is preserved on stable; under `unstable-v5` it also mirrors its argument into the new tri-state field so the two APIs stay coherent. Six tests cover default-behavior regression, forward propagation, three-level nesting, child override of parent, `Option::<bool>::None` reset, and `Resettable::Reset` reset. Closes clap-rs#6227. Signed-off-by: Sean Collins <sean@sunlitmoon.online> Assisted-by: claude-opus-4-7
cf6c758 to
4d03563
Compare
Author
|
Sorry — been testing some things and this leaked out. Closing. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat: add
Command::help_subcommandbuilder methodCloses #6227.
Summary
Issue #6227 reports that
helpsubcommands are auto-generated only oncommands that have non-
helpchildren, socmd helpworks for the rootbut
cmd one helpfails for leaf subcommandsoneandtwo. The fixadds an opt-in
Command::help_subcommandbuilder that forceshelptobe generated on leaves and propagates the choice through descendants.
This implementation follows @epage's design guidance verbatim. From
#6227 comment:
And the follow-up:
The new API matches that shape exactly:
Command::help_subcommand(impl IntoResettable<bool>).API shape
Tri-state via
IntoResettable<bool>:true: force-generatehelphere and on every descendant (including leaves).false: suppresshelphere and on every descendant.Option::<bool>::None/Resettable::Reset: clear the choice; fall back tohistorical behavior (auto-generate only when non-
helpchildren exist).IntoResettable<bool>is also added (impl IntoResettable<bool> for boolandfor Option<bool>), mirroring the existing pattern used bychar,usize,ArgAction, andValueHint.Why
unstable-v5The existing
disable_help_subcommand(false)is a no-op for leaves because of:Letting
help_subcommand(true)override that line and then propagating thechoice to children changes the help-subcommand surface of any pre-existing
command tree whose leaves did not previously expose
help(e.g. completiontrees built for
clap_complete). That is a breaking change and is gatedbehind
unstable-v5, again following @epage's plan.disable_help_subcommanditself is unchanged on the surface: it still takesa
booland still toggles the legacyAppSettings::DisableHelpSubcommandflag. Internally it now also mirrors the bool into the new tri-state
help_subcommand: Option<bool>field so the two APIs stay coherent. Stablebuilds never consult the new field.
Implementation summary
Command::help_subcommand: Option<bool>field, defaulted toNone.Command::help_subcommand(impl IntoResettable<bool>)setter gated onunstable-v5. Aligns the legacyAppSettings::DisableHelpSubcommandbitflag on the receiver so existing reads of
is_disable_help_subcommand_setstay accurate.
disable_help_subcommand(yes)now also setshelp_subcommand = Some(!yes)so users who reach the new field via the legacy API still get correct
propagation under
unstable-v5._build_self, the historical!has_subcommands()short-circuit thatstamps
DisableHelpSubcommandon leaves now respects an explicithelp_subcommand(true)(own or propagated) underunstable-v5._propagate_subcommand, propagate the parent's tri-state choice withsc.help_subcommand.get_or_insert(parent_choice), matching @epage'sget_or_insertpattern. Child explicit choices win over parent.IntoResettable<bool>impls added forboolandOption<bool>.Test coverage
tests/builder/help_subcommand.rs, six tests:default_behavior_unchanged_leaf_has_no_help_subcommand(no feature flag) -regression guard. Root
helpworks; leafone helpfails. Required by@epage's step 2.
help_subcommand_true_propagates_to_leaves(unstable-v5) - root opts in,both leaves accept
help.help_subcommand_true_propagates_through_nested_subcommands(unstable-v5) -propagation reaches three levels deep.
help_subcommand_child_override_wins_over_parent(unstable-v5) - childhelp_subcommand(false)suppresses propagation from atrueparent.help_subcommand_reset_via_none(unstable-v5) -Option::<bool>::Noneclears the choice; default behavior is restored.
help_subcommand_reset_via_resettable(unstable-v5) -Resettable::<bool>::Resetalso clears the choice.Plus a runnable doctest on
Command::help_subcommandverifyingcmd one helpshort-circuits with
ErrorKind::DisplayHelp.CI gate verification
Run locally with
CARGO_TARGET_DIRredirected to non-tmpfs:cargo fmt --check: clean.cargo clippy -p clap_builder --no-deps -- -D warnings: clean.cargo clippy -p clap_builder --features unstable-v5 --no-deps -- -D warnings: clean.cargo test -p clap_builder --lib --features unstable-v5: 79 passed.cargo test -p clap_builder --doc: 345 passed (default features).cargo test -p clap_builder --doc --features unstable-v5: 344 passed.cargo test --test builder: 912 passed (default features).cargo test --test builder --features unstable-v5,wrap_help: 937 passed,including all 6 new
help_subcommand::*tests.(
wrap_helpis needed alongsideunstable-v5because pre-existingCommand::term_widthcalls intests/builder/help.rsare gated oncfg(any(not(feature = "unstable-v5"), feature = "wrap_help")). Unrelatedto this PR.)
Total: 3,217 tests passed, 0 failed.
Compatibility note
disable_help_subcommand(true)anddisable_help_subcommand(false)behaveidentically to today on stable builds. The new tri-state field is only
consulted under
unstable-v5.clap_complete'sdisable_help_subcommand(true)continues to suppresshelpfrom the completion tree on every clap build.help_subcommandsetter and thepropagation logic are both
#[cfg(feature = "unstable-v5")].Files touched
clap_builder/src/builder/resettable.rs:IntoResettable<bool>impls.clap_builder/src/builder/command.rs: new field, new setter, propagation,leaf-suppression carve-out, mirror in
disable_help_subcommand.tests/builder/help_subcommand.rs: six new tests (new file).CHANGELOG.md: one bullet under 5.0.0 Features.