跳轉到

Zsh 補全最佳實踐

editorcfg 的 verbs/presets 由成對的 69_editorcfg_completion.zsh/.bash 補全;只接收檔名的 dotfiles-editor 使用兩個 shell 的檔案補全。兩者皆為受管 shell CLI(策略 B)。

本 dotfiles 專案中 zsh 自動補全 (tab completion) 的組織方式。

Terminology rule (zh-TW pages)

技術名詞首次出現以「中文 (English original)」格式呈現,例:依賴注入 (dependency injection)。不自創翻譯——若無公認譯名直接保留英文 (如 embedding、tokenizer)。代碼、API 名、CLI flag、套件名、檔名一律不翻。

架構 (Architecture)

compinit runs once (inside oh-my-zsh.sh)
        │
        ├── ~/.zfunc/                          ← user-generated completions (NOT tracked by chezmoi)
        ├── ~/.oh-my-zsh/custom/plugins/       ← community completions (184 files, cloned by ansible)
        │     └── zsh-completions/src/
        ├── ~/.docker/completions/             ← Docker-shipped completions
        ├── $(brew --prefix)/share/zsh/        ← Homebrew-managed completions (via `brew completions link`)
        │     └── site-functions/
        └── $ZSH/completions/                  ← oh-my-zsh built-in completions

所有 fpath 的新增都在 dot_zshrc.tmpl 中、且位於 source "$ZSH/oh-my-zsh.sh" 之前,因此 compinit 只會執行一次並載入所有項目。

補全分類 (Completion Categories)

工具可分為四大類:

A. 自我產生 (tool completion zsh > ~/.zfunc/_tool)

大多數現代 CLI 工具能夠輸出自己的補全腳本 (script)。安裝後執行一次,版本升級後重新執行。

Tool Command
uv uv generate-shell-completion zsh
mise mise completion zsh
chezmoi chezmoi completion zsh
just just --completions zsh
bat bat --completion zsh
delta delta --generate-completion zsh
starship starship completions zsh
rg rg --generate complete-zsh
fd fd --gen-completions zsh
zellij zellij setup --generate-completion zsh
sesh sesh completion zsh
pueue pueue completions zsh
docker docker completion zsh
gh gh completion -s zsh
opencode opencode completion zsh
omp omp completions zsh
pia pia completion zsh
translate translate completion zsh
dev dev completion zsh
lazyclash lazyclash completion zsh
lazychezmoi lazychezmoi completion zsh
lazymlflow lazymlflow completion zsh
lazypueue lazypueue completion zsh
exp exp completion zsh
lazyansible lazyansible completion zsh
lazycrontab lazycrontab completion zsh
lazyfind lazyfind completion zsh
lazypkg lazypkg completion zsh
lazymermaid lazymermaid completion zsh
lazyset lazyset completion zsh
bw bw completion --shell zsh

個人工具由 personal_tools 安裝;macOS 使用 personal tap、Linux 使用驗證過的 release binaries。Completion 同樣由每次 apply 的 run_after_50 產生;檔案放在未納入版本控制的 ~/.zfunc/_lazyclash 與 bash 使用者 completion 目錄。若只要刷新它,執行:

scripts/generate_completions.sh --tool lazyclash --force

--tool 不會改動其他工具;未知名稱會在建立 output 目錄之前失敗。 目前 .zshrc 已在 Oh My Zsh 的 compinit 之前加入 ~/.zfunc,不需再加 startup 設定。第一次安裝後開新 shell 即可,不要清掉所有 compdump。 原生 Cobra zsh bridge 每次 Tab 都向目前 binary 取得候選,所以新命令、flags 與本機動態候選不需要另一層 startup cache。Bridge 本身則在 apply 或手動刷新 時更新;legacy Bash 靜態 script 不具備相同保證,仍需維持生成檔的新鮮度。 just upgrade-go 本身不執行 completion 生成。

Fresh apply 若尚未重載 PATH,bulk generator 也會探測 ~/.local/bin/<tool>;因此剛安裝的 OMP 不需要第二次開 shell/apply 就能 生成 completion。pia 則直接使用 ~/.local/share/pi-agents/bin/pia,並以 checkout 的 .git/index 判斷 repo revision 是否較新;因此不依賴 shell PATH,也不會因 launcher mtime 沒變而留下過期 completion。

使用模式:

# 產生一次(或升級後)
mkdir -p ~/.zfunc
uv generate-shell-completion zsh > ~/.zfunc/_uv
mise completion zsh > ~/.zfunc/_mise

B. 預先打包(無需動作)

補全隨套件 (package) 一起出貨,或經由 zsh-completions 社群外掛 (plugin) 提供。

Tool Source
eza Homebrew formula 將 _eza 安裝到 site-functions
git oh-my-zsh git plugin
yazi release 資產中包含 _yazi(zsh-completions 也有)
lazygit 不支援補全;不需要(TUI app)
btop 不支援補全;不需要(TUI app)
其他眾多工具 zsh-completions plugin 涵蓋 184 個工具

C. 啟動時 eval/source(shell 整合)

這些工具在更廣泛的 shell 整合中注入補全。已在 dot_config/zsh/tools/ 中處理。

Tool Where How
fzf tools/10_fzf.zsh source <(fzf --zsh)
zoxide tools/20_zoxide.zsh eval "$(zoxide init zsh)"
thefuck tools/25_thefuck.zsh eval $(thefuck --alias)
direnv tools/30_direnv.zsh eval "$(direnv hook zsh)"
marimo tools/29_marimo.zsh eval "$(_MARIMO_COMPLETE=zsh_source marimo)"

D. 不支援補全

claude、gemini、btop、lazygit、summarize —— 沒有可用的產生命令。

