Libghostty 即将到来
原文由 Mitchell Hashimoto 于 发布,订阅该博客
两年多前,在我最早几次关于 Ghostty 的公开分享之一中,我分享了对 libghostty 的构想:一个可嵌入的库,让任意应用都能嵌入属于自己的、功能完备、现代且高速的终端模拟器。如今 Libghostty 终于初具雏形,我很高兴能分享关于它的更多规划。
首个 libghostty 库将是 libghostty-vt:一个零依赖的库,提供用于解析终端序列和维护终端状态的 API,直接从 Ghostty 久经实战检验的核心中提取而来。它甚至连 libc 都不需要!
免责声明:本文主要是关于 libghostty 的路线图更新,并公布其首个可交付的组件。Zig API 目前已可测试,但 C API 尚未就绪,很快就会推出。两者目前都仍处于早期测试阶段,尚未达到可普遍使用的程度。
为什么要做 libghostty?
先来谈谈我为什么认为 libghostty 必须存在。
有数百个程序在以某种形式实现终端模拟。最显而易见的是 Ghostty、Kitty、iTerm2 等通用终端模拟器。但像 tmux 或 zellij 这样的终端复用器,本身也是完整的终端模拟器!1 编辑器也会内嵌自己的终端模拟器,例如 JetBrains 系列产品中的 jediterm、VS Code 中的 Xterm.js,或是 Zed 中使用的 Alacritty。
除了功能完备的终端模拟器,许多网站和应用也会实现只读的终端模拟来展示日志或命令输出。例如,GitHub Actions 的输出会解析简单的颜色序列(但几乎不做其他处理)。而 Vercel 或 Render 这类托管平台也会实现一种简单的终端模拟,在构建日志中支持清行、重绘以及颜色解析。
这些实现中有许多都是临时性的、一次性的方案。它们并未使用任何共享的库或代码库。2 终端模拟是一个经典问题,表面上看起来简单,却充斥着意想不到的复杂性和边界情况。3 因此,这些实现大多不完整、有缺陷且速度缓慢。4
抛开正确性不谈,对大多数开发者而言,实现任何形式的终端模拟都是浪费时间。终端模拟并非 JetBrains、Visual Studio Code、GitHub、Vercel、Render 等公司的核心业务。如果能有一个稳定、可复用且处处一致的解决方案,对他们会大有裨益。
我的答案就是 libghostty:一个跨平台、依赖极少的库,通过 C API 对外提供功能丰富、正确且快速的终端能力,让任何应用在任何地方都能嵌入。
起点:libghostty-vt
首个 libghostty 库将是 libghostty-vt:一个零依赖(甚至不依赖 libc)的库,提供用于解析终端序列并维护终端状态的 API,例如光标位置、当前样式、文本换行等。
解析终端序列是终端模拟器最核心的功能,从 Ghostty 这样完整的终端模拟器,到 GitHub Actions 或 Vercel 构建输出中那种简单的只读、仅样式的视图,都需要它。
状态图初看似乎相对简单,但要正确实现却出乎意料地困难。例如,Jediterm 没有正确处理中间字符,导致在本文撰写时,这个被广泛支持的“改变光标形状”序列会在每个 JetBrains 编辑器中吞掉一个字符。
对于仅处理样式的解析,许多开发者会跳过完整的状态图。相反,他们只是简单地在网上搜索一下,解析像 \e[31 或 \e[41m 这样简单的 ANSI 序列,就宣称支持“颜色”。但仅样式的序列要复杂得多,例如它们支持 RGB,而 RGB 本身就有十几种格式。而且我至今还没找到一个能正确渲染这个复杂样式序列的网页控制台。5
libghostty-vt 正是要解决所有这些问题。
libghostty-vt 从 Ghostty 中抽取而来,继承了所有经过现实检验的优势:经 SIMD 优化的解析、出色的 Unicode 支持、高度优化的内存占用、经过模糊测试和 Valgrind 测试的健壮代码库,以及对 Kitty 图形协议或 Tmux 控制模式等特性的出色兼容性,等等。
所有这些都被打包进一个单一的零依赖 C API(甚至不依赖 libc),使其可以轻松嵌入到任何主流语言生态中。
得益于极小的体积,libghostty-vt 将具备广泛的可移植性。初期目标是 macOS 和 Linux 的 x86_64 和 aarch64 架构,因为这些是 Ghostty 应用程序的主要目标平台。但我计划将支持扩展到更多目标,例如 Windows、嵌入式设备以及通过 WASM 实现的 Web。由于职责范围更聚焦,libghostty 的支持范围将比 Ghostty 图形界面更广。
长远规划
libghostty-vt 仅仅是开始。从长远来看,我们将提供更多 libghostty-<x> 系列库,开放更多功能,例如输入处理(键盘编码是其中很重要的一项)、GPU 渲染(只需提供一个 OpenGL 或 Metal 表面,剩下的交给我们)、处理整个终端视图的 GTK 组件和 Swift 框架等等。
随着基础组件逐渐稳定,我们会持续提供越来越多的功能。这些库将以家族的形式组织,以最大程度降低依赖需求、代码体积和整体维护复杂度。
libghostty-vt 现状
我刚刚合并了将 libghostty-vt 作为 Zig 模块开放的 Pull Request。这个 PR 还包含一个最小示例程序。如果你是 Zig 开发者,现在就可以开始尝试 libghostty-vt 了。
C API 尚未就绪,但这正是我当下正在做的工作,很快就会开放测试。所需的工作主要是定义 C API,因为核心逻辑当然早已存在,并且已被 Ghostty 使用多年。此外,Ghostty 的 macOS 应用已经在使用一个仅限内部使用的 C API。
如果你查看这个仅限内部使用的 C 头文件,请忽略其中的混乱。它算不上一个好的 C API。它仅供内部使用,目的是满足 macOS 应用的需求。这并不是一个可供普遍使用的 libghostty,尽管它已经被一些真正的商业产品用于嵌入 Ghostty。我们将以全新的方式来为更广泛的用途定义 C API。
我计划将 libghostty 的版本与 Ghostty 应用程序分开管理。本文标志着公开 alpha 阶段的开始(不保证 API 稳定),我希望能吸引一些开发者来试用,并在 C API 就绪后为其编写语言绑定。
我希望在未来 6 个月内发布 libghostty-vt 的带标签版本,但最终还是要看它是否已经就绪。
征求反馈
我们正处于 libghostty 设计 API 的关键阶段,而设计 API 的最佳方式就是来自真实使用者的反馈。Ghostty 是一个使用者,我们也有一些社区成员正在做其他基于 libghostty 的项目,但我们希望能得到越多反馈越好!
如果你认为自己的项目或组织中有适合 libghostty 的使用场景,请加入 Ghostty Discord,与正在从事这项工作的开发者们协作。如果你不想加入 Discord,也可以给我发邮件(邮箱地址在本网站页脚)。
现阶段 libghostty 的状态可以视为 alpha,所以不要期待一个精致、稳定的体验。我们正在寻找愿意早期参与的极客。
“alpha”指的是 API(函数和类型)本身的质量。核心逻辑与 Ghostty 共享,在真实环境中极为稳定且久经考验。
下一个前沿
Ghostty 应用程序终于达到了足够稳定的状态,让我们可以开始向 libghostty 的目标迈进,对此我感到非常兴奋。libghostty 是 Ghostty 的下一个前沿,我认为它有能力产生比 Ghostty 作为独立应用本身大得多的影响力。
不用担心,Ghostty 应用程序本身仍有大量更新计划,这丝毫不会减弱我对它的热情和规划。libghostty 被更广泛地使用,也会让 Ghostty 应用本身变得功能更丰富、更稳定,因为 Ghostty 自身就是 libghostty 的使用者。
Boo. 👻
脚注
它们为子进程持有 pty,解析所有转义序列,管理屏幕状态,并最终通过向父终端模拟器发送自己的转义序列来完成“渲染”。 ↩
许多网站确实在使用 Xterm.js,GTK 生态中也有 libvte。但这只覆盖了整个领域的极小一部分,而且上述每个例子在其各自的范围内都有局限。 ↩
我花了将近 3 年时间从事终端模拟相关工作,我们至今仍在发现奇怪的边界情况。 ↩
这里有几个真实且影响较大的问题示例:Jediterm 没有正确处理中间字符,Apple 的 Terminal.app 会把 DCS 序列直接泄露到输出中。我并不是要特意点名谁,只是想说明这些问题确实存在,而终端模拟很难做到完全正确。 ↩
许多通用终端模拟器也曾在这方面出错,包括 9 个月前的 Ghostty。 ↩
随机一篇博客
评论
登录后参与讨论