Markdown 语言服务器简介
2022 年 8 月 16 日,作者:Matt Bierner,@MattBierner
当我 2016 年加入 Visual Studio Code 时,Markdown 支持是我负责的第一个功能。哇,真的已经六年了吗?但这真是天作之合。我使用 Markdown 已经足够长的时间了,以至于我经常发现自己下意识地在 Twitter、Outlook 以及几乎所有光标落入的文本框中输入反引号和星号。多年来,看到 VS Code 的内置 Markdown 支持不断发展壮大,并看到我们的 Markdown 扩展如何直接和间接地塑造了 Webview 和 Notebooks 等核心功能,我感到非常有成就感。
因此,我很高兴与大家分享一个我过去半年一直在默默努力的项目,以及一个我认为代表了 VS Code Markdown 工具的下一步的项目:Markdown 语言服务器。借助这个语言服务器,我们将 VS Code 大部分内置的 Markdown 语言工具(从文档大纲到智能折叠,再到路径补全)提供给其他编辑器和工具。我们的目标是利用通常与编程语言相关的智能来推动 Markdown 工具的发展。
Markdown 语言服务器的工作分为两个新的(且名称相似!)开源库
-
Markdown 语言服务 - 一个 TypeScript 库,提供用于处理 Markdown 的工具。
-
Markdown 语言服务器 - 一个使用语言服务构建的 Markdown 语言服务器。
虽然这些库仍处于早期阶段,但它们已经被 VS Code 1.70+ 使用(希望您甚至没有注意到 :-))。我们甚至看到了这种转换的一些好处,例如将 Markdown 工具移至单独的进程,这样它就不会阻塞其他扩展。
但在我过于超前之前,您可能想知道:为什么需要 Markdown 语言服务器?说实话,我也花了这六年时间才明白这一点。这也跟踪了我从最初将 Markdown 简单地视为带有少量星号、方括号和井号的纯文本,到后来将其理解为一种标记语言的演变,并且这种语言可以从我们为 TypeScript 或 Python 等编程语言提供的许多相同工具中受益。
深入了解 Markdown 工具
在发现 VS Code 之前,我主要使用简单的文本编辑器进行编码。这意味着我必须记住符号名称,并在每次想使用它们时都手动输入。如果我想重命名一个变量,我会进行文本查找/替换,并希望我的单元测试能够捕获到不可避免的名称拼写错误或损坏的情况。这是一种缓慢且不可靠的工作方式,但我很满足,因为我不知道事情可以变得更好。直到我最终接触到更智能的工具后,我才真正理解我的工作流程有多么原始。
最近我对 Markdown 也有了同样的认识。多年来,我一直对 VS Code 相对简单的 Markdown 编辑器感到满意。我对语法高亮和内置的 Markdown 预览感到满足。文档大纲和可点击的编辑器链接只是额外的奖励。我已经习惯了手动写出链接。我已经接受了如果我更改了标题名称,我就需要进行文本搜索来更新所有指向该标题的链接。而且因为我将 Markdown 视为只不过是花哨的纯文本,所以我甚至无法想象会有更好的方法。
但是有一天,在第一百次(感觉上)输错图像路径后,我终于意识到:这不好玩!我为什么要浪费生命手动输入和验证这些链接?那是工具应该做的!我知道我不仅仅想要任何工具,我想要一个能够帮助我将 Markdown 作为文本阅读和编写,而不是将 Markdown 源代码隐藏在某些 WYSIWYG 风格的 UI 魔术背后的工具。这非常符合 VS Code 的精神以及我们对编程语言支持的看法。为什么我们为传统编程语言提供的许多相同的智能不也适用于 Markdown 呢?第二天我就开始着手链接补全的工作。
链接补全是帮助您编写指向当前文件或工作区中其他文件中标题的链接的建议。我甚至添加了对完成指向其他 Markdown 文件中标题的链接的支持。真棒!这是一个小小的补充,但对我的生产力产生了巨大的影响。很快我就无法想象没有它我过去是怎么生活的。
沉浸在 Markdown 补全的成功中,我幻想着接下来我可以为 Markdown 带来哪些其他语言智能。我设想自己自信地在标题上按 F2 来安全地重命名它们。我梦想着红色的波浪线穿透浑浊的文本海洋,帮助识别无效链接。这一切似乎都如此显而易见!为什么我几年前就没想到呢?我开始将 Markdown 理解为结构化文本,而不仅仅是纯文本,而改进 Markdown 工具的可能性似乎是无穷无尽的。
Markdown 语言功能
我不会用每个新功能背后的故事来让您感到厌烦,也不会深入探讨所有实现的细节。我只想说,我采取了渐进式的方法,这使得在有限的时间内投入到 VS Code 的 Markdown 支持成为可能。例如,我没有直接跳到构建重命名支持,而是首先获得了一个可靠的查找所有引用版本(因为如果您想重命名一个符号,您首先需要知道所有引用它的地方)。增量式地工作并在每个功能之上构建也帮助我在实现新功能时测试旧功能。例如,在链接上实现重命名帮助我捕获了大量链接检测错误。(这种方法的唯一缺点是意识到您已经将您“如此优雅”的塔楼建立在一些非常复杂的正则表达式之上)。
当实验性地报告无效文件/图像链接的支持在春末推出时,我退后一步审视我的工作。现在 Markdown 语言功能集包括
- 文档大纲
- 工作区符号
- 文档链接
- 智能折叠
- 智能选择
- 补全
- 重命名
- 查找所有引用
- 转到定义
- 断开链接的诊断
- 在文件移动/重命名时更新链接
我知道这些新工具将使使用 Markdown 更快更安全。但是,当我回顾这个编程语言常见的特性列表时,一个想法一直困扰着我。几个月前我把它当作荒谬的想法驳回了,但现在,当我再次思考它时,我意识到现在可能是时候推出 Markdown 语言服务器了。
您正在被服务吗?
到 2022 年春末,VS Code 的所有 Markdown 工具仍然在正常的扩展 API 上运行。虽然我想探索将所有这些工具迁移到合适的语言服务器上,但进行更改将产生实际的工程成本。我需要确保这是值得的。
我为此来回纠结了一个多月。即使现有的代码状况良好,也仍然有很多未知数。如果我只完成了一部分才意识到它行不通怎么办?我以前甚至从未认真地研究过语言服务器。
在我就这一切进行辩论时,我让自己忙于重构 Markdown 扩展源代码,就好像它要被迁移到语言服务器一样。我试图隔离对 VS Code 扩展 API 的依赖,我切换了更多逻辑以使用服务注入,并且我确保测试不依赖于文件系统。这样,即使我永远不深入研究语言服务器,至少我也在清理代码库。
一些考虑最终使我相信 Markdown 语言服务器是正确的下一步。首先是一个相当平凡的考虑:我发现有效地实现 Markdown 文件的链接诊断非常具有挑战性。在像 vscode-docs 这样的大型 Markdown 工作区上,我一直不小心阻塞扩展主机几百毫秒。这不好。另一方面,语言服务器作为其自己的进程运行。不仅如此,语言服务器现在还为诊断提供了一个新的拉取模型,我很想尝试一下。
然后还有更崇高的理由。例如,Markdown 语言服务器对其他编辑器和工具很有用。这包括 VS Code 团队发布的另一个编辑器:Monaco!更不用说像 Markdown CLI 工具这样的可能性了。如果我没有时间自己构建这样的工具,也许其他人可以使用语言服务器作为起点。我为 VS Code 的 Markdown 工具投入了大量工作,如果所有这些工作也能使其他人受益,那就太好了。
通过提供新的语言服务器,我也许能够启动围绕改进 Markdown 工具的共同努力。VS Code 既是开源软件的 prolific 生产者又是用户,而且我已经看到了这些类型的项目提供的明显好处。开源 Markdown 语言服务器将帮助其他编辑器,但反过来也会邀请贡献,最终也会帮助 VS Code!语言服务器可以将开发人员聚集在一起,共同致力于一个更大的项目,这将使每个人都受益,而不是每个编辑器/工具都重复努力实现自己的 Markdown 支持。
如果没有关于如何实际构建语言服务器的计划,所有这些宏伟的思考都是无关紧要的。即使在我所有的重构之后,将代码迁移到语言服务器仍然需要大量工作!这似乎让人感到难以承受,直到我意识到我不必一次性完成所有工作。我可以逐步构建服务器,一次从 VS Code Markdown 扩展迁移一个功能到新的 Markdown 语言服务器。如果我做得对,我可以签入每个小的增量迁移,以便用户在构建新的语言服务器时对其进行测试。理想情况下,用户永远不会注意到功能何时从扩展迁移到语言服务器。
也许这很明显,但我已经成为这种对大型代码更改采取增量方法的坚定信徒。没有数十万 LOC 的 PR 或持续数月(或数年!)的大型功能分支。相反,对 main
进行大量小的、安全的更改。如果一切按计划进行,那么完成所有这项工作的提交应该是反高潮的。这就是我们逐步在整个 VS Code 代码库中使用 严格的 null 检查 的方法,这就是我觉得我可以快速且尽可能少地将 VS Code 的所有 Markdown 工具迁移到新的语言服务器的方式。
剧透警告:它奏效了!我一次迁移一个语言功能。我在做的过程中学习,并在清楚需要时进行重构。诊断是最后一个迁移的功能,因为我不仅要将它们迁移到语言服务器,而且还要重写它们以使用语言服务器新的拉取诊断模型。整个工作的最后一次提交主要是删除了 Markdown 扩展中现在未使用的代码。因此,今天,如果您使用的是 VS Code 1.70+,几乎所有的 Markdown 语言功能都使用了新的语言服务器。
共同构建更好的 Markdown 工具
在许多方面,过去六个月 VS Code Markdown 工具的进步比我过去六年在这个领域的工作还要多。今天,我们正在发布许多新工具,其中一些工具以前 Markdown 无法使用。这些功能中的许多功能使最普通的 Markdown 阅读者和作者受益,而另一些功能只有高级用户才会欣赏。然而,尽管取得了所有这些进步,但我知道我们才刚刚开始探索 Markdown 工具的潜力。
真正让我对 Markdown 语言服务器感到兴奋的是,现在这个项目已经不仅仅是 VS Code 的项目了。通过使我们的 Markdown 工具易于使用,我希望我们能够帮助推动所有人的 Markdown 工具向前发展。这些开源项目是帮助共同构建 Markdown 工具未来的邀请。如果您有兴趣贡献力量,请查看新项目,看看您可以使用它们创建什么。您可以提交错误报告和功能请求,甚至可能提交 PR!还有很多我甚至没有梦想过的智能 Markdown 语言功能。让我们一起构建它们!
如果您有兴趣查看源代码或贡献力量,您可以在 GitHub 和 npm 上找到 Markdown 语言服务和服务器
-
Markdown 语言服务 - 一个 TypeScript 库,提供用于处理 Markdown 的工具。
-
Markdown 语言服务器 - 一个使用语言服务构建的 Markdown 语言服务器。
祝您编码愉快!
Matt Bierner,@MattBierner