介绍Markdown语言服务器

2022年8月16日,由Matt Bierner发布,@MattBierner

Markdown支持是我在2016年加入Visual Studio Code时负责的第一个功能。哇,真的已经六年了吗?不过这是一个很好的匹配。我使用Markdown已经足够长时间了,以至于我经常发现自己会在Twitter、Outlook以及几乎每个光标停留的文本框中满怀希望地输入反引号和星号。多年来,看到VS Code内置的Markdown支持不断增长,以及我们的Markdown扩展如何直接或间接地塑造了像webviews和notebooks这样的核心功能,这让我感到非常欣慰。

这就是为什么我很高兴分享一个我过去半年一直在默默努力的项目,一个我认为代表了VS Code的Markdown工具下一步发展的项目:一个Markdown语言服务器。通过这个语言服务器,我们将VS Code内置的大部分Markdown语言工具——从文档大纲到智能折叠,再到路径补全——提供给其他编辑器和工具使用。我们的目标是推动Markdown工具的发展,使其具备更多通常与编程语言相关的智能功能。

Markdown 语言服务器的工作被分配到了两个新的(并且名字相似的!)开源库中:

虽然这些库仍处于早期阶段,但它们已经被 VS Code 1.70+ 使用(希望您甚至没有注意到 :-))。我们甚至从这次切换中看到了一些好处,例如将 Markdown 工具移动到单独的进程中,这样它就不会阻塞其他扩展。

但在我走得太远之前,也许你在想:为什么需要一个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既是开源软件的积极生产者也是用户,我已经看到了这类项目带来的明显好处。一个开源的Markdown语言服务器将帮助其他编辑器,但反过来也会邀请贡献,最终帮助VS Code!与其每个编辑器/工具重复努力实现自己的Markdown支持,一个语言服务器可以将开发者聚集在一起,共同致力于一个更大的项目,这将使每个人都受益。

所有这些宏大的思考如果没有一个实际构建语言服务器的计划都是无关紧要的。即使在我所有的重构之后,将代码迁移到语言服务器也将是一项巨大的工作!这似乎令人望而生畏,直到我意识到我不必一次性完成所有工作。我可以逐步构建服务器,一次将VS Code Markdown扩展中的一个功能迁移到新的Markdown语言服务器。如果我做得对,我可以检查每一个小的增量迁移,以便用户在构建过程中测试新的语言服务器。理想情况下,用户永远不会注意到某个功能从扩展迁移到语言服务器。

也许这是显而易见的,但我已经成为了这种渐进式大规模代码更改方法的坚定支持者。没有十万行代码的拉取请求或持续数月(甚至数年)的大型功能分支。相反,对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语言服务和服务器:

编程快乐!

马特·比尔纳, @MattBierner