In my time using Vim, I switched between MacVim, regular Vim and NeoVim, project drawers and fuzzy file finding, Janus and custom configurations, and so on. My current configuration is a result of that journey which tries to stay light on plugins and key mapping, while still providing a somewhat modern editor configuration.
My .vimrc
file is extracted from this document1, meaning both should remain in sync.
Unless I’m experimenting with something locally that I haven’t pushed yet, this document describes the configuration I’m currently using in my editor.
NeoVim
Recent versions of Vim caught up to most features NeoVim introduced, like true color support, background jobs and the inline terminal. However, NeoVim comes with sensible defaults out of the box by implementing most of vim-sensible by default.
As a good starting point, either install both Vim and vim-sensible, or NeoVim. This configuration chooses the latter.
Installation
brew install neovim
nvim --version | head -n1
NVIM v0.8.3
Setup
Vim and NeoVim use different locations for the configuration file and home directory. This configuration is checked out in Vim’s default home directory, which contains the configuration file:
home directory | configuration file | |
---|---|---|
Vim | ~/.vim |
~/.vimrc |
NeoVim | ~/.config/nvim |
~/.config/nvim/init.vim |
This configuration | ~/.vim |
~/.vim/.vimrc |
To use this configuration, clone its repository to Vim’s home directory path:
git clone git@github.com:jeffkreeftmeijer/.vim.git ~/.vim
To support NeoVim, symlink NeoVim’s home directory and configuration file paths to Vim’s:
mkdir -p ~/.config/ ln -s ~/.vim ~/.config/nvim ln -s ~/.vim/.vimrc ~/.config/nvim/init.vim ln -s ~/.vim/.vimrc ~/.vimrc
Package management
Vim 8 and NeoVim have a native package manager, which loads plugins from the ~/.vim/pack/plugins/start
directory2.
To install a package, clone its repository into ~/.vim/pack/plugins/start
:
git clone git@github.com:tpope/vim-commentary.git \
~/.vim/pack/plugins/start/vim-commentary
When publishing dotfiles to a repository for reuse, it’s convenient to use Git submodules instead of regular checkouts. This allows for checking the dependencies into version control. Instead of cloning, add a plugin as a submodule:
git submodule add git@github.com:tpope/vim-commentary.git \
~/.vim/pack/plugins/start/vim-commentary
Another option for installing plugins is using a plugin manager like vim-plug. Instead of using Git checkouts or submodules, vim-plug handles the installing and updating of plugins.
The plugins themselves are configured through a list of calls to the Plug
function in the ~/.vimrc
file:
Plug 'tpope/vim-commentary'
This configuration uses the latter in an attempt to contain most of the configuration in a single file.
Vim-plug
Vim-plug’s documentation mentions installing the plugin into the autoload directory directly by running a script that downloads plug.org
to the ~/.vim/autoload
directory:
curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
Instead, to have Vim install vim-plug on startup (again, to contain the configuration to a single file), this snippet automatically downloads plug.vim
from its repository if it doesn’t exist yet:
" Download plug.vim if it doesn't exist yet if empty(glob('~/.vim/autoload/plug.vim')) silent !curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim endif
Normally, plugins are installed when calling :PlugInstall
from within Vim.
To remove an extra step from the setup, this configuration runs a script on startup that checks for missing packages on startup and install them if needed:
" Run PlugInstall if there are missing plugins autocmd VimEnter * if len(filter(values(g:plugs), '!isdirectory(v:val.dir)')) \| PlugInstall --sync | source ~/.vimrc \| endif
All other plugins are installed through vim-plug.
Installing packages
To install plugins with vim-plug, call the Plug
function inside the plug-block:
call plug#begin("~/.vim/plugged") " TODO Add plugins call plug#end()
The plug#begin("~/.vim/plugged")
function sets up the plugin directory3 and the plug#end()
function initializes the plugin system.
To install a plugin, call the Plug
function inside the plug-block with an URL to a git repository:
Plug 'tpope/vim-commentary'
The user/repository
assumes the plugin is hosted on GitHub.
Creating and restoring package snapshots
To write a lock file based on the currently installed plugin versions, run :PlugSnapshot ~/.vim/snapshot.vim
inside Vim.
This creates a snapshot file in the specified path, which lists all installed plugins with their commit hashes.
" Generated by vim-plug " Sat Aug 14 14:14:55 2021 " :source this file in vim to restore the snapshot " or execute: vim -S snapshot.vim silent! let g:plugs['coc.nvim'].commit = '6a9a0ee38d2d28fc978db89237cdceb40aea6de3' silent! let g:plugs['fzf'].commit = '7191ebb615f5d6ebbf51d598d8ec853a65e2274d' silent! let g:plugs['fzf.vim'].commit = 'e34f6c129d39b90db44df1107c8b7dfacfd18946' silent! let g:plugs['vim-commentary'].commit = '349340debb34f6302931f0eb7139b2c11dfdf427' silent! let g:plugs['vim-dim'].commit = '8320a40f12cf89295afc4f13eb10159f29c43777' silent! let g:plugs['vim-nightfall'].commit = '47c7c74e9ce605581a1492ed163b6b3ae7604c48' silent! let g:plugs['vim-numbertoggle'].commit = '075b7478777e694fbac330ee34a74590dad0fee1' silent! let g:plugs['vim-polyglot'].commit = 'ce31cd1d2f4e8eee9fd91325e4599f15cb9566fd' silent! let g:plugs['vim-surround'].commit = 'f51a26d3710629d031806305b6c8727189cd1935' PlugUpdate!
To restore from a snapshot, source the snapshot file inside Vim:
:source ~/.vim/snapshot.vim
Clipboard
Vim uses the “unnamed” register as the clipboard when copying or deleting text from a buffer.
To use the system clipboard, prefix the copy or delete command with "*
.
For example, to copy the current line to the system clipboard, use "*yy
.
To always use the system clipboard, append unnamedplus
to the clipboard
setting:
" Always use the system clipboard set clipboard+=unnamedplus
With this setting, yy
copies the current line to the system clipboard, without needing to add the "*
prefix.
Packages
This configuration consists of nine packages installed with vim-plug and configuration for some of the packages. The vim-plug plugin block lists all nine:
call plug#begin("~/.vim/plugged") Plug 'sheerun/vim-polyglot' Plug 'jeffkreeftmeijer/vim-dim' Plug 'jeffkreeftmeijer/vim-nightfall' Plug 'jeffkreeftmeijer/vim-numbertoggle' Plug 'tpope/vim-surround' Plug 'tpope/vim-commentary' Plug 'neoclide/coc.nvim', {'branch': 'release'} Plug 'junegunn/fzf', { 'do': { -> fzf#install() } } Plug 'junegunn/fzf.vim' call plug#end()
The rest of this section lists each plugin and describes its configuration.
Polyglot
Polyglot is a curated and frequently updated list list of more than 600 language packs4 to auto-load syntax highlighting and indentation rules. Although the packs are downloaded on install, they’re loaded on demand, so using Polyglot does not affect Vim’s startup time.
Plug 'sheerun/vim-polyglot'
Dim
Vim’s default color scheme uses hardcoded color values (comments and some keywords are light blue, for example) that ignore the terminal’s set ANSI colors. Dim is a clone of Vim’s default colorscheme, with some improvements. It only uses ANSI colors, so specific color values are configured in the terminal emulator instead of in Vim itself.
Dim’s syntax highlighting is consistent to prevent color shifts between dark and light backgrounds. It also makes sure to use dimmed colors for comments and other non-code elements, to help distinguishing code from everything else.
Plug 'jeffkreeftmeijer/vim-dim'
After installing Dim, use it as the default colorscheme by setting colorscheme
in ~/.vimrc
:
" Use Dim as the default color scheme colorscheme dim
Nightfall
Nightfall automatically switches Vim’s bg
between “dark” and “light” based on macOS’s dark mode.
Plug 'jeffkreeftmeijer/vim-nightfall'
Surround.vim and commentary.vim
Tim Pope’s plugins are a staple of most Vim configurations. This configuration includes Tim’s surround.vim and commentary.vim for working with surroundings and comments.
The former enables s
, allowing for ci"
to replace the contents of a double-quoted string, among many other examples.
The latter adds quick commenting.
Press gcc
to comment out a line and gc
to comment out a selection.
Plug 'tpope/vim-surround' Plug 'tpope/vim-commentary'
Vim-numbertoggle
Vim has absolute, relative and “hybrid” line numbers to help with locating lines in a file, and moving between files quickly. Vim-numbertoggle is a plugin that automatically switches between absolute and hybrid line numbers when switching between normal and insert mode, or when Vim loses focus.
Plug 'jeffkreeftmeijer/vim-numbertoggle'
" Turn on line numbers set number
Coc.nvim
Coc.nvim is a language server plugin to add code completion, inline documentation and compiler checks.
Plug 'neoclide/coc.nvim', {'branch': 'release'}
After installing Coc.nvim, set g:coc_global_extensions
to add language server extensions for Elixir, Ruby, Rust, Typescript and VimL:
" Install Coc extensions for Elixir, Ruby, Rust, Typescript and VimL let g:coc_global_extensions = ['coc-elixir', 'coc-solargraph', 'coc-rls', 'coc-tsserver', 'coc-vimlsp']
Automatically format Elixir, Rust and Typescript files on save by setting g:coc_user_config
instead of using Coc’s default JSON configuration file:
" Automatically format Elixir, Rust and Typescript files on save let g:coc_user_config = {"coc.preferences.formatOnSaveFiletypes": ["elixir", "rust", "typescript"]}
Finally, use <cr>
to select the topmost option during completion:
" Use <cr> to select the first completion inoremap <silent><expr> <cr> pumvisible() ? coc#_select_confirm() : "\<C-g>u\<CR>"
Fzf.vim
Fzf.vim is a Vim plugin for the fzf command-line fuzzy finder.
It provides the :Files
, :Buffers
and :Rg
commands to find and filter files, buffers, and lines, respectively.
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } } Plug 'junegunn/fzf.vim'
Initially, this configuration didn’t exist in this form, but I’ve published my Vim configuration in one way or another since 2010. This document is the current revision.
↩︎The name of the
↩︎start
directory in~/.vim/pack/plugins/start
can be anything, but “start” seems to make sense.Vim-plug uses the
↩︎~/.config/nvim/plugged
directory by default, but passing a different path toplug#begin()
overwrites the plugin directory.Polyglot should have all languages you need. For language packs that aren’t yet included, add them by sending a pull request. For example, this pull request adds support for Gleam through gleam.vim.
↩︎