(´ワ`)

主に技術系備忘録、たまに日記。

nvim-lspのジャンプ機能をcoc.nvimの頃のものから置き換える

Zenn に投稿した以下の記事のおまけを今更書く。

zenn.dev

背景

以前まで LSP クライアントプラグインとして coc.nvim を使用していた。 その時はジャンプ先の挙動をカスタマイズするために、 VimScript を用いて独自の挙動を行うスクリプトを書いていた。 当日の記事は以下。

nnsnico.hatenablog.jp

しかし、Neovim への完全な置き換えに合わせて、 builtin LSP へ置き換えることにした。

機能・変更点

上記記事で紹介したスクリプトの主な機能は以下。

  • ジャンプ先ファイル名が同じ場合は edit コマンドで開く
  • ジャンプ先ファイル名が違う場合は split 、あるいは vsplit で開く

builtin LSP は LSP の仕様に柔軟に対応されているため、上記に加えてジャンプ先のカーソル位置も取得できるようになったため、よりリッチな動作が可能になった。

しかし、カスタマイズについて考慮する範囲は coc.nvimプラグイン以外に増えることがなかったことに対して、 builtin LSP は少し異なる。

ジャンプ先の一覧画面と画面内の動作について、 coc.nvim は全てプラグイン内の View を用いている。 一方で builtin LSP はこれを QuickFix リストで表示する。 そのため、以下 2 つに対して考慮する必要がある。

  1. 通常のジャンプ先の挙動を差し替える入口
  2. QuickFix より選択されたときの動作

Zenn の記事で書いたとおり、 vim.lsp.handlers に関数を渡すことで引数からジャンプ先の挙動をデフォルトのものから差し替えられる。 前者はこれを用いて、関数の引数から、ジャンプ先の情報を含むレスポンス( Location , LocationLink など)を受け取れるため、これでカスタマイズが可能となる。

QuickFix リストでの挙動変更はファイルタイプ別にスクリプトを読み込むように、 ftpluginafter/ftplugin で定義するのが良さそう。 QuickFix のファイルタイプは基本的に qf とされているため、この名前で作成されたファイル内にジャンプの挙動を定義する。

以上を以って、以下でこれらを作成している。

  1. 通常のジャンプ先の挙動を差し替える入口
  2. QuickFix より選択されたときの動作
  3. ウィンドウの分割処理全般

以前より記述量が増えたため、多少ややこしくなっているが、簡単に説明すると、順序としては以下の動作をしている。

  1. vim.lsp.utils.locations_to_items() でレスポンスからロケーションリストを作成する
    • レスポンスがリストでない場合、作成できないため、単一のテーブルが返ってくる場合などはリストにラップして返す
    1. のリストの個数が 1 個の場合でかつ、それが現在のファイルであればカーソルの移動のみ行う。さもなくばvsplit あるいはsplit を用いて分割で対象へ表示、カーソル移動する
    1. のリストの個数が複数である場合、ロケーションリストをセットし、lopenで QuickFix リストを表示する
      • 以降の挙動は QuickFix より選択されたときの動作 で示すファイルタイププラグイン内の処理が行う

まとめ

つらつらと書いたが、 builtin LSP で注意することは coc.nvim のように、 LSP の機能をプラグイン全てが担っている訳ではないという点のみだと思う。 いつでもカスタマイズしやすいように、スクリプトを単体で動作できるようにメンテナンスしておくことが大事である。

おまけ

QuickFix を使う場合、 nvim-bqf を用いるとジャンプ先のコードをプレビューできるため、非常に便利。 また、 nvim-bqf の README に記載されているイースターエッグを使うことで QuickFix リストのフォーマットとシンタックスハイライトをカスタマイズできるためおすすめ。

github.com