Markdown Language Server のご紹介
2022年8月16日 Matt Bierner 著、@MattBierner
Markdown サポートは、私が 2016 年に Visual Studio Code に参加したときに最初に担当した機能でした。もう 6 年も経つなんて、信じられません。しかし、これは素晴らしい出会いでした。私は Markdown を長く使ってきたので、Twitter や Outlook など、カーソルを置いたほぼすべてのテキストボックスで、ついついバッククォートやアスタリスクを入力してしまいます。長年にわたって VS Code の組み込み Markdown サポートを成長させ、私たちの Markdown 拡張機能が Webview や Notebook のようなコア機能に直接的、間接的に影響を与えてきたのを見るのは、非常にやりがいのあることでした。
だからこそ、私がこの半年間、静かに取り組んできたプロジェクト、そして VS Code の Markdown ツールの次のステップを示すと信じているプロジェクトである「Markdown Language Server」を共有できることを嬉しく思います。この Language Server を使うことで、ドキュメントのアウトラインからスマートな折りたたみ、パス補完まで、VS Code の組み込み Markdown 言語ツールのほとんどを、他のエディターやツールで利用できるようになります。私たちの目標は、よりプログラミング言語に関連付けられるようなインテリジェンスで、Markdown ツールを前進させることです。
Markdown Language Server の取り組みは、2 つの新しい (そして名前が似ている!) オープンソースライブラリに分かれています。
-
Markdown Language Service - Markdown を扱うためのツールを提供する TypeScript ライブラリ。
-
Markdown Language Server - この Language Service を使って構築された Markdown 用の Language Server。
これらのライブラリはまだ初期段階ですが、すでに VS Code 1.70 以降で使われています (そして、皆さんが気づいていないことを願っています :-))。この切り替えによって、Markdown ツールを別のプロセスに移動させて他の拡張機能をブロックしないようにするなど、いくつかの利点も得られました。
しかし、先走りすぎる前に、おそらくあなたは疑問に思うでしょう。「なぜ Markdown Language Server が必要なのか?」と。正直なところ、私自身がこの考えに至るまでに 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 Language Server の時が来たのかもしれないと気づきました。
サーバーは提供されていますか?
2022年春の終わりまでに、VS Code の Markdown ツーリングはすべて、まだ 通常の拡張機能 API 上で実行されていました。私はこれらのツールをすべて本格的な Language Server に移行することを検討したかったのですが、その変更には実際のエンジニアリングコストが伴います。それが価値あるものになるか、確かめる必要がありました。
私はこれについて1ヶ月以上も考えあぐねました。既存のコードはまずまずの状態でしたが、未知の要素がたくさんありました。途中でうまくいかないと気づいたらどうしよう?私はこれまで Language Server に本格的に取り組んだことさえありませんでした。
このすべてを議論している間、私は Markdown 拡張機能のソースコードを、まるで Language Server に移行するかのようにリファクタリングすることで忙しくしていました。VS Code の拡張機能 API への依存を分離しようと試み、より多くのロジックをサービスインジェクションを使用するように切り替え、テストがファイルシステムに依存しないようにしました。そうすれば、たとえ Language Server への移行を決断しなくても、少なくともコードベースをきれいにすることができました。
いくつかの考慮事項が、最終的に Markdown Language Server が正しい次の一歩であると私を確信させました。まず、かなりありふれた理由です。Markdown ファイルのリンク診断を効率的に実装することが非常に難しいと感じていました。vscode-docs のような大規模な Markdown ワークスペースでは、誤って拡張機能ホストを数百ミリ秒ブロックしてしまうことが度々ありました。これは良くありません。一方、Language Server は独自のプロセスとして実行されます。それだけでなく、Language Server には診断のための新しいプルモデルがあり、それを試してみるのが楽しみでした。
そして、より崇高な理由もありました。例えば、Markdown Language Server は他のエディターやツールにとっても有用です。これには、VS Code チームが出荷しているもう一つのエディターである Monaco も含まれます!Markdown CLI ツーのようなものの可能性は言うまでもありません。もし私にそのようなツールを自分で作る時間がなくても、おそらく他の誰かが Language Server を出発点として作ることができるでしょう。私は VS Code の Markdown ツーリングに多大な労力を注いできたので、このすべての作業が他の人々の利益にもなれば素晴らしいことです。
新しい Language Server を利用可能にすることで、Markdown ツーリングの改善に向けた共同の取り組みを始動させることができるかもしれません。VS Code はオープンソースソフトウェアの多作な生産者であり、利用者でもあり、私はこの種のプロジェクトがもたらす明確な利点を見てきました。オープンソースの Markdown Language Server は他のエディターを助けるだけでなく、ひいては VS Code を助ける貢献を招くことにもなります!各エディター/ツールが独自の Markdown サポートを実装するために労力を重複させるのではなく、Language Server によって開発者が集まり、すべての人に利益をもたらすより大きなプロジェクトに取り組むことができるのです。
これらすべての壮大な思索も、実際に Language Server を構築する方法の計画がなければ無意味です。すべてのリファクタリングの後でも、コードを Language Server に移行するのは大変な作業になるでしょう!それは圧倒的に思えましたが、一度にすべてを行う必要はないことに気づきました。サーバーを段階的に構築し、VS Code Markdown 拡張機能から新しい Markdown Language Server へと一度に一つの機能を移行していくことができるのです。そして、それを正しく行えば、各小さな段階的な移行をチェックインして、ユーザーが構築中の新しい Language Server をテストできるようにすることができます。理想的には、ユーザーは機能が拡張機能から Language Server に移動したことに決して気づかないでしょう。
これは当たり前のことかもしれませんが、私はこの種の大規模なコード変更に対する段階的なアプローチを強く信じるようになりました。何十万行もの LOC を含む PR や、数ヶ月(あるいは数年!)も続く巨大な機能ブランチはありません。代わりに、`main` に対して小さくて安全な変更をたくさん行います。すべてが計画通りに進めば、このすべての作業を締めくくるコミットは、あっけないものになるはずです。これは、VS Code のコードベース全体で strict null チェックを段階的に使用するために私たちが取ったアプローチであり、これこそが、VS Code のすべての Markdown ツールを、迅速かつできるだけドラマなく新しい Language Server に移行できると感じた方法です。
そしてネタバレですが、うまくいきました!私は言語機能を一つずつ移行しました。進めながら学び、必要だと明らかになったときにはリファクタリングしました。診断機能は最後に移行した機能で、Language Server に移行するだけでなく、Language Server の新しいプル診断モデルを使用するように書き直しました。このすべての作業の最後のコミットは、主に Markdown 拡張機能から不要になったコードを削除するものでした。そして今日、VS Code 1.70 以降をお使いであれば、ほとんどすべての Markdown 言語機能が新しい Language Server を使用しています。
より良い Markdown ツールを共に構築する
多くの点で、過去半年間は、私がこの分野で働いてきた過去 6 年間よりも、VS Code の Markdown ツールに多くの進歩が見られました。今日、私たちは多くの新しいツールを提供しており、その中にはこれまで Markdown で利用できなかったものもあります。これらの機能の多くは、Markdown を時々読むだけの人や書くだけの人にも利益をもたらしますが、一部は上級ユーザーにしか評価されないでしょう。しかし、このすべての進歩にもかかわらず、私たちは Markdown ツールで可能なことの探求を始めたばかりだと知っています。
Markdown Language Server について本当に興奮するのは、今やこのプロジェクトが VS Code だけのものではなくなったということです。私たちの Markdown ツールを簡単に利用できるようにすることで、すべての人のために Markdown ツールを前進させる手助けができることを願っています。これらのオープンソースプロジェクトは、Markdown ツールの未来を共に築くための招待状です。貢献に興味がある方は、新しいプロジェクトをチェックして、それらを使って何を作成できるか見てみてください。バグレポートや機能リクエスト、あるいは PR を提出することもできます!私がまだ夢にも見ていないスマートな Markdown 言語機能はたくさんあります。それらを一緒に作りましょう!
ソースコードの確認や貢献に興味がある方は、GitHub と npm で Markdown Language Service と Server を見つけることができます。
-
Markdown Language Service - Markdown を扱うためのツールを提供する TypeScript ライブラリ。
-
Markdown Language Server - この Language Service を使って構築された Markdown 用の Language Server。
ハッピーコーディング!
Matt Bierner, @MattBierner