Ghostty 开发日志 005
原文由 Mitchell Hashimoto 于 发布,订阅该博客
大家好!欢迎来到 Ghostty 👻 的官方开发日志!
距离上一篇开发日志已经过去两个多月,Ghostty 迎来了大量的更新。这段时间我忙于新手爸爸的身份,平时能用电脑的时间也基本都花在了改进 Ghostty 上,所以有些疏于更新开发日志,抱歉!
如果你错过了之前的开发日志,或者想进一步了解 Ghostty 是什么,请查看本站的 Ghostty 介绍页面。
社区动态
过去两个月里,内测人数已从 100 人增长到 350 多人!太惊人了!两个月前内测人数还不到 50 人。非常感谢大家对这个终端项目的关注,也感谢所有参与内测的朋友。如此庞大且不断壮大的测试群体,将确保 Ghostty 在正式公开发布时已经是一个强大而稳定的项目。
之所以每一批都能大幅扩大内测规模,是因为 Ghostty 在功能完整度和稳定性上都有了长足进步。以前每批只敢邀请 5 个人,就能收集到十几个 bug 或功能需求;现在邀请 50 个人才会有同样数量的反馈。而且这个数字还会继续增长。看到项目变得越来越真实、越来越稳定,真的很有成就感。
如果你想加入内测计划,请加入 Ghostty Discord,就有机会进入下一批内测。写下这篇日志时,Discord 社区中大约有 20% 的成员已加入内测。
终端检查器(#728)
终端是一个应用平台。我觉得“平台”这个词被用得太泛滥了,很多人用它来让自己的工作显得比实际更重要(或者至少想让投资人觉得更重要),但终端确实是一个面向文本交互的平台1。
没有运行于其上的应用,终端本身毫无趣味;更进一步说,没有应用,终端就毫无意义。提升终端应用数量和质量的一个途径,就是让终端开发变得更简单。
回看 Web 领域,对我而言开发体验的一次飞跃来自 Firebug 的出现,如今它更常被称为“网页检查器”,而且所有主流浏览器都已具备类似功能。我想把类似的体验带到终端,因此 Ghostty 现在拥有了终端检查器。
终端检查器的工作方式与网页检查器类似:它是每个终端窗口独立的面板,会实时显示当前终端的运行信息。你可以看到键盘输入(及其编码方式)、终端模式、字体大小、网格尺寸、单元格元数据、调色板颜色等大量信息。
我们的目标是让终端检查器成为终端开发者不可或缺的工具,让终端应用的开发和调试变得更轻松(而且这些应用可在任意终端中运行,不限于 Ghostty)。
终端检查器目前还处于非常早期、非常实验性的阶段。现在它还是一个纯只读界面,但我计划未来让它支持读写,这样你就可以修改单元格、切换终端模式、创建模拟输入事件等等。
终端检查器最初的想法来自一位内测社区成员,包括我在内的一小群人很快聚在一起,把它发展成了一个真正可行的功能。感谢所有参与其中的朋友!
亚洲语言输入(#八百八十八)
在最近几批内测中,我有意邀请了来自更多不同时区的朋友。这带来了更多使用中文、日文、韩文等语言的测试者。他们反馈了近十个与亚洲语言输入和渲染相关的问题。因此,Ghostty 现在对这些语言的支持已经非常完善。
在开发日志 003中,我有一个专门讲键盘输入的章节,标题叫“键盘输入处理让你头疼”。当时我大谈 Ghostty 在这方面做得多好,现在我要再强调一次,这一切有多么复杂,同时也要再说一遍:Ghostty 把这些都处理得很好2。
更复杂的输入状态
在开发日志 003中,我介绍了死键状态的概念。当时的 Ghostty 只处理单码点的死键状态。我以带重音的英文字母为例,比如先输入 '(撇号),再输入字母 a,就会得到 á。
而在日文等语言中,你会先输入一些字符,得到一个候选输入(有时还会弹出更多候选的下拉列表),然后可以按回车或 Tab 等按键来确认候选。
此前的 Ghostty 无法处理多码点的候选,也会在显示候选时错误地处理回车或 Tab 等按键。现在这些问题都已修复,你可以正常输入日文(以及其他语言)了。
这种多码点候选状态还带来了一些边界情况:在行尾输入,以及在过窄的窗口中输入。现在 Ghostty 也都已妥善处理。需要注意的是,上面的视频录制于另一个 bug 修复之前(如果你能发现的话),但那个问题现在也已经解决了。
中文字符对齐(#982)
在等宽的终端网格中以整洁、协调的方式渲染多种字体(以及 Emoji)是一项挑战,此前中文字符的显示就不太对劲:

可以看到,以 草 开头的词语渲染位置有点偏低。这是由于在混排某些字体时使用了错误的字体度量计算(这里是单元格基线)导致的。现在 Ghostty 已经修复了这个问题。

Linux 上的 IME 输入(#919)
macOS 系统内置了对输入法编辑器(IME)的良好支持。而在 Linux 的 GTK 环境下,IME 由可选安装的插件提供。正因如此,它们之前在 Ghostty 上没有得到充分测试,中文、日文、韩文的输入完全无法使用。
好在我在 Ghostty 的共享核心中已经为 IME 支持做了大量工作,因此要让它在 Linux 上正常工作,只需要一个 +47/-1 的改动来衔接好 GTK 与 Ghostty 的相关 API。结果就是,IME 在 Linux 上也能正常工作了:
注:该视频录制于上述修复之前,因此还能看到字符渲染不正确的情况。
自定义着色器(#903)
你有没有想过让终端看起来像一台复古 CRT 显示器?或者像一盘坏掉的 VHS 录像带?我他妈在说些什么?我疯了吗?不管怎样,现在你可以通过指定自定义着色器在 Ghostty 中实现这些效果,甚至更多。
撇开实用性不谈,这类功能看起来似乎会严重影响续航。现代软件普遍效率低下,把我们都给忽悠了!实际上 CPU 和 GPU 速度非常快,这点计算几乎不算什么。在我的机器上,上面的效果只占用约 1% 的 CPU 和约 2% 的 GPU。当然,它肯定比不用这个功能时更耗电,但还不至于让风扇狂转。
Ghostty 是一个由 GPU 驱动的终端模拟器。在 macOS 上它直接使用 Metal,在 Linux 上使用 OpenGL。GPU 通过调用着色器来渲染内容。着色器嘛,双手一摊,就是在 GPU 上运行的程序。
着色器通常用与技术栈相关的编程语言编写。例如,macOS 上的 Metal 使用 MSL(Metal Shading Language),OpenGL 使用 GLSL(GL Shading Language)等。Ghostty 接受用 GLSL 编写的着色器,并在 macOS 上实时将其转换为 MSL。为此,Ghostty 使用glslang 将 GLSL 转换为 SPIR-V(大致相当于一种中间表示),再用SPIRV-Cross 将 SPIR-V 转换为 MSL 等目标格式。我们通过它们暴露的 C API 编译并集成了这两个工具。
这个功能另一个非常酷的细节是,Ghostty 暴露了 Shadertoy 接口,因此你可以把许多 Shadertoy 上的着色器直接拿来放到 Ghostty 中,无需任何修改。更重要的是,你还可以把 Shadertoy 本身当作 Ghostty 自定义着色器的实时交互式开发工具!
不用担心,这个功能不会对性能造成负面影响。Ghostty 采用多线程渲染架构,在帧与帧之间有大量空闲时间。启用自定义着色器时,空闲时间会减少,但对其他线程(IO 和界面)几乎没有影响。未启用自定义着色器时,Ghostty 仍使用原有的渲染管线,不会为现有执行增加任何额外开销(除了对是否启用自定义着色器的一次布尔检查,以及用于表示空着色器列表的极小内存占用)。
好吧,但这一切难道完全没意义吗? 最常见的用途就是好玩,而好玩当然不是必需的(是啊,去他妈的好玩,对吧?)。不过,自定义着色器最主要的实用价值在于无障碍。自定义着色器非常适合针对特定类型的色盲进行优化、调整对比度或亮度以提高可读性、实现“放大镜”效果等等。
我并不是想把无障碍的责任推给别人,我也愿意将各种无障碍功能做成一等公民特性,但在 Ghostty 尚未提供某些功能的情况下,这为用户提供了一种自己动手解决问题的好方法。
Xterm 兼容性审查与行为文档化(#632)
终端模拟器是模拟器,但它们到底在模拟什么?传统上,终端模拟器模拟的是 VT52、VT100、VT220 等实体终端。但实际上,这些硬件已经很久没有被广泛获取或实际使用了,以至于大多数现代终端模拟器只是在相互模仿彼此的行为。这导致不同终端模拟器之间存在各种行为不一致,许多模拟器在边界情况上也存在 bug3。
xterm 是 X 窗口系统的标准终端模拟器,常被誉为历史终端行为的黄金标准。此外,xterm 的使用足够广泛,即使抛开历史终端不谈,它对所支持功能的实现方式也可被视为事实标准。
我已决定,在可能且合理的情况下,Ghostty 应该完全与 xterm 的行为保持一致。这让项目对于“为什么 <feature> 会这样表现?”这个问题有了统一的答案4。
“在可能且合理的情况下”是什么意思?我的意思是,默认情况下实现某个功能时,我们应该对齐 xterm。如果某个功能被报告有 bug,我们总会先问“xterm 在这种情况下会怎么做?”如果有足够有说服力的理由需要偏离 xterm 的行为,那也只是例外,而非常态。
为此,我已开始逐步审查 xterm 的每一项已文档化的功能,并与 Ghostty 进行对比。在这个过程中,我也在不断完善我们自己的文档,并尽量写得详尽。文档中还包含了带有预期输出的 shell 脚本验证用例,以便编写端到端测试来确保兼容性。效果如下图所示:

终端支持的功能繁多,xterm 的代码库也很复杂,这项工作非常繁琐,不可能一蹴而就。但在过去几个月里,我一直在逐项核对,至今已在 Ghostty 中修复了数十个 bug,也在其他终端中发现了数十个 bug(有些已报告,有些稍后会报告,但都不是严重问题)。
这并不意味着 Ghostty 会支持 xterm 支持的所有功能。相反,对于 Ghostty 已有且 xterm 也支持的功能,Ghostty 将力求与 xterm 保持最大程度的兼容(在有充分理由时允许例外)。
结语
在开发日志中,我只会挑选一些我觉得有趣、想要分享的改动。开发日志不是更新日志,我也不希望它变成枯燥的改动清单。不过还是要说一下,过去两个月里 Ghostty 项目还有超过100 项 bug 修复和改进,Ghostty 每天都在离公开发布更近一步。
随着内测规模的扩大,贡献者的数量也在增长。已有近 50 人为 Ghostty 贡献过代码(几乎每 6 个内测用户中就有 1 人不只是报告 bug,还贡献了代码!)。这真的非常了不起,我非常感谢大家为项目投入的时间和热情。
如果你想保持关注,可以在 Twitter 或 Mastodon 上关注我(链接在页脚)。本博客也提供 RSS 订阅。
Boo. 👻
脚注
我不是在寻找投资人。希望没有人会那样解读这一段,但我觉得有必要说明一下。这也不是那种“嘴上说不要其实想要”的暗示,我是真的不感兴趣。 ↩
输入处理非常复杂,我确信还有更多 bug 存在,但现在的状态已经让使用日文、韩文和中文的内测用户能够全天候使用 Ghostty 了。 ↩
几乎没有终端模拟器能正确处理将宽字符(如
草)拆开的转义序列。这里的“正确”是有争议的,因为并没有相关规范,所以它们想怎么做都可以。换句话说,其行为极不一致。 ↩当然,这仅适用于 xterm 已实现的功能。像 Kitty Graphics Protocol 这样的功能由 Kitty 明确定义,在这种情况下我们会尽可能完全对齐 Kitty 的实现。 ↩
随机一篇博客
评论
登录后参与讨论