From 037f526bfbff56e491ab0443b86e6ed4d03316cf Mon Sep 17 00:00:00 2001 From: Juri Pakaste Date: Sun, 1 Feb 2026 08:44:32 +0200 Subject: [PATCH 1/4] Add support for fish --- README.md | 8 ++++- cmd/wut/cmd_init.go | 75 ++++++++++++++++++++++++++++++++++++++++++++- cmd/wut/main.go | 2 +- 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a92b90c..0309369 100644 --- a/README.md +++ b/README.md @@ -42,12 +42,18 @@ brew tap simonbs/wut https://github.com/simonbs/wut.git brew install wut ``` -You'll need Git on your machine. After installation, add shell integration to your `~/.zshrc` or `~/.bashrc`: +You'll need Git on your machine. After installation, add shell integration: +**Bash/Zsh** - Add to `~/.bashrc` or `~/.zshrc`: ```sh eval "$(wut init)" ``` +**Fish** - Add to `~/.config/fish/config.fish`: +```fish +wut init | source +``` + This enables automatic directory changing when you run `wut new` or `wut go`. Without it, these commands will prompt you to set up shell integration. ## 🧭 Usage diff --git a/cmd/wut/cmd_init.go b/cmd/wut/cmd_init.go index b7c44e1..82d6f33 100644 --- a/cmd/wut/cmd_init.go +++ b/cmd/wut/cmd_init.go @@ -3,13 +3,50 @@ package main import ( "fmt" "os" + "strings" "github.com/simonbs/wut/src/context" "github.com/simonbs/wut/src/worktree" ) -func cmdInit() { +func detectShell() string { + shell := os.Getenv("SHELL") + if strings.Contains(shell, "fish") { + return "fish" + } + if strings.Contains(shell, "zsh") { + return "zsh" + } + return "bash" +} + +func cmdInit(args []string) { + shell := "" + for _, arg := range args { + switch arg { + case "--fish": + shell = "fish" + case "--bash": + shell = "bash" + case "--zsh": + shell = "zsh" + } + } + if shell == "" { + shell = detectShell() + } + binPath, _ := os.Executable() + + switch shell { + case "fish": + printFishWrapper(binPath) + default: + printBashZshWrapper(binPath) + } +} + +func printBashZshWrapper(binPath string) { wrapper := `wut() { local wut_bin="` + binPath + `" export WUT_WRAPPER_ACTIVE=1 @@ -63,6 +100,42 @@ fi` fmt.Println(wrapper) } +func printFishWrapper(binPath string) { + wrapper := `function wut + set -l wut_bin "` + binPath + `" + set -x WUT_WRAPPER_ACTIVE 1 + set -l output ($wut_bin $argv 2>&1) + set -l exit_code $status + set -l cd_marker (echo "$output" | grep "^__WUT_CD__:" | head -1) + if test -n "$cd_marker" + set -l target_dir (string replace "__WUT_CD__:" "" "$cd_marker") + if test -d "$target_dir" + cd "$target_dir" + end + set -l filtered (printf "%s" "$output" | grep -v "^__WUT_CD__:") + if test -n "$filtered" + printf "%s\n" "$filtered" + end + else + if test -n "$output" + printf "%s\n" "$output" + end + end + return $exit_code +end + +# Subcommands +complete -c wut -f -n "__fish_use_subcommand" -a "new" -d "Create new worktree" +complete -c wut -f -n "__fish_use_subcommand" -a "list" -d "List worktrees" +complete -c wut -f -n "__fish_use_subcommand" -a "go" -d "Go to worktree" +complete -c wut -f -n "__fish_use_subcommand" -a "path" -d "Print worktree path" +complete -c wut -f -n "__fish_use_subcommand" -a "rm" -d "Remove worktree" + +# Branch completions for go/path/rm +complete -c wut -f -n "__fish_seen_subcommand_from go path rm" -a "(` + binPath + ` --completions branches 2>/dev/null)"` + fmt.Println(wrapper) +} + func cmdCompletions(args []string) { if len(args) < 1 { return diff --git a/cmd/wut/main.go b/cmd/wut/main.go index 5744d3f..2789540 100644 --- a/cmd/wut/main.go +++ b/cmd/wut/main.go @@ -18,7 +18,7 @@ func main() { switch cmd { case "init": - cmdInit() + cmdInit(args) case "new": cmdNew(args) case "list": From 01eac634b7f12cf111ad3cef6b637f1d0e6c3873 Mon Sep 17 00:00:00 2001 From: Juri Pakaste Date: Sun, 1 Feb 2026 09:11:38 +0200 Subject: [PATCH 2/4] Detect shell for help message --- cmd/wut/cmd_init.go | 12 ------------ cmd/wut/help.go | 18 ++++++++++++++++-- cmd/wut/utils.go | 11 +++++++++++ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/cmd/wut/cmd_init.go b/cmd/wut/cmd_init.go index 82d6f33..9d7a472 100644 --- a/cmd/wut/cmd_init.go +++ b/cmd/wut/cmd_init.go @@ -3,23 +3,11 @@ package main import ( "fmt" "os" - "strings" "github.com/simonbs/wut/src/context" "github.com/simonbs/wut/src/worktree" ) -func detectShell() string { - shell := os.Getenv("SHELL") - if strings.Contains(shell, "fish") { - return "fish" - } - if strings.Contains(shell, "zsh") { - return "zsh" - } - return "bash" -} - func cmdInit(args []string) { shell := "" for _, arg := range args { diff --git a/cmd/wut/help.go b/cmd/wut/help.go index 23655db..d81d9e5 100644 --- a/cmd/wut/help.go +++ b/cmd/wut/help.go @@ -31,9 +31,23 @@ func printUsage() { fmt.Println(" wut rm [--force] 🗑 Remove a worktree") if !context.IsWrapperActive() { + dotfile := "" + command := "" + switch detectShell() { + case "bash": + dotfile = "~/.bashrc" + command = "eval \"$(wut init)\"" + case "fish": + dotfile = "~/.config/fish/config.fish" + command = "wut init | source" + case "zsh": + dotfile = "~/.zshrc" + command = "eval \"$(wut init)\"" + } + fmt.Println() - fmt.Println("⚠️ Add shell integration to ~/.zshrc or ~/.bashrc:") + fmt.Println("⚠️ Add shell integration to " + dotfile + ":") fmt.Println() - fmt.Println(" eval \"$(wut init)\"") + fmt.Println(" " + command) } } diff --git a/cmd/wut/utils.go b/cmd/wut/utils.go index 3c07f96..7db4275 100644 --- a/cmd/wut/utils.go +++ b/cmd/wut/utils.go @@ -18,3 +18,14 @@ func tildify(path string) string { } return path } + +func detectShell() string { + shell := os.Getenv("SHELL") + if strings.Contains(shell, "fish") { + return "fish" + } + if strings.Contains(shell, "zsh") { + return "zsh" + } + return "bash" +} From 1eac8a6d963782293242c074a4fe75696b66e15d Mon Sep 17 00:00:00 2001 From: Juri Pakaste Date: Sun, 1 Feb 2026 11:59:59 +0200 Subject: [PATCH 3/4] Fix fish function output to keep newlines --- cmd/wut/cmd_init.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/wut/cmd_init.go b/cmd/wut/cmd_init.go index 9d7a472..848e60f 100644 --- a/cmd/wut/cmd_init.go +++ b/cmd/wut/cmd_init.go @@ -94,19 +94,19 @@ func printFishWrapper(binPath string) { set -x WUT_WRAPPER_ACTIVE 1 set -l output ($wut_bin $argv 2>&1) set -l exit_code $status - set -l cd_marker (echo "$output" | grep "^__WUT_CD__:" | head -1) + set -l cd_marker (printf "%s\n" $output | grep "^__WUT_CD__:" | head -1) if test -n "$cd_marker" set -l target_dir (string replace "__WUT_CD__:" "" "$cd_marker") if test -d "$target_dir" cd "$target_dir" end - set -l filtered (printf "%s" "$output" | grep -v "^__WUT_CD__:") + set -l filtered (printf "%s\n" $output | grep -v "^__WUT_CD__:") if test -n "$filtered" - printf "%s\n" "$filtered" + printf "%s\n" $filtered end else - if test -n "$output" - printf "%s\n" "$output" + if test (count $output) -gt 0 + printf "%s\n" $output end end return $exit_code From 986ea4dd6a0e9fec561506c80c4d421f4d11d3b7 Mon Sep 17 00:00:00 2001 From: Juri Pakaste Date: Sun, 1 Feb 2026 12:04:33 +0200 Subject: [PATCH 4/4] Document wut init parameters in README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0309369..410e91d 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,8 @@ eval "$(wut init)" wut init | source ``` +`wut init` uses the `$SHELL` environment variable to detect the shell. You can pass in `--zsh`, `--bash` or `--fish` to override the autodetection. + This enables automatic directory changing when you run `wut new` or `wut go`. Without it, these commands will prompt you to set up shell integration. ## 🧭 Usage