介绍 Markdown 语言服务器
2022 年 8 月 16 日,作者:Matt Bierner,@MattBierner
Markdown 支持是我 2016 年加入 Visual Studio Code 后接手的第一项功能。哇,真的已经六年了吗?不过这是一场绝配。我使用 Markdown 的时间已经足够长了,我经常发现自己会不假思索地在 Twitter、Outlook 以及几乎我光标所落到的每个文本框中输入反引号和星号。这些年来,看到 VS Code 内置的 Markdown 支持不断发展,以及我们的 Markdown 扩展如何直接和间接地塑造了 webview 和笔记本等核心功能,真是令人无比欣慰。
因此,我很高兴与大家分享一个我已经秘密进行了一半年的项目,我认为这个项目代表了 VS Code Markdown 工具的下一步发展:Markdown 语言服务器。借助这个 语言服务器,我们将 VS Code 大多数内置的 Markdown 语言工具(从文档大纲到智能折叠,再到路径完成)提供给其他编辑器和工具。我们的目标是通过更常用于编程语言的智能,来推动 Markdown 工具的发展。
Markdown 语言服务器工作分为两个新的(并且名称相似!)开源库
-
Markdown 语言服务 - 一个 TypeScript 库,它提供用于处理 Markdown 的工具。
-
Markdown 语言服务器 - 一个 语言服务器,用于使用语言服务构建 Markdown。
虽然这些库仍处于早期阶段,但它们已经开始在 VS Code 1.70+ 中使用(希望您甚至没有注意到 :-))。我们甚至从这次切换中看到了一些好处,例如将 Markdown 工具迁移到一个单独的进程,这样它就不会阻塞其他扩展。
但在我过于乐观之前,也许您会想:为什么需要一个 Markdown 语言服务器?说实话,我花了六年才真正明白这一点。这同时也反映了我从将 Markdown 简单地视为带有一些星号、方括号和井号的普通文本,到理解 Markdown 是一种标记语言,并且可以从我们为 TypeScript 或 Python 等编程语言提供的许多相同工具中受益,这一过程的演变。
深入了解 Markdown 工具
在我发现 VS Code 之前,我主要使用一个简单的文本编辑器进行编码。这意味着我必须记住符号名称,并在每次想使用它们时都手动输入。如果我想重命名一个变量,我会进行文本查找/替换,并希望我的单元测试能够捕获不可避免的错误情况,这些错误情况可能是由于名称输入错误或被破坏造成的。这是一种缓慢且不可靠的工作方式,但我很满意,因为我不知道还有更好的方法。只有在我最终接触到更智能的工具后,我才真正意识到自己的工作流程有多么原始。
我最近在 Markdown 上有了同样的体会。多年来,我一直很乐意使用 VS Code 比较简单的 Markdown 编辑器。我对语法高亮和内置的 Markdown 预览很满意。文档大纲和可点击的编辑器链接只是额外的好处。我已经习惯了手动编写链接。我接受了这样一个事实:如果我更改了标题名称,我需要进行文本搜索来更新指向该标题的所有链接。而且因为我将 Markdown 看作不仅仅是花哨的普通文本,所以我甚至无法想象还有更好的方法。
但有一天,当我第无数次错误地输入图像路径时,我突然意识到:这真是一件无聊的事情!我为什么要浪费生命手动输入和验证这些链接?工具就是用来做这个的!我知道我想要的不只是一般工具,我想要一个能帮助我将 Markdown 视为文本而不是隐藏在某种 WYSIWYG 样式的 UI 魔法背后的 Markdown 源代码的工具。这与 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 语言服务 - 一个 TypeScript 库,它提供用于处理 Markdown 的工具。
-
Markdown 语言服务器 - 一个 语言服务器,用于使用语言服务构建 Markdown。
编码愉快!
Matt Bierner,@MattBierner