LSP
Language Server Protcol
そう、プロトコルだ!
プロトコルは規定されているが、通信手段は決められていない
標準入出力でもhttpでも良い
クライアントが対応しているならば。
データの型は各プログラミング言語の型ほど具体的ではない
ASTやコンパイラシンボルを標準化したわけではない
データ型がシンプルであることで、言語に中立でかつ簡素な仕様にできている
プログラミング言語に依存した型ではなくエディタやIDEレベルの型になっている
つまりファイルのURIやカーソル位置でやりとりするフォーマットになっている
一つのワークスペース上で異なる複数の言語のファイルを開くと、裏側では複数の言語サーバーを起動する
2016/06~
にほんご
Version 5.3.0
2019/8/14現在
何が嬉しいのか
プログラミング言語はどの言語でもコンパイラインフラストラクチャが必要としている機能は似たようなもの
なので、言語やIDEごとにばらばらにやるんじゃなくて統一した仕様を決めよう
そしたら、IDE作成者も言語プラグイン作成者も個別で作らなくて済むでしょ、的な?
サーバーから見れば、クライアントがどの言語を使おうとも同じように処理できるし、
クライアント(言語)から見ても、どのIDEを使おうとも同じように利用できる
これまでは言語の数*IDEの数だけプラグインを開発する必要があった
それがN+Mで耐える
LSPをサポートする複数のIDEで言語サーバーを再利用することができる
誰が嬉しい
エディタの開発者
具体的な言語をサポートするために新たに何かを作らなくて済む
VSCode開発者「とりあえずLSPには対応したから、何の言語でも耐える」
エディタ用の言語プラグインの開発者
各エディタごとにNim用のプラグインを作らなくて済む
プログラマ
どの言語をどのエディタで書いても良い感じにプログラミングできる
https://microsoft.github.io//language-server-protocol/overviews/lsp/img/language-server-sequence.png
ファイルを開いたというNotificationをサーバーへ送る(左上)
textDocument/didOpen
なんかしれっとすごいこと言ってない?mrsekut.icon
クライアントとサーバーが同期される
ファイルを編集する
textDocument/didChange
ファイルの変更をサーバーに通知する
このタイミングでサーバーはファイルを解析し、エラーや警告などをレスポンスとして返す
上から3番目の左向きの矢印のことだねmrsekut.icon
ユーザーがGo to Definitionをしたとき
2つの引数を伴ってtextDocument/definitionをリクエスト
ファイルのURI
テキスト上の位置
何行目の何文字目とか
レスポンスは結果の↑この2つの情報を返す
ファイルを閉じる
‘textDocument/didClose
メモリ上からも消し、ファイルシステム上に記録する
作るためには何を知っている必要がある?
言語の仕様?
特定のIDEの仕様?
プログラミングしてるどのタイミングでサーバーとやり取りする?
cmd-sしたとき?
一文字打つたびにリクエスト送信?
違う。completionの処理はそこまで軽くないので。
必要となったタイミングで送信する
5秒ごとにリクエスト送信?
initializeリクエストを送った時にサーバーがcompletionのトリガーとなる文字を提示する
クライアントが打ち込んだ文字がそれに該当していたらcompletionを送る
現状、全ての言語サーバーがLSPにあるすべての機能を実装しているわけではない
サーバー側がレスポンスで使える機能を提示する
クライアント側にもすべての機能があるわけではない
よね?
クライアントが何らかのリクエストを送ってもサーバーにその機能がなければその処理は失敗する
サーバーはサポートするcapabilitiesを示すことで、コード検証に使える機能を提示することができる
クライアントは何をサーバーに送る?
書いた文字全部?
エディタ上の編集内容を送る
リクエストの種類
自動補完
「.」などをタイプした時に送信?
今入力してたオブジェクトが利用できるプロパティの一覧を表示
completionItem/resolve
自動補完候補の選択
選択した時に送信?
textDocument/hover
ホバーしたときにヒントを表示する
vscodevimのghとかで出るやつか
textDocument/signatureHelp
メンバー定義(signature)候補の表示
わからん
メソッドを呼び出す時に引数を指定しているタイミング
今何番目の引数を指定しているのかなど
textDocument/definition
シンボルの定義の位置を取得
上の方にでてるパンくずリストみたいなやつ
VScodeでは左側のツリーに地味に「アウトライン」という項目があるが、これもか。
textDocument/references
その関数やメソッドがプロジェクト内のどこで使われているかの一覧を表示
textDocument/documentHighlight
その変数が開いているファイルのどこで使われているかをハイライトするやつ
同名の変数がいくつかあってもスコープも正しく該当のものだけをハイライト
textDocument/documentSymbol
ドキュメント中で定義されている全シンボルの取得
なにこれ
cmd-f?
workspace/symbol
ワークスペース全体からクエリ条件に合致するシンボルの取得
cmd-shift-f
textDocument/codeAction
コード アクションのリストの取得
エディタ上のカーソル位置を送信
実行できる補助アクションの一覧を受け取る
cmd-.とか?
textDocument/codeLens
code lensのリストの取得
わからん
codeLens/resolve
code lensの処理の実行
textDocument/formatting
ドキュメントの整形
Goならgofmt
textDocument/rangeFormatting
選択範囲の整形
textDocument/onTypeFormatting
タイプ時の整形
textDocument/rename
識別子の変更
workspace/didChangeConfiguration
ワークスペースの設定変更
textDocument/didOpen
ドキュメントを開いたという通知
textDocument/didChange
ドキュメントの内容を変更したという通知
textDocument/didClose
ドキュメントを閉じたという通知
textDocument/didSave
ドキュメントを保存したという通知
workspace/didChangeWatchedFiles
監視していたファイルへの変更を検出したという通知
textDocument/publishDiagnostics
ドキュメントに対する検証処理の結果通知
リクエストのキャンセルなどのリクエストもある
2種類のメッセージの受け取り方
Notification
通知を送る。レスポンスは要求しない
サーバー→クライアント
クライアント→サーバー
ファイルのopenとか
Request/Responce
サーバー→クライアント
開いているファイルのリストなどをクライアントから受け取る
クライアント→サーバー
コード補完とか
リクエストの内容はHTTPに似ている
以下の2つのセクションで構成される
ヘッダー
Content-Lengthとタイプを示す2つのフィールド
言語サーバーに送られたリクエスト、それから受け取ったレスポンス
メッセージ、通知、コマンドの送信に使われる
異なる言語サーバーに同時に複数のリクエストを送っても、エディタがそれぞれの応答を区別できるよう、各パケットにはIDフィールドが含まれている。ref idはどのクライアントから送られたかを識別する?
それとも同時にいくつかのリクエストを送ることもあるので、その識別?
そもそも「同時にいくつかのリクエストを送ることがある」のかどうか知らないけど
textDocument/definitionのリクエストとレスポンスの例
request
code:json
{
"jsonrpc": "2.0",
"id" : 1,
"method": "textDocument/definition",
"params": {
"textDocument": {
"uri": "file:///p%3A/mseng/VSCode/Playgrounds/cpp/use.cpp"
},
"position": {
"line": 3,
"character": 12
}
}
}
response
code:json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"uri": "file:///p%3A/mseng/VSCode/Playgrounds/cpp/provide.cpp",
"range": {
"start": {
"line": 0,
"character": 4
},
"end": {
"line": 0,
"character": 11
}
}
}
}
↓これらってクライアント側がやることなん?
自動補完
静的解析
コードジャンプ
シンボルの検索
編集中のファイル同期
非同期
高速
サーバーからのレスポンスを受けてそれをエディタ上に表示する
VSCodeは両方とも統合した
わからん
今までは一つの言語につき複数の言語サーバーがあった?
今までは一つの言語と一つのエディタごとに言語サーバーがあった?
それを一つの実装を再利用できるようにした?
疑問
後で調べる
サーバー内部の処理
go to definitionとかどうやって実装するん
クライアント内部の処理
受け取った情報をどうやって画面に表示する?
lspのサンプル
何これキーワード
Visual Studio SDK
MEF
Mono Develop Addin, Eclipse Platform NetBeans Platform
Mono.Addins
emacs, vim, atom, vscode
関連
TypeScriptの話
参考
めっちゃ良いスライド、もう一回読みたい
実装方法と仕様