實測 summarize 0.22.0 的 summarize completion zsh 會回報 too many arguments,因此不應列入自動產生清單。

E. 透過 shtab / tyro 的 Python 工具

Python CLI 框架 (framework) 可以產生補全:

  • tyro:python my_cli.py --tyro-write-completion zsh ~/.zfunc/_my_cli
  • shtab:shtab --shell=zsh my_module.parser > ~/.zfunc/_my_tool
  • argcomplete:register-python-argcomplete tool_name(使用 eval,屬於 C 類)
  • click(mlflow、litellm 等使用):_TOOL_COMPLETE=zsh_source tool > ~/.zfunc/_tool

為何 ~/.zfunc/ 不由 chezmoi 追蹤

決定:~/.zfunc/ 不納入版本控制。 理由:

  1. 補全與工具版本相依。 由 uv 0.6 產生的補全腳本可能不符合 uv 0.7。追蹤過時檔案會造成隱微的損壞。
  2. 不是所有使用者都安裝相同工具。 若沒安裝 pueue,_pueue 補全檔案毫無用處(且會丟出警告)。
  3. 重新產生很簡單。 每個工具只需要一行命令。
  4. Brew 安裝的工具自動管理其補全,透過 site-functions。在 ~/.zfunc/ 中重複會造成衝突。

我們有追蹤的內容

  • dot_zshrc.tmpl 中的 fpath+=~/.zfunc(確保此目錄在搜尋路徑中)
  • 由 ansible 複製 (clone) 的 zsh-completions 外掛(社群補全)
  • ~/.docker/completions 的 fpath 條目
  • dot_config/zsh/tools/ 中工具特定的 eval/source 整合

全新安裝後產生補全

自動產生失敗時,即使使用 --quiet,仍會顯示工具名稱、shell 與退出碼 (或 empty output),並保留原有補全。完整執行會繼續處理其他工具、 顯示失敗數;指定 --tool 時失敗會回傳非零退出碼。 exit 137 (SIGKILL) 表示程式被強制終止;macOS 可先查該工具在 ~/Library/Logs/DiagnosticReports 的紀錄與程式簽章,不要直接歸因於記憶體不足。

在新機器上執行 chezmoi apply 後,多數補全已可透過 zsh-completions 外掛和 Homebrew site-functions 運作。對於想要更豐富/更新版補全的工具,可將其產生到 ~/.zfunc/:

mkdir -p ~/.zfunc

# 核心工具(永遠安裝)
chezmoi completion zsh > ~/.zfunc/_chezmoi
mise completion zsh > ~/.zfunc/_mise
uv generate-shell-completion zsh > ~/.zfunc/_uv
just --completions zsh > ~/.zfunc/_just
starship completions zsh > ~/.zfunc/_starship

# 開發工具(若已安裝)
command -v gh    && gh completion -s zsh > ~/.zfunc/_gh
command -v docker && docker completion zsh > ~/.zfunc/_docker
command -v rg    && rg --generate complete-zsh > ~/.zfunc/_rg
command -v fd    && fd --gen-completions zsh > ~/.zfunc/_fd
command -v bat   && bat --completion zsh > ~/.zfunc/_bat
command -v delta && delta --generate-completion zsh > ~/.zfunc/_delta
command -v zellij && zellij setup --generate-completion zsh > ~/.zfunc/_zellij
command -v sesh  && sesh completion zsh > ~/.zfunc/_sesh
command -v pueue && pueue completions zsh > ~/.zfunc/_pueue

# Coding agents(若已安裝)
command -v opencode && opencode completion zsh > ~/.zfunc/_opencode
command -v omp   && omp completions zsh > ~/.zfunc/_omp
command -v pia   && pia completion zsh > ~/.zfunc/_pia
command -v bw    && bw completion --shell zsh > ~/.zfunc/_bw

# 強制重建補全快取
rm -f ~/.zcompdump && compinit

小提示: 你可以將其儲存為 ~/.local/bin/ 中的腳本,或將其作為函式 (function) 加入 ~/.zshrc.adhoc。

優先順序 / 覆寫順序

當同一個 _tool 檔案存在於多個 fpath 目錄中時,第一個符合者勝出:

1. ~/.zfunc/                                    (最高 - 你的覆寫)
2. ~/.oh-my-zsh/custom/plugins/zsh-completions/src/
3. ~/.docker/completions/
4. $(brew --prefix)/share/zsh/site-functions/   (Homebrew-managed)
5. /usr/share/zsh/*/functions/                  (system, lowest)

目前 dot_zshrc.tmpl 的順序:

fpath+=~/.zfunc                     # appended (lowest of custom)
fpath=(zsh-completions/src $fpath)  # prepended (higher than ~/.zfunc)
fpath=(~/.docker/completions $fpath) # prepended (highest of custom)

若你希望 ~/.zfunc/ 覆寫社群補全,改為前置 (prepend):

fpath=(~/.zfunc $fpath)  # prepend instead of append

FAQ

Q:對於 zsh-completions 已涵蓋的工具,我還應該產生補全嗎? A:只有當你想要最新版本時。社群外掛可能落後。對於快速演進的工具(uv、mise),自行產生是值得的。

Q:解除安裝某工具後,補全檔案丟出錯誤,該怎麼辦? A:移除該檔案:rm ~/.zfunc/_toolname。fpath 中過時的 _tool 檔案除非有語法錯誤,否則無害(會被靜默忽略)。

Q:我該如何除錯補全問題? A:執行 echo $fpath | tr ' ' '\n' 查看所有 fpath 條目。使用 which _toolname 查看正在使用哪個補全檔案。透過 rm -f ~/.zcompdump && compinit 強制重建。