2年間ほとんどメンテしていなかったinit.luaを整理した話
はじめに
振り返ると、vimrcからinit.luaに乗り換えてluaを使うようになってから約2年ほど経ちました。
しかし、それ以降はinit.luaをまともにメンテしておらず、ずっと一枚岩のままでした。
一枚岩の設定ファイルは検索するのは便利ではありますが、見通しが悪いなとは前から感じていたので、重い腰を上げてファイル分割することにしました。
本記事はどんな感じの構成になったのかについて、ざっくり書いていこうと思います。
メンテの結果
メンテ前はinit.lua一枚でしたが、メンテ後はinit.luaが7行になりました。
require('my/settings/disable')
require('my/settings/options')
require('my/settings/lsp')
require('my/settings/autocmd')
require('my/settings/keymaps')
require('my/command')
require('my/plugins/lazy')
また、ディレクトリ構成に次のようになりました。
ディレクトリ構成
├── init.lua
└── lua
   └── my
       ├── command.lua
       ├── plugins
       │   ├── colorscheme
       │   │   └── nightfox.lua
       │   ├── completion
       │   │   ├── copilot.lua
       │   │   ├── emmet.lua
       │   │   ├── nvim-autopairs.lua
       │   │   ├── nvim-cmp.lua
       │   │   └── sonictemplate.lua
       │   ├── develop
       │   │   ├── capture.lua
       │   │   ├── graphql.lua
       │   │   ├── prettyprint.lua
       │   │   ├── quickrun.lua
       │   │   ├── ssr.lua
       │   │   ├── vital-whisky.lua
       │   │   └── vital.lua
       │   ├── docs
       │   │   ├── gyazo.lua
       │   │   ├── helpful.lua
       │   │   ├── helpgenerator.lua
       │   │   ├── list2tree.lua
       │   │   ├── maketable.lua
       │   │   ├── markdown.lua
       │   │   ├── memolist.lua
       │   │   ├── previm.lua
       │   │   ├── silicon.lua
       │   │   ├── tabular.lua
       │   │   ├── translate.lua
       │   │   └── vimdoc-ja.lua
       │   ├── etc
       │   │   ├── denops.lua
       │   │   ├── kensaku.lua
       │   │   └── skkeleton.lua
       │   ├── filer
       │   │   ├── fern-renderer-nerdfont.lua
       │   │   └── fern.lua
       │   ├── fuzzyfinder
       │   │   ├── telescope-egrepify.lua
       │   │   └── telescope.lua
       │   ├── git
       │   │   ├── gina.lua
       │   │   └── gitsigns.lua
       │   ├── infra
       │   │   ├── docker.lua
       │   │   └── k8s.lua
       │   ├── lang
       │   │   ├── go
       │   │   │   └── goimports.lua
       │   │   └── rust
       │   │       └── crates.lua
       │   ├── lazy.lua
       │   ├── list.lua
       │   ├── lsp
       │   │   ├── fidget.lua
       │   │   ├── lang
       │   │   ├── lsp_lines.lua
       │   │   ├── lsp_signature.lua
       │   │   ├── mason.lua
       │   │   └── null-ls.lua
       │   ├── quickfix
       │   │   ├── bqf.lua
       │   │   └── qfreplace.lua
       │   ├── statusline
       │   │   ├── bufferline.lua
       │   │   └── lualine.lua
       │   ├── test
       │   │   ├── test.lua
       │   │   └── themis.lua
       │   ├── ui
       │   │   ├── hlchunk.lua
       │   │   └── treesitter.lua
       │   ├── utils
       │   │   ├── dial.lua
       │   │   ├── guise.lua
       │   │   ├── octo.lua
       │   │   └── open-browser.lua
       │   └── window
       │       ├── winresizer.lua
       │       ├── winselector.lua
       │       └── zoom.lua
       ├── settings
       │   ├── autocmd.lua
       │   ├── disable.lua
       │   ├── keymaps.lua
       │   ├── lsp.lua
       │   └── options.lua
       └── utils.lua
ディレクトリ構成について
myディレクトリ配下に各種プラグインとその設定や、それ以外の設定などをまとめています。
myというディレクトリを切っているのは、なるべく他のプラグインと名前空間をかぶらないようにするためです。
myプレフィックスがない場合、たとえばcmp.luaという設定ファイルがあるとcmpプラグインと名前空間が被ってしまいrequire('cmp')はパスで見つけたファイルを優先してimportしてしまうからです。
プラグインマネージャーはlazy.nvimを使っていて、plugins配下には各種プラグインとその設定の定義をおいています。
プラグインは、おおまかなカテゴリごとにさらにディレクトリを切っています。
local plugins = utils.array_map(
  require('my/plugins/list'),
  function(plugin)
    return require('my/plugins/' .. plugin)
  end
)
require("lazy").setup(plugins)
list.luaで実際に使うプラグイン一覧を管理しています。
local plugins = {
  -- etc
  'etc/kensaku',
  'etc/skkeleton',
  'etc/denops',
  -- ui
  'ui/treesitter',
  'ui/hlchunk',
  -- omitted
}
もし一時的に無効にしたいプラグインがある場合は配列の要素をコメントアウトすれば済むし、
プラグイン追加時はplugins/foo/bar.luaを追加したあとに配列に追加するだけなので、もろもろ管理が楽です。
各種プラグインの定義は次のようになっています。
lazy.nvimに渡すオブジェクトの形になっています。
local utils = require('my/utils')
local nmap = utils.keymaps.nmap
local config = function()
  vim.g['fern#renderer'] = 'nerdfont'
  vim.g['fern#window_selector_use_popup'] = true
  vim.g['fern#default_hidden'] = 1
  vim.g['fern#default_exclude'] = '\\.git$\\|\\.DS_Store'
  vim.api.nvim_create_autocmd('FileType', {
    pattern = 'fern',
    callback = function()
      nmap('q', ':q<CR>', { silent = true, buffer = true })
      nmap('<C-x>', '<Plug>(fern-action-open:split)', { silent = true, buffer = true })
      nmap('<C-v>', '<Plug>(fern-action-open:vsplit)', { silent = true, buffer = true })
      nmap('<C-t>', '<Plug>(fern-action-tcd)', { silent = true, buffer = true })
    end,
    group = vim.api.nvim_create_augroup('fernInit', { clear = true }),
  })
end
local fern = {
  'lambdalisue/fern-hijack.vim',
  dependencies = {
    'lambdalisue/fern.vim',
    cmd = 'Fern',
    config = config,
  },
  init = function()
    nmap('<Leader>f', '<Cmd>Fern . -drawer<CR>', { silent = true })
  end
}
return fern
ただ、このように動的にrequireするファイルパスを組み上げているため、定義ジャンプが効かないのが少し不便だなと思っています。
なにかよい改善方法があれば知りたいところです。
さいごに
vimrcからinit.lua乗り換え時は一日かかっていたんですが、整理は意外とそれほど時間がかからずあっさり終わりました。
しばらくこの構成を試しつつ改善していきたいと思います。
Discussion