LSPのcompletionメモ
LSPを使ううえで、最も嬉しいことのひとつに、補完機能があるだろう。 LSPをサポートした各種IDEやテキストエディタのサンプル画面や動画では、補完機能を利用してサクサクと入力していく例が示されている。
ただ、実際のLSPサーバから送られる補完情報(Completion Response)は、ややこしいという感想。 現時点での各種サーバのレスポンスをメモってみる。
Solargraph
rubyのLSPサーバのSolargraph。個人的に一番使っている。 Rubocopによるメッセージ(Diagnostics)をがしがし送ってくる。 formattingリクエストを出すと、整形後のテキスト全部を一気に送り返してくる。 あとは、onTypeFormatting機能があればなぁ。
0.48.0というバージョンでの動作。
put
という文字を入力したときのcompletion response。
{ "jsonrpc": "2.0", "id": 9, "result": { "isIncomplete": false, "items": [ { "label": "putc", "kind": 2, "detail": "(ch)", "data": { "path": "Kernel#putc", "return_type": "undefined", "location": null, "deprecated": false, "uri": "file:///Users/masahino/Program/mrbmacs/mruby/test.rb" }, "textEdit": { "range": { "start": { "line": 0, "character": 0 }, "end": { "line": 0, "character": 9 } }, "newText": "putc" }, "sortText": "0000putc" }, { "label": "puts", "kind": 2, "detail": "(*args)", "data": { "path": "Kernel#puts", "return_type": "undefined", "location": { "filename": "/Users/masahino/Program/mrbmacs/mruby/mrbgems/mruby-io/mrblib/kernel.rb", "range": { "start": { "line": 19, "character": 2 }, "end": { "line": 21, "character": 5 } } }, "deprecated": false, "uri": "file:///Users/masahino/Program/mrbmacs/mruby/test.rb" }, "textEdit": { "range": { "start": { "line": 0, "character": 0 }, "end": { "line": 0, "character": 9 } }, "newText": "puts" }, "sortText": "0000puts" } ] } }
label
は必須項目。
detail
には、この場合引数の情報を入れているのかな?
選択したときのテキストはtextEdit
で指定している。
textEdit
で送ってもらえると、入力途中の文字も含めて編集できるのでありがたい。
この場合は、すでに1文字put
を入力しているが、そのput
を置き換える形で、putc
やputs
を入力することができる。
付加情報はdata
で送られる。
sortText
は補完候補に出すソート順だが、0000
を文字列の前に付けているようだ。
clangd
次はclangd。C/C++用のLSP。機能豊富なイメージ。onTypeFormattingも対応。
バージョンは、15.0.7。
こちらもput
という文字を入力したときのレスポンス。
{ "id": 5, "jsonrpc": "2.0", "result": { "isIncomplete": false, "items": [ { "documentation": { "kind": "plaintext", "value": "From <stdio.h>" }, "filterText": "putc_unlocked", "insertText": "putc_unlocked", "insertTextFormat": 1, "kind": 1, "label": " putc_unlocked(x, fp)", "score": 1.119854211807251, "sortText": "4070a89eputc_unlocked", "textEdit": { "newText": "putc_unlocked", "range": { "end": { "character": 5, "line": 3 }, "start": { "character": 2, "line": 3 } } } }, { "detail": "int", "documentation": { "kind": "plaintext", "value": "From <stdio.h>" }, "filterText": "putc", "insertText": "putc", "insertTextFormat": 1, "kind": 3, "label": " putc(int, FILE *)", "score": 0.5933540463447571, "sortText": "40e819f3putc", "textEdit": { "newText": "putc", "range": { "end": { "character": 5, "line": 3 }, "start": { "character": 2, "line": 3 } } } }, { "detail": "int", "documentation": { "kind": "plaintext", "value": "From <stdio.h>" }, "filterText": "puts", "insertText": "puts", "insertTextFormat": 1, "kind": 3, "label": " puts(const char *)", "score": 0.5933540463447571, "sortText": "40e819f3puts", "textEdit": { "newText": "puts", "range": { "end": { "character": 5, "line": 3 }, "start": { "character": 2, "line": 3 } } } } ] } }
長いので一部のみ。
detail
にint
とあるのは、戻り値か?
textEdit
もあるが、さらにinsertText
も付いている。
付加情報はdocumentation
にあるようだ。
sortText
にはなにやら個別の数値が16進数で付いている。
そのほかにscore
なるものもある。
pyls
python用のpyls。バージョンは0.36.2。
print
まで入力した。
{ "jsonrpc": "2.0", "id": 14, "result": { "isIncomplete": false, "items": [ { "label": "print(values, sep, end, file, flush)", "kind": 3, "detail": "builtins", "documentation": "print(*values: object, sep: Optional[Text]=..., end: Optional[Text]=..., file: Optional[_Writer]=..., flush: bool=...) -> None\n\nprint(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n\nPrints the values to a stream, or to sys.stdout by default.\nOptional keyword arguments:\nfile: a file-like object (stream); defaults to the current sys.stdout.\nsep: string inserted between values, default a space.\nend: string appended after the last value, default a newline.\nflush: whether to forcibly flush the stream.", "sortText": "aprint", "insertText": "print" } ] } }
textEdit
は無い。なので、選択された場合には、insertText
を挿入することになる。
この場合、既に入力済み文字列の扱いが面倒。
detail
にはbuiltins
とある。
付加情報はdocumentation
にたっぷりと。
sortText
は挿入する文字列の先頭にa
を付けている?
gopls
{ "jsonrpc": "2.0", "result": { "isIncomplete": true, "items": [ { "label": "print", "kind": 3, "detail": "func(args ...Type)", "preselect": true, "sortText": "00000", "filterText": "print", "insertTextFormat": 1, "textEdit": { "range": { "start": { "line": 10, "character": 0 }, "end": { "line": 10, "character": 5 } }, "newText": "print" } }, { "label": "println", "kind": 3, "detail": "func(args ...Type)", "sortText": "00001", "filterText": "println", "insertTextFormat": 1, "textEdit": { "range": { "start": { "line": 10, "character": 0 }, "end": { "line": 10, "character": 5 } }, "newText": "println" } }, { "label": "fmt.Print", "kind": 3, "detail": "func(a ...any) (n int, err error)", "documentation": "Print formats using the default formats for its operands and writes to standard output.\nSpaces are added between operands when neither is a string.\nIt returns the number of bytes written and any write error encountered.\n", "sortText": "00004", "filterText": "fmt.Print", "insertTextFormat": 1, "textEdit": { "range": { "start": { "line": 10, "character": 0 }, "end": { "line": 10, "character": 5 } }, "newText": "fmt.Print" } } ] }, "id": 6 }
数が多いので、途中省略。
isIncomplete
がtrue
だった。
編集テキストはtextEdit
のみ。
documentation
に詳しい情報。
sortText
には数字が入っている。
今日のまとめ
と、ここまで3つのサーバで試してみたが、それぞれの個性が表われている。
completion responseで必須なのはlabel
だけなので、あとはあったりなかったり。
kind
は3つともあったが。
clangdとpylsはlabel
の内容に実際に補完する文字列以上の情報を入れているが、solargraphは挿入する文字列情報のみと見えた。
detail
の内容は、それぞれバラバラのようで、使いづらい。
documentation
の内容の詳細具合も違っているようなので、一律で扱うのはしんどそう。