构建高性能文本编辑器

2021-02-18 05:50:53

从库到命令行,开发人员工具一直是我的激情所在。十年前,我下载了一个新的跨平台文本编辑器的beta。我几乎不知道该产品最终会对我的职业产生多少影响。

在社区的多年参与下,2016年,我有机会加入团队。以下是我对Sublime Text定义的一些反思-无论是现在还是展望未来。

我在职业生涯的早期阶段就在网络代理商工作,在那里我们为许多不同的客户构建了站点和应用程序。在这样的环境中,我能够学到很多有关编程,设计的知识,甚至还可以学到一些有关业务开发的知识。通过与客户会面并讨论他们的项目,很清楚了解项目为什么重要。它使我们能够在工作中做出更好的决策。结果是真正满足了用户需求,而不仅仅是建立规范。

一直在寻找改进我的工具的方法,我在2011年初发现了Sublime TextX。以前它仅用于Windows,但是新版本也支持Linux和Mac。特别是在Linux上,编辑器体验与其他任何东西都不相同。性能,多个游标和可扩展性的结合使它成为了热门产品。感觉类似于TextMate,只是我不需要Mac。小细节引起了我的注意,例如选择角的四舍五入。

在开始的几个星期中,我开始编写一个Python插件以部署到我们的开发服务器。迭代使用后,我决定将其转换为产品。意识到该插件需要频繁的错误修复,我知道我需要一种简单的方法来发布更新。当时,Sublime Text社区主要使用zip文件和源代码存储库来分发插件。用户体验不是很好,需要太多的手动工作。

在2011年夏天,我整晚都在Package Control上进行黑客操作。独特功能之一是可用插件的捆绑列表。另一个定义功能是开箱即用的自动更新。它最终不是第一个为Sublime Text发布的软件包管理器,但是我将其成功的很大一部分归因于易用性。

在2011年和2012年期间,Sublime Text 2变得非常流行。功能和视觉的结合引起了众多程序员的共鸣,并且可用软件包的数量稳步增长。

2013年,我为Package Control开发了一个新网站,将其从我的个人网站移到了子域。有超过1,500个软件包可用,该站点每月消耗的带宽超过TB。 2014年,该网站迁移到了自己的域,现在列出了约2500个软件包,每天提供一百万份软件包列表。即使实施了bzip2 HTTP压缩后,该服务器每月仍消耗4TB以上的带宽。

2014年中,我辞去了日常工作,将精力集中在插件和新软件产品上。 2015年底,我们得知我们的第四个孩子即将来临,这促使我寻求更一致的工作。我给Sublime Text作者Jon发了一封电子邮件。主题:全职工作?三个星期后,我以第二工程师的身份加入了公司。

最大的变化之一是适应在世界另一端的公司工作。悉尼比波士顿提前16小时。传统上,我真的很喜欢与同事在协作空间中工作。但是,我认为公司规模较小,加上我的背景和自我激励,带来了非常积极的经历。

我最喜欢在Sublime HQ工作的一个方面是,规模可以而且几乎要求工程团队更倾向于通才。除了大多数“纯”工程工作之外,我还有机会对我们的视觉设计和标识工作进行了推动,改进了基础架构,改善了文档,并通过一些开源组件与社区互动。我已经变得真正地欣赏并参与各种各样的工作,这些工作可以使具有出色用户体验的出色产品成为现实。

成为通才的一个重要方面就是,它如何使您在整个产品和公司中都可以承受决策结果。当您负责工程,设计,文档编制和发布工作时,我相信您会获得独特的见解。您可以查看实现设计所需的工作,也可以使用记录功能的反馈以使其易于使用。除此之外,您还具备了构想并从头到尾看到它的能力。

加入Sublime团队之前,我从大学时代开始就没有接触过C ++。我的职业生涯的大部分时间都是全职工程师,以各种高级动态语言工作。我对某些C代码库进行了一些简单的编程,但是我的知识绝对是表面的。

我从使用C ++的工作中获得的一个观点是,高级语言可以掩盖多少计算量。像in这样的简单运算符可以很容易地模糊遍历数组中每个元素的工作。更加接近金属,这有助于我对所编写代码的性能影响形成更广泛的直觉。

人们经常问我们在Sublime Text中使用什么UI工具包。我们也被问到它是用什么编程语言编写的。有时人们想知道我们使用什么库。我认为这些问题中有很多隐含地询问我们如何快速实现Sublime。答案可能比大多数人期望的要平凡。

