From 89f102a4b4617ceac91ab7fbd5ff33b1a37607b7 Mon Sep 17 00:00:00 2001 From: Samuel Kunst Date: Wed, 1 May 2024 12:48:11 +0200 Subject: [PATCH 1/2] feat: support flag descriptions for zsh completion --- help.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/help.go b/help.go index dc970009f0..82a4b76846 100644 --- a/help.go +++ b/help.go @@ -192,6 +192,11 @@ func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) { continue } + usage := "" + if docFlag, ok := flag.(DocGenerationFlag); ok { + usage = docFlag.GetUsage() + } + name := strings.TrimSpace(flag.Names()[0]) // this will get total count utf8 letters in flag name count := utf8.RuneCountInString(name) @@ -206,8 +211,10 @@ func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) { // match if last argument matches this flag and it is not repeated if strings.HasPrefix(name, cur) && cur != name && !cliArgContains(name) { flagCompletion := fmt.Sprintf("%s%s", strings.Repeat("-", count), name) + if usage != "" && strings.HasSuffix(os.Getenv("SHELL"), "zsh") { + flagCompletion = fmt.Sprintf("%s:%s", flagCompletion, usage) + } fmt.Fprintln(writer, flagCompletion) - } } } From fa5316efe923ade742a57d5f3d40733b53ce404b Mon Sep 17 00:00:00 2001 From: Samuel Kunst Date: Thu, 2 May 2024 17:02:35 +0200 Subject: [PATCH 2/2] test: add cases for checking flag usage output with zsh completion --- help_test.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/help_test.go b/help_test.go index db3d2eb34b..91612d1f35 100644 --- a/help_test.go +++ b/help_test.go @@ -1080,18 +1080,18 @@ func TestDefaultCompleteWithFlags(t *testing.T) { origArgv := os.Args t.Cleanup(func() { os.Args = origArgv }) - t.Setenv("SHELL", "bash") - for _, tc := range []struct { name string cmd *Command argv []string + env map[string]string expected string }{ { name: "empty", cmd: &Command{}, argv: []string{"prog", "cmd"}, + env: map[string]string{"SHELL": "bash"}, expected: "", }, { @@ -1113,6 +1113,7 @@ func TestDefaultCompleteWithFlags(t *testing.T) { }, }, argv: []string{"cmd", "--e", "--generate-shell-completion"}, + env: map[string]string{"SHELL": "bash"}, expected: "--excitement\n", }, { @@ -1135,6 +1136,7 @@ func TestDefaultCompleteWithFlags(t *testing.T) { }, }, argv: []string{"cmd", "--generate-shell-completion"}, + env: map[string]string{"SHELL": "bash"}, expected: "futz\n", }, { @@ -1157,8 +1159,49 @@ func TestDefaultCompleteWithFlags(t *testing.T) { }, }, argv: []string{"cmd", "--url", "http://localhost:8000", "h", "--generate-shell-completion"}, + env: map[string]string{"SHELL": "bash"}, expected: "help\n", }, + { + name: "zsh-autocomplete-with-flag-descriptions", + cmd: &Command{ + Name: "putz", + Flags: []Flag{ + &BoolFlag{Name: "excitement", Usage: "an exciting flag"}, + &StringFlag{Name: "hat-shape"}, + }, + parent: &Command{ + Name: "cmd", + Flags: []Flag{ + &BoolFlag{Name: "happiness"}, + &IntFlag{Name: "everybody-jump-on"}, + }, + }, + }, + argv: []string{"cmd", "putz", "-e", "--generate-shell-completion"}, + env: map[string]string{"SHELL": "zsh"}, + expected: "--excitement:an exciting flag\n", + }, + { + name: "zsh-autocomplete-with-empty-flag-descriptions", + cmd: &Command{ + Name: "putz", + Flags: []Flag{ + &BoolFlag{Name: "excitement"}, + &StringFlag{Name: "hat-shape"}, + }, + parent: &Command{ + Name: "cmd", + Flags: []Flag{ + &BoolFlag{Name: "happiness"}, + &IntFlag{Name: "everybody-jump-on"}, + }, + }, + }, + argv: []string{"cmd", "putz", "-e", "--generate-shell-completion"}, + env: map[string]string{"SHELL": "zsh"}, + expected: "--excitement\n", + }, } { t.Run(tc.name, func(ct *testing.T) { writer := &bytes.Buffer{} @@ -1166,6 +1209,9 @@ func TestDefaultCompleteWithFlags(t *testing.T) { rootCmd.Writer = writer os.Args = tc.argv + for k, v := range tc.env { + t.Setenv(k, v) + } f := DefaultCompleteWithFlags(tc.cmd) f(context.Background(), tc.cmd)