主题与终端适配 · 在五花八门的终端里都好看
从 truecolor 到 16 色、从 iTerm 到 ConHost、从跟随系统明暗到 OSC 11 探测——让配色在任意终端里都不崩,是一大堆不起眼的适配。这一章看 grok 的语义主题、颜色能力探测与降级、终端品牌识别。
主题与终端适配 · 在五花八门的终端里都好看
一个终端产品要面对的现实:用户的终端千差万别——truecolor 还是 16 色、深色还是浅色、iTerm 还是 Windows ConHost、裸终端还是 tmux+SSH。让配色在任意终端里都不崩,是一大堆不起眼的适配(都在 xai-grok-pager-render)。
语义主题
Theme 是约 60 个语义颜色字段:accent_user/accent_assistant/accent_thinking/accent_tool、bg_base、diff_delete_bg/diff_insert_bg……设计原则是全部走语义字段,模块注释直说别处不许硬编码颜色(代码块的语法高亮另走内置的 .tmTheme)。ThemeKind 有 GrokNight(默认)、GrokDay、TokyoNight、RosePineMoon、OscuraMidnight,其中几个 requires_truecolor() 的主题在非 truecolor 终端会被自动降级成 GrokNight。还有一个灰度中的 Terminal 主题:背景全用 Reset,让终端自己的底色透出来,不依赖明暗探测,要打开 features.terminal_theme 才看得到。
颜色能力探测与降级
Theme::current() 是热点访问器(缓存的是主题种类和颜色等级,Theme 本身按需构造),干这几件事:探测颜色等级 → Windows 上先做对比度增强(ConHost 的 gamma 会让深色 RGB 挤成一团;增强只对 RGB 生效,所以必须排在量化之前)→ 量化颜色 → 在 16 色/老 ConHost 上做 ANSI-16 chrome 覆盖(否则深色 RGB 全塌成黑)。
ColorLevel 分 None / Basic / Ansi256 / TrueColor,探测(detect)很讲究:NO_COLOR → None;否则用 supports-color crate;非 TTY → TrueColor(TUI 安全默认);若探到 < TrueColor 但终端品牌是 iTerm2、Ghostty、Kitty、WezTerm、Alacritty、Rio、Warp、VS Code、Windows Terminal、Foot 之一(原生 Windows 也算)→ 升级到 TrueColor——因为 tmux/SSH 常把 COLORTERM 剥掉,靠品牌名把它补回来。量化时 Rgb → 最近 256 色 / 最近 16 色(平方欧氏距离)。
跟随系统明暗
Auto 主题要跟随系统深浅色,探测是一条四级链(前一级没结果才走下一级):① dark_light crate 读桌面 API;② 环境变量 GROK_APPEARANCE / LC_GROK_APPEARANCE(后者能搭 SSH 的 LC_* 顺风车,grok wrap 会自动写入本地的明暗);③ 启动期向终端发 OSC 11 查询背景色,读回复、按 ITU-R BT.709 亮度阈值判明暗;④ 最后才看 COLORFGBG。OSC 11 查询必须在 crossterm 抢占 stdin 之前跑,自己临时管 termios;在 tmux 里还会改用 DCS 包装的查询再试一次,结果缓存下来供之后的轮询复用。
终端品牌识别
TerminalContext 认约 20 个终端品牌(TerminalName 是 19 个具名品牌加 Unknown,VS Code、Cursor、Windsurf、Zed、JetBrains 这些 IDE 的集成终端都算品牌)+ 多路复用器(tmux/screen/Zellij 等)+ 是否 SSH + 内嵌编辑器(Neovim/Vim/Emacs 里的 :terminal)。这些驱动一堆能力判断:键盘协议(Kitty keyboard)、超链接(OSC 8)支持、图形协议、是否会带外重绘 pane。识别靠环境变量,外加少量探测:只有在 tmux 里才会跑 tmux -V、tmux show-option 这类子进程;XTVERSION、DA2 则是直接发给终端的带内查询。
pager.toml
外观配置是两层:Raw*Config(从 ~/.grok/pager.toml 反序列化,字段自带文档)→ 运行时 AppearanceConfig。它在启动时读一次,改完重启生效——代码里的 watcher 只剩静态模式,注释里「开发模式热重载」的说法已跟不上实现;/settings 里改的部分外观项则会实时生效并回写这个文件。它控制 alt-screen 模式、动画、prompt、scrollback 布局等;主题、时间戳这类开关则在 config.toml 的 [ui] 里(比如 ui.theme,也可以用 /theme 切换)。排查配色问题时可以跑 grok doctor(会话里是 /doctor,旧名 /terminal-setup 仍是它的别名),看颜色等级和当前终端能用哪些主题。
和《从 LLM 到 Coding Agent》对照
教学实现根本不管终端差异——ANSI 转义直接吐。grok 的增量是能力门控的降级贯穿始终:颜色 truecolor→256→16→无、主题按能力钳制、按品牌反推 truecolor、多级探测明暗、约 20 个品牌识别。这些代码不产生任何「功能」,却决定产品在你的终端里是好看还是花屏。下一章看更炫也更硬核的:在终端里显示图片、以及让复制穿透 SSH。
上一篇:diff 与工具调用可视化 · 下一篇:PTY 包装与内联媒体