Markdown Language Server のご紹介

2022年8月16日 Matt Bierner, @MattBierner

Markdown サポートは、2016年に Visual Studio Code に入社した際に私が最初に担当した機能でした。もう6年も経つなんて、本当に驚きです。でも、私にはぴったりの仕事でした。Markdown を長年使ってきたので、Twitter や Outlook、そしてカーソルが置かれるほとんどすべてのテキストボックスに、バッククォートやアスタリスクを無意識に入力してしまうほどです。VS Code の組み込み Markdown サポートを長年にわたって成長させ、私たちの Markdown 拡張機能が、Webview やノートブックのようなコア機能に直接的、間接的に影響を与えてきたのを見るのは、非常にやりがいのあることでした。

そのため、過去半年間静かに取り組んできたプロジェクト、そして VS Code の Markdown ツールにとって次のステップとなるプロジェクトである Markdown Language Server を共有できることを嬉しく思っています。この 言語サーバー によって、ドキュメントのアウトラインから、スマートフォールディング、パス補完まで、VS Code の組み込み Markdown 言語ツールのほとんどを、他のエディターやツールでも利用できるようにします。私たちの目標は、プログラミング言語によく見られるようなスマートさを備えた Markdown ツールを推進することです。

Markdown Language Server の取り組みは、2つの新しい(そして名前が似ている!)オープンソースライブラリに分かれています

これらのライブラリはまだ初期段階ですが、すでに VS Code 1.70 以降で使用されています(そして、おそらく皆さんは気づいていないでしょう :-))。この切り替えによって、Markdown ツールを別のプロセスに移動することで、他の拡張機能をブロックしないなど、いくつかの利点も確認されています。

しかし、話が先走りすぎましたが、おそらく皆さんは「なぜ Markdown 言語サーバーが必要なのか?」と思っているかもしれません。実を言うと、私自身もそう思うようになるまで6年かかりました。これは、私が Markdown を単なるプレーンテキストにアスタリスク、括弧、ポンド記号をいくつか追加して面白くしたものと見ていた状態から、Markdown をマークアップ言語として理解し、TypeScript や Python のようなプログラミング言語向けに提供しているツールと同じような多くの恩恵を受けられるものだと理解するようになった進化の過程でもあります。

Markdown ツールを使いこなす

VS Code を発見する前は、主にシンプルなテキストエディタでコーディングしていました。そのため、シンボル名を覚えておき、使いたいときに毎回タイプする必要がありました。変数をリネームしたい場合は、テキストの検索/置換を行い、タイプミスや名前の破損が起こった場合に、ユニットテストがそれを検出してくれることを願っていました。それは遅くて信頼性の低い作業方法でしたが、私はそれで満足していました。なぜなら、もっと良い方法があることを知らなかったからです。自分のワークフローがいかに原始的だったかを本当に理解したのは、最終的にもっとスマートなツールを手に入れてからです。

最近、Markdown についても同じことに気づきました。長年、VS Code の比較的シンプルな Markdown エディタで満足していました。シンタックスハイライトや組み込みの Markdown プレビューには満足していました。ドキュメントのアウトラインやクリック可能なエディタリンクは、単なるボーナスでした。リンクを手で書き出すことに慣れていました。ヘッダー名を変更した場合、そのヘッダーへのすべてのリンクを更新するためにテキスト検索を行う必要があることを受け入れていました。そして、Markdown を単なる凝ったプレーンテキストとしか見ていなかったので、もっと良い方法があるとは想像もできませんでした。

しかしある日、画像のパスを100回目くらいにタイプミスした後、ついに気づきました。「これは楽しくない!」なぜ私は手動でリンクをタイプして検証するような無駄な時間を過ごしているんだ?それはツールの仕事じゃないか!私はどんなツールでもいいわけではなく、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 で実行されていました。これらのツールをすべて適切な言語サーバーに移行することを検討したかったのですが、変更を行うには実際のエンジニアリングコストがかかります。それが価値のあるものになることを確認する必要がありました。

この件について1ヶ月以上も迷っていました。既存のコードはまともな状態でしたが、不明な点がたくさんありました。途中でうまくいかないことに気づいたらどうしよう?言語サーバーについて真剣に取り組んだことすらなかったのです。

あれこれ悩んでいるうちに、Markdown 拡張機能のソースコードを言語サーバーに移行するかのようにリファクタリングすることで気を紛らわせました。VS Code の拡張機能 API への依存関係を分離しようとし、より多くのロジックをサービスインジェクションを使用するように切り替え、テストがファイルシステムに依存しないようにしました。そうすることで、言語サーバーに飛び込むことがなかったとしても、少なくともコードベースをクリーンアップしていました。

