From f9939edc79dc822360baa665ed372e9f905c5ffd Mon Sep 17 00:00:00 2001 From: Eslam Nasser Date: Fri, 15 May 2026 11:13:02 +0200 Subject: [PATCH 1/2] fix(shell): initialize zsh completions before registration --- cmd/wut/cmd_init.go | 9 ++++-- cmd/wut/cmd_init_test.go | 65 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 cmd/wut/cmd_init_test.go diff --git a/cmd/wut/cmd_init.go b/cmd/wut/cmd_init.go index e1a64a0..8546c6d 100644 --- a/cmd/wut/cmd_init.go +++ b/cmd/wut/cmd_init.go @@ -116,12 +116,15 @@ _wut_completions() { fi } -complete -F _wut_completions wut - # zsh completion if [[ -n ${ZSH_VERSION-} ]]; then + if (( ! $+functions[compdef] )); then + autoload -U +X compinit && compinit + fi autoload -U +X bashcompinit && bashcompinit -fi` +fi + +complete -F _wut_completions wut` fmt.Println(wrapper) } diff --git a/cmd/wut/cmd_init_test.go b/cmd/wut/cmd_init_test.go new file mode 100644 index 0000000..3bdc516 --- /dev/null +++ b/cmd/wut/cmd_init_test.go @@ -0,0 +1,65 @@ +package main + +import ( + "io" + "os" + "strings" + "testing" +) + +func TestCmdInitLoadsZshBashCompletionBeforeRegisteringCompletion(t *testing.T) { + output := captureStdout(t, cmdInit) + + compdefCheck := strings.Index(output, "if (( ! $+functions[compdef] )); then") + compinitSetup := strings.Index(output, " autoload -U +X compinit && compinit") + bashcompinitSetup := strings.Index(output, "autoload -U +X bashcompinit && bashcompinit") + registerCompletion := strings.Index(output, "complete -F _wut_completions wut") + + if compdefCheck == -1 { + t.Fatal("init output must check whether compdef is already available") + } + if compinitSetup == -1 { + t.Fatal("init output is missing zsh compinit setup") + } + if bashcompinitSetup == -1 { + t.Fatal("init output is missing zsh bashcompinit setup") + } + if registerCompletion == -1 { + t.Fatal("init output is missing completion registration") + } + if compdefCheck > compinitSetup { + t.Fatal("zsh compdef check must guard compinit setup") + } + if compinitSetup > bashcompinitSetup { + t.Fatal("zsh compinit setup must run before bashcompinit setup") + } + if bashcompinitSetup > registerCompletion { + t.Fatal("zsh bashcompinit setup must run before completion registration") + } +} + +func captureStdout(t *testing.T, fn func()) string { + t.Helper() + + originalStdout := os.Stdout + reader, writer, err := os.Pipe() + if err != nil { + t.Fatalf("create stdout pipe: %v", err) + } + defer func() { + os.Stdout = originalStdout + }() + + os.Stdout = writer + fn() + if err := writer.Close(); err != nil { + t.Fatalf("close stdout writer: %v", err) + } + + output, err := io.ReadAll(reader) + if err != nil { + t.Fatalf("read stdout: %v", err) + } + + return string(output) +} From d5526658e8fac01a13391951e4ba13f0a6773159 Mon Sep 17 00:00:00 2001 From: Eslam Nasser Date: Fri, 15 May 2026 11:20:53 +0200 Subject: [PATCH 2/2] fix(shell): detect incomplete zsh completion state --- cmd/wut/cmd_init.go | 2 +- cmd/wut/cmd_init_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/wut/cmd_init.go b/cmd/wut/cmd_init.go index 8546c6d..7c5ec84 100644 --- a/cmd/wut/cmd_init.go +++ b/cmd/wut/cmd_init.go @@ -118,7 +118,7 @@ _wut_completions() { # zsh completion if [[ -n ${ZSH_VERSION-} ]]; then - if (( ! $+functions[compdef] )); then + if (( ! $+functions[compdef] || ! $+parameters[_comps] )); then autoload -U +X compinit && compinit fi autoload -U +X bashcompinit && bashcompinit diff --git a/cmd/wut/cmd_init_test.go b/cmd/wut/cmd_init_test.go index 3bdc516..ee5d68d 100644 --- a/cmd/wut/cmd_init_test.go +++ b/cmd/wut/cmd_init_test.go @@ -10,13 +10,13 @@ import ( func TestCmdInitLoadsZshBashCompletionBeforeRegisteringCompletion(t *testing.T) { output := captureStdout(t, cmdInit) - compdefCheck := strings.Index(output, "if (( ! $+functions[compdef] )); then") + compdefCheck := strings.Index(output, "if (( ! $+functions[compdef] || ! $+parameters[_comps] )); then") compinitSetup := strings.Index(output, " autoload -U +X compinit && compinit") bashcompinitSetup := strings.Index(output, "autoload -U +X bashcompinit && bashcompinit") registerCompletion := strings.Index(output, "complete -F _wut_completions wut") if compdefCheck == -1 { - t.Fatal("init output must check whether compdef is already available") + t.Fatal("init output must check whether compdef and _comps are already available") } if compinitSetup == -1 { t.Fatal("init output is missing zsh compinit setup")