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.
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.
brew install neovim
nvim --version | head -n1
NVIM v0.8.3
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
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'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.
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.
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
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.
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 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'
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 automatically switches Vim's bg
between "dark" and "light" based on macOS's dark mode.
Plug 'jeffkreeftmeijer/vim-nightfall'
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 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 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 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'
1 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.
2 The name of the start
directory in ~/.vim/pack/plugins/start
can be anything, but "start" seems to make sense.
3 Vim-plug uses the ~/.config/nvim/plugged
directory by default, but passing a different path to plug#begin()
overwrites the plugin directory.
4 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.