隆重推出 Markdown 语言服务器
2022 年 8 月 16 日,作者:Matt Bierner,@MattBierner
当我于 2016 年加入 Visual Studio Code 时,Markdown 支持是我负责的第一个功能。哇,真的已经六年了吗?不过,这确实是一个完美的契合。我从事 Markdown 工作已经很长时间了,以至于我经常发现自己会在 Twitter、Outlook 以及几乎所有光标落地的文本框中,怀着希望地输入反引号和星号。多年来,看到 VS Code 内置的 Markdown 支持不断发展,并看到我们的 Markdown 扩展如何直接或间接地塑造了 Webview 和 Notebook 等核心功能,这真是令人无比欣慰。
因此,我很高兴分享一个我过去半年一直在默默努力的项目,我认为这个项目代表了 VS Code Markdown 工具的下一步:Markdown 语言服务器。借助这个语言服务器,我们将 VS Code 的大部分内置 Markdown 语言工具——从文档大纲、智能折叠到路径补全——开放给其他编辑器和工具。我们的目标是推动 Markdown 工具向前发展,注入通常只与编程语言相关联的智能功能。
Markdown 语言服务器的开发分为两个(名称相似!)新开源库
-
Markdown Language Service - 一个提供 Markdown 操作工具的 TypeScript 库。
-
Markdown Language Server - 一个使用语言服务构建的 Markdown语言服务器。
虽然这些库仍处于早期阶段,但它们已经被 VS Code 1.70+ 使用(希望您从未注意到 :-))。我们甚至从这次切换中看到了一些好处,例如将 Markdown 工具移至单独的进程,这样就不会阻塞其他扩展。
但在我过分激动之前,您可能想知道:为什么需要 Markdown 语言服务器?老实说,我花了这六年时间才自己理解这一点。这也很能说明我的转变,从仅仅将 Markdown 视为带有几个用于活跃气氛的反引号、星号和井号的纯文本,转变为理解 Markdown 是一种标记语言,并且可以从我们为 TypeScript 或 Python 等编程语言提供的许多相同工具中受益。
深入了解 Markdown 工具
在我发现 VS Code 之前,我主要使用一个简单的文本编辑器进行编码。这意味着我每次想使用符号时都必须记住它们的名称并输入它们。如果我想重命名一个变量,我会进行文本查找/替换,并希望我的单元测试能够捕获名称拼写错误或篡改的不可避免的情况。这是一种缓慢且不可靠的工作方式,但我很满足,因为我不知道可以做得更好。直到我终于接触到更智能的工具,我才真正认识到我的工作流程有多么原始。
最近,我对 Markdown 也有了同样的认识。多年来,我一直满意于使用 VS Code 相对简单的 Markdown 编辑器。我对语法高亮和内置的 Markdown 预览感到满意。文档大纲和可点击的编辑器链接只是额外的奖励。我已经习惯了手动编写链接。我接受了如果我更改了标题名称,我需要进行文本搜索来更新所有指向该标题的链接。因为我将 Markdown 视为比精美的纯文本多不了多少的东西,所以我甚至无法想象有更好的方法。
但是有一天,在我第 N 次(感觉像是第一百次)错误输入图像路径后,我终于意识到了:这不好玩!我为什么要浪费生命手动输入和验证这些链接?这正是工具的用武之地!我知道我想要的不仅仅是任何工具,我想要一个能帮助我以文本形式阅读和编写 Markdown 的工具,而不是隐藏 Markdown 源文件在某种所见即所得的 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 文件有效地实现链接诊断非常困难。在一个大型 Markdown 工作区(如vscode-docs)上,我总是意外地阻塞扩展主机几百毫秒。这不好。另一方面,语言服务器作为其自己的进程运行。不仅如此,语言服务器现在还拥有了一个新的诊断拉取模型,我对此很感兴趣。
然后是一些更崇高的原因。例如,Markdown 语言服务器将对其他编辑器和工具很有用。这包括 VS Code 团队发布的另一个编辑器:Monaco!更不用说像 Markdown CLI 工具这样的可能性了。如果我没有时间自己构建这样的工具,也许别人可以,以语言服务器为起点。我在 VS Code 的 Markdown 工具上付出了很多努力,如果这些努力能够惠及他人,那将是很棒的。
通过提供一个新的语言服务器,我也许还能启动一个关于改进 Markdown 工具的共享工作。VS Code 是开源软件的多产生产者和用户,我曾见过这些项目带来的明显好处。开源的 Markdown 语言服务器将有助于其他编辑器,但反过来也将吸引有助于 VS Code 的贡献!与其让每个编辑器/工具都重复实现自己的 Markdown 支持,不如让语言服务器将开发者聚集在一起,共同致力于一个造福所有人的大型项目。
所有这些宏伟的构想都与如何实际构建语言服务器的计划无关。即使在我进行了所有重构之后,将代码迁移到语言服务器仍然是一项艰巨的工作!这似乎令人望而生畏,直到我意识到我不必一次性完成所有工作。我可以增量地构建服务器,一次将一个功能从 VS Code Markdown 扩展迁移到新的 Markdown 语言服务器。如果我做得对,我可以检入每一次小的增量迁移,这样用户就可以在构建新语言服务器的同时对其进行测试。理想情况下,用户将永远不会注意到一个功能何时从扩展迁移到了语言服务器。
也许这很明显,但我已经成为了这种大规模代码更改的增量方法的忠实拥护者。没有成千上万行的 PR 或持续数月(或数年)的庞大功能分支!相反,对 `main` 进行一系列小的、安全的更改。如果一切按计划进行,最终完成这项工作的提交应该是不那么激动人心的。这是我们采用的方法,用于在整个 VS Code 代码库中逐步使用严格空检查,这就是我觉得我可以快速且尽可能少地麻烦地将 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 Language Service - 一个提供 Markdown 操作工具的 TypeScript 库。
-
Markdown Language Server - 一个使用语言服务构建的 Markdown语言服务器。
编码愉快!
Matt Bierner,@MattBierner