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.analyses
initializationOptions.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
の実行をしてくれるようです。
未実装
以下のメソッドはまだ実装されていません。