Neovim Lua API の vim.cmd、皆さん使ってらっしゃいますよね?
vim.cmd('echo 42')
のように文字列を引数に渡せば Vim script のコマンドとして実行できる関数です
また、vim.cmd.echo('42')
のようにコマンド名をキーとすることでそのコマンドを実行する関数を取得することもできます
この機能ですが、前者と後者で厳密に挙動がおなじになるわけではありません。
local command_str = 'belowright vnew'
vim.cmd(command_str) -- 正常に実行される
local i = command_str:find(' ')
vim.cmd[command_str:sub(1, i - 1)](command_str:sub(i + 1)) -- エラー
まあ vim.cmd('foo')
形式であれば恐らく任意の形式のコマンドが実行できるのでそちらを使えば良いのですが、個人的に vim.cmd.foo()
形式の方が好みなので色々調べました
vim.cmd.foo()
形式での belowright vnew
の実現方法
結論から言うと、vim.cmd.vnew({ mods = { split = 'belowright' } })
で実現できます。
「mods
とか split
とかどこから出てきたんだよ」って感じですが、不明なことがあればヘルプを見るのが良いと理性では理解しているので非常に重い腰を上げて読んでみます
cmd({command}) *vim.cmd()*
(略)
Parameters:
• {command} string|table Command(s) to execute. If a string, executes
multiple lines of Vim script at once. In this case, it is
an alias to |nvim_exec2()|, where `opts.output` is set to
false. Thus it works identical to |:source|. If a table,
executes a single command. In this case, it is an alias to
|nvim_cmd()| where `opts` is empty.
これを読んだところ、引数が文字列であれば :source
と同様の挙動、そうでなければ nvim_cmd()
が呼ばれるとあります。:source
と同様の挙動であれば belowright vnew
も実行できそうなので次は nvim_cmd()
について調べます
nvim_cmd({*cmd}, {*opts}) *nvim_cmd()*
(略)
• {cmd} Command to execute. Must be a Dictionary that can contain the
same values as the return value of |nvim_parse_cmd()| except
"addr", "nargs" and "nextcmd" which are ignored if provided.
All values except for "cmd" are optional.
nvim_parse_cmd()
の返り値の形式を引数に取れるようなのでそちらも読みに行きます
nvim_parse_cmd({str}, {opts}) *nvim_parse_cmd()*
(略)
Parse command line.
Doesn't check the validity of command arguments.
Attributes:
|api-fast|
Parameters:
• {str} Command line string to parse. Cannot contain "\n".
これにコマンドを渡すと nvim_cmd()
に渡せる形式のオブジェクトが得られそうなので、belowright vnew
を渡してみます
local obj = vim.api.nvim_parse_cmd('belowright vnew', {})
vim.notify(vim.inspect(obj))
--[[
{
addr = "?",
args = {},
bang = false,
cmd = "vnew",
mods = {
(略)
split = "belowright",
(略)
]]
良さそうなオブジェクトが得られました。読み飛ばしましたが、多分 vim.cmd.foo()
とすると vim.cmd({ cmd = 'foo' })
が渡ると思うので mods.split
だけ引数に渡してみようと思います
vim.cmd.vnew({ mods = { split = 'belowright' } })
問題なく実行できました。これで任意のコマンドを vim.cmd.foo()
形式で実行できるようになりました。めでたい!
早速ほかのコマンドも試してみましょう。新しいタブでターミナルを開く tabe +terminal
を実行できるようにしたかったんですよね
local obj = vim.api.nvim_parse_cmd('tabe +terminal', {})
vim.notify(vim.inspect(obj))
--[[
{
args = { "+terminal" },
cmd = "tabedit",
(略)
]]
vim.cmd.tabedit({ args = { "+terminal" } })
+terminal
というタイトルの空のタブが開きました・・・
しばらく試行錯誤と調査をしたところ、下記の Issue を見つけました
現時点では ++opt
と +cmd
はサポートされていないようです。無念1
-
コントリビュートチャンスかもしれない ↩