Vim Cheatsheet

Plugins and Tooling

Use this Vim reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Plugin Managers

Vim 8 and Neovim both have a built-in package system, so a manager is optional but still the norm.

ManagerNotes
Built-in packagesDrop a repo in ~/.vim/pack/x/start/, no plugin needed
vim-plugSingle file, works in Vim and Neovim, the common default
lazy.nvimNeovim only, Lua, lazy loading
packer.nvimNeovim, Lua, largely superseded by lazy.nvim
# Built-in packages: no manager at all
mkdir -p ~/.vim/pack/plugins/start
git clone https://github.com/tpope/vim-surround ~/.vim/pack/plugins/start/vim-surround
# Optional (load on demand with :packadd name)
mkdir -p ~/.vim/pack/plugins/opt
" vim-plug
call plug#begin('~/.vim/plugged')
Plug 'tpope/vim-surround'
Plug 'tpope/vim-commentary'
Plug 'tpope/vim-fugitive'
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'
Plug 'nvim-treesitter/nvim-treesitter', { 'do': ':TSUpdate' }
Plug 'preservim/nerdtree', { 'on': 'NERDTreeToggle' }
call plug#end()
vim-plug commandAction
:PlugInstallInstall anything missing
:PlugUpdateUpdate everything
:PlugCleanRemove plugins no longer in the config
:PlugStatusShow status
:PlugUpgradeUpdate vim-plug itself
:helptags ALL       " rebuild help tags after installing manually
:packadd name       " load an optional package now

Plugins Worth Knowing

PluginWhat it adds
vim-surroundcs"' change surrounding quotes, ds( delete them, ysiw" add them
vim-commentarygcc comment a line, gc{motion} comment a range
vim-repeatMakes . repeat plugin commands too
targets.vimMore text objects: arguments, next/last pairs
vim-fugitive:Git, :Git blame, :Gvdiffsplit
vim-gitgutter / gitsigns.nvimChange markers in the sign column
fzf.vim / telescope.nvimFuzzy find files, buffers, lines, git objects
nvim-treesitterReal parse trees: better highlighting and text objects
nvim-lspconfig / coc.nvimLanguage servers: completion, rename, diagnostics
aleAsync linting and fixing
vim-airline / lualine.nvimStatus line
undotreeVisualize the undo tree
vim-easymotion / leap.nvimJump anywhere on screen in a few keys

vim-surround Idioms

Surround is the plugin most worth muscle memory, because it fills the gap in Vim's grammar around delimiters.

KeysDoes
cs"'Change surrounding " to '
cs'<q>Change ' to <q> tags
ds"Delete the surrounding quotes
dstDelete the surrounding tag
ysiw"Surround the word with quotes
yss)Surround the whole line with parens
yS{motion}Surround on its own indented lines
S" in VisualSurround the selection

Completion Without Plugins

Vim's built-in completion covers a lot before you reach for an LSP.

Insert-mode keyCompletes from
Ctrl-n / Ctrl-pWords in open buffers
Ctrl-x Ctrl-fFilenames
Ctrl-x Ctrl-lWhole lines
Ctrl-x Ctrl-oOmni completion (filetype aware)
Ctrl-x Ctrl-kDictionary words
Ctrl-x Ctrl-tThesaurus
Ctrl-x Ctrl-iIncluded files
Ctrl-x Ctrl-]Tags
Ctrl-x Ctrl-vVim command line
Ctrl-x sSpelling suggestions
set completeopt=menuone,noinsert,noselect
set omnifunc=syntaxcomplete#Complete
set complete-=i          " do not scan included files (slow on big projects)

Tags

Tags are a pre-LSP way to jump to definitions, and they still work anywhere ctags is installed.

ctags -R .                       # generate a tags file
ctags -R --exclude=node_modules .
KeyAction
Ctrl-]Jump to the definition under the cursor
Ctrl-tJump back up the tag stack
g Ctrl-]Show a menu when there are several matches
:tag nameJump to a tag by name
:tagsShow the tag stack
:tselect nameList every match
:ptag namePreview the tag in a split
Ctrl-w }Preview the tag under the cursor
:pcloseClose the preview window

Language Servers

In Neovim, LSP is built in. These are the default keymaps most configs set up, and they replace tags entirely.

KeyAction
gdGo to definition
gDGo to declaration
grList references
giGo to implementation
KHover documentation
<leader>rnRename symbol
<leader>caCode action
[d / ]dPrevious / next diagnostic
<leader>fFormat the buffer

In Vim, coc.nvim or ALE provide the same features. Either way the underlying protocol and the language servers (tsserver, pyright, gopls, rust-analyzer, clangd) are the same ones VS Code uses.

Debugging Your Config

:scriptnames              " everything sourced, in load order
:verbose set option?      " which file last set an option
:verbose nmap <C-h>       " which file defined a mapping
:messages                 " the message history
:redir @a | messages | redir END   " capture messages into a register
vim -u NONE file          " no config at all
vim -u minimal.vim file   " a minimal repro config
vim --startuptime log.txt " profile startup
:profile start prof.txt
:profile func *
:profile pause

When a plugin misbehaves, bisect it: start with vim -u NONE, confirm the problem is gone, then add plugins back to a minimal config until it returns. --startuptime is the tool for "why does my editor take 800ms to open".