From f89647bd19dac132bbf382f3377bcdee022ae791 Mon Sep 17 00:00:00 2001 From: Ihor Urazov Date: Thu, 14 Jan 2021 21:14:32 +0200 Subject: [PATCH 1/4] Simplify zsh completion Completion file shouldn't be sourced. It should provide only completion code (source of _command) for command. It's task for package manager or user to put under $fpath. --- autocomplete/zsh_autocomplete | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/autocomplete/zsh_autocomplete b/autocomplete/zsh_autocomplete index cf39c888af..b3872bf1ac 100644 --- a/autocomplete/zsh_autocomplete +++ b/autocomplete/zsh_autocomplete @@ -1,23 +1,16 @@ #compdef $PROG -_cli_zsh_autocomplete() { +local -a opts +local cur +cur=${words[-1]} +if [[ "$cur" == "-"* ]]; then + opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}") +else + opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}") +fi - local -a opts - local cur - cur=${words[-1]} - if [[ "$cur" == "-"* ]]; then - opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}") - else - opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}") - fi - - if [[ "${opts[1]}" != "" ]]; then - _describe 'values' opts - else - _files - fi - - return -} - -compdef _cli_zsh_autocomplete $PROG +if [[ "${opts[1]}" != "" ]]; then + _describe 'values' opts +else + _files +fi From 1150c2e180e571fc3460db4c67bac76bf67cbd80 Mon Sep 17 00:00:00 2001 From: Ihor Urazov Date: Fri, 29 Jan 2021 17:04:54 +0200 Subject: [PATCH 2/4] Properly detect Zsh shell There is no need to define custom shell var, when Zsh can be detected by checking SHELL env var. --- app_test.go | 2 +- autocomplete/zsh_autocomplete | 4 ++-- docs/v2/manual.md | 9 ++++----- help.go | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/app_test.go b/app_test.go index 76e211d681..6afc681a83 100644 --- a/app_test.go +++ b/app_test.go @@ -355,7 +355,7 @@ func ExampleApp_Run_bashComplete() { func ExampleApp_Run_zshComplete() { // set args for examples sake os.Args = []string{"greet", "--generate-bash-completion"} - _ = os.Setenv("_CLI_ZSH_AUTOCOMPLETE_HACK", "1") + _ = os.Setenv("SHELL", "/usr/bin/zsh") app := NewApp() app.Name = "greet" diff --git a/autocomplete/zsh_autocomplete b/autocomplete/zsh_autocomplete index b3872bf1ac..ee1b562743 100644 --- a/autocomplete/zsh_autocomplete +++ b/autocomplete/zsh_autocomplete @@ -4,9 +4,9 @@ local -a opts local cur cur=${words[-1]} if [[ "$cur" == "-"* ]]; then - opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}") + opts=("${(@f)$(${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}") else - opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}") + opts=("${(@f)$(${words[@]:0:#words[@]-1} --generate-bash-completion)}") fi if [[ "${opts[1]}" != "" ]]; then diff --git a/docs/v2/manual.md b/docs/v2/manual.md index 56be65bb68..27b5c62e1f 100644 --- a/docs/v2/manual.md +++ b/docs/v2/manual.md @@ -1211,14 +1211,13 @@ func main() { #### ZSH Support Auto-completion for ZSH is also supported using the `autocomplete/zsh_autocomplete` -file included in this repo. Two environment variables are used, `PROG` and `_CLI_ZSH_AUTOCOMPLETE_HACK`. -Set `PROG` to the program name as before, set `_CLI_ZSH_AUTOCOMPLETE_HACK` to `1`, and -then `source path/to/autocomplete/zsh_autocomplete`. Adding the following lines to your ZSH -configuration file (usually `.zshrc`) will allow the auto-completion to persist across new shells: +file included in this repo. One environment variable is used, `PROG`. Set +`PROG` to the program name as before, and then `source path/to/autocomplete/zsh_autocomplete`. +Adding the following lines to your ZSH configuration file (usually `.zshrc`) +will allow the auto-completion to persist across new shells: ``` PROG= -_CLI_ZSH_AUTOCOMPLETE_HACK=1 source path/to/autocomplete/zsh_autocomplete ``` #### ZSH default auto-complete example diff --git a/help.go b/help.go index 0a421ee99a..a7b3a944a2 100644 --- a/help.go +++ b/help.go @@ -102,7 +102,7 @@ func printCommandSuggestions(commands []*Command, writer io.Writer) { if command.Hidden { continue } - if os.Getenv("_CLI_ZSH_AUTOCOMPLETE_HACK") == "1" { + if strings.Contains(os.Getenv("SHELL"), "zsh") { for _, name := range command.Names() { _, _ = fmt.Fprintf(writer, "%s:%s\n", name, command.Usage) } From f3ef95f8ccf8a8d98d87a61009ff8690b0a7bf4a Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 30 Apr 2022 14:16:54 -0400 Subject: [PATCH 3/4] Tighten up restriction on SHELL match --- help.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/help.go b/help.go index 1455689310..4b03abea1d 100644 --- a/help.go +++ b/help.go @@ -102,7 +102,7 @@ func printCommandSuggestions(commands []*Command, writer io.Writer) { if command.Hidden { continue } - if strings.Contains(os.Getenv("SHELL"), "zsh") { + if strings.HasSuffix(os.Getenv("SHELL"), "zsh") { for _, name := range command.Names() { _, _ = fmt.Fprintf(writer, "%s:%s\n", name, command.Usage) } From e66017d73a69165ac6216f85dffed3d2cc78c68c Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 22 May 2022 09:07:03 -0400 Subject: [PATCH 4/4] Refinements to removal of zsh hack --- app_test.go | 5 ++++- autocomplete/zsh_autocomplete | 30 +++++++++++++++++------------- docs/v2/manual.md | 8 ++++---- help_test.go | 4 ++++ 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/app_test.go b/app_test.go index 5f20078f88..26ae28a95c 100644 --- a/app_test.go +++ b/app_test.go @@ -228,6 +228,7 @@ func ExampleApp_Run_subcommandNoAction() { } func ExampleApp_Run_bashComplete_withShortFlag() { + os.Setenv("SHELL", "bash") os.Args = []string{"greet", "-", "--generate-bash-completion"} app := NewApp() @@ -255,6 +256,7 @@ func ExampleApp_Run_bashComplete_withShortFlag() { } func ExampleApp_Run_bashComplete_withLongFlag() { + os.Setenv("SHELL", "bash") os.Args = []string{"greet", "--s", "--generate-bash-completion"} app := NewApp() @@ -283,6 +285,7 @@ func ExampleApp_Run_bashComplete_withLongFlag() { // --similar-flag } func ExampleApp_Run_bashComplete_withMultipleLongFlag() { + os.Setenv("SHELL", "bash") os.Args = []string{"greet", "--st", "--generate-bash-completion"} app := NewApp() @@ -315,7 +318,7 @@ func ExampleApp_Run_bashComplete_withMultipleLongFlag() { } func ExampleApp_Run_bashComplete() { - // set args for examples sake + os.Setenv("SHELL", "bash") os.Args = []string{"greet", "--generate-bash-completion"} app := &App{ diff --git a/autocomplete/zsh_autocomplete b/autocomplete/zsh_autocomplete index ee1b562743..b519666f80 100644 --- a/autocomplete/zsh_autocomplete +++ b/autocomplete/zsh_autocomplete @@ -1,16 +1,20 @@ #compdef $PROG -local -a opts -local cur -cur=${words[-1]} -if [[ "$cur" == "-"* ]]; then - opts=("${(@f)$(${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}") -else - opts=("${(@f)$(${words[@]:0:#words[@]-1} --generate-bash-completion)}") -fi +_cli_zsh_autocomplete() { + local -a opts + local cur + cur=${words[-1]} + if [[ "$cur" == "-"* ]]; then + opts=("${(@f)$(${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}") + else + opts=("${(@f)$(${words[@]:0:#words[@]-1} --generate-bash-completion)}") + fi -if [[ "${opts[1]}" != "" ]]; then - _describe 'values' opts -else - _files -fi + if [[ "${opts[1]}" != "" ]]; then + _describe 'values' opts + else + _files + fi +} + +compdef _cli_zsh_autocomplete $PROG diff --git a/docs/v2/manual.md b/docs/v2/manual.md index 3d96bb86cc..fd5656a569 100644 --- a/docs/v2/manual.md +++ b/docs/v2/manual.md @@ -1165,10 +1165,10 @@ func main() { ``` #### ZSH Support -Auto-completion for ZSH is also supported using the `autocomplete/zsh_autocomplete` -file included in this repo. One environment variable is used, `PROG`. Set -`PROG` to the program name as before, and then `source path/to/autocomplete/zsh_autocomplete`. -Adding the following lines to your ZSH configuration file (usually `.zshrc`) +Auto-completion for ZSH is also supported using the `autocomplete/zsh_autocomplete` +file included in this repo. One environment variable is used, `PROG`. Set +`PROG` to the program name as before, and then `source path/to/autocomplete/zsh_autocomplete`. +Adding the following lines to your ZSH configuration file (usually `.zshrc`) will allow the auto-completion to persist across new shells: ``` diff --git a/help_test.go b/help_test.go index 98530dd2a6..17a263deb6 100644 --- a/help_test.go +++ b/help_test.go @@ -1040,12 +1040,16 @@ func TestHideHelpCommand_WithSubcommands(t *testing.T) { } func TestDefaultCompleteWithFlags(t *testing.T) { + origEnv := os.Environ() origArgv := os.Args t.Cleanup(func() { os.Args = origArgv + resetEnv(origEnv) }) + os.Setenv("SHELL", "bash") + for _, tc := range []struct { name string c *Context