🐶

[Neovim] filetype毎の設定をluaの関数単位で分ける

2022/07/04に公開

はじめに

以前このような記事 を書きました。
filetype毎の設定をVim scriptを使って関数単位に分けたのですが、
最近Neovimを使い始めたので、luaでも同じような設定を書いてみました。

luaで作る

例として 以下を作ってみます

  • filetype=help の場合 q でwindowを閉じれるように設定
  • filetype=javaの場合
    • indentの幅4
    • タブではなくスペースでインデント
-- $XDG_CONFIG_HOME/nvim/init.lua
local my_filetype = require('my.filetype')

vim.api.nvim_create_augroup('vimrc_augroup', {})
vim.api.nvim_create_autocmd('FileType', {
  group = 'vimrc_augroup',
  pattern = '*',
  callback = function(args) my_filetype[args.match]() end
})

init.luaでは $XDG_CONFIG_HOME/nvim/lua/my/filetype.lua を読み込みます。
読み込んだモジュールの各要素にはfiletype毎の関数が設定されているので、FileTypeイベントをトリガーにモジュール内の関数を呼び出します( my_filetype[args.match]() の部分です。 args.match には"help"や"java"等のfiletype毎の文字列が入ってきます)

次にfiletype.luaを作成します。

-- $XDG_CONFIG_HOME/nvim/lua/my/filetype.lua
local M = {}

local function set_indent(tab_length, is_hard_tab)
  if is_hard_tab then
    vim.bo.expandtab = false
  else
    vim.bo.expandtab = true
  end

  vim.bo.shiftwidth  = tab_length
  vim.bo.softtabstop = tab_length
  vim.bo.tabstop     = tab_length
end

M.help = function()
  vim.api.nvim_buf_set_keymap(0, 'n', 'q', 'ZZ', { noremap = true })
end

M.java = function()
  set_indent(4, false)
end

return setmetatable(M, {
  __index = function()
    return function()
      print('Unexpected filetype!')
      set_indent(2, false)
    end
  end
})

Mというtableにfiletype毎の関数を詰めて返しています。
(M.helpには filetype=help 用の関数を詰めています)

luaのmetatableを使ってみたかったので、想定していないfiletypeのbufferを開いた場合何かしらの関数が呼び出せるよう作りこんでいます。setmetatableで __index キーに関数を設定するだけで完了でした。簡単...!

終わりに

metatableには __index というキー以外にも __add__call というキーも存在します。面白い。。触れる機会は当分先だと思いますが、luaでジェネレータも作れるようで、色々作ってみたいですね。

sumneko/lua-language-serverを使えば書き心地も問題なく、annotationを指定すれば型チェックも行ってくれます

元々luaはおろかNeovimも触れていなかったので、init.luaへの移植やbuiltin LSPの使い方についても慣れていない部分が多いですが、今のところは楽しく書けているので引き続きNeovim & luaで何かしらを書いていきたいと思います。

Discussion