From bfa07661b12f7be60934a326ed998cdd6e0c2b11 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Mon, 19 Sep 2022 08:18:05 -0400 Subject: [PATCH] Include --help and --version flag in completion Fixes #1786 The --help, -h, --version and -v flags are normally added when the `execute()` function is called on a command. When doing completion we don't call `execute()` so we need to add these flags explicitly to the command being completed. Signed-off-by: Marc Khouzam --- completions.go | 6 ++++++ completions_test.go | 42 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/completions.go b/completions.go index f8bf4f69d..f89e1700c 100644 --- a/completions.go +++ b/completions.go @@ -274,6 +274,12 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi } finalCmd.ctx = c.ctx + // These flags are normally added when `execute()` is called on `finalCmd`, + // however, when doing completion, we don't call `finalCmd.execute()`. + // Let's add the --help and --version flag ourselves. + finalCmd.InitDefaultHelpFlag() + finalCmd.InitDefaultVersionFlag() + // Check if we are doing flag value completion before parsing the flags. // This is important because if we are completing a flag value, we need to also // remove the flag name argument from the list of finalArgs or else the parsing diff --git a/completions_test.go b/completions_test.go index c5f11fa52..aa4657e94 100644 --- a/completions_test.go +++ b/completions_test.go @@ -493,8 +493,9 @@ func TestFlagNameCompletionInGo(t *testing.T) { Run: emptyRun, } childCmd := &Command{ - Use: "childCmd", - Run: emptyRun, + Use: "childCmd", + Version: "1.2.3", + Run: emptyRun, } rootCmd.AddCommand(childCmd) @@ -528,6 +529,8 @@ func TestFlagNameCompletionInGo(t *testing.T) { expected = strings.Join([]string{ "--first", "-f", + "--help", + "-h", "--second", "-s", ":4", @@ -561,7 +564,11 @@ func TestFlagNameCompletionInGo(t *testing.T) { expected = strings.Join([]string{ "--second", "-s", + "--help", + "-h", "--subFlag", + "--version", + "-v", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") @@ -576,9 +583,10 @@ func TestFlagNameCompletionInGoWithDesc(t *testing.T) { Run: emptyRun, } childCmd := &Command{ - Use: "childCmd", - Short: "first command", - Run: emptyRun, + Use: "childCmd", + Short: "first command", + Version: "1.2.3", + Run: emptyRun, } rootCmd.AddCommand(childCmd) @@ -612,6 +620,8 @@ func TestFlagNameCompletionInGoWithDesc(t *testing.T) { expected = strings.Join([]string{ "--first\tfirst flag", "-f\tfirst flag", + "--help\thelp for root", + "-h\thelp for root", "--second\tsecond flag", "-s\tsecond flag", ":4", @@ -645,7 +655,11 @@ func TestFlagNameCompletionInGoWithDesc(t *testing.T) { expected = strings.Join([]string{ "--second\tsecond flag", "-s\tsecond flag", + "--help\thelp for childCmd", + "-h\thelp for childCmd", "--subFlag\tsub flag", + "--version\tversion for childCmd", + "-v\tversion for childCmd", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") @@ -688,6 +702,7 @@ func TestFlagNameCompletionRepeat(t *testing.T) { expected := strings.Join([]string{ "--array", "--bslice", + "--help", "--second", "--slice", ":4", @@ -709,6 +724,7 @@ func TestFlagNameCompletionRepeat(t *testing.T) { expected = strings.Join([]string{ "--array", "--bslice", + "--help", "--slice", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") @@ -731,6 +747,7 @@ func TestFlagNameCompletionRepeat(t *testing.T) { "--array", "--bslice", "--first", + "--help", "--second", "--slice", ":4", @@ -756,6 +773,8 @@ func TestFlagNameCompletionRepeat(t *testing.T) { "-b", "--first", "-f", + "--help", + "-h", "--second", "-s", "--slice", @@ -1792,6 +1811,7 @@ func TestFlagCompletionWithNotInterspersedArgs(t *testing.T) { expected := strings.Join([]string{ "--bool\ttest bool flag", + "--help\thelp for child", "--string\ttest string flag", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n") @@ -2602,6 +2622,8 @@ func TestCompleteWithDisableFlagParsing(t *testing.T) { expected := strings.Join([]string{ "--persistent", "-p", + "--help", + "-h", "--nonPersistent", "-n", "--flag", @@ -2624,6 +2646,8 @@ func TestCompleteWithDisableFlagParsing(t *testing.T) { expected = strings.Join([]string{ "--persistent", "-p", + "--help", + "-h", "--nonPersistent", "-n", ":4", @@ -2753,6 +2777,8 @@ func TestCompletionForGroupedFlags(t *testing.T) { expectedOutput: strings.Join([]string{ "--ingroup1", "--ingroup2", + "--help", + "-h", "--ingroup3", "--nogroup", ":4", @@ -2851,6 +2877,8 @@ func TestCompletionForMutuallyExclusiveFlags(t *testing.T) { expectedOutput: strings.Join([]string{ "--ingroup1", "--ingroup2", + "--help", + "-h", "--ingroup3", "--nogroup", ":4", @@ -2861,6 +2889,8 @@ func TestCompletionForMutuallyExclusiveFlags(t *testing.T) { args: []string{"child", "--ingroup1", "8", "-"}, expectedOutput: strings.Join([]string{ "--ingroup1", // Should be suggested again since it is a slice + "--help", + "-h", "--nogroup", ":4", "Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"), @@ -2869,6 +2899,8 @@ func TestCompletionForMutuallyExclusiveFlags(t *testing.T) { desc: "group ignored if some flags not applicable", args: []string{"--ingroup1", "8", "-"}, expectedOutput: strings.Join([]string{ + "--help", + "-h", "--ingroup1", "--ingroup2", ":4",