How to unpack functions' arguments?

map is a wrapper around vim.keymap.set:

local map = function(mode, lhs, rhs, opt)
  local options = { noremap = true, silent = true }
  if opt then
    options = vim.tbl_extend("force", options, opt)
  end

  vim.keymap.set(mode, lhs, rhs, opt)
end

I want to create a function that adds the buffer option to map. This is what i came up with:

local buf_map = function(...)
  map(..., { buffer = bufnr })
end

And i use it like this:

buf_map("n", "<leader>e", function()
  vim.diagnostic.open_float()
end)

But it fails with this error

Error executing vim.schedule lua callback: vim/keymap.lua:0: lhs: expected
 string, got table

I tried unpacking the arg but I get a different error. What is the right way to do that in neovim?

lua has select command that you can use

local function foo(bar, ...)
  -- Either
  local args = {...}
  local baz = args[1]
 -- or directly
   local baz = select(1, ...) -- Selects the first arg - remember lua indexes from 1 not 0
end
1 Like

TLDR: ... will expand completely only if put as the last argument of a function.

This problem here is that doing map(..., {}) will actually only put the first argument of ... as the argument of map (as indicated by the error, saying that {}is actually passed as the second argument here).

My advice would be to just list the arguments exhaustively and pass them down manually. I don’t think that this case is a good use of ....

1 Like

Thank you guys, I ended up with this:

local buf_map = function(...)
  local key, lhs, rhs = ...
  map(key, lhs, rhs, { buffer = bufnr })
end

Or you could just simplify it as:

local map = function(mode, lhs, rhs, opt)
  local options = { silent = true }
  options = vim.tbl_extend("force", options, opt or {})

  vim.keymap.set(mode, lhs, rhs, options)
end

local buf_map = function(mode, lhs, rhs, opt)
  map(mode, lhs, rhs, { buffer = bufnr })
end

P.S: There’s no need to set noremap = true for vim.keymap.set as it’s the default behaviour i.e remap = false.

1 Like