It's 9:30PM, I'm on vacation, and I drank an energy drink an hour ago. It's time to shave some yaks as hard as possible.
Of course I'm talking about my Neovim configuration file, and migrating it from the Vimscript-based init.vim
to a Lua-based init.lua
.
Why would you do this to yourself?
A few reasons:
-
init.lua
is backwards compatible withinit.vim
, but not the other way around - Lua has applications outside of Vim, and this is a good excuse to familiarize myself with Lua more.
- I haven't done any benchmarking whatsoever, but Lua is probably faster than Vimscript, right? I mean, Lua is pretty fast...
- I wanted to try some Lua-based plugins like NvimTree
- Oh, do you know Vimscript? Yeah, didn't think so.
The API docs for the Lua + Neovim are here: https://neovim.io/doc/user/api.html
Migration Strategy
My overall strategy was pretty simple: first wrap everything in vim.cmd([[ ... ]])
and then pluck things out individually as candidates for conversion to Lua.
The code that follows exemplifies this process, and highlights certain categories of settings and what the Lua code looked like in the end.
vim.cmd
Vim's Lua APIs provide a convenience function vim.cmd
that takes a string literal as its only argument. Anything in that string is evaluated as Vimscript. Kind of scary, but since we're controlling what goes into it it becomes extremely convenient for our migration.
Just:
vim.cmd([[
" the contents of your existing init.vim
]])
And you're off to the races... but where's the fun in that? Where's the Lua?
Settings and Options
The first low-hanging fruit is your Vimscript set
directives like set wrap
. You have three options here and it can be a little confusing as to which options live where. I hate to sound like one of those vim people, but :help
is really good here.
vim.g
This is for global commands, basically anything in the let g:***
Vimscript namespace. For example, let g:mapleader = " "
becomes vim.g.mapleader = " "
vim.o
This will likely be the bread and butter of your migration, as it's the most consistent 1:1 mapping of set
options and Lua expressions. See for yourself:
vim.o.spell = "yes"
vim.o.splitbelow = true
vim.o.splitright = true
vim.o.swapfile = false
vim.o.synmaxcol = 30
Note they even kept the weird "yes"
-instead-of-true
convention.
vim.opt
This is a special Lua table (read: hash map or associative array) that allows you to use more Lua-friendly syntax to set options.
For example, vim.opt.listchars
is pretty nice:
vim.opt.listchars = {
tab = "» ",
trail = "·",
extends = "›",
precedes = "‹",
nbsp = "␣",
}
vim.api: Keymapping and Autocommands
For more advanced functionality like keymapping and autocommands, you have vim.api
vim.api.nvim_create_autocmd({ "FileType" }, {
pattern = "rust",
callback = function()
vim.api.nvim_buf_set_option(0, "tabstop", 4)
vim.api.nvim_buf_set_option(0, "shiftwidth", 4)
vim.api.nvim_buf_set_option(0, "softtabstop", 4)
end
})
vim.api.nvim_set_keymap('n', '<leader>s', ':split<CR>',
{ noremap = true })
Conclusion
These are just some of the ideas and examples I was able to pull out of my experience in migrating to a Lua-based Neovim config. What do you think?
Another highlight of this adventure in yak-shaving is that it makes me review my old configuration code, allowing me to change, edit, and re-contextualize the ideas that I had and my previous intentions.
How about you? Have you done this same migration? Did I miss anything? Have you shaved any good yaks recently? I'd love to hear from you.
Top comments (0)