はじめに
こんにちは、Futureでアルバイトをしている川渕です。アルバイトの前はFutureのインターンシップでRust製SQLフォーマッタの作成を行っていました(その時の記事はこちら)。現在はそのSQLフォーマッタをVSCodeの拡張機能にする作業を行っており、そのための方法を学んでいます。
本記事ではLanguage Server Protocol(以下LSP)を用いたVSCode拡張機能開発について説明します。
前編ではLSPを用いたVSCodeの拡張機能開発チュートリアルと、チュートリアルに使用したサンプルコードの解説を行います。
後編ではサンプルコードに機能を追加する方法を説明します。
Language Serverとは
Language Serverとは、自動補完、エラーチェック、型チェックなどの様々な言語機能をIDEに提供するものです。
Language Server Protocol (LSP)とは
LSPとは2016年6月にMicrosoftが発表したプロトコルで、IDEとLanguage Server間の通信を標準化するものです。
LSPがない場合は各IDEに対応した言語、仕様で言語サーバを実装しなければならず、非常に労力がかかってしまいます。しかし、LSPを使用することで1つの言語サーバを複数のIDEで利用できるようになり、実装言語の制約も無くなります。
つまり、LSPを用いて開発した拡張機能はVSCodeだけでなく、VimやEmacsなどでも使用できます。
本記事で説明すること
- LSPを用いたVSCodeの拡張機能開発チュートリアル
- チュートリアルコードの解説
本記事で説明しないこと
- VSCode以外で使用する方法
- 拡張機能の公開方法
LSPチュートリアル
まずVSCodeの公式で配布されているLSPのサンプルコードを動かしてみます。
1. サンプルリポジトリのダウンロード
まず適当なディレクトリで以下のコマンドを実行してVSCode拡張機能サンプルリポジトリをダウンロードします。
git clone https://github.com/microsoft/vscode-extension-samples.git |
2. 必要なパッケージのインストール
次にnpmを用いて必要なパッケージをインストールします。
- まず先程ダウンロードしたリポジトリ内のlsp-sampleディレクトリをvscodeで開く
- Ctrl+@(macOSの場合は^+@)でターミナルを開き、以下を実行する
npm install |
3. コンパイルと実行
- Ctrl+Shift+Bでクライアントとサーバをコンパイル
- Ctrl+Shift+Dで「実行とデバッグ」を開き、Launch Clientを選択する
- ▷をクリックする
- 新たにVSCodeのウィンドウが開くのでそのVSCode上で適当なテキストファイルを作成
- テキストファイルで以下の機能が確認できれば完了
- jと入力すると補完の候補としてJavaScriptが表示される
- tと入力すると補完の候補としてTypeScriptが表示される
- 全て大文字、かつ長さが2以上の単語には警告が表示される
4. サーバのデバッグ
- Launch Clientしている状態で「実行とデバッグ」のAttach to Serverを選択
- ▷をクリック
- サーバのブレークポイントが効くようになる
サンプルコードの解説
先程実行したlsp-sampleの実装について詳しく解説します。
ファイル構成
ファイル構成は以下の通りです。
extension.tsにクライアントサイドの処理、server.tsにサーバサイドの処理を記述しています。
. |
pakcage.json
クライアントの機能について記述しています。詳しい情報は以下に記載されています。
この中から一部のフィールドを説明します。
name
拡張機能の名前で、今回のサンプルコードではlsp-sampleとなっています。
マーケットプレースでの表示名はdisplayNameで別に設定できます。
publisher
拡張機能を公開する際に使用するフィールドです。
vsceというVSCode拡張機能用コマンドラインツールで作成したpublisherIDをこのフィールドに入力します。
拡張機能の公開方法は以下に記載されています。
categories
拡張機能のカテゴリを入力します。
許容するカテゴリ一覧
- Programming Languages
- Snippets
- Linters
- Themes
- Debuggers
- Formatters
- Keymaps
- SCM Providers
- Other
- Extension Packs
- Language Packs
- Data Science
- Machine Learning
- Visualization
- Notebooks
- Education
- Testing
activateEvents
activateEventsに記述したイベントが発生すると、拡張機能が有効になります。
lsp-sampleでのactivateEventsは以下のようになっています。
"activationEvents": [ |
これは、「プレーンテキスト(.txtなど)を開く」というイベントが発生すると拡張機能が有効になることを表しています。
他にもコマンド実行イベントやデバッグイベントなどを登録できます。詳しい情報は以下に記載されています。
contributes
拡張機能の機能についての情報を記述します。
詳しい情報は以下に記載されています。
extension.ts
extension.tsにはクライアント側の処理を記述します。
拡張機能の起動時の処理
拡張機能の起動時に関数activate()
が実行されます。
activate()
内では接続先のサーバ、クライアントの設定、クライアントの起動処理を行います。
export function activate(context: ExtensionContext) { |
ちなみに、lsp-sampleではUntitledなファイル(新規作成した保存されていないファイル)には対応していませんが、clientOptions
のdocumentSelector
を以下のように変更することで対応できます。
// クライアントのオプション |
拡張機能の終了時の処理
拡張機能の終了時に関数deactive()
が実行されます。
lsp-sampleでは関数deactive()
にクライアントを終了する処理を記述しています。
GitHub
export function deactivate(): Thenable<void> | undefined { |
server.ts
server.tsにはサーバ側の処理を記述します。
サーバの接続を作成
サーバの接続を作成し、その接続を監視することで拡張機能を提供します。
- サーバの接続の作成
GitHub
const connection = createConnection(ProposedFeatures.all); |
- 接続の監視
GitHub
connection.listen(); |
ドキュメントマネージャの作成
ドキュメントマネージャとはサーバとクライアントのドキュメントを同期するものです。
ドキュメントマネージャを作成し、ドキュメントの監視を行います。
- ドキュメントマネージャの作成
GitHub
const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument); |
- ドキュメントマネージャの監視
GitHub
documents.listen(connection); |
ドキュメントマネージャはドキュメントを開くイベント、閉じるイベント、変更イベントを検知します。
初期化
最初のリクエスト受信時に実行されます。ここでサーバの設定を初期化します。
connection.onInitialize((params: InitializeParams) => { |
警告表示機能の実装
lsp-sampleではテキストドキュメントの変更時に全て大文字で、かつ長さが2以上の単語を特定し、その箇所に警告を表示します。
この機能の実装方法について説明します。
テキストドキュメントが変更、または初めて開かれた場合にこのメソッドが呼び出されます。
documents.onDidChangeContent((change) => { |
このメソッド内で呼び出している関数validateTextDocument
の処理は以下の通りです。
async function validateTextDocument(textDocument: TextDocument): Promise<void> { |
診断メッセージ、診断の発行元、関連情報は以下のように表示されます。
補完機能の実装
lsp-sampleでは”TypeScript”、”JavaScript”という2つの単語の補完を提供します。
補完はconnection
のonCompletion
メソッドで提供します。
GitHub
connection.onCompletion( |
また、onCompletionResolve
メソッドに各補完が選択された場合に表示する情報を記述しています。
GitHub
connection.onCompletionResolve((item: CompletionItem): CompletionItem => { |
補完、追加情報は以下のように表示されます。
まとめ
LSPを用いたVSCodeの拡張機能開発チュートリアルとチュートリアルコードの解説を行いました。
後編 ではlsp-sampleに機能を追加する方法を説明しています。