Ghostty 开发日志 004
原文由 Mitchell Hashimoto 于 发布,订阅该博客
你好!欢迎阅读 Ghostty 的第四期官方开发日志 👻!
如果你错过了之前的开发日志,或想进一步了解 Ghostty 是什么,请查看本站上的 Ghostty 页面。
社区动态
上周,我公开了我们的公开 Discord 服务器,还发表了一场关于 Ghostty 与 Zig 的演讲。如果你错过了这两项,请务必去看看。新的 Beta 测试邀请将通过 Discord 社区分发。另外,我们的 Discord 社区人数已超过 600 人。太棒了!
自上一期 Ghostty 开发日志以来,封闭测试的规模已从约 30 人增长到约 100 人。在项目早期,每一轮新增的测试者只有几人,但随着 Ghostty 变得越来越稳定,现在每一轮我们都能轻松新增 15 到 20 人。我认为这是个非常好的信号!
精美的图形界面
在深入探讨终端内部原理和那些古老技术之前,我们先来聊聊图形界面的改进,欣赏一些视觉效果。如果你期待的是硬核技术内容,后面的章节会深入细节。
macOS 和 Linux 上的原生界面都有了长足进步。在 Linux 上,Ghostty 现在拥有标题栏菜单、宽标签页(可配置)、“关于”窗口等。与 Gnome Terminal 和其他基于 GTK 的终端并排放置时,Ghostty 显得十分协调:

在 Linux 方面,现在已有不少 Beta 测试者通过 Sway、Hyprland 等合成器在 Wayland 上使用 Ghostty。我们修复了不少问题,Ghostty 如今在 Wayland 上运行得非常出色。
在 macOS 上,我们新增了 window-theme 设置,让你可以将 Ghostty 固定为深色或浅色模式,而不再只是跟随系统。我个人平时将 macOS 设为浅色模式,但希望终端始终保持深色,所以可以强制设为深色。我们还让失去焦点的分屏会变淡(可配置)。整体效果非常漂亮:

