功能价格文档博客
获取 mote
← 博客
工程·2026年6月28日·阅读需 5 分钟

在一个 Rust 核心上搭载各平台外壳的理由

如果要在三个操作系统上推出同一款编辑器,有一种方法只需编写一次 UI。我们曾经走过这条路,后来又退了回来,改为在一个核心之上叠加一组针对各平台的轻量外壳。

m
mote
外壳组在上方,核心在中间,文本渲染和门槛检查在下方。Markdown 解析、编辑操作和文件写入全都位于中间的方框内。
外壳组在上方,核心在中间,文本渲染和门槛检查在下方。Markdown 解析、编辑操作和文件写入全都位于中间的方框内。

如果要在 Linux、macOS 和 Windows 上推出同一款编辑器,就得制作三次 UI。

一开始,我们想避开这项成本。我们使用一个跨平台工具包,在三个操作系统上绘制相同的界面。这个决定让我们通过了第一项性能门槛,也达成了韩文输入的第一个里程碑。

后来,优先级发生了变化。

性能比设计重要,设计比成本重要。时间和成本不再作为约束条件。

按照这个标准重新审视后,答案也变了。

我们放弃了统一的 UI

跨平台工具包有明确的优点。制作一次的功能可以在多个操作系统上使用。

但也有必须付出的代价。它会多占用 40~60MB 内存,启动速度会慢 150~200ms。文字呈现不如操作系统的默认文本引擎,系统原生的视觉效果也无法完整使用。

在开发成本很重要的时候,这是一个合理的选择。但当成本不再是约束条件后,就没有理由继续承受这些代价了。

因此,我们决定用 Rust 构建处理文档的核心,并为每个操作系统分别构建负责界面的外壳。

这并不是因为原有技术不好。优先级发生变化后,即使面对相同的选项,也会得出不同的答案。我们决定付出将功能制作三次的成本,以换回性能、文字质量和符合系统习惯的体验。

不过,我们并没有舍弃一切。

我们保留了整套测量规范。把指针移到窗口外、通过名称准确找到窗口、同步计算帧数。韩文输入的设计原则也一并迁移了过来。只向操作系统展示光标所在的行,不修饰正在组合的文字。如果状态出现偏差,就不进行猜测,而是重新同步。

代码可以丢弃,但经过验证的原则会留下来。

我们把外壳的职责限定得很小

如果各平台的外壳开始承担大量工作,三个产品很快就会变得不同。因此,我们明确规定了外壳应该做什么,以及不应该做什么。

外壳负责创建窗口和绘制文字。它把键盘和指针输入传递给核心,并将韩文输入转换为编辑命令。它也会应用操作系统的视觉效果。

另一方面,它不解析 Markdown。除换行之外,它也不决定布局,不保存文件,也不判断许可证。

这项原则并不只是写在文档里。如果外壳中加入了 Markdown 解析代码,自动检查就会让构建停止。

如果只有某个外壳开始处理语法,各操作系统上的结果就可能逐渐产生差异。这类问题也很难发现。因为即使表格只在某个外壳中显示得不一样,真正的原因也未必出在绘制表格的代码上。

我们让核心成为唯一长期保留的部分

核心不依赖任何 UI 技术。即使没有窗口,也可以在终端中单独测试。

文档编辑、Markdown 解析、撤销、搜索、大纲、文件保存、导出和许可证验证,全都由核心负责。

在没有 UI 的情况下于终端中运行的核心测试。194 项单元测试和单独的增量块测试均已通过。
在没有 UI 的情况下于终端中运行的核心测试。194 项单元测试和单独的增量块测试均已通过。

用户按下一个按键后,外壳会将该输入传递给核心。核心修改文档,并且只重新解析变更部分的周边区域。它只计算屏幕上可见的内容,然后把发生变化的结果返回给外壳。外壳只重新绘制受影响的行,并完成一帧。

如果在这个过程中重新读取整个文档,那就不只是一个单纯的性能问题。那意味着违反了最初设定的预算。

正确性也只在核心中验证一次。它必须通过全部 652 个 CommonMark 官方示例,只要通过数量减少,构建就会失败。我们还会进行模糊测试,不断输入预料之外的内容。

我们也会确认保存后的文件是否与原文件逐字节相同。如果往返一致率低于 1.0,那就不是速度慢,而是文件内容丢失了。

即使外壳发生变化,核心也会保持不变。在 Linux 和 Windows 上直接连接核心,在 macOS 上则使用 Swift 连接代码。macOS 外壳使用 AppKit 和 TextKit 2 构建,Windows 外壳则使用 DirectWrite 构建。

我们的目标是让文档保持一致,同时让操作手感符合各个操作系统的特点。

文档相同,使用感受不同

确定边界之后,需要统一的内容也变得清晰了。

需要统一的是文档。无论在哪个操作系统上保存,文件内容都必须逐字节一致。表格对齐、行尾和最后的换行也不能发生变化。

Markdown 的正确性已经在核心中完成验证。每次制作新的外壳时都不必重新证明。在新平台上需要确认的是使用感受和性能。

相反,我们不会统一直接触达用户的体验。

文字使用各操作系统的文本引擎绘制。韩文输入法也直接采用操作系统的方式。半透明效果同样在 macOS 和 Windows 上使用系统功能,而在没有相同功能的 Linux 上,只自行绘制必要的部分。

我们也不会强行统一窗口按钮的位置、菜单的形式和快捷键的辅助键。我们的目标并不是在不同的操作系统上显示相同的像素。在每个操作系统上都让人感觉自然更加重要。

发布条件也针对各操作系统分别制定。只有通过性能标准,并使用默认韩文输入法完成实际测试后,才能发布。

基准测试表中对应平台的行,也只有在构建产物真正生成之后才会出现。因为如果提前写入尚未测量的行,表格中的其他行也会变得难以信任。

这个选择有着明确的代价

相同的功能必须制作三次。韩文输入也要实现三次,构建环境也要维护三套。

目前使用的机器无法构建或调试 Windows 和 macOS 版本。我们需要额外的硬件和自动化环境。因此,我们不会为这两个平台标注日期。

我们也保留了重新审视这项决定的条件。将成本排除在约束条件之外,是做出这项决定的前提。如果无法获得所需的硬件,就只推迟对应平台的日程。Linux 版本仍会照常发布。

一项决定不仅需要理由,也需要明确重新考虑它的条件。这样在情况发生变化时,就不必从头重复争论。

需要长期保留的是核心。外壳必须随时都可以被丢弃。

我们只把可以丢弃的部分交给平台。

← 较早即使切换模式,文档仍是同一份较新 →不直接绘制文字,而是交给平台处理的理由
通过RSS持续关注。
只留下文字
简体中文
© 2026 mote