From f93f9844dc3ffd987379dc78d2d7733924846994 Mon Sep 17 00:00:00 2001 From: rootiest Date: Mon, 11 May 2026 23:22:18 -0400 Subject: [PATCH 1/5] build(ignore): add case-insensitive patterns for local testing and temporary files Consolidates and expands the .gitignore to ignore various temporary and testing directories. This allows for local experimentation with new ideas and the preservation of disabled functions without the risk of accidentally committing them to the repository. --- .gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index ac7181e..be064e2 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,10 @@ OLD/ # Auto-managed by fish; contains machine-local state and universal vars fish_variables .claude + +# Personal testing/temporary files +[Tt][Mm][Pp]/ +[Tt][Ee][Mm][Pp]/ +[Tt][Ee][Mm][Pp][Oo][Rr][Aa][Rr][Yy]/ +[Tt][Ee][Ss][Tt][Ii][Nn][Gg]/ +[Dd][Ee][Bb][Uu][Gg]/ -- 2.52.0 From 2e3230974cbf5a67a13717d439da3a3bc54d6098 Mon Sep 17 00:00:00 2001 From: rootiest Date: Mon, 11 May 2026 23:26:33 -0400 Subject: [PATCH 2/5] feat(completions): unify cd/z completions across CWD, CDPATH, and zoxide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous to this commit, tab completion and auto-suggestions for cd/z were inconsistent — only one or two of: CWD, CDPATH, and zoxide frecency results would work at a time, with different sourced matches shown in tab completion, shown in auto-suggest, and execution after pressing . - Add _zoxide_z_complete in functions/zoxide.fish that merges all three sources into a single completion list (CWD via __fish_complete_cd, CDPATH via __fish_complete_directories, zoxide via query -l capped at 25) - Wire the new completer to both z and cd via complete directives in conf.d/zoxide.fish, replacing the previous incomplete approach - Add completions/zoxide.fish for full tab completion of the zoxide CLI itself (add, query, remove, import, init subcommands) - Update README to document the unified completion behavior and fix structural issues in Personalization/Attribution/Dependencies sections --- README.md | 20 ++++-- completions/zoxide.fish | 41 +++++++++++ conf.d/zoxide.fish | 152 +++++++++++++++------------------------- functions/zoxide.fish | 45 ++++++++++++ 4 files changed, 158 insertions(+), 100 deletions(-) create mode 100644 completions/zoxide.fish create mode 100644 functions/zoxide.fish diff --git a/README.md b/README.md index f61a3b2..e9d3f62 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ A feature-rich Fish shell configuration for CachyOS (Arch Linux), built around a - [Dependencies](#dependencies) - [Installation](#installation) - [Personalization](#personalization) -- [Full Requirements](#full-requirements) +- [Attribution](#attribution) - [License](#license) --- @@ -107,7 +107,14 @@ See [FZF Bindings](#fzf-bindings) under Key Bindings for the default FZF shortcu ### Zoxide -Smart `cd` replacement. `cd` (or `z`) `` jumps to the best frecency match; `cdi` (or `zi`) opens an interactive selector. +Smart `cd` replacement powered by frecency scoring. `cd`, `z`, and `cdi`/`zi` are all mapped to zoxide-backed navigation functions. + +| Command | Description | +|---|---| +| `cd ` / `z ` | Jump to a matching directory by frecency; falls back to exact path | +| `cdi` / `zi` | Open an interactive fzf selector across all frecency-ranked directories | + +Tab completions for `cd` and `z` blend standard directory entries (CWD and `CDPATH`) with zoxide frecency results, so familiar paths and frequently-visited destinations appear together in a single list. Full tab completions for the `zoxide` CLI itself (subcommands: `add`, `query`, `remove`, `import`, `init`) are provided via `completions/zoxide.fish`. ### DirEnv @@ -493,6 +500,10 @@ Named context shortcuts (e.g. `dcr`, `dck`) live in `~/.config/.user-dots/fish/l | [Kitty](https://sw.kovidgoyal.net/kitty/) / [WezTerm](https://wezfurlong.org/wezterm/) | Terminal emulator | | [WakaTime](https://wakatime.com/) | Activity tracking | +### Full Requirements + +For a complete, categorized list of all non-standard tools required or used by this configuration, see [requirements.md](requirements.md). + --- ## Installation @@ -512,7 +523,6 @@ Then open a new Fish shell — Fisher and all plugins will be installed automati A [chezmoi](https://www.chezmoi.io/) dotfile manager is also configured — secrets are sourced from `~/.config/.user-dots/fish/secrets.fish` and excluded from version control. --- - ## Personalization Sensitive credentials and machine-specific paths are kept out of version control via a secondary private directory at `~/.config/.user-dots/fish/`. Two files are sourced automatically by `config.fish` if they exist: @@ -585,9 +595,9 @@ end --- -## Full Requirements +## Attribution -For a complete, categorized list of all non-standard tools required or used by this configuration, see [requirements.md](requirements.md). +The core of the [Zoxide integration](#zoxide) in this repository was originally adapted from the [icezyclon/zoxide.fish](https://github.com/icezyclon/zoxide.fish) plugin (MIT Licensed) and has since been heavily customized for performance and Fish 4.x compatibility. --- diff --git a/completions/zoxide.fish b/completions/zoxide.fish new file mode 100644 index 0000000..3c2dad7 --- /dev/null +++ b/completions/zoxide.fish @@ -0,0 +1,41 @@ +set -l commands add help import init query remove + +# disable normal all-files completion +complete -c zoxide -f + +# onyl show base options if none was used already +complete -c zoxide -n __fish_use_subcommand -a add -d "Add a new directory or increment its rank" +complete -c zoxide -n __fish_use_subcommand -a help -d "Prints this message or the help of the given subcommand(s)" +complete -c zoxide -n __fish_use_subcommand -a import -d "Import from z database" +complete -c zoxide -n __fish_use_subcommand -a init -d "Generates shell configuration" +complete -c zoxide -n __fish_use_subcommand -a query -d "Search for a directory" +complete -c zoxide -n __fish_use_subcommand -a remove -d "Remove a directory" + +# zoxide add +complete -c zoxide -n "_zoxide_equals_first_token add" -n "__fish_is_nth_token 2" -a "(__fish_complete_directories)" + +# zoxide help +complete -c zoxide -n "_zoxide_equals_first_token help" -n "__fish_is_nth_token 2" -a "$commands" + +# zoxide import +complete -c zoxide -r -F -n "_zoxide_equals_first_token import" -n "__fish_is_nth_token 2" +complete -c zoxide -r -n "_zoxide_equals_first_token import" -l merge -d "Merge entries into existing database" + +# zoxide init +set -l initshells bash fish posix powershell zsh +complete -c zoxide -n "_zoxide_equals_first_token init" -n "__fish_is_nth_token 2" -a "$initshells" +complete -c zoxide -n "_zoxide_equals_first_token init" -l cmd -d "Renames the 'z' command and corresponding aliases [default: z]" +complete -c zoxide -n "_zoxide_equals_first_token init" -l hook -a "none prompt pwd" -d "Chooses event on which an entry is added to the database [default: pwd]" +complete -c zoxide -n "_zoxide_equals_first_token init" -l no-aliases -d "Prevents zoxide from defining any commands other than 'z'" + +# zoxide query +complete -c zoxide -r -n "_zoxide_equals_first_token query" -s i -l interactive -d "Opens an interactive selection menu using fzf" +complete -c zoxide -r -n "_zoxide_equals_first_token query" -s l -l list -d "List all matching directories" +complete -c zoxide -r -n "_zoxide_equals_first_token query" -s s -l score -d "Display score along with result" + +# zoxide remove +complete -c zoxide -n "_zoxide_equals_first_token remove" -n "__fish_is_nth_token 2" -a "(zoxide query -l)" + +# Always possible +complete -c zoxide -x -s h -l help -d "Prints help information" +complete -c zoxide -x -s V -l version -d "Prints version information" diff --git a/conf.d/zoxide.fish b/conf.d/zoxide.fish index 17f7e62..6e041df 100644 --- a/conf.d/zoxide.fish +++ b/conf.d/zoxide.fish @@ -1,106 +1,68 @@ -# ============================================================================= -# -# -# Utility functions for zoxide. -# +# Adapted from icezyclon/zoxide.fish (MIT) +# Heavily customized for Fish 4.x compatibility and performance -if not type -q zoxide - return -end +if status is-interactive -# pwd based on the value of _ZO_RESOLVE_SYMLINKS. -function __zoxide_pwd - builtin pwd -L -end + if type -q zoxide -# A copy of fish's internal cd function. This makes it possible to use -# `alias cd=z` without causing an infinite loop. -if ! builtin functions --query __zoxide_cd_internal - string replace --regex -- '^function cd\s' 'function __zoxide_cd_internal ' <$__fish_data_dir/functions/cd.fish | source -end + # ------------- + # 'zoxide init fish' is very different for different versions of zoxide + # to guarantee the same behavior we define these functions ourself, + # especially because the apt package is so old + # most of these functions were taken from https://github.com/ajeetdsouza/zoxide + # from version 0.8.1 -# cd + custom logic based on the value of _ZO_ECHO. -function __zoxide_cd - if set -q __zoxide_loop - builtin echo "zoxide: infinite loop detected" - builtin echo "Avoid aliasing `cd` to `z` directly, use `zoxide init --cmd=cd fish` instead" - return 1 - end - __zoxide_loop=1 __zoxide_cd_internal $argv -end + if ! builtin functions -q _zoxide_cd + if builtin functions -q cd + builtin functions -c cd _zoxide_cd + else + alias _zoxide_cd='builtin cd' + end + end -# ============================================================================= -# -# Hook configuration for zoxide. -# + function _zoxide_hook --on-variable PWD + test -z "$fish_private_mode" + and command zoxide add -- (builtin pwd -L) + end -# Initialize hook to add new entries to the database. -function __zoxide_hook --on-variable PWD - test -z "$fish_private_mode" - and command zoxide add -- (__zoxide_pwd) -end + function z + set argc (count $argv) + if test $argc -eq 0 + _zoxide_cd $HOME + else if test "$argv" = - + _zoxide_cd - + else if test -d $argv[-1] + _zoxide_cd $argv[-1] + else + set -l result (command zoxide query $argv) + and _zoxide_cd $result + end + end -# ============================================================================= -# -# When using zoxide with --no-cmd, alias these internal functions as desired. -# + function zi + set -l result (command zoxide query -i -- $argv) + and _zoxide_cd $result + end -# Jump to a directory using only keywords. -function __zoxide_z - set -l argc (builtin count $argv) - if test $argc -eq 0 - __zoxide_cd $HOME - else if test "$argv" = - - __zoxide_cd - - else if test $argc -eq 1 -a -d $argv[1] - __zoxide_cd $argv[1] - else if test $argc -eq 2 -a $argv[1] = -- - __zoxide_cd -- $argv[2] + # ------------- + + alias cd=z + + # use custom completion + complete -c z -f # disable files by default + complete -c z -x -a '(_zoxide_z_complete)' else - set -l result (command zoxide query --exclude (__zoxide_pwd) -- $argv) - and __zoxide_cd $result + echo "[plugin: zoxide] Command 'zoxide' cannot be found. Not installed or not in path" + end + +end + +function _zoxide_uninstall --on-event zoxide_uninstall + if alias | grep "alias cd z" >/dev/null + functions -e cd + end + if builtin functions -q _zoxide_cd && not functions -q cd + # restore old cd + builtin functions -c _zoxide_cd cd end end - -# Completions. -function __zoxide_z_complete - set -l tokens (builtin commandline --current-process --tokenize) - set -l curr_tokens (builtin commandline --cut-at-cursor --current-process --tokenize) - - if test (builtin count $tokens) -le 2 -a (builtin count $curr_tokens) -eq 1 - # If there are < 2 arguments, use `cd` completions. - complete --do-complete "'' "(builtin commandline --cut-at-cursor --current-token) | string match --regex -- '.*/$' - else if test (builtin count $tokens) -eq (builtin count $curr_tokens) - # If the last argument is empty, use interactive selection. - set -l query $tokens[2..-1] - set -l result (command zoxide query --exclude (__zoxide_pwd) --interactive -- $query) - and __zoxide_cd $result - and builtin commandline --function cancel-commandline repaint - end -end -complete --command __zoxide_z --no-files --arguments '(__zoxide_z_complete)' - -# Jump to a directory using interactive search. -function __zoxide_zi - set -l result (command zoxide query --interactive -- $argv) - and __zoxide_cd $result -end - -# ============================================================================= -# -# Commands for zoxide. Disable these using --no-cmd. -# - -abbr --erase z &>/dev/null -alias z=__zoxide_z - -abbr --erase zi &>/dev/null -alias zi=__zoxide_zi - -abbr --erase cdi &>/dev/null -alias cdi=__zoxide_zi - -# ============================================================================= -# Initialize zoxide: - -zoxide init --cmd=cd fish | source diff --git a/functions/zoxide.fish b/functions/zoxide.fish new file mode 100644 index 0000000..9c3268c --- /dev/null +++ b/functions/zoxide.fish @@ -0,0 +1,45 @@ +# Adapted from icezyclon/zoxide.fish (MIT) +# Heavily customized for Fish 4.x compatibility and performance + +function _zoxide_z_complete -d "Complete directory first or zoxide queries otherwise" --argument-names comp desc + # comp is the currently completing token + if not set -q comp[1] + set comp (commandline -ct) + end + # cmd are all tokens including the current one except the command + set -l cmd (commandline -opc) $comp + set -e cmd[1] + + # 1. Get standard completions (CWD, CDPATH, etc.) + # We call the underlying functions directly to avoid recursion. + if test (count $cmd) -le 1 + # CDPATH results + __fish_complete_cd + # Local directory results (CWD) + __fish_complete_directories "$comp" "" + end + + # 2. Get zoxide results + # Cap results to 25 to avoid overwhelming the completion engine + set -l zresults (zoxide query -l $cmd | head -n 25) + for res in $zresults + set -l bname (basename $res) + # If the basename matches the prefix, show it as a short name. + if string match -qi "$comp*" -- $bname + printf "%s/\tzoxide: %s\n" $bname $res + end + # Also provide the absolute path. Fish will filter it if it doesn't match. + printf "%s/\tzoxide\n" $res + end +end + +function _zoxide_equals_first_token -a check -d "Test if first non-switch token equals given one" + set -l tokens (commandline -co) + set -e tokens[1] + set -l tokens (string replace -r --filter '^([^-].*)' '$1' -- $tokens) + if set -q tokens[1] + test $tokens[1] = $check + else + return 1 + end +end -- 2.52.0 From 6d91f49521ddc213d13e552649fe61408c12df00 Mon Sep 17 00:00:00 2001 From: rootiest Date: Mon, 11 May 2026 23:37:21 -0400 Subject: [PATCH 3/5] fix(completions): add cdi function as alias for zi cdi was documented and expected to work as an interactive zoxide directory picker but was never defined as a function, causing it to silently fail. Wraps zi so completions are inherited correctly. --- functions/cdi.fish | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 functions/cdi.fish diff --git a/functions/cdi.fish b/functions/cdi.fish new file mode 100644 index 0000000..f5c563d --- /dev/null +++ b/functions/cdi.fish @@ -0,0 +1,6 @@ +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later + +function cdi --wraps zi --description 'Interactively jump to a directory using zoxide (alias for zi)' + zi $argv +end -- 2.52.0 From 4e255f4502cc7d4ba70a57ec2ac8735eda4e8164 Mon Sep 17 00:00:00 2001 From: rootiest Date: Mon, 11 May 2026 23:47:27 -0400 Subject: [PATCH 4/5] chore(license): add copyright/SPDX headers to zoxide files - Add copyright + SPDX header to functions/zoxide.fish and conf.d/zoxide.fish (modified from original, owned by Rootiest) - Add sourced-from attribution to completions/zoxide.fish (unmodified from icezyclon/zoxide.fish, MIT) --- completions/zoxide.fish | 2 ++ conf.d/zoxide.fish | 2 ++ functions/zoxide.fish | 2 ++ 3 files changed, 6 insertions(+) diff --git a/completions/zoxide.fish b/completions/zoxide.fish index 3c2dad7..8aeaeaf 100644 --- a/completions/zoxide.fish +++ b/completions/zoxide.fish @@ -1,3 +1,5 @@ +# Sourced from icezyclon/zoxide.fish (MIT) + set -l commands add help import init query remove # disable normal all-files completion diff --git a/conf.d/zoxide.fish b/conf.d/zoxide.fish index 6e041df..e2dc307 100644 --- a/conf.d/zoxide.fish +++ b/conf.d/zoxide.fish @@ -1,3 +1,5 @@ +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later # Adapted from icezyclon/zoxide.fish (MIT) # Heavily customized for Fish 4.x compatibility and performance diff --git a/functions/zoxide.fish b/functions/zoxide.fish index 9c3268c..6adb377 100644 --- a/functions/zoxide.fish +++ b/functions/zoxide.fish @@ -1,3 +1,5 @@ +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later # Adapted from icezyclon/zoxide.fish (MIT) # Heavily customized for Fish 4.x compatibility and performance -- 2.52.0 From 520217d4a9c11538fea2a5bcbc24015205f79670 Mon Sep 17 00:00:00 2001 From: rootiest Date: Mon, 11 May 2026 23:57:46 -0400 Subject: [PATCH 5/5] fix(zoxide): suppress missing-zoxide startup message Silent degradation is cleaner; the shell already handles the missing binary gracefully without any output. --- conf.d/zoxide.fish | 2 -- 1 file changed, 2 deletions(-) diff --git a/conf.d/zoxide.fish b/conf.d/zoxide.fish index e2dc307..1972277 100644 --- a/conf.d/zoxide.fish +++ b/conf.d/zoxide.fish @@ -53,8 +53,6 @@ if status is-interactive # use custom completion complete -c z -f # disable files by default complete -c z -x -a '(_zoxide_z_complete)' - else - echo "[plugin: zoxide] Command 'zoxide' cannot be found. Not installed or not in path" end end -- 2.52.0