Posted: 2022-02-20
Last modified: 2022-02-20 @ d92f9b9

Reconfiguring Neovim

I was recently inspired by a friend to nuke my Neovim config and start over from scratch, doing things a bit more “properly” this time. But I didn’t want to entirely destroy my current config – which I had not yet put under version control – before I had the new one set up in a way I was sure worked and I was happier with than my current one. This post documents my approach for when I feel like doing the same thing again some time in the future. Although I am now going to put my config under version control, so technically I won’t have to. You never know, though.

Making a Neovim config sandbox

Neovim respects the $XDG_CONFIG_HOME and $XDG_DATA_HOME environment variables, so the approach here is actually very simple: set those to paths other than $HOME/.config/ and $HOME/.local/share! In particular, I made a directory at $HOME/tmp/nvim-setup/ where I wanted the sandbox to be for experimentation, but only while I was in the sandbox. In this directory, I created two subdirectories – one for each environment variable – called config and data. Neovim will take care of putting an nvim subdirectory in each of these:

$HOME/tmp/nvim-setup/
├── config/
└── data/

I used direnv to accomplish this, setting the environment variables when the current working directory was the sandbox directory and resetting them when I changed to somewhere else. This way I didn’t have to change my shell setup or remember to run Neovim like

XDG_CONFIG_HOME=$HOME/tmp/nvim-setup/config nvim

to test things. As long as the current working directory is the sandbox directory, simply launching nvim will use the sandbox configs.

Vimscript or Lua?

I previously had my Neovim config in Lua, since that’s the thing I figured you were supposed to do. However, I’m not that comfortable with Lua and I actually had a hard time reading my old config to pick out things I wanted to keep. So the new config will use Vimscript, because I’m more familiar with it and it feels better as a config language. I may revisit this decision next time I feel like redoing my setup and if I become more comfortable with Lua.

init.vim

My old init.lua was one big file with all settings, mappings, plugins and stuff just shoved in there. I didn’t want this to be the way the new setup worked, because it made it harder to find and tweak certain settings when I felt like I needed to. Instead, init.vim will just dispatch the setup to other .vim files with the runtime! command:

runtime! options.vim
runtime! mappings.vim
runtime! plugins.vim
runtime! plugin-settings/**/*.vim
runtime! plugin-settings/**/*.lua

These files then actually do the setup their name suggests they do.

File structure

In the config directory, the four files init.vim, mappings.vim, options.vim, and plugins.vim reside along with the directory plugin-settings/, where every plugin has its own config file (in Vimscript or Lua depending on the plugin). This way I get nice separation of global config and plugin-specific config. Any other vim runtime directories – like ftplugin for filetype-specific config – are also here. Here’s a directory tree:

$XDG_CONFIG_HOME/nvim/
├── ftplugin/
│   └── rust/
│       ├── rust_mappings.vim
│       └── rust.vim
├── plugin-settings/
│   ├── foldmk.vim
│   ├── gruvbox-material.vim
│   ├── nvim-cmp.lua
│   ├── nvim-treesitter.lua
│   ├── rust-tools.lua
│   └── telescope.lua
├── init.vim
├── mappings.vim
├── options.vim
└── plugins.vim

Plugins

I usually only use a handful of plugins if any at all. It sort of goes in cycles of completely spartan zero plugin configs and full-blown “make-vim-into-an-ide” configs. But I wanted to test plugins in the sandbox, so I added vim-plug into the proper $XDG_DATA_HOME subdirectory:

$XDG_DATA_HOME/nvim/
└── site/
    └── autoload/
        └── plug.vim

Then I could install any plugins I wanted to try in the plugins.vim config file, with configs in plugin-settings/.

Editing configs when they’re spread out

One might think that not having everything in one file will make it harder to remember what the files were called exactly and take longer to find, but this is not the case. I have a mapping in Neovim, <Leader>e, which opens init.vim in a vertical split. Now this file only contains runtime! commands, but putting the cursor on any of the filenames and hitting gf in normal mode will open that config file. This even works for the plugin-settings/ directory, opening the directory in netrw so I can browse to the right plugin’s config file. I don’t have to remember or type in any filenames. It’s pretty neat.

Version control

This time I’ve actually put my Neovim config under version control. It’s available here.