fix(help): Do not propagate global args to help

This prevents global args from showing in help completions,
since help completions should only suggest subcommands.
Adds tests to ensure the args still show in the generated
help messages of subcommands.
This commit is contained in:
Andrew Shu 2022-08-26 17:40:48 -07:00
parent 1f3df00388
commit eec047a6f6
8 changed files with 118 additions and 30 deletions

View file

@ -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

View file

@ -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]

View file

@ -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

View file

@ -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
}
})

View file

@ -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

View file

@ -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",
},
],
},

View file

@ -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 <TAB>`, 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!(

View file

@ -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 <someglobal>\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 <someglobal>\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 <someglobal>\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