diff --git a/clap_complete/tests/snapshots/basic.bash b/clap_complete/tests/snapshots/basic.bash index f55933fd1e2..08b27e0bbde 100644 --- a/clap_complete/tests/snapshots/basic.bash +++ b/clap_complete/tests/snapshots/basic.bash @@ -39,7 +39,7 @@ _my-app() { return 0 ;; my__app__help) - opts="-c test help" + opts="test help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -53,7 +53,7 @@ _my-app() { return 0 ;; my__app__help__help) - opts="-c" + opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -67,7 +67,7 @@ _my-app() { return 0 ;; my__app__help__test) - opts="-c" + opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/clap_complete/tests/snapshots/basic.elvish b/clap_complete/tests/snapshots/basic.elvish index 71494e466e4..2465d3ca750 100644 --- a/clap_complete/tests/snapshots/basic.elvish +++ b/clap_complete/tests/snapshots/basic.elvish @@ -32,15 +32,12 @@ set edit:completion:arg-completer[my-app] = {|@words| cand --help 'Print help information' } &'my-app;help'= { - cand -c 'c' cand test 'Subcommand' cand help 'Print this message or the help of the given subcommand(s)' } &'my-app;help;test'= { - cand -c 'c' } &'my-app;help;help'= { - cand -c 'c' } ] $completions[$command] diff --git a/clap_complete/tests/snapshots/basic.fish b/clap_complete/tests/snapshots/basic.fish index 54415fd69e9..5a719a2a707 100644 --- a/clap_complete/tests/snapshots/basic.fish +++ b/clap_complete/tests/snapshots/basic.fish @@ -6,8 +6,5 @@ complete -c my-app -n "__fish_use_subcommand" -f -a "help" -d 'Print this messag complete -c my-app -n "__fish_seen_subcommand_from test" -s d complete -c my-app -n "__fish_seen_subcommand_from test" -s c complete -c my-app -n "__fish_seen_subcommand_from test" -s h -l help -d 'Print help information' -complete -c my-app -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from test; and not __fish_seen_subcommand_from help" -s c complete -c my-app -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from test; and not __fish_seen_subcommand_from help" -f -a "test" -d 'Subcommand' complete -c my-app -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from test; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' -complete -c my-app -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from test" -s c -complete -c my-app -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from help" -s c diff --git a/clap_complete/tests/snapshots/basic.ps1 b/clap_complete/tests/snapshots/basic.ps1 index 242b7e2d7f4..89aae1dc097 100644 --- a/clap_complete/tests/snapshots/basic.ps1 +++ b/clap_complete/tests/snapshots/basic.ps1 @@ -37,17 +37,14 @@ Register-ArgumentCompleter -Native -CommandName 'my-app' -ScriptBlock { break } 'my-app;help' { - [CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'c') [CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, 'Subcommand') [CompletionResult]::new('help', 'help', [CompletionResultType]::ParameterValue, 'Print this message or the help of the given subcommand(s)') break } 'my-app;help;test' { - [CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'c') break } 'my-app;help;help' { - [CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'c') break } }) diff --git a/clap_complete/tests/snapshots/basic.zsh b/clap_complete/tests/snapshots/basic.zsh index ad6c2aecab1..f7407180d8f 100644 --- a/clap_complete/tests/snapshots/basic.zsh +++ b/clap_complete/tests/snapshots/basic.zsh @@ -38,7 +38,6 @@ _arguments "${_arguments_options[@]}" / ;; (help) _arguments "${_arguments_options[@]}" / -'*-c[]' / ":: :_my-app__help_commands" / "*::: :->help" / && ret=0 @@ -51,12 +50,10 @@ _arguments "${_arguments_options[@]}" / case $line[1] in (test) _arguments "${_arguments_options[@]}" / -'*-c[]' / && ret=0 ;; (help) _arguments "${_arguments_options[@]}" / -'*-c[]' / && ret=0 ;; esac diff --git a/clap_complete_fig/tests/snapshots/basic.fig.js b/clap_complete_fig/tests/snapshots/basic.fig.js index e488df4bd7c..a8cd3fccde3 100644 --- a/clap_complete_fig/tests/snapshots/basic.fig.js +++ b/clap_complete_fig/tests/snapshots/basic.fig.js @@ -26,25 +26,10 @@ const completion: Fig.Spec = { { name: "test", description: "Subcommand", - options: [ - { - name: "-c", - }, - ], }, { name: "help", description: "Print this message or the help of the given subcommand(s)", - options: [ - { - name: "-c", - }, - ], - }, - ], - options: [ - { - name: "-c", }, ], }, diff --git a/src/builder/command.rs b/src/builder/command.rs index d4f6212ff8e..9e0a64e6d00 100644 --- a/src/builder/command.rs +++ b/src/builder/command.rs @@ -4070,7 +4070,17 @@ impl Command { pub(crate) fn _propagate_global_args(&mut self) { debug!("Command::_propagate_global_args:{}", self.name); + let autogenerated_help_subcommand = !self.is_disable_help_subcommand_set(); + for sc in &mut self.subcommands { + if sc.get_name() == "help" && autogenerated_help_subcommand { + // Avoid propagating args to the autogenerated help subtrees used in completion. + // This prevents args from showing up during help completions like + // `myapp help subcmd `, which should only suggest subcommands and not args, + // while still allowing args to show up properly on the generated help message. + continue; + } + for a in self.args.args().filter(|a| a.is_global_set()) { if sc.find(&a.id).is_some() { debug!( diff --git a/tests/builder/help.rs b/tests/builder/help.rs index 3224321c25a..ac68374da1f 100644 --- a/tests/builder/help.rs +++ b/tests/builder/help.rs @@ -2097,6 +2097,111 @@ Arguments: ); } +#[test] +fn global_args_should_show_on_toplevel_help_message() { + static HELP: &str = "myapp\x20 + +Usage: + myapp [OPTIONS] [SUBCOMMAND] + +Subcommands: + subcmd\x20\x20\x20\x20 + help Print this message or the help of the given subcommand(s) + +Options: + -g, --some-global \x20\x20\x20\x20 + -h, --help Print help information +"; + + let cmd = Command::new("myapp") + .arg( + Arg::new("someglobal") + .short('g') + .long("some-global") + .global(true), + ) + .subcommand(Command::new("subcmd").subcommand(Command::new("multi").version("1.0"))); + + utils::assert_output(cmd, "myapp help", HELP, false); +} + +#[test] +fn global_args_should_not_show_on_help_message_for_help_help() { + static HELP_HELP: &str = "myapp-help\x20 +Print this message or the help of the given subcommand(s) + +Usage: + myapp help [SUBCOMMAND]... + +Arguments: + [SUBCOMMAND]... The subcommand whose help message to display +"; + + let cmd = Command::new("myapp") + .arg( + Arg::new("someglobal") + .short('g') + .long("some-global") + .global(true), + ) + .subcommand(Command::new("subcmd").subcommand(Command::new("multi").version("1.0"))); + + utils::assert_output(cmd, "myapp help help", HELP_HELP, false); +} + +#[test] +fn global_args_should_show_on_help_message_for_subcommand() { + static HELP_SUBCMD: &str = "myapp-subcmd\x20 + +Usage: + myapp subcmd [OPTIONS] [SUBCOMMAND] + +Subcommands: + multi\x20\x20\x20\x20 + help Print this message or the help of the given subcommand(s) + +Options: + -g, --some-global \x20\x20\x20\x20 + -h, --help Print help information +"; + + let cmd = Command::new("myapp") + .arg( + Arg::new("someglobal") + .short('g') + .long("some-global") + .global(true), + ) + .subcommand(Command::new("subcmd").subcommand(Command::new("multi").version("1.0"))); + + utils::assert_output(cmd, "myapp help subcmd", HELP_SUBCMD, false); +} + +#[test] +fn global_args_should_show_on_help_message_for_nested_subcommand() { + static HELP_SUB_SUBCMD: &str = "myapp-subcmd-multi 1.0 + +Usage: + myapp subcmd multi [OPTIONS] + +Options: + -g, --some-global \x20\x20\x20\x20 + -h, --help Print help information + -V, --version Print version information +"; + + let cmd = Command::new("myapp") + .arg( + Arg::new("someglobal") + .short('g') + .long("some-global") + .global(true), + ) + .subcommand(Command::new("subcmd").subcommand(Command::new("multi").version("1.0"))); + + utils::assert_output(cmd, "myapp help subcmd multi", HELP_SUB_SUBCMD, false); +} + #[test] fn option_usage_order() { static OPTION_USAGE_ORDER: &str = "order