Open28

Neovim設定記録

tekkoctekkoc

正月だし Neovim の設定を Lua で書き直そうと思ったので、せっかくなので zenn のスクラップも試してみることに。

tekkoctekkoc

dotfiles に nvim ディレクトリを作って ~/.config/nvim にシンボリックリンクを作った。
nvim/init.lua を作りつつ、今までのvimrcは削除。

tekkoctekkoc

まずはキーマップを移植した。
vim.keymap.set を使うといいらしい。

vim.g.mapleader = ","

-- ; : の入れ替え
vim.keymap.set('n', ';', ':')
vim.keymap.set('n', ':', ';')

-- <C-l> を ESC に
vim.keymap.set({'v', 'i', 'c'}, '<C-l>', '<ESC>')
vim.keymap.set('n', '<C-l>', ':nohlsearch<CR>')

-- 移動
vim.keymap.set({'n', 'v'}, 'J', '10j')
vim.keymap.set({'n', 'v'}, 'K', '10k')
vim.keymap.set({'n', 'v'}, 'H', '10h')
vim.keymap.set({'n', 'v'}, 'L', '10l')

-- 保存
vim.keymap.set('n', '<SPACE>w', ':write<CR>')

-- Qキーをマクロに
vim.keymap.set('n', 'q', '<NOP>')
vim.keymap.set('n', 'Q', 'q')

-- s を 画面移動系のprefixに
vim.keymap.set('n', 's', '<NOP>')

vim.keymap.set('n', 'sq', ':quit<CR>')

-- 分割
vim.keymap.set('n', 'ss', ':sp<CR>')
vim.keymap.set('n', 'sv', ':vs<CR>')

-- 分割移動
vim.keymap.set('n', 'sj', '<C-w>j')
vim.keymap.set('n', 'sk', '<C-w>k')
vim.keymap.set('n', 'sh', '<C-w>h')
vim.keymap.set('n', 'sl', '<C-w>l')
vim.keymap.set('n', 'sJ', '<C-w>J')
vim.keymap.set('n', 'sK', '<C-w>K')
vim.keymap.set('n', 'sH', '<C-w>H')
vim.keymap.set('n', 'sL', '<C-w>L')

-- タブページ
vim.keymap.set('n', 'st', ':tabnew<CR>')
vim.keymap.set('n', 'sn', 'gt')
vim.keymap.set('n', 'sp', 'gT')
vim.keymap.set('n', 'sN', ':tabmove +1<CR>')
vim.keymap.set('n', 'sP', ':tabmove -1<CR>')

-- 編集支援系
vim.keymap.set('n', '<CR>', 'o<ESC>')
vim.keymap.set('n', '<SPACE>d', 'cc<ESC>')
  • Leader は ,
    • 主にプラグイン関連のマッピングのプレフィックスにしてる
  • 英字キーボードなので : ; を入れ替えてる
  • <C-l> を Esc の代わりに使う
  • JKHL で多めに移動できるように。
    • shift押して強化するイメージで、結局高速移動系のプラグインを入れてもこれあるから使わなくなりがち
  • 分割・タブ系を s を prefix にしたしたマッピングに

もっと色々設定してた気もするけど、プラグイン系を除くとこれくらいだった。

tekkoctekkoc

コマンドを読んでいる系のマッピングに {silent = true} を足した。

tekkoctekkoc

オプション系

-- カーソルを真ん中に
vim.o.scrolloff = 999

-- 行番号表示
vim.o.number = true
vim.o.relativenumber = true

-- 現在行・列を強調
vim.o.cursorline = true
vim.o.cursorcolumn = true

-- 各種ファイルを生成しない
vim.o.autoread = true
vim.o.backup = false
vim.o.writebackup = false
vim.o.swapfile = false
vim.o.undofile = false

-- 改行文字表示
vim.o.list = true
vim.o.listchars = 'tab:¦ ,eol:↴,trail:-,nbsp:%,extends:>,precedes:<'

-- 検索
vim.o.ignorecase = true
vim.o.smartcase = true
vim.o.wrapscan = true
vim.o.incsearch = true

-- 新しいウィンドウを下に開く
vim.o.splitbelow = true

-- クリップボード
vim.o.clipboard='unnamedplus'

