Neovimには組み込みのLSPがあります。 しかし機能が貧弱もいいところなのでtelescope.nvimとdressing.nvimなどを入れるわけですが、 依然としてコードアクション(修正を提案してくれる機能)周りは不満が残ります。
例えば、Neovim標準のvim.lsp.buf.code_action
やtelescope.nvim・dressing.nvimを使うとこうなります。
分かりますか?そう、
コードアクションがどう適用されるか分からん!!!
と言うわけでこの不満を解消するプラグインを作りました。
使い方
このプラグインはコードアクションの候補をtelescope.nvimやnui.nvimを使って綺麗に表示し、 選択中のアクションの適用結果をプレビューエリアに差分として表示します。 複数ファイルや新規ファイル作成も差分が出ますし、ビジュアルモードでもちゃんと動作します。
導入は適当にpacker.nvimを使ってこんな感じでやります。 nvim-lightbulbを入れるとカーソル位置でコードアクションが使える場合に💡が出るので一緒に入れておくと良いです。
packer用luaスクリプト
require("packer").startup(function(use) -- ... -- telescope.nvimを使わないならいらない use { "nvim-telescope/telescope.nvim", requires = "nvim-lua/plenary.nvim", config = function() require("telescope").setup { -- 必要なら設定 } end } use { "kosayoda/nvim-lightbulb", config = function() require("nvim-lightbulb").setup { autocmd = { enabled = true }, -- 行番号ではなく行末に出す sign = { enabled = false }, virtual_text = { enabled = true }, } end, } use { "aznhe21/actions-preview.nvim", -- nuiを使う場合はコメントを外す -- requires = "MunifTanjim/nui.nvim", config = function() require("actions-preview").setup { -- バックエンドに使うプラグインの優先順位。デフォルトではtelescopeを優先的に使う -- backend = { "nui", "telescope" }, -- telescopeで表示する場合の設定。ウィンドウ小さめでもいい感じに出す telescope = { sorting_strategy = "ascending", layout_strategy = "vertical", layout_config = { width = 0.8, height = 0.9, prompt_position = "top", preview_cutoff = 20, preview_height = function(_, _, max_lines) return max_lines - 15 end, }, }, -- nuiで表示する場合の設定。枠線をカラースキーマの色で出す nui = { preview = { win_options = { winhighlight = "Normal:Normal,FloatBorder:FloatBorder", }, }, select = { win_options = { winhighlight = "Normal:Normal,FloatBorder:FloatBorder", }, }, }, } end, } end)
あとはLSPのon_attach
やautocmdのLspAttach
(Neovim 0.8以降限定)などを使ってキーマップを設定し、
コードアクションが使用できる箇所(nvim-lightbulbで💡が表示される場所)でキーを押します。
vim.keymap.set({ "v", "n" }, "gf", require("actions-preview").code_actions)
どう動作するのか見てみましょう。
めっちゃ便利!!!!!(自画自賛)
差分のカスタマイズ
差分の表示にはvim.diff()
という今回の用途におあつらえ向きのAPIを使用しています(本体のLua部分で使われていないのでなぜあるのか謎)。
このAPIはgitと同じ差分生成ライブラリが使われており、カスタマイズが色々と可能なのでオプションを説明しておきます。
require("actions-preview").setup { diff = { -- 差分生成のアルゴリズム algorithm = "myers", -- デフォルト algorithm = "minimal", -- 時間が掛かるができるだけ小さい差分を生成する algorithm = "patience", -- 賢めなアルゴリズムのpatienceを使用する algorithm = "histogram", -- patienceとほぼ同じ結果だが速いらしい -- 差分がある部分の前後に表示する行数。git diff --unified=<n>相当 ctxlen = 3, -- 同一ファイルの差分塊間の行数がこれ以下なら全部表示する。git diff --inter-hunk-context=<lines>相当 interhunkctxlen = 0, -- あらゆるスペースの変更を無視する。trueならgit diff --ignore-all-space相当 ignore_whitespace = false, -- 行頭や連続するスペースの変更を無視する。trueならgit diff --ignore-space-change相当 ignore_whitespace_change = false, -- 行末スペースの変更を無視する。trueならgit diff --ignore-space-at-eol相当 ignore_whitespace_change_at_eol = false, -- 改行前のCR(\r)を無視する。trueならgit diff --ignore-cr-at-eol相当 ignore_cr_at_eol = false, -- 連続した空行の変更を無視する。trueならgit diff --ignore-blank-lines相当 ignore_blank_lines = false, -- 差分のズレを抑制する。trueならgit diff --indent-heuristic相当。actions-preview.nvimではデフォルト無効 indent_heuristic = false, }, -- ... telescopeやnuiの設定 }
元ネタ
nvim-code-action-menuというプラグインがあってほぼ同じ事をしてくれるんですが、 見た目がダサいのと差分がちゃんと出ないパターンがあったので自作することにしました。