VimからNeovimへの移行とプラグインの棚卸し
2019年ごろにVim/Neovimで開発できる環境を整えてから3年経過しました。
Neovim関連のプラグインが充実しているようで、最近はGitHub copilot XのようなGPT4ベースのツールもNeovimに対応しています。AstroNvimとか、もはやVSCodeと見間違いそうなカッコいい設定ツールも出てきました。
VimとNeovim両方で動くように.vimrcを設定していましたが、そろそろNeovimへ寄せようと思い、プラグインなどの棚卸しを行いました。
プラグインマネージャーの変更
packer.nvimへ移行しました。
READMEを参考に設定後、nvimで下記コマンドを実行することで、設定ファイルに記載したプラグインがインストールされます。
1:PackerUpdate
LSP設定用のプラグイン
nvim-lspconfigに移行しました。goplsなどのLanguage Server Protocolを設定することで、コーディング時にVSCodeのような静的解析が可能になります。
vim-lspはLSPの設定を自動化してくれるので、使い勝手はnvim-lspconfigより良かったかもしれません。nvim-lspconfigを採用した理由は、Neovimネイティブの機能であるNvim LSP client用のコンフィグだからです。
関数や変数の定義ジャンプなどの設定はREADMEに書かれていた内容をほぼそのまま利用しました。定義元へジャンプしたいときはgd
、参照先へ飛びたいときはgr
でジャンプできます。omnifuncによる補完はデフォルトのキーバインド<C-x><C-o>
だと使いにくかったので、<C-n>
で補完されるようにしました(「補完用のプラグイン」の項を参照)。
1require'lspconfig'.gopls.setup{}
2require'lspconfig'.golangci_lint_ls.setup{}
3
4-- Global mappings.
5-- See `:help vim.diagnostic.*` for documentation on any of the below functions
6vim.keymap.set('n', '<space>e', vim.diagnostic.open_float)
7vim.keymap.set('n', '[d', vim.diagnostic.goto_prev)
8vim.keymap.set('n', ']d', vim.diagnostic.goto_next)
9vim.keymap.set('n', '<space>q', vim.diagnostic.setloclist)
10
11-- Use LspAttach autocommand to only map the following keys
12-- after the language server attaches to the current buffer
13vim.api.nvim_create_autocmd('LspAttach', {
14 group = vim.api.nvim_create_augroup('UserLspConfig', {}),
15 callback = function(ev)
16 -- Enable completion triggered by <c-x><c-o>
17 vim.bo[ev.buf].omnifunc = 'v:lua.vim.lsp.omnifunc'
18
19 -- Buffer local mappings.
20 -- See `:help vim.lsp.*` for documentation on any of the below functions
21 local opts = { buffer = ev.buf }
22 vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, opts)
23 vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts)
24 vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts)
25 vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, opts)
26 vim.keymap.set('n', '<C-k>', vim.lsp.buf.signature_help, opts)
27 vim.keymap.set('n', '<space>wa', vim.lsp.buf.add_workspace_folder, opts)
28 vim.keymap.set('n', '<space>wr', vim.lsp.buf.remove_workspace_folder, opts)
29 vim.keymap.set('n', '<space>wl', function()
30 print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
31 end, opts)
32 vim.keymap.set('n', '<space>D', vim.lsp.buf.type_definition, opts)
33 vim.keymap.set('n', '<space>rn', vim.lsp.buf.rename, opts)
34 vim.keymap.set('n', '<space>ca', vim.lsp.buf.code_action, opts)
35 vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts)
36 vim.keymap.set('n', '<space>f', function()
37 vim.lsp.buf.format { async = true }
38 end, opts)
39 end,
40})
フォーマッターとリンター用のプラグイン
aleからnull-ls.nvimに移行しました。非常に動作が軽くなった気がします。
nvim-lspconfigでもLSPに対応しているリンターを設定できるみたいですが、LSPに対応していないリンターやフォーマッター用に使います。
1local null_ls = require("null-ls")
2
3-- ------------------------------
4-- Autoformat settings.
5-- https://github.com/jose-elias-alvarez/null-ls.nvim/wiki/Formatting-on-save
6-- https://github.com/jose-elias-alvarez/null-ls.nvim/wiki/Avoiding-LSP-formatting-conflicts
7-- ------------------------------
8local augroup = vim.api.nvim_create_augroup("LspFormatting", {})
9local lsp_formatting = function(bufnr)
10 vim.lsp.buf.format({
11 filter = function(client)
12 return client.name == "null-ls"
13 end,
14 bufnr = bufnr,
15 })
16end
17
18-- ------------------------------
19-- null_ls setup.
20-- ------------------------------
21null_ls.setup({
22 sources = {
23 null_ls.builtins.formatting.shfmt,
24 null_ls.builtins.formatting.stylua,
25 null_ls.builtins.diagnostics.eslint,
26 -- null_ls.builtins.completion.spell,
27 -- null_ls.builtins.diagnostics.golangci_lint,
28 null_ls.builtins.formatting.goimports,
29 null_ls.builtins.diagnostics.markdownlint_cli2,
30 null_ls.builtins.formatting.markdownlint,
31 },
32 on_attach = function(client, bufnr)
33 if client.supports_method("textDocument/formatting") then
34 vim.api.nvim_clear_autocmds({ group = augroup, buffer = bufnr })
35 vim.api.nvim_create_autocmd("BufWritePre", {
36 group = augroup,
37 buffer = bufnr,
38 callback = function()
39 lsp_formatting(bufnr)
40 end,
41 })
42 end
43 end,
44})
補完用のプラグイン
変数や関数、メソッドの入力時に自動で補完するためのプラグインnvim-cmpに移行しました。以前はasyncomplete.vimを利用していました(vim-lspを開発したエンジニアが公開しているプラグインです)。
nvim-cmpの利用に際し下記の依存ツールが必要だったので、合わせて導入しました。
- vim-vsnip: スニペット用プラグイン
- cmp-nvim-lsp: nvim-cmpでLSPを利用できるようにするためのプラグイン
以下、luaの設定内容。
omnifunkを<C-n>
と<C-p>
で実行できるようにしました。それ以外はREADMEに記載されている内容と同じです。
1local cmp = require'cmp'
2
3cmp.setup({
4 snippet = {
5 -- REQUIRED - you must specify a snippet engine
6 expand = function(args)
7 vim.fn["vsnip#anonymous"](args.body) -- For `vsnip` users.
8 end,
9 },
10 window = {
11 -- completion = cmp.config.window.bordered(),
12 -- documentation = cmp.config.window.bordered(),
13 },
14 mapping = cmp.mapping.preset.insert({
15 ["<C-p>"] = cmp.mapping.select_prev_item(),
16 ["<C-n>"] = cmp.mapping.select_next_item(),
17 ['<CR>'] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
18 }),
19 sources = cmp.config.sources({
20 { name = 'nvim_lsp' },
21 }, {
22 { name = 'buffer' },
23 })
24})
その他
下記のプラグインは引き続き利用することにしました。
- lambdalisue/fern.vim: ファイルマネージャー
- Morhetz/gruvbox: カラースキーマ
- nathanaelkane/vim-indent-guides: インデントを見やすくする
- airblade/vim-gitgutter:
git diff
がわかるようにする - vim-airline/vim-airline: 見た目を整える
- vim-airline/vim-airline-themes: 見た目を整える
- sebdah/vim-delve: Goのデバッガ支援
まとめ
nvim-dapなど気になるプラグインはまだあるのですが、取り急ぎ業務でも問題なく使える状態にアップデートしました。
今はGoのコーディングとMarkdownに特化した設定ですが、少しずつ他の言語の開発も行えるように整えていきたいです。