-- タブ関連
vim.o.expandtab = true
vim.o.tabstop = 2
vim.o.shiftwidth = 2
vim.o.softtabstop = 2
vim.o.autoindent = true
vim.o.smartindent = true

relativenumber を on にしたり、cursorline だけじゃなく cursorcolumn も有効にしてるのはちょっと変わってるかもしれない。

tekkoctekkoc

プラグイン管理は packer.nvim を採用した

https://github.com/wbthomason/packer.nvim

推奨通り plugin 関連の設定は nvim/lua/plugins.lua にまとめるようにして plugin.lua の更新時に :PackerCompile を実行するような設定を追加した。
単なるコピペになるので割愛。

tekkoctekkoc

比較的単機能なプラグインの内、今も使っているなというものをとりあえず引き続き使うことに。

use 'mattn/vim-findroot'
use 'jiangmiao/auto-pairs'
use 'mhinz/vim-signify'
use 'cohama/vim-insert-linenr'

use {
  'tpope/vim-commentary',
  setup = function()
    vim.keymap.set('n', 'CC', 'gcl', {remap = true})
    vim.keymap.set('', 'C', 'gc', {remap = true})
  end,
}

-- textobj系
use 'kana/vim-textobj-user'
use 'kana/vim-textobj-entire'
use 'kana/vim-textobj-indent'
use 'kana/vim-textobj-line'

-- operator系
use 'kana/vim-operator-user'
use {
  'kana/vim-operator-replace',
  setup = function()
    vim.keymap.set('v', 'p', '<Plug>(operator-replace)')
    vim.keymap.set('', 'R', '<Plug>(operator-replace)')
  end,
}
use {
  'tyru/operator-camelize.vim',
  setup = function()
    vim.keymap.set('', '<leader>c', '<Plug>(operator-camelize)')
    vim.keymap.set('', '<leader>C', '<Plug>(operator-decamelize)')
  end,
}

プラグインに関する設定も一緒に書くように。

tekkoctekkoc

この時点までプラグインの設定以外はすべて init.lua に書いていたがファイルを分けることに。
そのために、とりあえず fuzzy-finder 系のプラグインを入れてファイルを分けてもサクッと開けるように。

telescope を採用してみた。

https://github.com/nvim-telescope/telescope.nvim

設定は次の通り。

  use {
    'nvim-telescope/telescope.nvim', tag = '0.1.0',
    requires = { {'nvim-lua/plenary.nvim'} },
    config = function()
      local builtin = require('telescope.builtin')
      vim.keymap.set('n', '<leader>uf', builtin.find_files)
      vim.keymap.set('n', '<leader>ub', builtin.buffers)
      vim.keymap.set('n', '<leader>uh', builtin.help_tags)
      vim.keymap.set('n', '<leader>ug', builtin.live_grep)
      require('telescope').setup{
        defaults = {
          mappings = {
            i = {
              ["<C-l>"] = "close"
            }
          }
        }
      }
    end,
  }

<leader> をプラグイン系マッピングのプレフィックスにしている。
<leader>u にしているのは、最初にこれ系で使ったのが Unite.vim で、その名残で u キーを当てている。

<C-l> Esc の代わりにしているので telescope も同じように閉じれるように。

とりあえずで入れたが、動作も軽快で良さそう。

tekkoctekkoc