Ghostty 的既定目标之一,就是提供原生体验,让你感觉 Ghostty 就是为你当前使用的平台量身打造的。我们非常重视图形界面的改进,确保 Ghostty 在不同平台上都遵循符合其设计规范的原生风格。上述改进正是我们在这一理念上取得进展的体现。
我们发现了一个 Vim Bug!还有其他“不乖”的程序
在很长一段时间里,Ghostty 都将自己标识为 TERM=xterm-ghostty。xterm- 前缀的存在,是因为有许多“不乖”的程序会通过对 TERM 进行字符串匹配来判断终端是否支持某项功能。这种做法是错误的,也非常不规范,千万不要这么做!正确的做法是查询 terminfo 数据库。
Terminfo 本身就是一个极其有趣(主要是因为它相当“折磨人”)的话题。我希望将来能专门写一篇关于 terminfo 的博客文章。本期开发日志不会深入探讨 terminfo。如果你想一窥这个古老怪物的面貌,可以在终端里运行 infocmp 看看。
过去一个月里,我们一直在尝试去掉 xterm- 前缀,直接使用 TERM=ghostty。在这个过程中,我们发现了自身 terminfo 数据库中的不少 Bug,也遇到了一些上游问题。我们正一边推进一边修复这两类问题。
最近,我们被一个 Vim Bug 卡住了。Vim 9.0 支持 Kitty 键盘协议,但它硬编码了支持该协议的终端列表,而没有正确遵循 terminfo 数据库。这是一个 Bug,令人惊喜的是,一位 Ghostty 社区成员已经提交了修复它的 Pull Request。这个问题不会影响 Neovim。
Vim 毕竟还是有点重要的1,所以在该 Bug 被修复且下游发行版广泛更新之前,我们不得不暂时回退到 TERM=xterm-ghostty。尽管如此,我仍为已取得的进展感到自豪,也乐观地相信我们很快就能摆脱 xterm 的束缚。
我们还发现了其他上游 Bug,令我自豪的是,Ghostty 社区的成员不仅报告了问题,还主动提供了修复。Tim 向热门 Go 库 tcell 提交了一个 PR,修复了一个相当严重的问题。这个库非常重要,因为它被 lazygit、lazydocker 等热门 TUI 应用所使用。如果没有这个修复,除非你显式地以 TERM=xterm-256color 运行,否则这些程序都会输出乱码。希望这个修复能尽快被合并!
这些 Bug 和修复都并非 Ghostty 独有,它们都有助于让各种程序在面对不熟悉的终端模拟器时表现得更加健壮。
这项工作主要由Tim Culverhouse 推动,我对他的付出深表感谢。
XTGETTCAP(#563)
terminfo 的一大问题在于,它依赖本地文件,需要由正在运行的程序去读取。这意味着,如果你通过 SSH 连接到远程主机,而远程主机上没有你所用终端的 terminfo,程序就无法判断你的终端具备哪些能力,可能会出现行为异常或无法发挥最佳效果。
XTGETTCAP 是终端的一项功能,它允许通过 VT 转义序列来查询终端的 terminfo 数据库,而不是读取本地文件。这带来了几个好处:程序无需知道如何解析二进制格式或查找文件路径,即使在远程运行时也能查询 terminfo。
XTGETTCAP 的形式如下:
# Query for stylized underline support (key "Smulx")
ESC P + q 536D756C78 ESC \
# Response from the terminal (Smulx=\E[4:%p1%dm)
ESC P 1 + r 536D756C78=5C45343A25703125646D ESC \一目了然,对吧?其实也没那么复杂。程序会发送 ESC P + q <key> ESC \ 这样的文本,其中 <key> 是一个经过十六进制编码的字符串。在上面的例子中,我们对 “Smulx” 进行了十六进制编码。而终端返回的响应中则包含了该 terminfo 条目的键和值,同样是十六进制编码的。
我们实现中一个特别酷的地方在于,利用了Zig 的 comptime 能力在编译期生成所有可能的请求和响应。这些内容与生成实际 terminfo 文件使用的是同一个源文件,因此我们的 terminfo 和 XTGETTCAP 始终保持完全同步。
XTGETTCAP 的性能其实根本无关紧要,但我们的 XTGETTCAP 实现快得离谱,因为它是一个在编译期优化好的查找表。我们无需进行任何内存分配、字符串格式化等操作,只需做一次简单查找,找到一个稳定的字符指针,然后直接写入 pty。非常酷。
可以看看生成这一切的 Zig 代码片段。我太喜欢 Zig 的 comptime 了。
可变字体(#345)
大多数字体都提供一组固定的样式,如 “Bold”、“Heavy”、“Medium”、“Italic” 等。而可变字体则只提供单一字形,却能让你通过某个范围内的连续数值来调节字重、倾斜度等各种轴向。Ghostty 现在已支持可变字体,并可配置变化轴。
首先,来看看可变字体是什么样子的。Inconsolata 就有可变字体版本,在下面的视频中,你可以看到我如何精细地控制字符的宽度和字重。
以下是 Ghostty 使用 Inconsolata 时的默认效果,未设置任何字体变化轴:

而下面则是我们稍微调整字重后的配置。差别很细微,但还是能看出来。先是配置内容,然后是截图。
font-family = Inconsolata
font-variation-bold = wght=500

为什么上面用的是 wght 而不是 weight?变化轴的键名由字体本身决定,且字体变化轴的键必须是四个字符。这些键名并未标准化,所以我们无法安全地将 weight 转换为 wght。Ghostty 的配置直接使用原始的变化轴键名,用户可以通过任何字体检查工具(如FontDrop)来查看有效的键名。
在终端模拟器中,对可变字体的支持还相对少见,因此我很自豪我们实现了这一功能(而且是跨平台的!)。这类特性让你能够将终端微调到完全符合自己喜好的状态,达到恰到好处的感觉。
尾声
再次感谢最新一批的 Beta 测试者。每一轮都会迎来一些非常出色的人,他们在某些领域有着深厚的专业知识,或是以新颖独特的方式使用终端,从而发现问题。
如果想保持关注,可以在 Twitter 或 Mastodon 上关注我(链接在页面底部)。本博客也提供了RSS 订阅。
Boo. 👻
脚注
愿 Bram Moolenaar 安息,感谢你为我们付出的一切。 ↩
随机一篇博客
评论
登录后参与讨论