How do I define a custom user command in Neovim Lua config that accepts arguments and has a description?
Answer
vim.api.nvim_create_user_command()
Explanation
Neovim's Lua API provides vim.api.nvim_create_user_command() for defining custom Ex commands that call Lua functions. Unlike the Vimscript :command approach, the Lua API lets you pass a table of options including a desc field (shown by which-key and :help) and define argument completion natively. This is the modern way to register project-specific or plugin commands in an init.lua config.
How it works
vim.api.nvim_create_user_command(
'OpenInSplit', -- command name (must start with uppercase)
function(opts) -- callback receives opts table
vim.cmd('vsplit ' .. opts.args)
end,
{
nargs = '?', -- 0 or 1 argument
complete = 'file', -- tab-complete as filenames
desc = 'Open a file in a vertical split',
}
)
Key fields in the options table:
nargs— number of arguments:'0','1','*'(any),'?'(0 or 1),'+'(1 or more)complete— completion type:'file','buffer','command', or a custom Lua functiondesc— human-readable description shown in which-key and:command MyCmdbang— set totrueto allow a!suffix (opts.bangwill betrueif used)range— set totrueor'%'to accept a line range
Example
Create a command that toggles colorcolumn:
vim.api.nvim_create_user_command('ToggleColorColumn', function()
if vim.o.colorcolumn == '' then
vim.o.colorcolumn = '80'
else
vim.o.colorcolumn = ''
end
end, { desc = 'Toggle 80-column guide' })
Then use :ToggleColorColumn in Neovim.
Tips
- For buffer-local commands (e.g., in an
ftplugin), usevim.api.nvim_buf_create_user_command(0, 'Name', fn, opts)— the0means current buffer - The
opts.argsfield contains the argument string; usevim.split(opts.args, ' ')to get a list of words - Always add
desc— it powers:Telescope commands, which-key popups, and:commandoutput