on
Fully moving onto neovim
tl;dr
Setup ~/.config/nvim/init.vim
. If you want modularity, use the following as well:
# this is where vim-plugs are specified
~/.config/nvim/plugs.vim
# this is where custom key-mappings are set
~/.config/nvim/mappings.vim
# this is where any customization can be done on a per-plugin basis
~/.config/nvim/after/plugin/<plugin>.rc.vim
A ~/.config/nvim/after/plugin/<plugin>.rc.vim
looks like:
" Check to see if the plugin was loaded at all
if !exists("g:loaded_<plugin>")
" Stop sourcing this file if the plugin was not found
" @see :help exists
finish
endif
" any customization happens below here
Preface
I’m a huge fan of neovim. It’s a better version of vim that is more lightweight, but also has an extensible API that is incredible and has a very active developer community, which means that they release many more features than vim. The more of a Vim power you become, the more that Neovim will become appealing to you.
The setup
Neovim’s primary user configuration directory is:
# For information, see `:help init.vim`
# In Unix
~/.config/nvim/
# In Windows
~/AppData/Local/nvim/
# If $XDG_CONFIG_HOME is defined
$XDG_CONFIG_HOME/nvim
Much like Vim, I use vim-plug
as my plugin manager for Neovim. My neovim directory structure looks like:
nvim/
- init.vim
- plug.vim
- maps.vim
- <language>-mappings.vim
- after/
- plugin/
- <plugin>.rc.vim
- <plugin2>.rc.lua
...
- <pluginN>.rc.vim
init file
The init
is the .vimrc
file equivalent, and can be either vimscript or lua (init.vim
or init.lua
). I went with vimscript, because my pre-existing .vimrc
file is in vimscript
, so I figured it’d be easier to adapt.
In this file, I have a conditional to auto-install vim-plug
at the very top:
syntax on
" Install vim-plug automatically
let data_dir = stdpath("data") . "/site"
if empty(glob(data_dir . "/autoload/plug.vim"))
silent "!curl -fLo ".data_dir."/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim"
autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
endif
Besides automatically installing vim-plug
, I have some defaults that I use (hlsearch
, number
, wrap
to name a few). Below the defaults, I use runtime
to reference the top-level files (plug.vim
, maps.vim
):
runtime plug.vim " install plugins first
runtime maps.vim " install any custom mappings not necessarily tied to a plugin
As neovim is parsing this file, the plugins are defined/installed first, then the custom mappings are set and lastly the after/plugin
directory is sourced. For more information on this, check out :help ftplugin
plug.vim
This file is where I store my vim-plug
plugin definitions. There’s nothing really special about this file. It looks like:
let g:plug_home = stdpath("data") . "/plugged"
call plug#begin()
" Default plugins
Plug 'scrooloose/nerdtree'
" Language plugins
Plug 'fatih/vim-go', { 'do': ':GoUpdateBinaries' }
" Colors
Plug 'pineapplegiant/spaceduck', { 'branch': 'main' }
" Neovim 0.5+ plugins, usually LSP related plugins
" This is interpreted as nvim >= 0.5
if has('nvim-0.5')
Plug 'neovim/nvim-lspconfig'
endif
" Lastly, any specific local plugins that people want installed
if filereadable(expand("~/.vimrc.plugins.local"))
source ~/.vimrc.plugins.local
endif
call plug#end()
maps.vim
This file contains any plugin-free mappings. They also contain references to language-specific mappings.
" Escape insert mode using jj
inoremap jj <Esc>
" normal mode mappings
nnoremap <Leader>ev :e $MYVIMRC<CR>
nnoremap <Leader>sv :source $MYVIMRC<CR>
" If the file type is a Ruby file, source the `ruby_mappings.vim` file in the top-level `nvim/' directory.
autocmd FileType ruby runtime ruby_mappings.vim
For the sake of example, this is what the ruby-mapping.vim
file looks like:
" Insert a pry
map <LocalLeader>rd Orequire "pry"; binding.pry<ESC>
" If `vimux` has been plugged, use these mappings
if has_key(plug, 'vimux')
map <silent> <LocalLeader>rb :wa<CR>:TestFile<CR>
endif
.rc.vim or .rc.lua
These files live in nvim/after/plugin/
, which mean that they are sourced after the plugins are loaded.
A plugin file for NerdTree
(nvim/after/plugin/nerdtree.rc.vim
) in vimscript looks like:
" If the plugin is not loaded, stop sourcing this file
" for more info on how this works, check out :help ftplugin
if !exists("g:loaded_nerd_tree")
finish
endif
" The plugin exists, so define these mappings
map <silent> <LocalLeader>nt :NERDTreeToggle<CR>
map <silent> <LocalLeader>nr :NERDTree<CR>
map <silent> <LocalLeader>nf :NERDTreeFind<CR>
" if you needed to use lua, use a HEREDOC-like syntax
lua << EOF
local var = 1
EOF
Note: the file name doesn’t really matter, but I like keeping them named after the plugins that are involved.
Closing thoughts
In my opinion, this is a super natural, clean and ergonomic setup for me. This works, has a clearly defined pattern and allows for the use of lua or vimscript.
The move over was super easy once I established the pattern was established. I might do a post separately for how I setup treesitter
, lsp
and telescope
which really take advantage of neovim.