mirror of
https://github.com/max-sixty/worktrunk.git
synced 2026-09-14 20:00:38 +08:00
03dbf5f70e
## Problem `wt switch <branch>` reported a successful switch but then failed to change directory under fish when the [`kidonng/zoxide.fish`](https://github.com/kidonng/zoxide.fish) plugin is active, printing `zoxide: no match found` / `Error: Directory not found` even though the worktree exists (#3159). The fish integration changed directory with a bare `cd -- "$target"`. `zoxide.fish` replaces `cd` with a zoxide query function. With `cd -- "$target"` it receives two arguments (`--` and the path), so its single-directory fast path (`argc -eq 1`) is skipped and it falls through to fuzzy-query mode, which finds no match for `-- /path/to/worktree`. The bash and zsh wrappers were already immune because they use `builtin cd`; only fish used a bare `cd`. ## Solution Use `builtin cd -- "$target"` in `templates/fish.fish`, bypassing any user `cd` override (verified: in fish `cd` is a regular function that `builtin cd` skips). The `--` is retained for consistency with the bash/zsh wrappers; the target is an absolute path written by the binary, so it can never be flag-injected. ## Testing - Added `test_fish_init_uses_builtin_cd` in `src/shell/mod.rs`, which fails on the old template (`cd -- "$target"`) and passes after the fix. - Updated the fish init snapshots (`src/shell/snapshots/...init_fish.snap`, `tests/snapshots/...init_fish.snap`). - Verified fish `3.7.0` behavior directly: `cd` is a function, `builtin cd` and `builtin cd --` both succeed, and `builtin cd` bypasses a user-defined `cd` function (the simulated override was not invoked). - `cargo test --test integration test_docs_are_in_sync` passes. --- Closes #3159 — automated triage Co-authored-by: worktrunk-bot <worktrunk-bot@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Maximilian Roos <5635139+max-sixty@users.noreply.github.com>
68 lines
2.5 KiB
Fish
68 lines
2.5 KiB
Fish
# worktrunk shell integration for fish
|
|
#
|
|
# This is the full function definition, output by `{{ cmd }} config shell init fish`.
|
|
# It's sourced at runtime by the wrapper in ~/.config/fish/functions/{{ cmd }}.fish.
|
|
|
|
# Override {{ cmd }} command with split directive passing.
|
|
# Creates two temp files: one for cd (raw path) and one for exec (shell).
|
|
# WORKTRUNK_BIN can override the binary path (for testing dev builds).
|
|
function {{ cmd }}
|
|
set -l use_source false
|
|
set -l args
|
|
|
|
for arg in $argv
|
|
if test "$arg" = "--source"; set use_source true; else; set -a args $arg; end
|
|
end
|
|
|
|
test -n "$WORKTRUNK_BIN"; or set -l WORKTRUNK_BIN (type -P {{ cmd }} 2>/dev/null)
|
|
if test -z "$WORKTRUNK_BIN"
|
|
echo "{{ cmd }}: command not found" >&2
|
|
return 127
|
|
end
|
|
set -l cd_file (mktemp)
|
|
set -l exec_file (mktemp)
|
|
|
|
# WORKTRUNK_SHELL tells the binary to escape the exec directive for fish's
|
|
# `eval` below — fish treats `\` as an escape inside '...', unlike POSIX.
|
|
# --source: use cargo run (builds from source)
|
|
if test $use_source = true
|
|
env WORKTRUNK_DIRECTIVE_CD_FILE=$cd_file WORKTRUNK_DIRECTIVE_EXEC_FILE=$exec_file \
|
|
WORKTRUNK_SHELL=fish \
|
|
cargo run --bin {{ cmd }} --quiet -- $args
|
|
else
|
|
env WORKTRUNK_DIRECTIVE_CD_FILE=$cd_file WORKTRUNK_DIRECTIVE_EXEC_FILE=$exec_file \
|
|
WORKTRUNK_SHELL=fish \
|
|
$WORKTRUNK_BIN $args
|
|
end
|
|
set -l exit_code $status
|
|
|
|
# cd file holds a raw path — read with fish builtin (no cat subprocess,
|
|
# safe even if CWD was removed by worktree removal).
|
|
if test -s "$cd_file"
|
|
set -l target (string trim < "$cd_file")
|
|
# `builtin cd` bypasses any user `cd` override (e.g. the zoxide.fish
|
|
# plugin replaces `cd` with a query function that mishandles the `--`
|
|
# separator). Matches the bash/zsh wrappers. (#3159)
|
|
builtin cd -- "$target"
|
|
set -l cd_exit $status
|
|
if test $exit_code -eq 0
|
|
set exit_code $cd_exit
|
|
end
|
|
end
|
|
|
|
# exec file holds arbitrary shell (e.g. from --execute)
|
|
if test -s "$exec_file"
|
|
set -l directive (string collect < "$exec_file")
|
|
eval $directive
|
|
set -l src_exit $status
|
|
if test $exit_code -eq 0
|
|
set exit_code $src_exit
|
|
end
|
|
end
|
|
|
|
command rm -f "$cd_file" "$exec_file"
|
|
return $exit_code
|
|
end
|
|
|
|
# Completions are in ~/.config/fish/completions/{{ cmd }}.fish (installed by `{{ cmd }} config shell install`)
|