Neovim: creating keymaps in lua
Tags: neovim, vim, shell
Published: 2024-03-10 23:57:10

---
title: Neovim: creating keymaps in lua
published: true
description: Explaining all the methods we can use to create keymaps in Neovim using lua
tags: #neovim #vim #shell
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2024-03-10 23:52 +0000
---

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](https://github.com/folke/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](https://neovim.io/doc/user/api.html#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.

```vim
: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

```lua
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](https://pynvim.readthedocs.io/en/latest/), you could write something like this.

```python
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](https://neovim.io/doc/user/lua.html#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.

```lua
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 specify `noremap = true`.

* Did you know `noremap` stands for "no recursive mapping"? Having that negative prefix is kind of confusing. So in `vim.keymap.set` if you want a recursive mapping you say `remap = 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.

```lua
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

```lua
{
  'nvim-telescope/telescope.nvim',
  branch = '0.1.x',
  dependencies = {'nvim-lua/plenary.nvim'},
  cmd = 'Telescope',
},
```

Here we have a configuration for [telescope.nvim](https://github.com/nvim-telescope/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.

```lua
{
  '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](https://github.com/NeogitOrg/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 [buy me a coffee ☕](https://www.buymeacoffee.com/vonheikemen).

[![buy me a coffee](https://res.cloudinary.com/vonheikemen/image/upload/v1618466522/buy-me-coffee_ah0uzh.png)](https://www.buymeacoffee.com/vonheikemen)