status line 変更系プラグインとして lualine.nvim` を入れた

https://github.com/nvim-lualine/lualine.nvim

ほとんどデフォルトの設定だけど、アイコンは使わない設定にした。

  use {
    'nvim-lualine/lualine.nvim',
    config = function()
      require('lualine').setup {
        options = {
          icons_enabled = false,
          theme = 'auto',
          component_separators = { left = '', right = ''},
          section_separators = { left = '', right = ''},
          always_divide_middle = true,
          globalstatus = false,
        },
        sections = {
          lualine_a = {},
          lualine_b = {'branch', 'diff', 'diagnostics'},
          lualine_c = {{'filename', path = 1}},
          lualine_x = {'filetype'},
          lualine_y = {},
          lualine_z = {'location'}
        },
        inactive_sections = {
          lualine_a = {'diff'},
          lualine_b = {{'filename', path = 1}},
          lualine_c = {},
          lualine_x = {},
          lualine_y = {},
          lualine_z = {'location'},
        },
      }
    end,
  }
tekkoctekkoc

……と、ここまでは振り返りつつ書いてみた。

何やったかメモるか→どうせメモるならあとでブログにしてみようか→zennのスクラップあったからそれでいいや

みたいな理由。
公開してもいいような作業工程を残すのに良いなと思ったので、飽きなければ続けます。

tekkoctekkoc

一時メモ用のコマンドを追加。
vim.api.nvim_create_user_command でユーザーコマンドを定義できた。

vim.api.nvim_create_user_command('Inbox', 'edit ~/.inbox.md', {})
vim.api.nvim_create_user_command('Temp', 'edit ~/.vim_tmp/tmp.<args>', {nargs = 1})

:Inbox でメモファイルを開く。一時的な作業領域的な扱い。
:Temp <拡張子> で言語別のメモファイル。

最近使ってなかったものの、設定作業とかしてると欲しくなるので再度設定した。
昔は Dropbox 管理化に置いて複数PC間で見れるようにしていたけど、今まともに vim を使っているPCが一台だしそもそも Dropbox をほとんど使っていないのでなしで。

tekkoctekkoc

ユーザーコマンドを定義した流れで vim-ambicmd を導入。

https://github.com/thinca/vim-ambicmd

  use {
    'thinca/vim-ambicmd',
    setup = function()
      vim.keymap.set('c', '<space>', [[ambicmd#expand("\<Space>")]], {expr = true})
      vim.keymap.set('c', '<CR>', [[ambicmd#expand("\<CR>")]], {expr = true})
    end,
  }

すっかり手に馴染んでてデフォルトの挙動だと思っていた。

tekkoctekkoc

require がキャッシュするので再読み込み時にキャッシュをクリアするようにした。

init.lua

setting_files = {
  'core',
  'keymap',
  'commands',
  'plugins',
}

for _, value in ipairs(setting_files) do
  require(value)
end

keymap.lua (一部)

vim.keymap.set('n', '<SPACE>.r', function()
  for _, value in ipairs(setting_files) do
    package.loaded[value] = nil
  end
  vim.cmd(':source ' .. init_path)
end)

マッピングを消したりしたときは素直に再起動で。

tekkoctekkoc

Packer の autocmd の設定を vim.api.nvim_create_autocmd を使うように書き換え。
ついでに PackerInstall, PackerClean を実行するようにした。

vim.api.nvim_create_augroup('packer_user_config', {})
vim.api.nvim_create_autocmd('BufWritePost', {
    group = 'packer_user_config',
    pattern = {"plugins.lua"},
    callback = function()
      vim.cmd('source ' .. vim.fn.expand("%"))
      vim.cmd('PackerCompile')
      vim.cmd('PackerInstall')
      vim.cmd('PackerClean')
    end,
  })
tekkoctekkoc

https://zenn.dev/botamotch/articles/21073d78bc68bf

↑をベースにしつつ最低限 LanguageServer を使って補完できるようにした。

  use {
    'neovim/nvim-lspconfig',
    config = function()
      vim.keymap.set('n', 'gk',  '<cmd>lua vim.lsp.buf.hover()<CR>')
      vim.keymap.set('n', 'gd', '<cmd>lua vim.lsp.buf.definition()<CR>')
      vim.keymap.set('n', 'gt', '<cmd>lua vim.lsp.buf.type_definition()<CR>')
    end,
  }
  use {
    'williamboman/mason.nvim',
    config = function()
      require('mason').setup()
    end,
  }
  use {
    'williamboman/mason-lspconfig.nvim',
    config = function()
      local lspconfig = require('lspconfig')
      require("mason-lspconfig").setup({
          ensure_installed = { "sumneko_lua" }
        })
      require('mason-lspconfig').setup_handlers({
          function(server)
            lspconfig[server].setup({})
          end,
          ["sumneko_lua"] = function ()
            lspconfig.sumneko_lua.setup {
              settings = {
                Lua = {
                  diagnostics = {
                    globals = { "vim" }
                  }
                }
              }
            }
          end,
        })
    end,
  }
  use {
    "hrsh7th/nvim-cmp",
    requires = {
      "hrsh7th/cmp-nvim-lsp",
      "hrsh7th/cmp-buffer",
      "hrsh7th/cmp-path",
    },
    config = function()
      local cmp = require("cmp")
      cmp.setup({
          sources = {
            { name = "nvim_lsp" },
            { name = "buffer" },
            { name = "path" },
          },
          mapping = cmp.mapping.preset.insert({
              ["<C-p>"] = cmp.mapping.select_prev_item(),
              ["<C-n>"] = cmp.mapping.select_next_item(),
              ['<C-c>'] = cmp.mapping.abort(),
              ["<CR>"] = cmp.mapping.confirm { select = true },
            }),
          experimental = {
            ghost_text = true,
          },
        })
    end,
  }

まだ導入するのは lua のみ。
マッピングも使うものだけ。

tekkoctekkoc

メモしたURLをブラウザで開けるようにするため open-browser を導入。

  use {
    'tyru/open-browser.vim',
    config = function()
      vim.keymap.set('n', '<leader>o', '<Plug>(openbrowser-open)')
    end,
  }
tekkoctekkoc

Luaのコードフォーマッタの Stylua を有効に。

まず cargo 経由でコマンドをインストールした。

次に null-ls を導入。

	use({
		"jose-elias-alvarez/null-ls.nvim",
		config = function()
			vim.api.nvim_create_augroup("lsp_format", {})
			vim.api.nvim_create_autocmd("BufWritePre", {
				group = "lsp_format",
				callback = function()
					vim.lsp.buf.format()
				end,
			})

			local null_ls = require("null-ls")
			null_ls.setup({
				sources = {
					null_ls.builtins.formatting.stylua,
				},
			})
		end,
	})

保存時にフォーマットを実行するようにした。

tekkoctekkoc

LSPの進捗を表示する fidget.nvim を入れた

https://github.com/j-hui/fidget.nvim

カッコよくて好き。
……というのもあるけど、LSPが有効になるまでどうしても時間がかかるので、進捗が表示されると嬉しい。

tekkoctekkoc

ファイラには telescope-file-browser.nvim を採用した。
telescopeはとりあえず入れただけだが結構気に入ってきたので、このままファイラも telescope に乗っかるものを採用することに。

	use({
		"nvim-telescope/telescope-file-browser.nvim",
		config = function()
			require("telescope").load_extension("file_browser")

			vim.keymap.set("n", "<leader>uF", ":Telescope file_browser<CR>", { noremap = true })
		end,
	})

,uf でファイルを開くようにしているので、その強化版ということで ,uF でファイラを開く感じに。
ファイラのときだけノーマルモードで起動したい気もする。

tekkoctekkoc

vim-quickrunを導入。

	use({
		"thinca/vim-quickrun",
		requires = { { "lambdalisue/vim-quickrun-neovim-job" } },
		setup = function()
			vim.g.quickrun_config = {
				["_"] = {
					["runner"] = "neovim_job",
					["outputter/buffer/opener"] = "new",
					["outputter/buffer/close_on_empty"] = 1,
				},
				["rust"] = {
					["exec"] = "cargo run",
				},
			}

			vim.keymap.set("n", "<leader>r", "<Nop>")
			vim.keymap.set("n", "<leader>rr", ":QuickRun<CR>", { silent = true })
		end,
	})

とりあえず rust の設定だけ

tekkoctekkoc

特定のプロジェクトだけ設定を変えたい、ということがあるので nvim-config-local を入れた。

https://github.com/klen/nvim-config-local

	use({
		"klen/nvim-config-local",
		config = function()
			require("config-local").setup({
				config_files = { "local.init.lua" },
			})
		end,
	})

quickrunの挙動を変えるのが目的。
設定済みの vim のグローバル変数の辞書の一部を変更しようとしてハマっていた。

https://github.com/neovim/neovim/issues/12544

tekkoctekkoc

quickrun の代わりに :teminal を使いたいと思い始めた。
プラグインの設定を外しつつ terminal mode から抜ける設定を追加。

vim.keymap.set("t", "<C-l>", "<C-\\><C-n>")
vim.keymap.set("t", "<ESC>", "<C-\\><C-n>")

分割しつつterminalを起動

vim.keymap.set("n", "sT", ":sp<CR>:terminal<CR>i", { silent = true })

コマンドの呼び出しはとりあえず

vim.keymap.set("n", "<leader>r", function()
	vim.cmd("split")
	vim.cmd("cd パス")
	vim.cmd("terminal コマンド")
end)

こんな感じで。あとでもうちょっと考えたい。