いくつかの考慮事項が最終的に、Markdown 言語サーバーが次のステップとして適切であると私を確信させました。まず、ごく平凡な理由として、Markdown ファイルのリンク診断を効率的に実装することが非常に困難であると感じていました。vscode-docs のような大規模な Markdown ワークスペースでは、拡張機能ホストを数百ミリ秒ブロックしてしまうことが頻繁にありました。これは良くありません。一方、言語サーバーは独自のプロセスとして実行されます。それだけでなく、言語サーバーには、私が試してみたかった診断用の新しいプルモデルもありました。

そして、もっと崇高な理由もありました。たとえば、Markdown 言語サーバーは、他のエディターやツールにも役立ちます。これには、VS Code チームが提供しているもう1つのエディターである Monaco も含まれます!Markdown CLI ツールのようなものの可能性も言うまでもありません。私が自分でそのようなツールを作成する時間がなかったとしても、誰かが言語サーバーを足がかりにして作成できるかもしれません。私は VS Code の Markdown ツールに多くの労力を費やしてきたので、このすべての作業が他の人にも役立つようになれば素晴らしいと思いました。

新しい言語サーバーを利用可能にすることで、Markdown ツールの改善に向けた共同の取り組みを始めることができるかもしれません。VS Code は、オープンソースソフトウェアの多作な生産者でありユーザーでもあり、これらのタイプのプロジェクトがもたらす明確な利点を見てきました。オープンソースの Markdown 言語サーバーは他のエディターの助けになりますが、ひいては VS Code に最終的に役立つ貢献を促すことにもなります!各エディター/ツールが独自の Markdown サポートを実装するために労力を重複させる代わりに、言語サーバーは開発者を結集して、すべての人に利益をもたらすより大きなプロジェクトに取り組むことができます。

これらすべての壮大な考えは、言語サーバーを実際に構築する方法の計画がなければ無意味でした。リファクタリングをすべて行った後でも、コードを言語サーバーに移行するのは大変な作業になるでしょう!すべてを一度に行う必要はないことに気づくまで、圧倒されるように感じました。VS Code Markdown 拡張機能から新しい Markdown 言語サーバーに一度に1つの機能を移行しながら、サーバーを段階的に構築することができました。そして、うまくいけば、小さな段階的な移行をそれぞれチェックインして、ユーザーが新しい言語サーバーが構築されている間にテストできるようにすることができます。理想的には、機能が拡張機能から言語サーバーに移動したときにユーザーが気づかないようにすることです。

これは当たり前のことかもしれませんが、私は大規模なコード変更に対するこの種の漸進的なアプローチを強く信じるようになりました。何十万行もの PR や、数ヶ月(または数年!)も残る大規模なフィーチャーブランチは不要です。代わりに、main に小さな安全な変更をたくさん加えます。すべてが計画通りに進めば、このすべての作業を締めくくるコミットは拍子抜けするはずです。これは、VS Code コードベース全体で厳密な null チェック を段階的に使用するために取ったアプローチであり、VS Code の Markdown ツールのすべてを新しい言語サーバーに迅速に、そしてできるだけドラマチックにならないように移行できると感じた方法でもあります。

そしてネタバレ注意:うまくいきました!言語機能を1つずつ移行しました。進めていくうちに学び、必要だとわかったらリファクタリングしました。診断は最後に移行した機能でした。言語サーバーに移行しただけでなく、言語サーバーの新しいプル診断モデルを使用するように書き直しました。全体の取り組みの最後のコミットは、Markdown 拡張機能から不要になったコードをほとんど削除しました。そして今日、VS Code 1.70 以降を使用している場合、ほとんどすべての Markdown 言語機能が新しい言語サーバーを使用しています。

より良い Markdown ツールを共に構築する

多くの点で、過去6ヶ月は、私がこの分野で働いてきた過去6年間よりも、VS Code の Markdown ツールにおいてより多くの進歩が見られました。今日、私たちは多くの新しいツールを出荷しており、その中にはこれまで Markdown では利用できなかったものもあります。これらの機能の多くは、Markdown の最もカジュアルな読者や書き手に恩恵をもたらしますが、他の機能は高度なユーザーにのみ評価されるでしょう。しかし、これらすべての進歩にもかかわらず、私たちは Markdown ツールで何が可能かをまだ探求し始めたばかりであることを知っています。

Markdown Language Server について本当にワクワクするのは、プロジェクトが VS Code だけにとどまらなくなったことです。私たちの Markdown ツールを簡単に利用できるようにすることで、すべての人にとって Markdown ツールを前進させる手助けができることを願っています。これらのオープンソースプロジェクトは、Markdown ツールの未来を共に構築するための招待状です。貢献に興味がある場合は、新しいプロジェクトをチェックして、それらを使用して何を作成できるかを確認してください。バグレポートや機能リクエスト、もしかしたら PR も提出できます!私がまだ夢にも思っていないスマートな Markdown 言語機能がたくさんあります。一緒に作りましょう!

ソースコードを確認したり、貢献したりすることに興味がある場合は、GitHub および npm で Markdown 言語サービスとサーバーを見つけることができます

ハッピーコーディング!

Matt Bierner, @MattBierner