gopls(v0.4.0)の機能
goplsは更新頻度が高く、何ができるのかをちゃんと把握できていなかったので、LSPのメソッドベースで今の時点(v0.4.0)の機能をざっと調べてみることにしました。
補完(textDocument/completion)
入力中の変数や定数、関数といった各種定義などをbuiltinも含めて補完してくれます。
この機能のためにgoplsを使っているという人もけっこう多いはず。
基本的に文脈に合わせた候補を返したり、優先度が高くなるようになっていますが、
- おかしな候補が返ってくる
- 期待する候補が返ってこない
という場合はコントリビュート(issue報告や修正する)チャンスかもしれません。
例えば、
- スコープに存在しない定義は候補にならない
- スコープ外の変数など
- カーソル位置で使えないキーワードは候補にならない
iota: const入力中のみrange: for入力中のみbreak: for、switch、select内continue: for内- など
- 型が合わないものは候補から外されることがある
- 代入時
のような制御があります。
また、以下の場合は補完で入力される内容自体が変化します。
- 参照が要求される場合、値には
&がつく
// vへの代入時、 var v *int i := 1 v = // iは&iになる // func f(i *int)を呼び出す際、 f( // iは&iに変換される
- 値が要求される場合、参照には
*がつく
// iへの代入時、 var v *int var i int = // vは*vになる // func f(i int)を呼び出す際、 f( // vは*vに変換される
- 可変長引数の場合に
...が展開される
func fn(v ...int) {} func do(v []int) { fn( // vはv...になる }
- 引数の型がわかる場合はその型が補完される
func(...[]int)を呼び出す際は[]int{}が候補になるvar _ []int = make()の第1引数は[]intが候補になる
ただし、プレースホルダー*1やスニペット*2が有効になっていないと変換されなかったり、候補として表示されません。
VS Codeはデフォルトで有効になっているはずですが、Vimの場合はプラグインによっては有効になっていないかもしれません。
そしてシグネチャを補完・展開する際にはこれらが必須となっているため、もしうまく動かない時は設定を確認してみましょう。
他にも、次の設定で補完の動作を変えることができます。
initializationOptions.matcher- デフォルトは
"fuzzy"なので多少違っている候補も返ってきますが、 "caseSensitive"や"caseInsensitive"に変更できます
- デフォルトは
initializationOptions.completeUnimported- デフォルトは
trueなので未importのパッケージからも候補が返ってきますが、 falseで無効化できます
- デフォルトは
initializationOptions.deepCompletion- デフォルトは
trueなので構造体のフィールドも候補として返ってきますが、 falseで無効化できます
- デフォルトは
// deepCompletion=trueだと type param struct{ i int } func fn(i int) {} func do(p param) { fn( // p.iが候補として表示される }
それ以外の特殊な動作としては、
if err != nilのスニペット展開errorを返す関数内のみ
- 公開される
varのgodoc補完- 次のバージョンでは
constやfunc、typeも対象になる
- 次のバージョンでは
があります。
ジャンプ系
自分の場合は補完よりこちらを多用しています。
ただ、definitionとtypeDefinitionは違いがわからないまま使っていました。
textDocument/definition
カーソル位置にあるシンボルの定義元にジャンプする時に使用します。
関数内の変数はその関数内で定義(宣言)された場所にジャンプします。
type myType struct{} func fn() { t := myType{} // ← t.method() // tが宣言されたのは1行上 }
コマンドラインからはgopls query definitionsで使えます。
※次のバージョンからqueryが不要になる
gopls query definition internal/lsp/definition.go:14:67
textDocument/typeDefinition
カーソル位置にあるシンボルの型定義にジャンプする時に使用します。
関数内の変数は実際の型のある場所にジャンプします。
type myType struct{} // ← func fn() { t := myType{} t.method() // tの型定義はfnの上にあるmyType }
textDocument/implementation
カーソル位置にあるシンボルの、
- インタフェースから型
- 型からインタフェース
にジャンプする時に使用します。
コマンドラインからはgopls implementationで使えます。
gopls implementation internal/lsp/implementation.go:14:10
textDocument/references
カーソル位置にあるシンボルが参照されている(使われている)場所にジャンプする時に使用します。
コマンドラインからはgopls referencesで使えます。
gopls references internal/lsp/references.go:14:18
textDocument/documentSymbol
現在開いているファイルのシンボル一覧を取得します。
結果はジャンプするためや、ファイルのアウトライン表示のためにも使われます。
コマンドラインからはgopls symbolsで使えます。
※CLIでうまく動かない? → https://go-review.googlesource.com/c/tools/+/232557
workspace/symbol
プロジェクト(リポジトリ本体と依存パッケージ)からシンボル一覧を検索します。
※LSPの仕様では依存パッケージは含まれないはずですが、その方が便利なのでそういう実装になっています
今のところ結果は100件までに制限されています。
※一度に全部返してしまうとクライアントが高負荷で固まってしまうことがあるため
また、検索方法は補完と同じでinitializationOptions.matcherに従います。
コマンドラインからはgopls workspace_symbolで使えます。
gopls workspace_symbol WorkspaceSymbols
Vimからはtagfunc経由でctagsのように使うこともできます。
設定例は下記参照。
daisuzu.hatenablog.com
その他
Diagnostic以外はほとんど使っていませんでした。。。
しかし、今回調べたことでrenameがgorenameの代わりになるくらい完成度が高くなっていたり、SuggestedFixの種類がだんだん増えていることがわかったのは大きな収穫でした。
Diagnostic
go vet(golang.org/x/tools/go/analysis/passes/...)やgofmt -s、staticcheckなどのチェックを行います。
実行するチェッカーは以下のオプションでカスタマイズできます。
initializationOptions.analysesinitializationOptions.staticcheck
結果にSuggestedFixが含まれている場合、codeAction経由で修正可能です。
SuggestedFixの例:
returnの返り値の数があっていない時に追加したり、削除したり- 2回目以降の
:=を=に変更したり - 未定義変数の
<変数名> :=を挿入したり
コマンドラインからはgopls checkで使えます。
gopls check internal/lsp/testdata/lsp/primarymod/analyzer/bad_test.go
textDocument/codeAction
SuggestedFixの実行やimportの追加・削除(go.modへの追加も含む)を行います。
コマンドラインからはgopls fixやgopls importsで使えます。
textDocument/codeLens
調べてもイマイチよくわかっていない機能ですが、現状は//go:generateコメントのある行でgo generateが実行できるよ、という情報を返してくれるようです。
また、go.modを開いている場合は依存パッケージのアップデートができるかどうかを教えてくれるようです。
textDocument/hover
カーソル位置のシグネチャや型などの情報を返してくれます。
textDocument/signatureHelp
カーソル位置のシグネチャやヘルプを返してくれます。
コマンドラインからはgopls signatureで使えます。
※<position>の指定方法がわからず...は関数呼び出しの()内の位置を指定する必要がある
gopls signature internal/lsp/signature_help.go:21:53
textDocument/documentHighlight
カーソル位置のシンボルが使われている場所をハイライトします。
コマンドラインからはgopls highlightで使えます。
gopls highlight internal/lsp/highlight.go:17:2
textDocument/documentLink
現在開いているファイルがimportしているパッケージの https://pkg.go.dev へのリンクや、
<org>/<repo>#<number>形式のコメントからGitHub Issuesへのリンクを返してくれます。
コマンドラインからはgopls linksで使えます。
gopls links internal/lsp/link.go
textDocument/formatting
現在開いているファイルを整形します。
コマンドラインからはgopls formatで使えます。
# -dでdiffを表示する gopls format -d internal/lsp/testdata/lsp/primarymod/format/bad_format.go.in
textDocument/rename
カーソル位置のシンボルをリネームします。
コマンドラインからはgopls renameで使えます。
# -dでdiffを表示する gopls rename -d internal/lsp/rename.go:14:18 doRename
リネーム可能かどうかを調べるためにはtextDocument/prepareRenameで確認できます。
コマンドラインからはgopls prepare_renameで使えます。
# rangeが表示されればリネーム可能
gopls prepare_rename internal/lsp/rename.go:14:18
textDocument/foldingRange
コードを折り畳む範囲を返してくれます。
コマンドラインからはgopls folding_rangesで使えます。
gopls folding_ranges internal/lsp/folding_range.go
workspace/executeCommand
codeLensの結果からgo generateやgo getの実行をしてくれるようです。
また、diagnosticの結果からgo mod tidyの実行をしてくれるようです。
未実装
以下のメソッドはまだ実装されていません。