My Neovim configuration
I use Neovim for 95%+ of my writing, both prose and code. I originally picked Vim over Emacs because I liked its modal text editing. Over the following years I’ve honed it to my preferences, building up over ~4000 lines of configuration. I’ve flirted with switching to Emacs with evil-mode for a better plugin ecosystem, but Vim is too deeply engraved in my muscle memory to move away from.
Lua vs Vimscript
I don’t have a strong preference for Lua/Vimscript. Historically, Vimscript was the only language for configuring Vim1 . I generally assume that I will always use Neovim nowadays. Neovim makes Lua a first class language for configuring Vim. In fact, in addition to bridging all of Vim’s APIs to Lua, new APIs (such as vim.lsp) are often only offered through Lua.
Rewriting all of my configuration in Lua just to lose support for Vim completely seems like a waste of time, so I still keep a lot of my configuration in Vimscript. I tend to prefer Vimscript’s syntax for mappings and autocommands to Lua’s anyways. Lua’s feels a little bit too verbose, and is harder to understand quickly in my opinion.
Neovim makes it very easy to mix Lua and Vimscript, which makes it possible to maintain interoperability even while maintaining configuration in both.
Escape key
Because the escape key is far in the top left corner of modern keyboards, mapping jj or jk to escape in insert mode is fairly common. I used to do this. At some point I learned that Vim and most Vim plugins for other text editors treat <C-[> as escape. Rebinding caps lock to control system wide, made it possible to press <C-[> with my two pinkies simultaneously. An escape key mapping was previously the only configuration I truly couldn’t do without so this has the added benefit of letting me use Vim-mode plugins in other editors (or Vim itself through SSH) well enough without needing to configure them.
Modularization
Because my config has grown quite large, I need to keep it modularized for it to stay maintainable.
Mostly I rely on the runtime directory structure which allows loading a lot of files flexibly:
init.vimhas logic that needs to run before other configuration, plus a bunch of stuff that I’ve been too lazy to move elsewhereplugins.vimis sourced frominit.vimand loads plugins. I have this separated out because I use a lot of pluginsftsyntaxdirectories for autocommands improving file type detection, or adding newftplugin/afterdirectories house language specific configuration to prevent needing to define autocommands for themautoloaddirectories store “library” functions that I use from other pieces of my configurationlua/mymodules serve the same purpose, but for Lua codeplugindirectories for configuration insensitive to loading order
Plugins
I still use vim-plug to manage my plugins because it works well enough, and well written plugins lazy load by design, thus not requiring anything fancier.
I’m a heavy plugin user so I’ll only go through my favorite plugins. The most notable category is plugins that add generic cross language features to the editor without conflicting with default keybindings:
tpope/vim-repeatmakes it possible to use.with custom actions provided by other plugins. This should really just be a built in Vim feature.tpope/vim-sleuthmakes indentation behave sanely by default.tpope/vim-surroundadds a truly essentialys/cs/dstext editing verbs for adding/changing/deleting surrounding texttommcdo/vim-exchangeprovides a very usefulcxtext editing verb for swapping textwellle/targets.vimadds extra text objects (e.g. for function arguments) and makes existing text objects more flexible (e.g. selecting the next instance of a text object if you aren’t already inside of it)
I use overcache/NeoSolarized for my color scheme because it’s the most modern true color Solarized color scheme that I could find. I use nvim-lualine/lualine + nvim-tree/nvim-web-devicons to make the UI a bit prettier.
For more IDE like features, I mostly rely on language servers, but some extra support is provided by plugins.
hrsh7th/nvim-cmpfor autocomplete though I’m considering switching off this because it is now unmaintainedLuaSnipfor snippets
Other than that, there’s pretty much just a bunch of syntax plugins.
I’ve also factored bits of my config as plugins (e.g. vim-magic-link-paste) plus a syntax plugin for moss-lang. A way to keep it easy to edit these even though they are no longer in my dotfiles repo is to branch on whether the repository exists on my computer:
if isdirectory($HOME.'/src/vim-magic-link-paste')
Plug $HOME.'/src/vim-magic-link-paste'
else
Plug 'lehmacdj/vim-magic-link-paste'
endif
This way, vim-plug won’t clone them, and I can edit the source and have it stay up to date automatically.
Making changes to configuration
I find being able to quickly navigate to a specific bit of configuration that I want to tweak important so that I’m able to fix problems / add new configuration without breaking my flow.
I use mappings that open up a configuration file in a split:
" Edit vimrc
nnoremap <Leader>ev <Cmd>split $MYVIMRC<CR>
" Edit plugins
nnoremap <Leader>ep <Cmd>split $VIMHOME/plugins.vim<CR>
My favorite is my one for editing language specific tweaks, it directly opens up the appropriate file for the current file type:
" Edit filetype file
nnoremap <expr> <Leader>ef '<Cmd>split '.$VIMHOME.'/after/ftplugin/'.&filetype.'.vim<CR>'
Language specific tweaks
I most frequently edit my language specific configuration when I’m learning a language, or using a language I haven’t edited in a while. Most commonly, language specific configuration is overrides for my global vim config like not converting tabs into spaces for Makefile or setting up soft wrapping for Markdown. I also include custom keybindings that are only relevant for particular file types, like publishing a note from my wiki.
Wiki specific stuff
For my notes specifically I have a custom language server that I use providing autocomplete + title transclusion from random ids + go to definition for navigating between notes. I rely heavily on conceal to keep markdown syntax hidden while reading notes in Neovim.
-
There also were remote plugins. But they require installing language runtimes, and have a more limited API than exposed through Vimscript. ↩