nvim-lspのジャンプ機能をcoc.nvimの頃のものから置き換える
Zenn に投稿した以下の記事のおまけを今更書く。
背景
以前まで LSP クライアントプラグインとして coc.nvim
を使用していた。
その時はジャンプ先の挙動をカスタマイズするために、 VimScript を用いて独自の挙動を行うスクリプトを書いていた。
当日の記事は以下。
しかし、Neovim への完全な置き換えに合わせて、 builtin LSP へ置き換えることにした。
機能・変更点
上記記事で紹介したスクリプトの主な機能は以下。
- ジャンプ先ファイル名が同じ場合は
edit
コマンドで開く - ジャンプ先ファイル名が違う場合は
split
、あるいはvsplit
で開く
builtin LSP は LSP の仕様に柔軟に対応されているため、上記に加えてジャンプ先のカーソル位置も取得できるようになったため、よりリッチな動作が可能になった。
しかし、カスタマイズについて考慮する範囲は coc.nvim
はプラグイン以外に増えることがなかったことに対して、 builtin LSP は少し異なる。
ジャンプ先の一覧画面と画面内の動作について、 coc.nvim
は全てプラグイン内の View を用いている。
一方で builtin LSP はこれを QuickFix リストで表示する。
そのため、以下 2 つに対して考慮する必要がある。
- 通常のジャンプ先の挙動を差し替える入口
- QuickFix より選択されたときの動作
Zenn の記事で書いたとおり、 vim.lsp.handlers
に関数を渡すことで引数からジャンプ先の挙動をデフォルトのものから差し替えられる。
前者はこれを用いて、関数の引数から、ジャンプ先の情報を含むレスポンス( Location
, LocationLink
など)を受け取れるため、これでカスタマイズが可能となる。
QuickFix リストでの挙動変更はファイルタイプ別にスクリプトを読み込むように、 ftplugin
や after/ftplugin
で定義するのが良さそう。
QuickFix のファイルタイプは基本的に qf
とされているため、この名前で作成されたファイル内にジャンプの挙動を定義する。
以上を以って、以下でこれらを作成している。
- 通常のジャンプ先の挙動を差し替える入口
- github.com
- LSP 上でのハンドリング周り
- github.com
- QuickFix より選択されたときの動作
- ウィンドウの分割処理全般
以前より記述量が増えたため、多少ややこしくなっているが、簡単に説明すると、順序としては以下の動作をしている。
vim.lsp.utils.locations_to_items()
でレスポンスからロケーションリストを作成する- レスポンスがリストでない場合、作成できないため、単一のテーブルが返ってくる場合などはリストにラップして返す
- のリストの個数が 1 個の場合でかつ、それが現在のファイルであればカーソルの移動のみ行う。さもなくば
vsplit
あるいはsplit
を用いて分割で対象へ表示、カーソル移動する
- のリストの個数が 1 個の場合でかつ、それが現在のファイルであればカーソルの移動のみ行う。さもなくば
- のリストの個数が複数である場合、ロケーションリストをセットし、
lopen
で QuickFix リストを表示する- 以降の挙動は
QuickFix より選択されたときの動作
で示すファイルタイププラグイン内の処理が行う
- 以降の挙動は
- のリストの個数が複数である場合、ロケーションリストをセットし、
まとめ
つらつらと書いたが、 builtin LSP で注意することは coc.nvim
のように、 LSP の機能をプラグイン全てが担っている訳ではないという点のみだと思う。
いつでもカスタマイズしやすいように、スクリプトを単体で動作できるようにメンテナンスしておくことが大事である。
おまけ
QuickFix を使う場合、 nvim-bqf
を用いるとジャンプ先のコードをプレビューできるため、非常に便利。
また、 nvim-bqf
の README に記載されているイースターエッグを使うことで QuickFix リストのフォーマットとシンタックスハイライトをカスタマイズできるためおすすめ。