If you've read old tutorials about Neovim configuration you've find the way they create keymaps is a little bit different from what people do now. And if you check other people's configuration sometimes you'll find they create their keymaps using lazy.nvim. This is causing confusion among Neovim users.
Here I will explain why each method for creating keymaps exists and tell you when they are useful.
I will not explain in detail every option and possibility of each method. I just want to give you enough information to decide which one you should use in what situation.
nvim_set_keymap
This function was introduced in Neovim v0.5 and it's part of the Nvim API. This means nvim_set_keymap is accesible from lua, vimscript and also remote plugins.
For example, you could use nvim_set_keymap
in command mode. This is a valid.
:call nvim_set_keymap('n', '<F2>', ':echo "hello"<cr>', {'noremap': v:true})
If you wanted to do the same in lua it'll be like this
vim.api.nvim_set_keymap('n', '<F2>', ':echo "hello"<cr>', {noremap = true})
And what about remote plugins. What's that? Those are plugins that communicate with external processes. They can be written in any programming language that can send messages through RPC.
In a python remote plugin using pynvim, you could write something like this.
vim.api.set_keymap('n', '<F2>', ':echo "hello"<cr>', {'noremap': True})
Note: I have never used
pynvim
. I just assume this is a valid method based on the documentation.
When to use it?
The only good reason to use nvim_set_keymap
in your own personal configuration is if you can't upgrade to Neovim v0.7 or greater.
vim.keymap.set
This function was introduced in Neovim v0.7 and its part of the lua API. This means its only accesible in lua.
But why?
nvim_set_keymap
exists and can be used in lua. What's the purpose of vim.keymap.set?
Short answer: to have better defaults.
Long answer: nvim_set_keymap
behaves like the vimscript command :map
. Now here's the thing, most people prefer the command :noremap
. And there's another issue, you can't assign a lua function in the third argument. You have to use the options in the fourth argument.
If you want to use a lua function in nvim_set_keymap
you end up with something like this.
vim.api.nvim_set_keymap(
'n',
'<F2>',
'',
{
noremap = true,
callback = function()
print('hello')
end,
}
)
Almost every configuration I saw online had some sort wrapper around nvim_set_keymap
to modify the defaults settings. And binding lua functions is very verbose. Because of details like these vim.keymap.set
was created.
What's the difference?
vim.keymap.set
is not recursive by default. You don't have to specifynoremap = true
.Did you know
noremap
stands for "no recursive mapping"? Having that negative prefix is kind of confusing. So invim.keymap.set
if you want a recursive mapping you sayremap = true
.You can use a lua function in the third argument.
Lua functions in combination with the option
expr = true
handles keycodes automatically.vim.keymap.set
can define buffer local keymaps.
So our previous example can be written like this.
vim.keymap.set('n', '<F2>', function()
print('hello')
end)
When to use it?
Whenever possible. This is the recommended way of creating keymaps in your personal configuration.
lazy.nvim's "keys" property
And then there were three...
lazy.nvim offers a bunch of features. Among those there is one that allows users to create keymaps, that is the keys
property in the plugin configuration.
Why?
One of the selling points of lazy.nvim is its ability to load plugins on demand using a (relatively) simple configuration. You can delay loading a plugin until you really, really need it.
Consider this example
{
'nvim-telescope/telescope.nvim',
branch = '0.1.x',
dependencies = {'nvim-lua/plenary.nvim'},
cmd = 'Telescope',
},
Here we have a configuration for telescope.nvim, a very popular fuzzy finder.
With this in your lazy.nvim setup it will install telescope.nvim
and also plenary.nvim
. But they will not be loaded until you use the command Telescope
. If you never use that command Neovim is not going to execute any files in the source code of telescope.nvim
.
Now, cmd
is not the only way to load a plugin on demand. You can also tell lazy.nvim to do it when you press a keymap. Like this.
{
'nvim-telescope/telescope.nvim',
branch = '0.1.x',
dependencies = {'nvim-lua/plenary.nvim'},
keys = {
{'<F2>', '<cmd>Telescope find_files<cr>'},
},
},
In this example telescope.nvim
will only be loaded after we press the <F2>
key.
Consider the side effects
When a plugin is not loaded is like it doesn't even exists.
In the previous example we had a keys
property. But notice it didn't have a cmd
property. So if the plugin is not loaded and you try to execute the command :Telescope find_files
manually in command mode, that would fail. If you try to use the command :help telescope.nvim
to read the help page, that would also fail. That is because Neovim doesn't even know where telescope.nvim
is installed. It can't give you access to anything.
Is worth mention some plugins do need to execute some commands or functions during Neovim's initialization process. So when you delay loading a plugin it may not work as expected.
When to use it?
I don't think there is ever a situation were you NEED to use this method. Is purely optional. You would use this when you want to delay loading a plugin.
I would use this feature of lazy.nvim in a plugin that I rarely need. Something like neogit for example. I can spend hours coding without using it. In that particular case I think is nice to have the option to load it when I actually call it.
Conclusion
I recommend using vim.keymap.set()
whenever possible.
lazy.nvim's keys
property does more than just create a keymap. It's one way the user can tell lazy.nvim to delay loading a plugin.
Thank you for your time. If you find this article useful and want to support my efforts, consider leaving a tip in ko-fi.com/vonheikemen.
Top comments (3)
i have an issue with regex command as keymaps. i want to create a key to convert comma seperated words into lists. Bu i also want to use this in virtual-line mode in Neovim. My goal is seleting the words and execute this convert operations:
i tried with vim.set.keymap() but somehow not worked properly:
but didn't tried nnoremap method yet. So could you help me with this problem if you have a suggestion. I want to solve this with vim.set.keymap() method.
Thnx in advance.
Maybe the backslash is not getting throught the command. Use
\\r
.Another option would be using
[[ ]]
to create the string, that way you don't have to escape the backlash.i saw two different format with square brackets and without it. i will try both and give the feedback.
this is working for me right now. thanks for your help.