Last active
September 9, 2025 10:27
-
-
Save jahands/f08844ca1a310b88881b62c8d117a016 to your computer and use it in GitHub Desktop.
zoxide wrapper to prevent leaving current repo (add to .zshrc)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # alias to jump to repo root | |
| alias zz='cd $(git rev-parse --show-toplevel)' | |
| # global cache for repo root | |
| typeset -A _ZO_REPO_CACHE | |
| # custom zoxide wrapper to prevent leaving the repo | |
| function z() { | |
| # special cases: use regular zoxide behavior | |
| # "-" = jump to previous dir, $HOME = unlikely to be a git repo | |
| if [[ "$1" == "-" || "$PWD" == "$HOME" ]]; then | |
| __zoxide_z "$@" | |
| return | |
| fi | |
| local root | |
| # canonicalize PWD and cached root to handle symlinks/case; do a literal prefix check | |
| local pwd_canon="${PWD:A:P}" | |
| local cache_canon="" | |
| if [[ -n "${_ZO_REPO_CACHE[root]:-}" ]]; then | |
| cache_canon="${_ZO_REPO_CACHE[root]:A:P}" | |
| fi | |
| if [[ -n "$cache_canon" ]] && { [[ "$pwd_canon" = "$cache_canon" ]] || [[ "${pwd_canon[1,${#cache_canon}+1]}" = "$cache_canon/" ]]; }; then | |
| root="$cache_canon" | |
| else | |
| # not in cached repo or no cache, get new root | |
| root="$(git rev-parse --show-toplevel 2>/dev/null)" || { | |
| # clear cache if we're not in a repo | |
| unset '_ZO_REPO_CACHE[root]' | |
| __zoxide_z "$@"; return | |
| } | |
| # cache the new root (canonicalized) | |
| _ZO_REPO_CACHE[root]="${root:A:P}" | |
| fi | |
| # get candidates from zoxide and filter to repo | |
| local -a candidates inside | |
| candidates=("${(@f)$(zoxide query --list -- "$@")}") | |
| local p | |
| for p in $candidates; do | |
| if [[ ${p:a} == ${_ZO_REPO_CACHE[root]}/* || ${p:a} == ${_ZO_REPO_CACHE[root]} ]]; then | |
| inside+="$p" | |
| fi | |
| done | |
| local count=${#inside} | |
| if (( count == 0 )); then | |
| print -u2 "zoxide: no match found" | |
| return 1 | |
| fi | |
| # find element after $PWD (wrap to first) | |
| local target=$inside[1] | |
| local i=1 | |
| for p in $inside; do | |
| if [[ ${p:a} == ${PWD:a} ]]; then | |
| target=$inside[$(( i % count + 1 ))] | |
| break | |
| fi | |
| (( i++ )) | |
| done | |
| if (( count == 1 )) && [[ ${target:a} == ${PWD:a} ]]; then | |
| print -u2 "zoxide: you are already in the only match" | |
| return 1 | |
| fi | |
| cd -- "$target" | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment