LoginSignup
3
1

Neovim vim.cmd 使用法

Last updated at Posted at 2023-12-13

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" } })

tab-titled-plus-terminal.png

+terminal というタイトルの空のタブが開きました・・・
しばらく試行錯誤と調査をしたところ、下記の Issue を見つけました

現時点では ++opt+cmd はサポートされていないようです。無念1

  1. コントリビュートチャンスかもしれない

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1