1 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
003d1167da fix(per-directory-history): push directory history context on cd
Co-authored-by: mcornella <1441704+mcornella@users.noreply.github.com>
2026-08-10 20:26:23 +00:00
20 changed files with 339 additions and 1700 deletions

View File

@@ -46,10 +46,9 @@ dependencies:
plugins/z:
branch: master
repo: agkozak/zsh-z
version: 102fb78036ed76feedf623907483691777a1d510
version: acd0e1984df350c189f8f9c4956ec586b6c73fca
precopy: |
set -e
rm -r tests
test -e README.md && mv -f README.md MANUAL.md
postcopy: |
set -e

View File

@@ -1,5 +1,5 @@
certifi==2026.7.22
charset-normalizer==3.5.0
charset-normalizer==3.4.9
idna==3.18
PyYAML==6.0.3
requests==2.34.2

View File

@@ -41,49 +41,3 @@ jobs:
./themes/*.zsh-theme; do
zsh -n "$file" || return 1
done
- name: Focused syntax check for bootstrap-adjacent touched files
if: github.event_name == 'pull_request'
run: |
mapfile -t touched < <(
git diff --name-only "${{ github.event.pull_request.base.sha }}" "${{ github.sha }}" \
| grep -E '^(lib/bootstrap\.zsh|lib/tests/bootstrap.*\.zsh|oh-my-zsh\.sh|lib/(completion|compfix|functions|theme-and-appearance)\.zsh|plugins/.+/.+\.plugin\.zsh|themes/.+\.zsh-theme)$' \
|| true
)
if [ "${#touched[@]}" -eq 0 ]; then
echo "No bootstrap-adjacent files touched"
exit 0
fi
for file in "${touched[@]}"; do
echo "Syntax checking $file"
zsh -n "$file"
done
- name: Run bootstrap unit test
if: github.event_name == 'pull_request'
run: zsh ./lib/tests/bootstrap.test.zsh
- name: Run inline bootstrap invariants smoke test
if: github.event_name == 'pull_request'
run: zsh ./lib/tests/bootstrap-inline-ci.test.zsh
plugin-manager-smoke:
name: Plugin manager smoke (${{ matrix.manager }}:${{ matrix.scenario }})
runs-on: ubuntu-latest
if: github.repository == 'ohmyzsh/ohmyzsh' && github.event_name == 'pull_request'
strategy:
fail-fast: false
matrix:
manager: [antigen, zinit]
scenario: [positive, negative]
steps:
- name: Set up git repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install zsh
run: sudo apt-get update; sudo apt-get install zsh
- name: Run plugin-manager bootstrap integration
run: zsh ./lib/tests/plugin-manager-bootstrap-integration.test.zsh "${{ matrix.manager }}" "${{ matrix.scenario }}"

View File

@@ -1,37 +0,0 @@
name: Plugin manager integration (advisory)
on:
schedule:
- cron: '0 6 * * *'
workflow_dispatch:
permissions:
contents: read
jobs:
plugin-manager-matrix:
name: ${{ matrix.manager }}:${{ matrix.scenario }}
runs-on: ubuntu-latest
if: github.repository == 'ohmyzsh/ohmyzsh'
continue-on-error: true
strategy:
fail-fast: false
matrix:
manager: [antigen, zinit, zgen, zplug, antibody, zulu]
scenario: [positive, negative]
steps:
- name: Set up git repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install zsh and go
run: sudo apt-get update; sudo apt-get install zsh golang
- name: Run plugin-manager bootstrap integration
run: zsh ./lib/tests/plugin-manager-bootstrap-integration.test.zsh "${{ matrix.manager }}" "${{ matrix.scenario }}"
- name: Rollout note
if: always()
run: |
echo "Phase 2 active: full manager matrix is advisory/nightly."
echo "Phase 3 target: promote full matrix to required after stability window."

View File

@@ -60,6 +60,6 @@ jobs:
retention-days: 5
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
with:
sarif_file: results.sarif

View File

@@ -23,7 +23,6 @@ you would make is not already covered.
- [A note on AI-assisted contributions](#a-note-on-ai-assisted-contributions)
- [Use the Search, Luke](#use-the-search-luke)
- [Commit Guidelines](#commit-guidelines)
- [Plugin And Theme Bootstrap Compatibility](#plugin-and-theme-bootstrap-compatibility)
- [Format](#format)
- [Style](#style)
- [Volunteer](#volunteer)
@@ -177,24 +176,6 @@ specification. The automatic changelog tool uses these to automatically generate
a changelog based on the commit messages. Here's a guide to writing a commit message
to allow this:
### Plugin And Theme Bootstrap Compatibility
Oh My Zsh now provides a shared bootstrap entrypoint at `lib/bootstrap.zsh` for plugin-manager setups that don't
source `oh-my-zsh.sh`.
When working on plugins/themes:
- assume bootstrap has already run in manager-driven setups
- rely on bootstrap guarantees (`ZSH*` defaults, cache/completions setup, required `fpath` entries)
- avoid adding per-plugin/per-theme copies of common setup unless truly plugin-specific
Common patterns we should migrate away from over time:
- repeated cache setup logic (`mkdir -p "$ZSH_CACHE_DIR/completions"`)
- repeated base `fpath` bootstrapping for OMZ core/custom directories
If your plugin/theme still needs custom initialization, keep it scoped to that plugin/theme behavior only.
### Format
```

115
README.md
View File

@@ -46,7 +46,6 @@ Twitter), and join us on [Discord](https://discord.gg/ohmyzsh).
- [Manual Installation](#manual-installation)
- [Installation Problems](#installation-problems)
- [Custom Plugins And Themes](#custom-plugins-and-themes)
- [Using Plugin Managers Without `oh-my-zsh.sh`](#using-plugin-managers-without-oh-my-zshsh)
- [Enable GNU ls In macOS And FreeBSD Systems](#enable-gnu-ls-in-macos-and-freebsd-systems)
- [Skip Aliases](#skip-aliases)
- [Async git prompt](#async-git-prompt)
@@ -350,120 +349,6 @@ If you have many functions that go well together, you can put them as a `XYZ.plu
If you would like to override the functionality of a plugin distributed with Oh My Zsh, create a plugin of the
same name in the `custom/plugins/` directory and it will be loaded instead of the one in `plugins/`.
### Using Plugin Managers Without `oh-my-zsh.sh`
Some plugin managers load individual OMZ plugins/themes directly and do not source `oh-my-zsh.sh`.
For those setups, source this bootstrap entrypoint before loading any OMZ plugin or theme:
```zsh
source "$ZSH/lib/bootstrap.zsh"
```
#### Bootstrap compatibility contract
`lib/bootstrap.zsh` is idempotent and is the only required pre-load step for plugin-manager setups.
It guarantees:
- `ZSH`, `ZSH_CUSTOM`, and `ZSH_CACHE_DIR` defaults
- writable cache fallback to `${XDG_CACHE_HOME:-$HOME/.cache}/oh-my-zsh`
- `$ZSH_CACHE_DIR/completions` directory creation
- required OMZ `fpath` entries for plugins/themes:
- `$ZSH/functions`
- `$ZSH/completions`
- `$ZSH_CUSTOM/functions`
- `$ZSH_CUSTOM/completions`
- `$ZSH_CACHE_DIR/completions`
- public signal: `OMZ_IS_BOOTSTRAPPED=true` (for one-time hook guards)
What still requires `oh-my-zsh.sh`:
- update checks
- plugin auto-discovery from the `plugins=(...)` list
- `compinit`/`compfix` orchestration and zcompdump metadata refresh
- alias filtering via `:omz:*` zstyles during file sourcing
- final full-init signal: `OMZ_IS_LOADED=true`
#### Plugin manager hook guidance
Run bootstrap once, before any OMZ plugin/theme load:
```zsh
[[ -n "${OMZ_IS_BOOTSTRAPPED:-}" ]] || source "$ZSH/lib/bootstrap.zsh"
```
- **Antigen** (pre-bundle hook pattern):
```zsh
omz_preload() { [[ -n "${OMZ_IS_BOOTSTRAPPED:-}" ]] || source "$ZSH/lib/bootstrap.zsh"; }
omz_preload
antigen bundle OMZ::plugins/git
antigen apply
```
- **Zinit** (`atinit` pre-load hook):
```zsh
zinit ice atinit'[[ -n "${OMZ_IS_BOOTSTRAPPED:-}" ]] || source "$ZSH/lib/bootstrap.zsh"'
zinit snippet OMZ::plugins/git/git.plugin.zsh
```
- **zgen** (pre-load hook function called before OMZ loads):
```zsh
omz_preload() { [[ -n "${OMZ_IS_BOOTSTRAPPED:-}" ]] || source "$ZSH/lib/bootstrap.zsh"; }
omz_preload
zgen load ohmyzsh/ohmyzsh plugins/git
```
- **zplug** (run pre-load hook immediately before OMZ entries):
```zsh
omz_preload() { [[ -n "${OMZ_IS_BOOTSTRAPPED:-}" ]] || source "$ZSH/lib/bootstrap.zsh"; }
omz_preload
zplug "plugins/git", from:oh-my-zsh
zplug load
```
- **antibody** (run pre-load hook before `antibody bundle`/`source` output):
```zsh
omz_preload() { [[ -n "${OMZ_IS_BOOTSTRAPPED:-}" ]] || source "$ZSH/lib/bootstrap.zsh"; }
omz_preload
source <(antibody bundle <<'EOF'
ohmyzsh/ohmyzsh path:plugins/git
EOF
)
```
- **zulu** (run pre-load hook before OMZ module loads):
```zsh
omz_preload() { [[ -n "${OMZ_IS_BOOTSTRAPPED:-}" ]] || source "$ZSH/lib/bootstrap.zsh"; }
omz_preload
zulu install oh-my-zsh
```
Compatibility matrix:
| Load mode | `OMZ_IS_BOOTSTRAPPED` | `OMZ_IS_LOADED` | Suitable for |
| :-- | :--: | :--: | :-- |
| `source $ZSH/oh-my-zsh.sh` | ✅ | ✅ | Full OMZ framework features |
| `source $ZSH/lib/bootstrap.zsh` + manager-loaded OMZ plugins/themes | ✅ | ❌ | Plugin/theme prerequisites only |
#### Manager entrypoints and OMZ-side auto-injection limits
Most plugin managers load OMZ by directly sourcing selected plugin/theme/lib entrypoints, not by sourcing
`oh-my-zsh.sh`, so OMZ cannot universally inject bootstrap on its own.
| Manager | Typical OMZ entrypoint(s) it loads | Can OMZ auto-inject bootstrap without user hook? |
| :-- | :-- | :--: |
| Antigen | `antigen bundle ...` targets after `antigen use oh-my-zsh` | ❌ |
| Zinit | `OMZ::`, `OMZL::`, `OMZP::`, `OMZT::` snippets | ❌ |
| zgen | `zgen oh-my-zsh ...` selected OMZ paths | ❌ |
| zplug | `from:oh-my-zsh` selected OMZ entries | ❌ |
| antibody | `ohmyzsh/ohmyzsh path:...` selected OMZ paths | ❌ |
| zulu | OMZ package/module entries selected by zulu | ❌ |
### Enable GNU ls In macOS And FreeBSD Systems
<a name="enable-gnu-ls"></a>

View File

@@ -1,44 +0,0 @@
#
# Shared Oh My Zsh bootstrap entrypoint.
#
# This file can be sourced by plugin managers that don't source `oh-my-zsh.sh`.
# It is safe to source multiple times.
#
# Keep source path for callers that invoke omz_bootstrap again later.
typeset -g _OMZ_BOOTSTRAP_SOURCE="${${(%):-%x}:a}"
omz_bootstrap() {
# If ZSH is not defined, infer from this file location.
[[ -n "${ZSH:-}" ]] || export ZSH="${_OMZ_BOOTSTRAP_SOURCE:h:h}"
# Set ZSH_CUSTOM to the path where custom config files and plugins exist.
[[ -n "${ZSH_CUSTOM:-}" ]] || ZSH_CUSTOM="$ZSH/custom"
# Set cache directory.
[[ -n "${ZSH_CACHE_DIR:-}" ]] || ZSH_CACHE_DIR="$ZSH/cache"
# Ensure cache dir is writable, otherwise fallback to a HOME-based cache.
if [[ ! -w "$ZSH_CACHE_DIR" ]]; then
ZSH_CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/oh-my-zsh"
fi
# Create cache and completions dir.
command mkdir -p "$ZSH_CACHE_DIR/completions"
# Add required OMZ search paths.
local dir
for dir in \
"$ZSH/functions" \
"$ZSH/completions" \
"$ZSH_CUSTOM/functions" \
"$ZSH_CUSTOM/completions" \
"$ZSH_CACHE_DIR/completions"; do
(( ${fpath[(Ie)$dir]} )) || fpath=("$dir" $fpath)
done
# Public signal: OMZ bootstrap has completed.
typeset -g OMZ_IS_BOOTSTRAPPED=true
}
omz_bootstrap "$@"

View File

@@ -1,35 +0,0 @@
#!/usr/bin/zsh -df
set -eu
bootstrap_file="${0:A:h:h}/bootstrap.zsh"
assert() {
local condition="$1" message="$2"
if ! eval "$condition"; then
print -u2 "\e[31mError\e[0m: $message"
exit 1
fi
}
tmp==(:)
mkdir -p "$tmp/ohmyzsh"/{functions,completions,cache} "$tmp/ohmyzsh/custom"/{functions,completions}
export ZSH="$tmp/ohmyzsh"
unset ZSH_CUSTOM ZSH_CACHE_DIR OMZ_IS_BOOTSTRAPPED
fpath=()
source "$bootstrap_file"
assert '[[ "$OMZ_IS_BOOTSTRAPPED" == true ]]' "OMZ bootstrap signal should be true"
assert '[[ -d "$ZSH_CACHE_DIR/completions" ]]' "cache completions directory should exist"
assert '[[ "${fpath[(Ie)$ZSH/functions]}" -gt 0 ]]' "fpath should include OMZ functions"
assert '[[ "${fpath[(Ie)$ZSH/completions]}" -gt 0 ]]' "fpath should include OMZ completions"
assert '[[ "${fpath[(Ie)$ZSH_CUSTOM/functions]}" -gt 0 ]]' "fpath should include custom functions"
assert '[[ "${fpath[(Ie)$ZSH_CUSTOM/completions]}" -gt 0 ]]' "fpath should include custom completions"
assert '[[ "${fpath[(Ie)$ZSH_CACHE_DIR/completions]}" -gt 0 ]]' "fpath should include cache completions"
touch "$ZSH_CACHE_DIR/completions/_bootstrap_ci_smoke"
assert '[[ -f "$ZSH_CACHE_DIR/completions/_bootstrap_ci_smoke" ]]' "completion cache write should succeed"
print -u2 "\e[32mSuccess\e[0m bootstrap inline invariants"

View File

@@ -1,88 +0,0 @@
#!/usr/bin/zsh -df
set -u
bootstrap_file="${0:A:h:h}/bootstrap.zsh"
_assert() {
local condition="$1" message="$2"
if ! eval "$condition"; then
print -u2 "\e[31mError\e[0m: $message"
return 1
fi
}
test_bootstrap_sets_defaults_and_paths() {
local tmp==(:)
mkdir -p "$tmp/ohmyzsh"/{functions,completions,cache} "$tmp/ohmyzsh/custom"/{functions,completions}
(
set -e
export ZSH="$tmp/ohmyzsh"
unset ZSH_CUSTOM ZSH_CACHE_DIR OMZ_IS_BOOTSTRAPPED
fpath=()
source "$bootstrap_file"
_assert '[[ "$ZSH_CUSTOM" == "'"$tmp/ohmyzsh/custom"'" ]]' "ZSH_CUSTOM default should be set"
_assert '[[ "$ZSH_CACHE_DIR" == "'"$tmp/ohmyzsh/cache"'" ]]' "ZSH_CACHE_DIR default should be set"
_assert '[[ -d "'"$tmp/ohmyzsh/cache/completions"'" ]]' "completions dir should be created"
_assert '[[ "${fpath[(Ie)'"$tmp/ohmyzsh/functions"']}" -gt 0 ]]' "fpath should include OMZ functions dir"
_assert '[[ "${fpath[(Ie)'"$tmp/ohmyzsh/completions"']}" -gt 0 ]]' "fpath should include OMZ completions dir"
_assert '[[ "${fpath[(Ie)'"$tmp/ohmyzsh/custom/functions"']}" -gt 0 ]]' "fpath should include custom functions dir"
_assert '[[ "${fpath[(Ie)'"$tmp/ohmyzsh/custom/completions"']}" -gt 0 ]]' "fpath should include custom completions dir"
_assert '[[ "${fpath[(Ie)'"$tmp/ohmyzsh/cache/completions"']}" -gt 0 ]]' "fpath should include cache completions dir"
_assert '[[ "$OMZ_IS_BOOTSTRAPPED" == true ]]' "bootstrap signal should be set"
)
}
test_bootstrap_is_idempotent() {
local tmp==(:)
mkdir -p "$tmp/ohmyzsh"/{functions,completions,cache} "$tmp/ohmyzsh/custom"/{functions,completions}
(
set -e
export ZSH="$tmp/ohmyzsh"
unset ZSH_CUSTOM ZSH_CACHE_DIR OMZ_IS_BOOTSTRAPPED
fpath=()
source "$bootstrap_file"
source "$bootstrap_file"
omz_bootstrap
_assert '[[ ${#fpath} -eq ${#${(u)fpath}} ]]' "fpath entries should not duplicate after repeated bootstrap"
_assert '[[ "$OMZ_IS_BOOTSTRAPPED" == true ]]' "bootstrap signal should remain true"
)
}
test_bootstrap_uses_writable_cache_fallback() {
local tmp==(:)
mkdir -p "$tmp/ohmyzsh"/{functions,completions} "$tmp/ohmyzsh/custom"/{functions,completions}
mkdir -p "$tmp/no-write" "$tmp/xdg-cache"
chmod 0555 "$tmp/no-write"
(
set -e
export ZSH="$tmp/ohmyzsh"
export XDG_CACHE_HOME="$tmp/xdg-cache"
export ZSH_CACHE_DIR="$tmp/no-write"
unset ZSH_CUSTOM OMZ_IS_BOOTSTRAPPED
fpath=()
source "$bootstrap_file"
_assert '[[ "$ZSH_CACHE_DIR" == "'"$tmp/xdg-cache/oh-my-zsh"'" ]]' "cache dir should fallback when not writable"
_assert '[[ -d "'"$tmp/xdg-cache/oh-my-zsh/completions"'" ]]' "fallback completions dir should be created"
_assert '[[ "${fpath[(Ie)'"$tmp/xdg-cache/oh-my-zsh/completions"']}" -gt 0 ]]' "fpath should include fallback completions dir"
)
}
tests=(
test_bootstrap_sets_defaults_and_paths
test_bootstrap_is_idempotent
test_bootstrap_uses_writable_cache_fallback
)
for test_name in $tests; do
print -u2 "Test: $test_name"
"$test_name" || exit 1
print -u2 "\e[32mSuccess\e[0m"
print -u2 ""
done

View File

@@ -1,104 +0,0 @@
#!/usr/bin/zsh -df
set -euo pipefail
if (( $# != 2 )); then
print -u2 "Usage: $0 <manager> <positive|negative>"
exit 1
fi
manager="$1"
scenario="$2"
if [[ "$scenario" != "positive" && "$scenario" != "negative" ]]; then
print -u2 "scenario must be 'positive' or 'negative'"
exit 1
fi
repo_root="${0:A:h:h:h}"
tmp==(:)
workspace="$tmp/workspace"
home_dir="$tmp/home"
cache_dir="$tmp/cache"
zshrc="$tmp/.zshrc"
mkdir -p "$workspace" "$home_dir" "$cache_dir"
manager_install=''
manager_source=''
case "$manager" in
antigen)
manager_install='git clone https://github.com/zsh-users/antigen.git "$MANAGER_HOME/antigen" >/dev/null 2>&1'
manager_source='source "$MANAGER_HOME/antigen/antigen.zsh"'
;;
zinit)
manager_install='git clone https://github.com/zdharma-continuum/zinit.git "$MANAGER_HOME/zinit" >/dev/null 2>&1'
manager_source='source "$MANAGER_HOME/zinit/zinit.zsh"'
;;
zgen)
manager_install='git clone https://github.com/tarjoilija/zgen.git "$MANAGER_HOME/zgen" >/dev/null 2>&1'
manager_source='source "$MANAGER_HOME/zgen/zgen.zsh"'
;;
zplug)
manager_install='git clone https://github.com/zplug/zplug "$MANAGER_HOME/zplug" >/dev/null 2>&1'
manager_source='export ZPLUG_HOME="$MANAGER_HOME/zplug"; source "$ZPLUG_HOME/init.zsh"'
;;
antibody)
manager_install='command -v go >/dev/null 2>&1; export GOBIN="$MANAGER_HOME/bin"; mkdir -p "$GOBIN"; go install github.com/getantibody/antibody@latest >/dev/null 2>&1'
manager_source='"$MANAGER_HOME/bin/antibody" --version >/dev/null 2>&1'
;;
zulu)
manager_install='git clone https://github.com/zulu-zsh/zulu.git "$MANAGER_HOME/zulu" >/dev/null 2>&1'
manager_source='source "$MANAGER_HOME/zulu/zulu.zsh"'
;;
*)
print -u2 "Unsupported manager: $manager"
exit 1
;;
esac
cat > "$zshrc" <<RC
set -eo pipefail
export HOME="$home_dir"
export XDG_CACHE_HOME="$cache_dir"
export OMZ_ROOT="$repo_root"
export ZSH="\$OMZ_ROOT"
export MANAGER_HOME="$workspace/$manager"
mkdir -p "\$MANAGER_HOME"
$manager_install
$manager_source
RC
if [[ "$scenario" == "positive" ]]; then
cat >> "$zshrc" <<'RC'
source "$OMZ_ROOT/lib/bootstrap.zsh"
[[ "${OMZ_IS_BOOTSTRAPPED:-}" == true ]] || { print -u2 "bootstrap signal missing before OMZ load"; return 1; }
RC
else
cat >> "$zshrc" <<'RC'
[[ -z "${OMZ_IS_BOOTSTRAPPED:-}" ]] || { print -u2 "bootstrap signal unexpectedly set without hook"; return 1; }
source "$OMZ_ROOT/lib/bootstrap.zsh"
RC
fi
cat >> "$zshrc" <<RC
[[ "\${OMZ_IS_BOOTSTRAPPED:-}" == true ]] || { print -u2 "bootstrap signal not set before OMZ entrypoint sourcing"; return 1; }
source "\$OMZ_ROOT/lib/functions.zsh"
source "\$OMZ_ROOT/plugins/git/git.plugin.zsh"
autoload -Uz compinit
compinit -i -d "\$ZSH_CACHE_DIR/.zcompdump"
source "\$OMZ_ROOT/themes/robbyrussell.zsh-theme"
[[ -d "\$ZSH_CACHE_DIR/completions" ]] || { print -u2 "completions cache directory missing"; return 1; }
touch "\$ZSH_CACHE_DIR/completions/_ci_${manager}_${scenario}" || { print -u2 "completion cache write failed"; return 1; }
[[ -f "\$ZSH_CACHE_DIR/completions/_ci_${manager}_${scenario}" ]] || { print -u2 "completion cache file missing"; return 1; }
RC
zsh -df "$zshrc"
print -u2 "\e[32mSuccess\e[0m $manager $scenario"

View File

@@ -50,14 +50,31 @@ unset -f omz_f
# If ZSH is not defined, use the current script's directory.
[[ -n "$ZSH" ]] || export ZSH="${${(%):-%x}:a:h}"
# Shared, manager-agnostic bootstrap.
source "$ZSH/lib/bootstrap.zsh"
# Set ZSH_CUSTOM to the path where your custom config files
# and plugins exists, or else we will use the default custom/
[[ -n "$ZSH_CUSTOM" ]] || ZSH_CUSTOM="$ZSH/custom"
# Set ZSH_CACHE_DIR to the path where cache files should be created
# or else we will use the default cache/
[[ -n "$ZSH_CACHE_DIR" ]] || ZSH_CACHE_DIR="$ZSH/cache"
# Make sure $ZSH_CACHE_DIR is writable, otherwise use a directory in $HOME
if [[ ! -w "$ZSH_CACHE_DIR" ]]; then
ZSH_CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/oh-my-zsh"
fi
# Create cache and completions dir and add to $fpath
mkdir -p "$ZSH_CACHE_DIR/completions"
(( ${fpath[(Ie)$ZSH_CACHE_DIR/completions]} )) || fpath=("$ZSH_CACHE_DIR/completions" $fpath)
# Check for updates on initial load...
source "$ZSH/tools/check_for_upgrade.sh"
# Initializes Oh My Zsh
# add a function path
fpath=($ZSH/{functions,completions} $ZSH_CUSTOM/{functions,completions} $fpath)
# Load all stock functions (from $fpath files) called below.
autoload -U compaudit compinit zrecompile
@@ -217,6 +234,3 @@ fi
# set completion colors to be the same as `ls`, after theme has been loaded
[[ -z "$LS_COLORS" ]] || zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}"
# Public signal: full Oh My Zsh init script has completed.
typeset -g OMZ_IS_LOADED=true

View File

@@ -22,21 +22,6 @@ RPS1='$(kubectx_prompt_info)'
PROMPT="$PROMPT"'$(kubectx_prompt_info)'
```
The context is loaded asynchronously on supported versions of zsh so that
`kubectl` does not block the prompt. To restore synchronous behavior, add this
before Oh My Zsh is sourced:
```zsh
zstyle ':omz:alpha:plugins:kubectx' async-prompt no
```
If your theme calls `kubectx_prompt_info` indirectly through another function,
force registration of the async handler instead:
```zsh
zstyle ':omz:alpha:plugins:kubectx' async-prompt force
```
### Custom context names
You can rename the default context name for better readability or additional formatting.

View File

@@ -1,6 +1,6 @@
typeset -g -A kubectx_mapping
function _omz_kubectx_prompt_info() {
function kubectx_prompt_info() {
(( $+commands[kubectl] )) || return
local current_ctx=$(kubectl config current-context 2> /dev/null)
@@ -13,34 +13,3 @@ function _omz_kubectx_prompt_info() {
# the context name, as it could contain a % character.
echo "${kubectx_mapping[$current_ctx]:-${current_ctx:gs/%/%%}}"
}
function kubectx_prompt_info() {
if (( ${+_OMZ_ASYNC_OUTPUT} )) \
&& [[ -n "${_OMZ_ASYNC_OUTPUT[_omz_kubectx_prompt_info]-}" ]]; then
echo -n "${_OMZ_ASYNC_OUTPUT[_omz_kubectx_prompt_info]}"
fi
}
local _style
if zstyle -t ':omz:alpha:plugins:kubectx' async-prompt \
|| { is-at-least 5.0.6 && zstyle -T ':omz:alpha:plugins:kubectx' async-prompt }; then
function _defer_async_kubectx_register() {
case "${PS1}:${PS2}:${PS3}:${PS4}:${RPROMPT-}:${RPS1-}:${RPS2-}:${RPS3-}:${RPS4-}" in
*(\$\(kubectx_prompt_info\)|\`kubectx_prompt_info\`)*)
_omz_register_handler _omz_kubectx_prompt_info
;;
esac
add-zsh-hook -d precmd _defer_async_kubectx_register
unset -f _defer_async_kubectx_register
}
autoload -Uz add-zsh-hook
precmd_functions=(_defer_async_kubectx_register $precmd_functions)
elif zstyle -s ':omz:alpha:plugins:kubectx' async-prompt _style && [[ $_style == "force" ]]; then
_omz_register_handler _omz_kubectx_prompt_info
else
function kubectx_prompt_info() {
_omz_kubectx_prompt_info
}
fi

View File

@@ -10,7 +10,6 @@ plugins=(... laravel)
|:-:|:-:|
| `artisan` | `php artisan` |
| `pas` | `php artisan serve` |
| `pad` | `php artisan dev` |
| `pats` | `php artisan test` |
## Database

View File

@@ -4,7 +4,6 @@ alias bob='php artisan bob::build'
# Development
alias pas='php artisan serve'
alias pad='php artisan dev'
alias pats='php artisan test'
# Database

View File

@@ -112,6 +112,9 @@ function _per-directory-history-change-directory() {
#read history in new file
if [[ -e $_per_directory_history_directory ]]; then
fc -R $_per_directory_history_directory
# -p: push the new directory's history file as the active history context,
# so that the history is kept up to date on every directory change.
fc -p $_per_directory_history_directory
fi
fi
}
@@ -153,6 +156,7 @@ function _per-directory-history-set-directory-history() {
HISTSIZE=$original_histsize
if [[ -e "$_per_directory_history_directory" ]]; then
fc -R "$_per_directory_history_directory"
# -p: push the directory's history file as the active history context.
fc -p "$_per_directory_history_directory"
fi
}
@@ -164,6 +168,7 @@ function _per-directory-history-set-global-history() {
HISTSIZE=$original_histsize
if [[ -e "$_per_directory_history_global" ]]; then
fc -R "$_per_directory_history_global"
# -p: push the global history file as the active history context.
fc -p "$_per_directory_history_global"
fi
}

View File

@@ -2,26 +2,20 @@
[![MIT License](img/mit_license.svg)](https://opensource.org/licenses/MIT)
![Zsh version 4.3.11 and higher](img/zsh_4.3.11_plus.svg)
![Version](https://img.shields.io/github/v/release/agkozak/zsh-z)
![Workflow Status](https://github.com/agkozak/zsh-z/actions/workflows/test.yml/badge.svg)
[![GitHub stars](https://img.shields.io/github/stars/agkozak/zsh-z.svg)](https://github.com/agkozak/zsh-z/stargazers)
![Zsh-z demo](img/demo.gif)
Zsh-z is a command-line tool that allows you to jump quickly to directories that you have visited frequently or recently -- but most often a combination of the two (a concept known as ["frecency"](https://en.wikipedia.org/wiki/Frecency)). It works by keeping track of when you go to directories and how much time you spend in them. Based on this data, it predicts where you want to go when you type a partial string. For example, `z src` might take you to `~/src/zsh`. `z zsh` might also get you there, and `z c/z` might prove to be even more specific -- it all depends on your habits and how long you have been using Zsh-z to build up a database. After using Zsh-z for a little while, you will get to where you want to be by typing considerably less than you would need to if you were using `cd`.
Zsh-z is a native Zsh port of [`rupa/z`](https://github.com/rupa/z), a tool written for `bash` and Zsh that uses embedded `awk` scripts to do the heavy lifting. `rupa/z` was my most used command-line tool for a couple of years. I decided to translate it, `awk` parts and all, into pure Zsh script, to see if by eliminating calls to external tools (`awk`, `sort`, `date`, `sed`, `mv`, `rm`, and `chown`) and reducing forking through subshells I could make it faster. The performance increase is impressive, particularly on systems where forking is slow, such as Cygwin, MSYS2, and WSL.
Zsh-z is a native Zsh port of [`rupa/z`](https://github.com/rupa/z), a tool written for `bash` and Zsh that uses embedded `awk` scripts to do the heavy lifting. `rupa/z` was my most used command-line tool for a couple of years. I decided to translate it, `awk` parts and all, into pure Zsh script, to see if by eliminating calls to external tools (`awk`, `sort`, `date`, `sed`, `mv`, `rm`, and `chown`) and reducing forking through subshells I could make it faster. The performance increase is impressive, particularly on systems where forking is slow, such as Cygwin, MSYS2, and WSL. I have found that in those environments, switching directories using Zsh-z can be over 100% faster than it is using `rupa/z`.
There is also a significant stability improvement. Race conditions have always been a problem with `rupa/z`, and users of that utility occasionally lose their `~/.z` databases. By having Zsh-z only use Zsh (`rupa/z` uses a hybrid shell code standard that works on `bash` as well), I have been able to implement a `zsh/system`-based file-locking mechanism. It is now nearly impossible to crash the database.
There is also a significant stability improvement. Race conditions have always been a problem with `rupa/z`, and users of that utility occasionally lose their `~/.z` databases. By having Zsh-z only use Zsh (`rupa/z` uses a hybrid shell code standard that works on `bash` as well), I have been able to implement a `zsh/system`-based file-locking mechanism similar to [the one @mafredri once proposed for `rupa/z`](https://github.com/rupa/z/pull/199). It is now nearly impossible to crash the database.
There are other, smaller improvements which I document below in [Other Improvements to the Original Functionality of `rupa/z`](#other-improvements-to-the-original-functionality-of-rupaz). For instance, tab completions are now sorted by frecency by default rather than alphabetically (the latter behavior can be restored if you like it -- [see below](#settings)).
There are other, smaller improvements which I document below in [Improvements and Fixes](#improvements-and-fixes). For instance, tab completions are now sorted by frecency by default rather than alphabetically (the latter behavior can be restored if you like it -- [see below](#settings)).
Zsh-z is a drop-in replacement for `rupa/z` and will, by default, use the same database (`~/.z`, or whatever database file you specify), so you can go on using `rupa/z` when you launch `bash`.
> ### Zsh-z v2.0
>
> **v2.0 is the most significant release in the project's history.** It is faster than ever at adding, searching, and listing on modern Zsh; it never makes your prompt wait on database writes -- on any platform; it hardens those writes against corruption and against prying eyes; and it makes tab completion "just work" even under `setopt COMPLETE_ALIASES`. See [**v2.0**](#v20) in the News below for the full rundown, and [Performance](#performance) for the benchmarks.
## Table of Contents
- [News](#news)
- [Installation](#installation)
@@ -29,45 +23,16 @@ Zsh-z is a drop-in replacement for `rupa/z` and will, by default, use the same d
- [Settings](#settings)
- [Case Sensitivity](#case-sensitivity)
- [`ZSHZ_UNCOMMON`](#zshz_uncommon)
- [`ZSHZ_OWNER`](#zshz_owner)
- [Making `--add` work for you](#making---add-work-for-you)
- [Performance](#performance)
- [Other Improvements to the Original Functionality of `rupa/z`](#other-improvements-to-the-original-functionality-of-rupaz)
- [Other Improvements to the Original Functionality of `rupa/z`](#other-improvements-to-the-original-functionality-of-rupa-z)
- [Migrating from Other Tools](#migrating-from-other-tools)
- [`COMPLETE_ALIASES`](#complete_aliases)
## News
### v2.0 (August 14, 2026)
Version **2.0** is a major step forward, and these are the changes most worth knowing about:
- **Zsh-z is even faster than before.** Version 2.0 builds on Zsh-z's past successes in optimizing adding to the datafile -- something it does at virtually every prompt -- by streamlining searching and listing, as well. See [Performance](#performance) for the numbers.
- **Database writes never block your prompt** -- on any platform. The per-prompt `--add` has long run in the background on most systems, but Cygwin and MSYS2 did the write in the foreground, because backgrounding there cost a wrapper subshell plus a job. `--add` now runs as a single disowned job (`&!`) everywhere: one fork, no wrapper subshell, no job-control noise. On Cygwin and MSYS2 that turns a foreground write whose cost grows with your datafile (~30 ms at 300 entries, ~300 ms at 1,000) into a flat ~10-12 ms fork. Elsewhere it halves the forks per prompt.
- **Safer, crash-resistant concurrent writes.** Writes are now guarded by a dedicated, stable lockfile using `zsh/system` file locking, with a bounded wait for lock acquisition (the new [`ZSHZ_LOCK_TIMEOUT`](#settings), default `1` second). Write errors are handled gracefully, and locks are always released even if a write is interrupted. On Cygwin and MSYS2 a write is also retried briefly if Windows refuses it: a virus scanner or the search indexer that opens the database in the instant between its being written and its being moved into place makes the move fail, which used to lose that one directory silently. Zsh-z now retries the move briefly.
- **Your database file now has `600` permissions** -- readable and writable only by you -- so that other users on a shared system cannot read your directory history ([#92](https://github.com/agkozak/zsh-z/issues/92)). On Zsh 5+ this uses the in-process `zf_chmod` builtin; on Zsh 4.3.11 it uses a `umask`-in-a-subshell technique that avoids the fork-and-exec of an external `chmod`.
- **`COMPLETE_ALIASES` works automatically in normal setups.** Tab completion no longer breaks when you have `setopt COMPLETE_ALIASES` enabled. Zsh-z registers the alias automatically on the first Tab press, so the manual `compdef` line that earlier versions required is no longer necessary. [See below](#complete_aliases).
- **Fixed a `can't clobber parameter tmpfd` error on some Zsh builds.** On certain Zsh builds, every database write could fail with `can't clobber parameter tmpfd containing file descriptor 0`, leaving an error at each new prompt. The file descriptor used for the temporary database file is now held in an unset scalar rather than one seeded with `0`, so the write never trips Zsh's file-descriptor-clobber guard ([#81](https://github.com/agkozak/zsh-z/issues/81)).
- **A misconfigured database file no longer closes your shell -- or nags you at every prompt.** When `ZSHZ_DATA` points at a directory, or names a file without a directory, Zsh-z now reports the problem and returns instead of calling `exit`. The per-prompt `--add` stays quiet about it, so you are told once, when you actually run `z`, rather than at every prompt ([#103](https://github.com/agkozak/zsh-z/issues/103); props @ahjota).
- **`z -x` can now remove the entry for a directory that no longer exists -- and can no longer crash Zsh 4.3.11.** The removal target used to have to exist on disk, so a database entry whose directory had been deleted -- exactly the entry you most want gone -- could not be removed. `z -x /deleted/dir` (and `z -xR`) now canonicalizes the argument without requiring it to exist, resolving symlinks in as much of the path as is still present. The same change fixes a crash on Zsh 4.3.11, where an upstream bug makes `${x:A}` segfault when the top-level component of the path is missing: `z -x /gone/sub` -- or a `ZSHZ_DATA` pointing into a missing top-level directory -- could kill the shell there.
- **More robust startup and operation.** A version check on an unsupported Zsh no longer risks exiting your interactive shell.
#### Smaller changes you may notice
None of these should need any action from you, but they are the things a v1 user is most likely to spot:
- **`-r` and `-t` can no longer be combined.** They name mutually exclusive sort orders -- rank versus recency -- so `z -rt foo` was always contradictory, and `-t` silently took precedence. It is now rejected with an error message instead of silently picking one.
- **A lockfile appears next to your database.** Writes are serialized through `~/.z.lock` (or `$ZSHZ_DATA` plus `.lock`). It is created `600`, it stays empty, and it is deliberately never deleted -- removing a lockfile that another shell has already opened would reintroduce the very race it exists to prevent. Where `zsh/system` is missing and `zsystem flock` is therefore unavailable -- MobaXterm's cut-down Cygwin is the case in practice -- you will see a short-lived `~/.z.lock.d` **directory** instead, which is created and removed for each write. See [`ZSHZ_LOCK_TIMEOUT`](#settings) for how that fallback behaves.
- **An existing database gets tightened to `600` on the next write.** If your `~/.z` predates this release and is `644`, the first write will re-mode it. This is the [#92](https://github.com/agkozak/zsh-z/issues/92) fix applied to databases you already have, not just newly created ones. Setting the mode is treated as part of the write rather than a courtesy afterwards: if it cannot be done, the write is abandoned and reports failure instead of publishing a database that anyone on the machine could read.
The dated entries below remain the historical record of changes leading up to v2.0.
<details>
<summary>Here are the older features and updates.</summary>
<summary>Here are the latest features and updates.</summary>
- May 6, 2026
+ Zsh-z will now handle paths with dollar signs (`$`) in them.
+ Workaround for Zsh emulating `sh`/`bash`/`ksh`.
- May 1, 2026
+ Various tab completion bugs resolved.
- April 27, 2026
@@ -125,7 +90,7 @@ The dated entries below remain the historical record of changes leading up to v2
- February 15, 2021
+ Ranks are displayed the way `rupa/z` now displays them, i.e. as large integers. This should help Zsh-z to integrate with other tools.
- January 31, 2021
+ Zsh-z is now efficient enough that, on MSYS2 and Cygwin, it is faster to run it in the foreground than it is to fork a subshell for it. (Behavior superseded in v2.0.)
+ Zsh-z is now efficient enough that, on MSYS2 and Cygwin, it is faster to run it in the foreground than it is to fork a subshell for it.
+ `_zshz_precmd` simply returns if `PWD` is `HOME` or in `ZSHZ_EXCLUDE_DIRS`, rather than waiting for `zshz` to do that.
- January 17, 2021
+ Made sure that the `PUSHD_IGNORE_DUPS` option is respected.
@@ -156,11 +121,11 @@ This plugin can be installed simply by putting the various files in a directory
source /path/to/zsh-z.plugin.zsh
Tab completion requires `compinit`. `_zshz` *must* also be in the same directory as `zsh-z.plugin.zsh`. The frameworks handle both of these requirements, but if you are not using a framework, put
For tab completion to work, `_zshz` *must* be in the same directory as `zsh-z.plugin.zsh`, and you will want to have loaded `compinit`. The frameworks handle this themselves. If you are not using a framework, put
autoload -U compinit; compinit
in your `.zshrc` somewhere below where you source `zsh-z.plugin.zsh` -- the plugin adds its directory to `fpath` at source time, and `compinit` needs to see it there in order to find `_zshz`.
in your `.zshrc` somewhere below where you source `zsh-z.plugin.zsh`.
If you add
@@ -230,7 +195,7 @@ Add a backslash to the end of the last line and add `'zsh-z'` to the list, e.g.,
Then relaunch `zsh`.
### For [zcomet](https://github.com/agkozak/zcomet) users
Simply add
zcomet load agkozak/zsh-z
@@ -270,7 +235,7 @@ Add the line
to your `.zshrc`.
Zsh-z supports `zinit`'s `unload` feature; just run `zinit unload agkozak/zsh-z` to restore the shell to its state before Zsh-z was loaded. It gives back only what it took: the `fpath` entry is removed only if Zsh-z was the one that added it, so a directory your plugin manager put there is left alone, and the Tab-completion mapping is dropped only while it still points at Zsh-z's own completer.
Zsh-z supports `zinit`'s `unload` feature; just run `zinit unload agkozak/zsh-z` to restore the shell to its state before Zsh-z was loaded.
### For [Znap](https://github.com/marlonrichert/zsh-snap) users
@@ -309,7 +274,6 @@ to install Zsh-z.
Zsh-z has environment variables (they all begin with `ZSHZ_`) that change its behavior if you set them. You can also keep your old ones if you have been using `rupa/z` (whose environment variables begin with `_Z_`).
* `ZSHZ_CASE` can be `ignore`, for case-insensitive matching, or `smart`, for Vim-like `smartcase` matching; [see below](#case-sensitivity) (default: empty, i.e., a case-sensitive match is tried first, then a case-insensitive one)
* `ZSHZ_CMD` changes the command name (default: `z`)
* `ZSHZ_CD` specifies the default directory-changing command (default: `builtin cd`)
* `ZSHZ_COMPLETION` can be `'frecent'` (default) or `'legacy'`, depending on whether you want your completion results sorted according to frecency or simply sorted alphabetically
@@ -317,10 +281,9 @@ Zsh-z has environment variables (they all begin with `ZSHZ_`) that change its be
* `ZSHZ_ECHO` displays the new path name when changing directories (default: `0`)
* `ZSHZ_EXCLUDE_DIRS` is an array of directories to keep out of the database (default: empty)
* `ZSHZ_KEEP_DIRS` is an array of directories that should not be removed from the database, even if they are not currently available (useful when a drive is not always mounted) (default: empty)
* `ZSHZ_LOCK_TIMEOUT` is the number of seconds to wait for the database lock before giving up on a write (default: `1`). Where `zsh/system` is unavailable and `zsystem flock` cannot be used -- MobaXterm's cut-down Cygwin, for instance -- Zsh-z serializes writes with an atomic `mkdir` on `~/.z.lock.d` instead, and this setting bounds the wait the same way. That fallback has no equivalent of the kernel releasing a lock when its holder dies, so a lock directory older than 30 seconds is treated as abandoned and cleared; a write takes milliseconds, so nothing legitimate is ever that old. A write that times out is dropped silently -- the automatic `precmd` add is best-effort -- so if the database seems to stop updating, the lock is probably contended: run `z --add .` by hand and check `$?`. A `2` is a lock-acquisition timeout, which confirms contention -- look for a stale process holding `~/.z.lock` (or a leftover `~/.z.lock.d` directory on the fallback path), or raise this setting. A `1` is something else entirely, usually a permissions or ownership problem, such as a root-owned `~/.z` or `~/.z.lock` left behind by an earlier `sudo -s` session.
* `ZSHZ_MAX_SCORE` is the maximum combined score the database entries can have before they begin to age and potentially drop out of the database (default: 9000)
* `ZSHZ_NO_RESOLVE_SYMLINKS` prevents symlink resolution (default: `0`)
* `ZSHZ_OWNER` is the username the database belongs to; set it to your own login name to keep `z` working in a root shell, such as under `sudo -E -s`; [see below](#zshz_owner) (default: empty)
* `ZSHZ_OWNER` allows usage when in `sudo -s` mode (default: empty)
* `ZSHZ_TILDE` displays the name of the `HOME` directory as a `~` (default: `0`)
* `ZSHZ_TRAILING_SLASH` makes it so that a search pattern ending in `/` can match the final element in a path; e.g., `z foo/` can match `/path/to/foo` (default: `0`)
* `ZSHZ_UNCOMMON` changes the logic used to calculate the directory jumped to; [see below](#zshz_uncommon) (default: `0`)
@@ -356,12 +319,6 @@ then there is no common prefix. In this case, `z code` will simply send you to t
You may enable an alternate, experimental behavior by setting `ZSHZ_UNCOMMON=1`. If you do that, Zsh-z will not jump to a common prefix, even if one exists. Instead, it chooses the highest-ranking match -- but it drops any subdirectories that do not include the search term. So if you type `z bat` and `/home/me/code/bat` is the best match, that is exactly where you will end up. If, however, you had typed `z code` and the best match was also `/home/me/code/bat`, you would have ended up in `/home/me/code` (because `code` was what you had searched for). This feature is still in development, and feedback is welcome.
## `ZSHZ_OWNER`
If you are using `root` privileges while keeping your personal home directory as `HOME` (as is the case with `sudo -E -s`), conflicts with file ownership arise. You can resolve them by using `ZSHZ_OWNER`. If you set this variable to your username, Zsh-z will be able to use your personal datafile, restoring its proper ownership with every write.
Setting `ZSHZ_OWNER` makes one thing stricter, because a privileged shell is then writing to a path that an unprivileged user controls: Zsh-z follows a symlink on the way to the datafile -- the file itself, or any parent directory -- only if `root` owns the link, and reports an error instead of writing otherwise. Symlinked system directories, such as `/home` → `/usr/home` on the BSDs or `/var` → `/private/var` on macOS, belong to root and still resolve. With `ZSHZ_OWNER` unset none of this applies: a symlinked `~/.z` is followed exactly as before, so pointing it at synced storage keeps working.
## Making `--add` Work for You
Zsh-z internally uses the `--add` option to add paths to its database. @zachriggle pointed out to me that users might want to use `--add` themselves, so I have altered it a little to make it more user-friendly.
@@ -374,33 +331,9 @@ A good example might involve a directory tree that has Git repositories within i
(As a Zsh user, I tend to use `**` instead of `find`, but it is good to see how deep your directory trees go before doing that.)
## Performance
One of the goals of the rewrite that culminated in v2.0 was to make Zsh-z simultaneously more stable and faster. On modern Zsh, Zsh-z outpaces `rupa/z`'s `z.sh` at adding, searching, and listing. Representative figures (N = 200 database entries, medians of seven interleaved runs on a Core i7-12700 desktop under WSL2):
**Modern Zsh (5.9) -- Zsh-z vs. `rupa/z`:**
| Operation | `rupa/z` (`z.sh`) | Zsh-z | Winner |
| --------- | ----------------- | ----------- | ----------------- |
| `add` | 6.25 ms/op | 1.99 ms/op | **Zsh-z** ~3.14x |
| `search` | 6.51 ms/op | 3.62 ms/op | **Zsh-z** ~1.80x |
| `list` | 8.93 ms/op | 4.36 ms/op | **Zsh-z** ~2.05x |
**Zsh 4.3.11 (the oldest supported release) -- Zsh-z vs. `rupa/z`:**
| Operation | `rupa/z` (`z.sh`) | Zsh-z | Winner |
| --------- | ----------------- | ----------- | ----------------- |
| `add` | 5.00 ms/op | 2.92 ms/op | **Zsh-z** ~1.71x |
| `search` | 4.93 ms/op | 4.47 ms/op | **Zsh-z** ~1.10x |
| `list` | 7.92 ms/op | 6.08 ms/op | **Zsh-z** ~1.30x |
Removal is absent from these tables: in `rupa/z`, the per-prompt hook re-adds the current directory right after `z -x` removes it, so the two implementations' `-x` are not doing comparable work.
Relative to the previous generation of Zsh-z, the v2.0 read path is dramatically faster -- on modern Zsh, listing the whole database is about 2.4x faster and searching about 1.6x faster.
## Other Improvements to the Original Functionality of `rupa/z`
* `z -x` works: a directory you remove stays removed.
* `z -x` works, with the help of `chpwd_functions`.
* Zsh-z is compatible with Solaris.
* Zsh-z uses the "new" `zshcompsys` completion system instead of the old `compctl` one.
* No error message is displayed when the database file has not yet been created.
@@ -422,10 +355,12 @@ If you are coming to Zsh-z (or even to the original `rupa/z`, for that matter) f
## `COMPLETE_ALIASES`
`z`, or any alternative you set up using `$ZSHZ_CMD` or `$_Z_CMD`, is an alias. `setopt COMPLETE_ALIASES` divorces the tab completion for aliases from the underlying commands they invoke, which historically broke Zsh-z's tab completion. Zsh-z now handles this automatically: the first Tab press registers the alias name with `_zshz` so completion works under `COMPLETE_ALIASES` without any extra setup.
`z`, or any alternative you set up using `$ZSHZ_CMD` or `$_Z_CMD`, is an alias. `setopt COMPLETE_ALIASES` divorces the tab completion for aliases from the underlying commands they invoke, so if you enable `COMPLETE_ALIASES`, tab completion for Zsh-z will be broken. You can get it working again, however, by adding under
That registration happens inside Zsh-z's own Tab widget. If a plugin loaded after Zsh-z replaces the Tab binding without invoking the previous widget, Zsh-z's widget never runs and the registration does not happen. Under `COMPLETE_ALIASES`, you would then have no completion for `z`. Once `compinit` has run, adding
setopt COMPLETE_ALIASES
the line
compdef _zshz ${ZSHZ_CMD:-${_Z_CMD:-z}}
below `setopt COMPLETE_ALIASES` in your `.zshrc` fixes that, and it is harmless if the automatic registration has already run.
That will re-bind `z` or the command of your choice to the underlying Zsh-z function.

View File

@@ -1,6 +1,6 @@
#compdef zshz ${ZSHZ_CMD:-${_Z_CMD:-z}}
#
# Zsh-z - jump around with Zsh - A native Zsh version of rupa/z without awk, sort,
# Zsh-z - jump around with Zsh - A native Zsh version of z without awk, sort,
# date, or sed
#
# https://github.com/agkozak/zsh-z
@@ -24,7 +24,11 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
################################################################################
#
# z (https://github.com/rupa/z) is copyright (c) 2009 rupa deadwyler and
# licensed under the WTFPL license, Version 2.a
#
# shellcheck shell=ksh
############################################################
# Zsh-z COMPLETIONS

File diff suppressed because it is too large Load Diff