4

How to Create Custom Keymaps in Neovim With Lua | Somraj Saha

 1 year ago
source link: https://jarmos.vercel.app/blog/create-custom-keymaps-using-lua-for-neovim
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

HomeAbout MeBlog

How to Create Custom Keymaps in Neovim Using the Embedded Lua Environment

Learn to create custom keymaps in Neovim using Lua

Neovim (or even Vim) is an excellent piece of software for any developers out there. The ability to create custom keybindings & do pretty much anything is testament to Vim's popularity. And if you've used Vim before, you should be aware of what's possible through custom Vim keybindings as well.

For the uninitiated, Vim's openness towards creating custom keybindings has pretty much no competition out there. As such, only your imagination is the limit to what you could possibly create using custom keybindings.

Vim users are also required to have working knowledge of Vimscript (which is a scripting language built for Vim configuration). It's not the most elegant language out there & neither has it any use outside of Vim. Also for many of you, the time investment & efforts required to pickup a redundant programming language mightn't be productive either. Fortunately, Neovim v0.5+ gave the community a signficant update to play around with & that's the inbuilt Lua runtime.

The optional Lua runtime also backwards compatible meaning you could still try out the optional runtime right from within Vimscript. We'll not discuss how to write Lua code within Vimscript since it's beyond the scope of this article. But feel free to refer to this amazing Neovim-Lua Guide on GitHub for a quick reference.

If that piqued your interests & you would like continue learning about how creating custom keybinds in Neovim is a much pleasant experience, then read ahead. The rest of the article starts with a brief intro to the optional Lua runtime, followed by creating a Lua function for mapping the custom keybinds. And towards the end of it all, we'll suggest further resources you might want to take a look at to learn about Neovim's Lua runtime better.

Introducing the Optional Lua Runtime

Before we proceed further into the article, let's briefly introduce the Lua runtime in Neovim. Having some idea of it will help better understand the how's & what's possible to create.

That said, Neovim was released with a set of some useful features. One such feature that makes Neovim stand out is its builtin API. The programmatic access to the API & the Lua runtime means you can let your imaginations go wild if you so desire.

And just so you know, like any other config files used to hack Neovim/Vim, the Lua code also needs to be placed in the runtimepath (see :h rtp for more info). These config files (with a .lua extensions) are placed inside a directory aptly named lua. And Neovim will source everything inside that directory when invoked.

Do note, the location to the Neovim runtimepath varies depending on the choice of your OS. So, for Linux users out there, check if your OS follows the XDG Base Directory specification, then the Lua files should be usually available at: $HOME/.config/nvim/lua. And my fellow Windows users out there, you should check for the Lua files at %LOCALAPPDATA%\nvim\lua.

For more info on where to place the config files, check out the "Where to put Lua files" section of the Neovim-Lua Guide on GitHub.

With our little introduction to the optional Lua runtime taken care of, lets check out the how to configure Neovim keybindings with Lua. In the next few sections we'll taking a look at, writing an example Lua function followed by an actual functional wrapper in Lua. This functional wrapper will be used to create our custom keybindings where & whenever necessary.

How to Write Lua Function for the Neovim Key Bindings

Back in the day when Neovim wasn't a thing, Vim provided the remap commands (and the noremap for non-recursive remaps) for customizing & remapping keybindings. As such it was a common scene to see nnoremap commands scattered all over one's .vimrc file. Here's one such example .vimrc file I picked up from the Internet. The file is huge (~1200 lines of code!), is unweidly & a totaly nightmare to maintain.

And here's a little code snippet I picked up from the .vimrc file above.



1" Example .vimrc file with hundreds of lines of code 2... 3nnoremap <silent> <leader> :<c-u>WhichKey ','<CR> 4nnoremap <leader>? :WhichKey ','<CR> 5nnoremap <leader>a :cclose<CR> 6nnoremap <leader><space> :nohlsearch<CR> 7...

Fortunately for us, Neovim provides a helper function through it's builtin API. Aptly named vim.keymap.set(), the users are expected to use this function directly or by wrapping it in Lua code. The later method is recommended since that way it's possible to adhere to standard coding practices. Using Lua code in tandem with the Neovim API also helps in modularising the configurations. Thus making maintenance much easier & keep your sanity intact.

Using wrapper functions also ensures the configurations are "DRY" & "SOLID". Adhering to such common development standard practices means the configurations looks clean & organized as well.

So what does a typical Neovim configuration look like when used with Lua? Following are some such examples:



