🌙
Neovim の Lua で Vim script 製プラグインの設定をする
はじめに
lua から vim の関数を実行する方法として、vim.fn
を使う方法があります。
例えば ddu.vim の設定を vim script で次のように行っているとします。
call ddu#custom#patch_global({
\ 'uiParams': {
\ 'ff': {
\ 'startFilter': v:true,
\ },
\ },
\ })
autocmd FileType ddu-ff call s:ddu_my_settings()
function! s:ddu_my_settings() abort
nnoremap <buffer><silent> <CR>
\ <Cmd>call ddu#ui#ff#do_action('itemAction')<CR>
endfunction
これを lua に書き換えたかった場合、次のようにすることができます。
vim.fn["ddu#custom#patch_global"] {
uiParams = {
ff = {
startFilter = true,
},
},
}
local function ddu_my_settings()
local map = vim.keymap.set
map("n", "<CR>", function()
vim.fn["ddu#ui#ff#do_action"] "itemAction"
end, { buffer = true })
end
vim.api.nvim_create_autocmd("FileType", {
pattern = "ddu-ff",
callback = ddu_my_settings,
})
問題点
ただの慣れの問題だとは思いますが、少し読みづらくないですか?
\
が無いのは良いものの、ぱっと見では ddu#custom#patch_global
や ddu#ui#ff#do_action
が関数なのかが分かりづらいですし、 "
や #
を打つのも面倒です。
また、vim.keymap.set
の引数にあるコールバック関数が Lua の関数で書くとかなり冗長になってしまっていて、短くするために vim script と同じように書くこともできるものの、 やはり出来れば Lua っぽく書きたいです。
解決策
と言う訳で、以下の関数を作ってみました。
local function call(module_name)
local metatable = { func = module_name, children = {} }
function metatable:__index(key)
local meta = getmetatable(self)
local child = call(meta.func .. '#' .. key)
meta.children[key] = child
setmetatable(self, meta)
return child
end
function metatable:__call(...)
local func_name = getmetatable(self).func ---@type string
if func_name:match '.+#_fn$' then
local args = { ... }
return function()
return vim.fn[func_name:gsub('#_fn$', '', 1)](unpack(args))
end
else
return vim.fn[func_name](...)
end
end
return setmetatable({}, metatable)
end
これを使うことで、上記の例を以下のように書き換えることができます。
local ddu = call "ddu"
ddu.custom.patch_global {
uiParams = {
ff = {
startFilter = true,
},
},
}
local function ddu_my_settings()
local map = vim.keymap.set
map("n", "<CR>", ddu.ui.ff.do_action._fn "itemAction", { buffer = true })
end
vim.api.nvim_create_autocmd("FileType", {
pattern = "ddu-ff",
callback = ddu_my_settings,
})
かなり読みやすくなったと思いませんか?
途中で _fn
というものが出てきますが、これは関数でラッピングしたものを返します。
local ddu = call "ddu"
-- vim.fn["ddu#ui#ff#do_action"] "itemAction"
ddu.ui.ff.do_action "itemAction"
-- function() vim.fn["ddu#ui#ff#do_action"] "itemAction" end
ddu.ui.ff.do_action._fn "itemAction"
その代わりに ddu#ui#ff#do_action#_fn()
は呼べなくなりますが、自分しか使わないので放置します。
おわりに
この記事を書いている途中で、vim-artemis という上位互換を見つけました。
変数の定義にも対応していて、本来の文法を拡張したような感じで書くことができるので、多分こちらを使った方がいいです()
Discussion