我们的代码库充满了专门构建的代码,可以完全满足我们的需要,而仅此而已。我认为这是有意追求最简单的解决方案与乔恩为自己的绝大部分存在而自行构建Sublime Text的事实的结合。随着产品的成熟以及我们增加了更多的工程资源,我们试图继续在使代码库更健壮的同时继续追求简化的平衡。

Sublime Text用C ++编写。我可以说说我们如何避免异常,使用移动语义,以及我们的代码看起来像C。这不是为什么Sublime产品速度很快,但它们可以带来一些好处。是的,选择正确的数据结构很重要。出乎意料的是,向量比我最初的推测更经常是正确的选择。我们的代码将向量预先分配为其最终大小。我们使用内存竞技场和内部字符串。我们注意结构填充,并使用连续的内存分配来改善缓存的局部性。

您可能会注意到有一个总体主题。我们使用更少的内存。我们分配的时间更少。我们使缓存无效的次数更少。我们做的工作少了。实际上,我们让用户的机器减少了工作量。有时我们最终会做更多的工作,以实现这一目标。是的,我们通过分析来提高性能,但是小小的决定加起来!

经常会听到Sublime Text的原始感觉。其他人很快指出我们并不是真正的本地人。真相在中间。

即使用户没有使用操作系统提供的UI工具包,也有很多方面可以使用户界面看起来很自然。最大的事情之一就是遵循平台约定。乔恩(Jon)先前曾解释说,特定于平台的层更多是功能的结合,而不是针对最低的公分母。

我们实现特定于平台的元素,例如macOS上的本机选项卡和代理图标,以及Windows上文件路径中的反斜杠。在所有平台上,我们都使用本机菜单和对话框。我们的文本渲染使用操作系统中的字形光栅化,同时尊重用户的反锯齿设置。我们着重实现标准修饰键和插入符号行为。

这些细节有助于使界面具有原生的感觉。快速也有帮助。

在其他情况下,native将是错误的选择。我们的编辑器控件是界面的核心,而实现它的方式对于使界面无滞后至关重要。自上而下拥有它可以使我们创新和调整UI,同时保持出色的性能。我们不需要解决为其他用例设计的灵活性和功能。

例如,我们使用相对静态的布局引擎来定位文本。我们无需担心布局中间的动画,扩展框中的重排文本对性能的影响。没有实现此功能。除此之外,我们可以在基本文本布局之上实现UI层。例如,在3.0版中,我们引入了“幻像”的概念,它们是与文件的文本内容内嵌的小型HTML文档。

而且,是的,我们甚至拥有自己的简单HTML解析器和布局引擎。它支持在格式化文本时非常有用的基本CSS。我们也自上而下拥有它。这意味着它最终将使用与编辑器控件相同的文本呈现,并且我们可以支持有用的实验功能。 CSS color mod函数就是这样一个例子。它使插件作者可以混合用户的配色方案中的颜色,甚至可以确保最低的对比度。

显然,快速实现Sublime Text不是一个决定或一个库,而是一个协调的方法。当然,我们确实有一些缓慢的病理案例,但是我们倾向于集中精力使95%的用例真正好用。

那么,有什么收获呢?我们必须编写和维护许多底层代码。我们也是一个很小的团队,只有六个工程师。我们的工程团队分布在两种产品上,处理与产品相关的所有内容-从工程设计到设计,文档再到基础架构。

因为我们是一支精干的团队,所以我们必须专注于我们认为适合Sublime Text产品的愿景的事物。我们还向您提供免费替代产品中的有偿产品。为使产品蓬勃发展,我们必须为用户提供明显的利益。

这些因素都有助于更及时地衡量产品开发速度。在实践中,我发现这最终会给人带来最大的好处,那就是限制。约束迫使您在实现目标方面具有创造力。但是,不,我们不会像使用Rails的SaaS初创公司那样大步向前。

拥有这么多堆栈的最大好处之一是,我们经常可以调整和修复其他项目无法实现的功能。我们没有大型的开源项目,我们需要说服我们的功能值得实施。我们可以自己做出决定。由于我们没有许可或发布UI工具包,因此我们可以进行大范围的更改,而不必大惊小怪。

另一个好处是一致性和跨平台共享代码。我们有三个非常底层的特定于平台的适配器,它们提供了构建UI的基础层。我们的UI工具包是100%自定义的,因此我们不需要针对三种不同的API来实现UI组件。平台渗入UI的唯一地方就是行为,并且由于我们拥有一切,因此我们可以轻松地自定义合适的自定义项。

到目前为止,我已经谈到了很多性能,但是它本身并不是一种引人注目的用户体验。它是功能的组合,并且使这些功能快速完成,从而创建了值得使用的产品。

