</> MoyiGeek's Blog

zsh-themes

· 7 分钟阅读 ·

Zsh 主题文件(.zsh-theme)的本质其实非常简单:它就是一个普通的 Shell 脚本,其核心工作就是给几个特定的环境变量赋值。

Zsh 提供了一套像“密码”一样的占位符(Prompt Expansion 语法),只要你弄懂了这些占位符,你就可以随心所欲地捏出任何你想要的主题。

下面为你详细拆解 Zsh 主题的语法核心:


1. 核心骨架:左右提示符

决定你在终端里看到什么的,主要是这两个变量:

  • PROMPT (或者叫 PS1):控制左侧的提示符内容。
  • RPROMPT (或者叫 RPS1):控制右侧的提示符内容。(Zsh 的绝活:当你在左边输入的命令太长,快碰到右侧内容时,RPROMPT 会自动隐藏,非常智能!)

2. 🎨 颜色与样式控制

颜色的语法就像 HTML 标签一样,需要“开启”和“闭合”。

  • 字体颜色 (Foreground):
    • 开启:%F{颜色名}%F{数字0-255}
    • 闭合:%f (重置为终端默认颜色,必须写,否则后面的字全变色)
    • 示例: %F{red}警告%f
  • 背景颜色 (Background):
    • 开启:%K{颜色名}
    • 闭合:%k
    • 示例: %K{blue}蓝底文字%k
  • 加粗与下划线:
    • 加粗:%B 开,%b
    • 下划线:%U 开,%u

支持的颜色名: black, red, green, yellow, blue, magenta (洋红), cyan (青色), white


3. ℹ️ 常用信息占位符

这就是提取系统信息的“快捷键”:

占位符含义示例输出
%n当前用户名 (name)root, user
%m主机名第一段 (machine)macbook, ubuntu
%M完整主机名macbook.local
%~当前路径(常用),遇到家目录会缩写为 ~~/Projects/demo
%d%/当前绝对路径,不会缩写为 ~/Users/user/Projects/demo
%c当前所在目录名(只显示最后一级)demo
%T24小时制时间14:30
%t12小时制时间2:30 PM

4. 🧠 高级魔法:条件判断(三元表达式)

我们在处理 箭头变色时,用了这段代码:%(?.%F{green}.%F{red})。 这是 Zsh 的条件语法,格式如下:

%(条件.成立时的结果.不成立时的结果)

  • ? 代表什么? ? 表示“上一条命令的退出状态码”。在 Linux/Unix 中,命令成功执行状态码就是 0(True),执行失败就是非 0(False)。
  • 拆解我们的代码: %(?.%F{green}.%F{red})❯%f 意思是:如果上一条命令成功执行 (?),输出 %F{green} (变绿);如果失败,输出 %F{red} (变红)。接着输出固定的 符号,最后 %f 恢复颜色。

5. 👻 避坑指南:零宽字符转义

(这就解释了为什么你之前输入时长命令会覆盖提示符)

终端在计算光标位置时,是靠数“有多少个字符”。 像 a1 这些是肉眼可见的,占 1 个宽度。 但是,如果你使用了自己写的原生 ANSI 颜色代码(比如 \e[31m),或者某些复杂的外部符号,终端如果认不出来,就会算错宽度,导致光标错位。

解决办法:%{...%} 如果你要包裹不占屏幕宽度的代码,必须用 %{%} 把它们包起来,告诉 Zsh:“这段代码不占屏幕宽度,算光标位置时跳过它!”。 (注:由于 %F{...} 是 Zsh 内置的颜色语法,它底层已经自动做了 %{%} 的处理,所以我们直接用 %F 就不需要额外加了。)


6. 🐙 Oh My Zsh 专属:Git 插件联动

你在主题开头看到的那些 ZSH_THEME_GIT_PROMPT_... 变量,并不是 Zsh 原生的语法,而是 Oh My Zsh 的 git 插件规定的接口。

当我们在 PROMPT 里写了 $(git_prompt_info) 时,它会去执行一段函数,检查当前是不是 Git 仓库:

  1. 如果是,先输出 PREFIX (前缀)。
  2. 获取当前分支名。
  3. 检查有没有未提交的修改:有就输出 DIRTY,没有就输出 CLEAN
  4. 最后输出 SUFFIX (后缀)。

所以,通过配置这 4 个变量:

ZSH_THEME_GIT_PROMPT_PREFIX=" git:("
ZSH_THEME_GIT_PROMPT_SUFFIX=")"
ZSH_THEME_GIT_PROMPT_DIRTY=" ✗"
ZSH_THEME_GIT_PROMPT_CLEAN=" ✔"

最后拼出来的结果就是: git:(main ✔)

总结

你现在的 PROMPT

PROMPT=$'%F{cyan}%n%f %F{yellow}%~%f$(git_prompt_info)\n%(?.%F{green}.%F{red})❯%f '

它的翻译过程是: 换青色 -> 输出用户名 -> 恢复默认 -> 敲个空格 -> 换黄色 -> 输出路径 -> 恢复默认 -> 拼上Git信息 -> 换行 -> (判断颜色) -> 输出❯ -> 恢复默认 -> 敲个空格结束。