1-- Functional wrapper for mapping custom keybindings 2function map(mode, lhs, rhs, opts) 3 local options = { noremap = true } 4 5 if opts then 6 options = vim.tbl_extend("force", options, opts) 7 end 8 9 vim.keymap.set(mode, lhs, rhs, options) 10end 11 12map("n", ",<Space>", ":nohlsearch<CR>", { silent = true }) 13map("n", "<Leader>", ":<C-u>WhichKey ','<CR>" { silent = true }) 14map("n", "<Leader>?", ":WhichKey ','<CR>") 15map("n", "<Leader>a", ":cclose<CR>")

At first glance, the Lua code might appear too verbose but it's a good thing as you'll see soon.

In the Lua code snippet we shared aboved, we defined a function called map(). It accepts four parameters namely:

  • mode (as in Vim modes like Normal/Insert mode)
  • lhs (the custom keybinds you need)
  • rhs (the commands or existing keybinds to customise)
  • opts (additional options like <silent>/<noremap>, see :h map-arguments for more info on it)

By default, the opts parameter of the map() function is assigned to a table { noremap = true }. In doing so, nested & recusive use of mappings are allowed (refer to :h map-commands for more info on it). You can expand the opts table further with additional map-arguments as you require. And at the core of the wrapper is the vim.keymap.set() function which accepts the list of parameters mentioned above.

This function can then be reused wherever you need them. As you'll see in the next we can modularise our Neovim configurations even further!

Using the Lua Functions Across the Neovim Runtime Files

The wrapper function we used in the section above does help in customising default Vim remappings. But defining the wrapper function & then using it right within our init.lua file doesn't adhere to the DRY and/or SOLID principles at all. To make the configs more compliant with standard dev practices, we'll use Lua Modules. Using Lua Modules ensures there's clear separation of logic in our configurations.

And if you need a refresher on how to create Lua Modules for Neovim, refer to the "Modules" section of the Neovim-Lua Guide on GitHub.

That said, create a utils.lua under the lua directory in your runtimepath. Lua Modules are identified if they contain the following lines of code:



1-- Assign an empty table to the local variable named M (it's standard to name the variable as "M") 2local M = {} 3 4-- Define your function & add it the M table 5function M.do_something() 6 -- Your functional logic 7end 8 9-- Since the M table is scoped, it has to be returned for usage elsewhere 10return M

Explaining Lua Modules are beyond the scope of this article as well, so perhaps refer to the Lua 5.1 documentations linked above for reference.

For our use case, the Lua Module we defined will contain the functional wrapper for the custom keybinds. As such this is what the contents of our utils.lua module will look like:



1-- Our lua/utils.lua file 2 3local M = {} 4 5function M.map(mode, lhs, rhs, opts) 6 local options = { noremap = true } 7 if opts then 8 options = vim.tbl_extend("force", options, opts) 9 end 10 vim.keymap.set(mode, lhs, rhs, options) 11end 12 13return M

Since Neovim sources & loads any Lua files located under the lua directory in the runtimepath our map() function will be available to be imported anywhere else as well. Hence, now it's possible to simply import the wrapper into your init.lua file & use it for creating your remaps. Thereby you can now keep the file clean, maintainable & fast to load.

Here's how you could rewrite the init.lua file by importing the map() function from the utils module;



1-- Our example init.lua file 2 3-- Import & assign the map() function from the utils module 4local map = require("utils").map 5 6map("n", ",<Space>", ":nohlsearch<CR>", { silent = true }) 7map("n", "<Leader>", ":<C-u>WhichKey ','<CR>" { silent = true }) 8map("n", "<Leader>?", ":WhichKey ','<CR>") 9map("n", "<Leader>a", ":cclose<CR>")

Now that the code is properly modularised, maintenance shouldn't be a chore & chances of something breaking will be much lower. Further, if you wish extending our rudimentary map() function is as simple making your necessary changes to the utils module!

That said, chances are, if you've been using Neovim for a while now, you're yet to migrate your configs to Lua code. And you'll be glad to hear that the Neovim devs went through great lengths to maintain backwards compatibility. If making migration changes from Vimscrip to Lua code for your existing configs makes you uneasy, then don't fret. You can even use Lua code right within Vimscript as well! For that, refer to :h heredocs for more info on the topic.

To help you figure your way around while migrating the existing configs, the next section will suggest some useful references you could take a look at.

Final Words & Things to Look Forward to

The optional Lua runtime within Neovim is a godsend & it's also one such feature which makes Neovim particularly stand out apart from Vim. But since the features & Neovim itself is comparatively new, resources around these features are hard to come by. As such following are some resources you might want to take a look at if configuring Neovim with Lua piques your interests.

  1. A Guide to Using Lua in Neovim
  2. h: lua for a comprehensive guide on how to use Lua within Neovim.

There is obviously a lot more that is possible with using Lua for Neovim configuration, so in case I missed out on something, do let me know?

And to conclude this article, what do you think of using Lua to configure Neovim? Are you current configuration in Vimscript or Lua? And have you noticed any difference while using either? Let me know...


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK