ざっくりLSP
2019/9/6
mrsekut.icon
丸末 皓太
普段はtryangle社でTSでReactとかReactNativeとか書いてる
フロントエンドとか、言語処理系とか機械学習が好き
このScrapboxに書いてあること周辺が関心事
最近は自作プログラミング言語を作り始めたりしてる
お詫び
TypeScriptの話は5%くらいしか出てきません (ミスった)
LSPをごりごり触っているわけではない
ちょっと調べてみた、って感じの内容
調べてみた動機
前々から気になっていた
LSPとは?
自分で言語作るならこういうところも知っておきたい
知ってますか?/emoji/raising hand.icon
皆さんが普段の開発時に恩恵を授かっているアレのことです!
アレ is 何
エディタを起動してファイルを開いてコーディング開始!
一文字打ったら補完機能!
https://gyazo.com/9291fd31202404791939d07b8190736f
TypeScriptの型エラーがあったら赤線で目立たさせてくれる!
https://gyazo.com/3098f580837f13c147ac42722ed0debc
「go to definition」を使えば定義元へとべる!
https://gyazo.com/ad313b2f9ee39615b7d5ace1510701b9
変数名を一発で変えられる!
https://gyazo.com/ec98f058111512ed60affb924d12f5a7
などなど
誰のおかげ?
→Language Serverのおかげ
日本語では「言語サーバー」とか (そのまま)
こんなことが出来る
補完候補の提示
エラーの表示
定義元へジャンプ
クライアントと通信する
クライアントというのはIDEやエディタのこと
クライアントとは別プロセスにローカルサーバーを立てる
LSP誕生の背景
言語サーバーは上記のようなことができて便利だが、実装が大変
言語ごとに言語サーバーを作る必要がある
TypeScript、Python、PHP、etc.
さらにエディタごとにも作る必要がある
VSCode、Vim、Emacs、etc.
$ M\times Nパターン実装する必要がある
いや、作るの大変すぎでしょ.. /emoji/raaage.icon
MS「そうだ、仕様を決めよう」
Language Server Protocol
言語サーバーの「プロトコル」です!
そう、プロトコルだ!
MicroSoftが作った
2016/6~
現在はver.3
何が嬉しいのか
言語ごとIDEごとに作っていたものが使い回せる
$ M\times Nを$ M+Nにできる
https://code.visualstudio.com/assets/api/language-extensions/language-server-extension-guide/lsp-languages-editors.png
リクエストにはどんな種類があるのか
textDocument/completion
自動補完
textDocument/hover
ホバーしたときにヒントを表示する
textDocument/definition
シンボルの定義の位置を取得
textDocument/references
その関数やメソッドがプロジェクト内のどこで使われているかの一覧を表示
etc.
どのタイミングでリクエストを飛ばすのか
状況に依る
一文字打つたびとか、保存したタイミング、というわけではない
例えば
ファイルを開いた時
ホバーした時
「.」を打った時
右クリックでメニューを出してそれを選択した時
具体例を見てみる
https://microsoft.github.io/language-server-protocol/img/language-server-sequence.png
左がクライアント、右が言語サーバー
一番上の線
https://gyazo.com/b3a29d2420c3c6c3319d62fa7e36b0b8
ファイルを開いたというNotificationをサーバーへ送る
これを実行してからは、ファイルの内容はファイルシステムではなく、メモリに保持される
クライアントとサーバーが同期される
2,3番目の線
https://gyazo.com/86053f5bff7efb44310a8acc428bffc3
ファイルを編集したタイミング
textDocument/didChangeを送る
このタイミングでサーバーはファイルを解析し、エラーや警告などをレスポンスとして返す
4,5番目の線
https://gyazo.com/bb5681382a418920e54637be8f2d3e3a
ユーザーがGo to Definitionをしたとき
2つの引数を伴ってtextDocument/definitionをリクエスト
ファイルのURI
テキスト上の位置
何行目の何文字目とか
レスポンスは結果の↑この2つの情報を返す
最後の線
https://gyazo.com/84658b4c1e9d7fd4163d9cf62cfb8f49
ファイルを閉じたタイミング
‘textDocument/didClose
メモリ上からも消し、ファイルシステム上に記録する
どういう情報をやり取りしてるの?
こんなの
textDocument/definitionしたときの例
request
code:json
{
"jsonrpc": "2.0",
"id" : 1,
"method": "textDocument/definition",
"params": {
"textDocument": {
"uri": "file:///path/to/hoge.ts"
},
"position": {
"line": 3,
"character": 12
}
}
}
response
code:json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"uri": "file:///path/to/piyo.ts",
"range": {
"start": {
"line": 0,
"character": 4
},
"end": {
"line": 0,
"character": 11
}
}
}
}
やりとりのサンプル
本来は、自作したものでログを取ってアップロードして可視化して使うツール
デバッグに使う
実装したいなら
ここを読めば出来る
サンプルがあるので小さいものを試せる
実装例
エディタごとではなく言語ごとにあるのがわかる
サーバーを実装するための言語は何でもいい
LSPの仕様に則っていれば
でも多くは言語Aの言語サーバーは言語Aで実装されていることが多い
で?TypeScriptは?
TypeScript言語サーバーとVSCode間はLSP準拠ではない
LSPができるよりも先にTypeScriptが開発されていた
なので最初の方のgif画像もLSPではない
https://raw.githubusercontent.com/wiki/Microsoft/TypeScript/images/architecture.png
黄色の部分がtsserver
一応TSの言語サーバーの実装もある
が、各々問題があるのでTS team頑張れみたいなことを言っている人もいる ref でっていう(まとめ)
僕たちが日頃何の気なしに便利に開発できてたのはLSPのおかげ
感謝しよう
参考文献