第 6 章:主题与提示符 —— 表现层如何消费公共状态¶
6.1 主题不是渲染器框架¶
Oh My Zsh 没有统一的 theme class 或组件接口。主题本质上就是一个会被 source 的 zsh 文件,通常直接设置 PROMPT、RPROMPT 和若干颜色/函数。
公共约定来自 lib/:
lib/theme-and-appearance.zsh → 颜色与主题默认常量
lib/git.zsh → git_prompt_info / git_prompt_status
lib/prompt_info_functions.zsh → ruby/pyenv/nvm 等 prompt helper
lib/vcs_info.zsh → vcs_info 的安全修补
所以主题的稳定性来自“共享函数名和变量名”,而不是来自类型系统。
6.2 最小主题:Robby Russell¶
themes/robbyrussell.zsh-theme 只有几行:
PROMPT="%(?:green-arrow:red-arrow) %c"
PROMPT+=' $(git_prompt_info)'
ZSH_THEME_GIT_PROMPT_PREFIX="git:("
ZSH_THEME_GIT_PROMPT_SUFFIX=") "
它做了三件事:
- 使用 zsh prompt condition 显示上一条命令成功/失败;
- 用
%c显示当前目录; - 调用公共
git_prompt_info拼接仓库状态。
这说明“主题”可以很薄:复杂的 Git 解析不需要每个主题重复实现。
6.3 Git prompt 的公共协议¶
lib/git.zsh 先通过 __git_prompt_git 包装 Git 命令,把 GIT_OPTIONAL_LOCKS=0 只作用于 prompt 查询,避免 prompt 刷新对其他 Git 进程产生可选锁影响。
_omz_git_prompt_info 大致按下面顺序取 ref:
- 当前 branch;
- 当前 tag;
- short SHA;
- 调用
parse_git_dirty附加 dirty/clean 标记; - 根据
ZSH_THEME_GIT_PROMPT_*变量拼接结果。
_omz_git_prompt_status 则使用 git status --porcelain -b,把 untracked、added、modified、renamed、deleted、unmerged、ahead、behind 等状态映射成主题可配置的字符串。
6.4 dirty 判断不是布尔值那么简单¶
parse_git_dirty 会考虑:
oh-my-zsh.hide-dirty:是否完全关闭 dirty 检查;DISABLE_UNTRACKED_FILES_DIRTY=true:是否忽略未跟踪文件;GIT_STATUS_IGNORE_SUBMODULES:如何处理 submodule;ZSH_THEME_GIT_PROMPT_DIRTY/CLEAN:最后显示什么。
大仓库中的 untracked 扫描会明显拖慢每个 prompt,因此这个开关是性能控制,而不只是视觉设置。
6.5 异步 Git prompt¶
当前快照的 lib/git.zsh 支持通过 :omz:alpha:lib:git zstyle 选择异步模式。启用后:
git_prompt_info不立即执行 Git,而是读取_OMZ_ASYNC_OUTPUT;_defer_async_git_register先检查 prompt 变量中是否真正使用了该函数;- 只有使用了函数才注册异步 handler;
- 下一次 prompt 刷新时显示后台结果。
“按需注册”很重要:不使用 Git prompt 的主题不会为它付出异步任务成本。异步功能是 alpha 级别,遇到提示消失或延迟异常时可以:
6.6 Agnoster:一个更复杂的主题¶
Agnoster 把 prompt 拆成 segment,用背景色和 Powerline 字符连接。它会按需显示:
- user@host;
- 当前目录;
- Git branch、dirty、ahead/behind;
- virtualenv、AWS profile、状态码和后台 job。
它要求 Powerline patched font,因为 、 等字符依赖字体 glyph。这个依赖不是 Oh My Zsh 核心可以解决的,主题文件只能在注释中说明环境要求。
6.7 prompt 中的 % 与不可信文本¶
Git branch、目录名和远端信息可能包含 %。源码多处使用 ${value//\%/%%},把普通百分号转义成 prompt expansion 可接受的形式;lib/vcs_info.zsh 还对 vcs_info hook 字段做了类似修补。
这是一个容易被忽略的安全点:如果外部仓库名称被直接放进 PROMPT,它可能被 zsh 当成 prompt 格式重新解释。主题开发应始终对来自 Git、文件名或外部命令的文本做 prompt-safe 处理。
6.8 编写自定义主题的最小模板¶
# $ZSH_CUSTOM/themes/minimal-safe.zsh-theme
autoload -Uz add-zsh-hook
function _my_prompt_precmd() {
PROMPT="%F{cyan}%~%f $(git_prompt_info) %# "
}
add-zsh-hook precmd _my_prompt_precmd
比直接在 source 时一次性计算更稳妥,因为目录和 Git 状态会随命令变化。主题还应避免每次 prompt 都启动多个昂贵的外部进程。