Zsh:补全、预览与启动排障
本页目录
按 Tab 后发生的事情可以拆成三步:补全函数生成候选,fzf-tab 展示候选,预览命令解释当前选项。候选为空、列表无法显示和预览报错属于不同问题。按这个顺序配置,比一次加载所有插件更容易排错。
本文从交互式 .zshrc 开始。登录 Shell 还可能读取 .zprofile 等文件;所有 Zsh 调用都可能受到 .zshenv 影响,因此不要把只适用于交互终端的输出和插件初始化放进 .zshenv。
先让原生补全工作
在 .zshrc 中,先把额外补全目录加入 fpath,再初始化补全系统:
新开一个 Zsh,分别测试 cd <Tab> 和 git switch <Tab>。前者应给目录候选,后者应在 Git 仓库中给分支候选。compinit 报告目录权限问题时,先运行 compaudit 查看具体目录并修正其归属/权限,不应长期用跳过检查掩盖问题。
临时排除个人启动配置可以使用:
然后手动执行上面的初始化。这个会话不会加载通常的用户启动文件;退出后回到原 Shell。如果基础补全正常,故障范围就收敛到日常配置或插件。
fzf-tab 负责选择,不负责知识
安装 fzf 和 fzf-tab 后,在 compinit 后加载插件。以下路径是示例,必须替换成实际安装位置:
它使用原有补全结果,并把选择界面交给 fzf。若分支候选本来就不正确,改变 fzf 颜色不会修复候选来源。fzf-tab 文档
加载顺序可以按下表检查:
| 顺序 | 内容 | 原因 |
|---|---|---|
| 1 | fpath 和补全定义准备 | 让初始化时能找到函数 |
| 2 | compinit | 建立补全系统 |
| 3 | fzf-tab | 使用已有候选并接管选择 |
| 4 | 历史建议等编辑插件 | 避免后续加载破坏前面的编辑器包装 |
| 5 | 语法高亮 | 遵守所用版本的加载约定 |
从目录预览开始
先只为 cd 添加一条预览:
realpath 在文件/目录补全上下文中表示候选路径;引号保留路径中的空格,-- 防止以连字符开头的名称被解释成选项。不要在所有命令的补全中都假定这个变量存在。
验证目录预览后,再为 Git 分支增加:
这里 word 是当前候选。预览只是帮助选择;真正执行命令仍由 Shell 在回车后完成。候选能显示但右侧为空时,把预览命令拿到普通终端,替换成一个实际目录或分支后单独运行。
carapace 的接入边界
carapace 可以为许多命令提供补全,但初始化脚本可能重新定义已有命令的补全函数。应先决定某个命令由原生补全还是 carapace 负责,再检查 git switch 等依赖上下文的预览是否仍然正常。
旧配置通过过滤初始化输出里的 compdef 行,让 carapace 只作为后备。该做法依赖生成脚本的具体格式,而且还需要 _carapace 与 _carapace_completer 之间的适配函数;仅复制一行过滤命令并不完整。新环境优先依据官方 Shell 设置接入,不将文本过滤技巧当作通用 API。
历史建议、提示符与别名
zsh-autosuggestions 根据历史命令提供灰色建议,语法高亮检查当前命令行的结构,Starship 显示目录与项目状态。它们都不替代补全。
交互别名可以简化常用命令,例如:
脚本中仍应使用明确的程序名和参数,避免脚本依赖某台机器的交互别名。预览所需的 bat、eza 等程序必须实际可执行;参见 CLI 工具箱。
启动慢或补全失效时
先做语法检查:
它不执行初始化,也不会证明插件路径正确。随后在新会话逐层加载:原生补全 → fzf-tab → 一条预览 → 其他插件。列表突然为空时,检查 fzf 版本、未知参数和是否有其他插件重绑 Tab。
启动耗时明显增加时,可临时在 .zshrc 顶部加入 zmodload zsh/zprof,末尾加入 zprof,观察最耗时的函数,完成后移除这两项。网络查询、重复初始化和大型提示符计算比单纯“插件数量多”更值得定位。
最终应分别验证路径含空格、Git 分支选择、无候选命令和普通历史建议。通过这些场景后再调整预览尺寸和颜色。