在编辑器领域,从简单的裸露文本编辑器到功能齐全的IDE(可以执行诸如自动重构代码之类的功能)的范围非常广泛。对Sublime Text在此领域中的位置有一个设想,这有助于我们确定在哪里投资我们的资源以及我们希望关注的经验类型。

在过去五年中,我致力于Sublime Text的开发,因此,我将以下内容视为我们的指导原则:

性能是一种功能,可以以健壮的方式使用工具。当动作是瞬时的时,用户将更多地使用它们。暂停,挂起和响应缓慢会导致工具中断当前的任务。只要有可能,我们应立即响应用户的输入。

我们的UI中很少有具有异步概念的组件。有助于简化界面,并使性能问题突出。

帮助用户轻松浏览代码至关重要。在编写软件时,会花费大量时间阅读代码。使导航无缝且可预测可以对用户体验产生重大影响。理想情况下,导航应该感觉流畅且简单,以便用户可以专注于理解。

定制行为应该很简单,可以轻松添加对新语言的支持,还可以添加功能。由于我们的规模,我们只能为有限的几种语言提供支持。当我们添加新功能或交互范例时,我们尝试使插件作者可以利用这项工作。

由于我们的限制,通过API完全改变行为或添加新概念并不是我们的主要目标。我们宁愿随着时间的推移开发专用组件,而不是带有编辑器控件的通用UI工具箱。

在插件领域,向后兼容性的突破很少。应该设置一个较高的标准:应该存在明显的明显好处,并且没有合理的方式来保持兼容性。

接口应该整洁,一致。将所有内容都放置为按钮,图标或选项卡可能与没有可见内容一样有害。当许多不同的事物引起用户的注意时,它们开始变得嘈杂。提供必需品并依靠插件进行扩充。

不要小看有吸引力的界面的价值。不可能适合每个人的口味,但是默认值可能会很高。界面应看起来清晰,具有合理的对比度,遵循现代设计风格并使用简单清晰的图像。允许用户自定义UI以适合自己的口味,并在可行时提供帮助程序。

遵循平台的约定,并根据大多数人的期望选择默认值。通过像用户操作系统上的其他应用程序一样操作,它可以帮助界面摆脱干扰。标准的键绑定和行为与视觉组件一样,都是界面的大部分。存在合理选择时,添加设置以自定义行为。

在期待未来的同时,我也花了一些时间来回顾我们的过去。

在Sublime Text 2的开发过程中,有130个公共开发版本和12个稳定版本。 Sublime Text 3具有166个开发版本和8个稳定版本。 3.0版于2017年发布,3.1版于2018年发布,而3.2版于2019年发布。获取Sublime Text版本3095并将其与我们现在的位置进行比较确实让人大开眼界。

其中一些比看起来更重要。例如,我们的语法定义不仅支持语法突出显示,而且还支持Goto Symbol,Projects中的Definitions弹出窗口和Goto Symbol。提高这些工具的质量可以对用户体验产生明显的影响。

那时,我们还推出了Sublime Merge。 Merge与Sublime Text共享了一大堆核心技术,但专注于制作专门用于Git的界面。这与我们的产品简单精致的愿景相吻合。我们没有尝试将两个工作流合并到一个界面中,而是决定构建一个专门用于该任务的UI。尽管Sublime Merge建立在Sublime Text的许多组件上,但它也贡献了一些功能,包括在3.2版中添加的Git集成。

过去五年来,我们的团队也不断成长,这成就了我们取得的成就。在我于2016年加入公司之前,乔恩是整个产品团队,而卡里则负责运营。在Sublime Merge的开发过程中,Dylan和Benjamin加入成为工程师。在2019年,我们又增加了两名工程师Tim和David。

尽管我们已经成长,但我们仍然是一个非常小巧的团队。这也意味着我们将继续有机会成为通才,并参与产品的所有不同方面。

除了壮大团队,我们还改善了与Sublime Text社区的互动。 许多聪明,敬业的社区成员为我们的错误跟踪器和我们的开源语法定义做出了重要贡献。 这些贡献使我们能够更快地修复错误,并更强大地支持各种编程语言。 除了论坛之外,我们的Discord服务器上还有一个活跃的社区。 在过去的一年中,我们为Sublime Text的下一个主要版本投入了大量工作。 迄今为止,我们已经发布了40多个开发版本,并即将发布公开版本。 我们提供了从渲染增强到用户界面添加,索引器改进以及大量新API的所有功能。 我最喜欢的一些东西包括: 其中一些听起来很琐碎,但结合起来我相信它们确实很出色。 我等不及每个人都有机会尝试一下!