cheat sheet
vim
Bram Moolenaar's modal editor. Covers modes, verb-noun grammar, text objects, registers, marks, windows, search-and-replace, quickfix, macros, configuration, and a high-value baseline .vimrc.
vim — Modal Text Editor
What it is
vim (Vi IMproved) is a modal, keyboard-driven text editor written in C and maintained since 1991 by Bram Moolenaar (and, since 2023, by a core team led by Christian Brabandt). It is the default visual editor on most Unix systems and runs comfortably over SSH, making it the editor most people learn for editing config files on a remote server. Reach for it when you want efficient, mouse-free text manipulation in a terminal; for a modernised fork with sane defaults, Lua scripting, and Tree-sitter, use neovim instead — most of the keybindings below apply unchanged.
The latest stable line is Vim 9.2 (Feb 2026), which adds experimental Wayland support, a GTK 4 GUI backend, native Windows dark mode, XDG Base Directory support, a vertical tab panel, and Vim9-script enhancements (enums, generic functions, tuple types, protected _new() constructors). Insert-mode completion gained fuzzy matching, CTRL-X CTRL-R (complete from register), and completeopt flags nosort / nearest. Neovim 0.11 (Mar 2025) makes the built-in LSP client first-class via vim.lsp.config() / vim.lsp.enable() (no plugin manager required), and rewrites tree-sitter highlighting, folding, and injected-query iteration as asynchronous — large-file startup is dramatically faster. Helix 25.01 is the most popular post-modern alternative if Vim's grammar order feels backwards: it flips to selection-first (noun-verb), bundles LSP / tree-sitter / DAP, and ships sane defaults out of the box.
Install
# Debian/Ubuntu (full feature build with clipboard + Python)
sudo apt install vim-gtk3
# Fedora
sudo dnf install vim-enhanced
# macOS (Homebrew)
brew install vim # Vim 9.2
brew install --cask macvim
# Alternative: neovim (0.11+)
sudo apt install neovim # or: brew install neovim
# Alternative: helix (post-modern modal, 25.01+)
brew install helix # or: sudo apt install helix
# Check version
vim --version | head -n 1
nvim --version | head -n 1
hx --version
Output:
VIM - Vi IMproved 9.2 (2026 Feb 13, compiled ...)
NVIM v0.11.0
helix 25.01 (...)
Configuration
Vim reads ~/.vimrc (or, on XDG-aware Vim 9.2+ builds, ~/.config/vim/vimrc); plugins live under ~/.vim/. Neovim reads ~/.config/nvim/init.lua (preferred) or ~/.config/nvim/init.vim, with plugins under ~/.local/share/nvim/. Helix reads ~/.config/helix/config.toml and languages.toml. Run :version (Vim/Neovim) or hx --health (Helix) to confirm which config files are being loaded and which features are compiled in.
# Vim 9.2 — files searched, in order
~/.vimrc
~/.vim/vimrc
$XDG_CONFIG_HOME/vim/vimrc # new in 9.2
# Neovim 0.11
~/.config/nvim/init.lua # preferred
~/.config/nvim/init.vim # legacy / Vimscript
# Helix 25.01
~/.config/helix/config.toml
~/.config/helix/languages.toml
# Inspect which files were sourced
vim --startuptime /tmp/vim.log +q && head /tmp/vim.log
nvim --startuptime /tmp/nvim.log +q && head /tmp/nvim.log
hx --health
Output (vim --startuptime excerpt):
000.012 000.012: --- VIM STARTING ---
001.842 000.318: sourcing /home/alice/.vimrc
Syntax
vim is invoked with one or more filenames; opening with no argument shows the start screen. The + flag jumps to a line or pattern, and -O / -o opens multiple files in vertical or horizontal splits.
vim FILE...
vim +42 FILE # open at line 42
vim +/pattern FILE # open at first match
vim -O file1 file2 # vertical splits
vim -p file1 file2 # tabs
vim -R FILE # read-only (like `view`)
Output: (none — exits 0 on success)
Modes
Vim is modal: the same key has different meanings depending on the mode you are in. Most editing is done in Normal mode, where letters trigger commands; text is typed in Insert mode; selections are made in Visual mode; long commands are typed in Command-line mode after :. Press Esc (or Ctrl-[) to return to Normal from any other mode.
| Mode | Enter from Normal | Exit | Purpose |
|---|---|---|---|
| Normal | (default) | — | Navigate, run commands |
| Insert | i a o I A O | Esc | Type text |
| Visual | v (char) V (line) Ctrl-v (block) | Esc | Select region |
| Command-line | : / ? | Enter or Esc | Run ex command or search |
| Replace | R | Esc | Overwrite as you type |
| Terminal | :terminal | Ctrl-\ Ctrl-n | Embedded shell (vim 8+) |
i Insert before cursor
a Append after cursor
I Insert at first non-blank of line
A Append at end of line
o Open new line below and insert
O Open new line above and insert
Output: (none — exits 0 on success)
Movement
Vim's strength is composable motion. Movement keys are commands in their own right, but they also act as the object of an operator (see "Verb-noun grammar"). Learn h j k l first, then layer in word, line, paragraph, and screen motions.
| Key | Move |
|---|---|
h j k l | left, down, up, right |
w / W | next word / WORD (whitespace-separated) |
b / B | previous word / WORD |
e / E | end of word / WORD |
0 | start of line |
^ | first non-blank character of line |
$ | end of line |
gg | first line of file |
G | last line of file |
42G or :42 | line 42 |
Ctrl-d / Ctrl-u | half-page down / up |
Ctrl-f / Ctrl-b | full page down / up |
H M L | top, middle, bottom of screen |
% | matching bracket / paren |
* / # | next / previous occurrence of word under cursor |
f<char> / F<char> | jump to next/previous <char> on line |
t<char> / T<char> | jump just before next/previous <char> |
; / , | repeat last f/t forward / backward |
# In Normal mode, these keys move the cursor without leaving Normal mode:
gg # top of file
G # bottom of file
42G # line 42
$ # end of line
* # find next occurrence of word under cursor
Output: (none — exits 0 on success)
Verb-noun grammar
Vim commands compose like English: an operator (verb) plus a motion or text object (noun) acts on a region. d (delete) + w (word) = "delete word"; c (change) + i" (inside double-quotes) = "change inside quotes". A leading count repeats the whole thing: 3dw = "delete three words". Mastering this grammar is the single biggest productivity unlock in Vim.
| Operator | Meaning |
|---|---|
d | delete (cuts to register) |
c | change (delete then enter Insert) |
y | yank (copy) |
> / < | indent right / left |
= | auto-indent |
gu / gU | lowercase / uppercase |
gq | format (wrap) |
! | filter through external command |
# Examples (typed in Normal mode):
dd # delete current line
3dd # delete three lines
dw # delete to start of next word
d$ # delete to end of line (synonym: D)
ciw # change inner word (delete word, enter Insert)
ci" # change inside double-quotes
ca( # change a parenthesised region (including the parens)
yip # yank inner paragraph
>ap # indent a paragraph
gUiw # uppercase inner word
=ip # auto-indent paragraph
!!sort # filter current line through `sort`
Output: (none — exits 0 on success)
Text objects
A text object is a region defined by a delimiter or structure — a word, a paragraph, a quoted string, an HTML tag. Combined with an operator, they let you edit by meaning rather than position. The prefix i means inner (excluding delimiters) and a means a / around (including delimiters).
| Object | What it selects |
|---|---|
iw / aw | inner / a word |
iW / aW | inner / a WORD (whitespace-separated) |
is / as | inner / a sentence |
ip / ap | inner / a paragraph |
i" / a" | inside / around double quotes |
i' / a' | inside / around single quotes |
i`` / a`` | inside / around backticks |
i( i) ib | inside parentheses |
i{ i} iB | inside curly braces |
i[ i] | inside square brackets |
it / at | inside / a tag (HTML/XML) |
# Practical edits:
vi" # visually select text inside double quotes
ci{ # delete everything inside { ... } and enter Insert
ya( # yank including parentheses
dat # delete an HTML tag and its contents
Output: (none — exits 0 on success)
Insert-mode shortcuts
A handful of keys still work in Insert mode and prevent constant trips back to Normal. They let you correct typos, indent, and paste registers without breaking flow.
| Key | Action |
|---|---|
Ctrl-w | Delete previous word |
Ctrl-u | Delete to start of line |
Ctrl-h | Backspace (works in all terminals) |
Ctrl-t / Ctrl-d | Indent / unindent current line |
Ctrl-r {reg} | Paste from register {reg} |
Ctrl-r = | Insert result of an expression |
Ctrl-n / Ctrl-p | Keyword completion (next / previous) |
Ctrl-x Ctrl-f | Filename completion |
Ctrl-o {cmd} | Run one Normal-mode command, then return to Insert |
# In Insert mode, typing the date:
Ctrl-r =strftime("%Y-%m-%d")<Enter>
Output:
2026-05-24
Search and substitute
/pattern searches forward, ?pattern backward; n and N repeat the search in the same / opposite direction. :s (substitute) replaces text using the same regex flavour. By default, :s is line-scoped and single-shot — add ranges and flags to broaden the effect.
/error # search forward for "error"
?TODO # search backward for "TODO"
n / N # next / previous match
:s/foo/bar/ # replace first foo on current line
:s/foo/bar/g # all foo on current line
:%s/foo/bar/g # all foo in file
:%s/foo/bar/gc # ...with confirmation per match
:5,20s/foo/bar/g # only lines 5–20
:'<,'>s/foo/bar/g # only the visual selection
# Case-insensitive for a single match
:%s/error/fail/gi
# Use word boundaries
:%s/\<log\>/trace/g
Output: (none — exits 0 on success)
Toggle
set ignorecaseandset smartcasein~/.vimrcso searches are case-insensitive unless the pattern contains an uppercase letter — the most useful pair of defaults in the editor.
Visual mode
Visual mode selects a region first and then applies an operator. v selects character-wise, V line-wise, and Ctrl-v block-wise (rectangular). Block mode is the trick behind editing multiple lines at once — type I/A after Ctrl-v to insert/append text at the same column on every selected line.
v # start char-wise visual
V # start line-wise visual
Ctrl-v # start block-wise visual
# Inside Visual mode:
o # jump cursor to the other end of the selection
gv # re-select the previous Visual region
Output: (none — exits 0 on success)
Block-edit recipe — comment three lines:
Ctrl-v # start block selection
jj # extend down two lines
I# <Esc> # insert "# " at the start of every selected line
Output: (none — exits 0 on success)
Registers
Every yank and delete goes into a register; pasting (p / P) reads from one. Registers are addressed with " plus a single character: "a–"z for named registers, "+ for the system clipboard, "* for the X11 PRIMARY selection, "0 for the most-recent yank (not deletes), "_ for the black hole (drops the text).
| Register | Contents |
|---|---|
"" | Default (unnamed) — last delete or yank |
"0 | Last yank only |
"1–"9 | Numbered delete history |
"a–"z | Named (uppercase appends instead of overwriting) |
"+ | System clipboard |
"* | X11 PRIMARY selection |
"_ | Black hole — discard text |
": | Last : command |
"/ | Last search pattern |
"ayy # yank current line into register a
"Ayy # append current line to register a
"ap # paste from register a
"+y$ # yank to end-of-line into system clipboard
"+p # paste from system clipboard
"_dd # delete a line WITHOUT clobbering the unnamed register
:registers # view all register contents
Output (:registers):
Type Name Content
l "" import sys\n
l "0 import sys\n
c "1 bad-line\n
l "a def main():\n return 0\n
c "+ ...
Marks and jumps
A mark is a named position in a file (or across files). Set with m{letter} and jump back with '{letter} (line) or `{letter} (exact column). Lowercase marks are local to a buffer; uppercase marks are global across buffers. Vim also keeps an automatic jump list (Ctrl-o back, Ctrl-i forward) and a change list (g; back, g, forward).
ma # set local mark a at cursor
'a # jump to line of mark a
`a # jump to exact position of mark a
mA # set global mark A (across files)
'A # jump back to file+line of mark A
Ctrl-o # jump backward in jump list
Ctrl-i # jump forward in jump list
'' # jump to position before the last jump
`. # jump to position of last change
gi # re-enter Insert mode at the last edit point
Output: (none — exits 0 on success)
Windows, buffers, and tabs
A buffer is an in-memory copy of a file, a window is a viewport onto a buffer, and a tab page is a layout of windows. Most editor work happens in a single tab with multiple split windows; tabs are best reserved for unrelated workspaces.
| Key | Action |
|---|---|
:e FILE | edit a file (loads it as a new buffer) |
:ls or :buffers | list buffers |
:b NAME or :bNUM | switch to buffer by name fragment or number |
:bd | delete current buffer |
Ctrl-w s | split horizontally |
Ctrl-w v | split vertically |
Ctrl-w h/j/k/l | move to split in direction |
Ctrl-w = | equalise split sizes |
Ctrl-w c | close split |
Ctrl-w o | close all other splits |
:tabnew | open a new tab |
gt / gT | next / previous tab |
:tabclose | close current tab |
# Inside Vim:
:e config.yaml # open another file
:vsplit Makefile # vertical split, edit Makefile
:b ma<Tab> # tab-completes to Makefile
:ls # list all loaded buffers
Output (:ls):
1 %a "config.yaml" line 1
2 h "Makefile" line 1
3 "src/main.py" line 42
Macros
A macro records a sequence of keystrokes into a register and replays them on demand — perfect for repetitive multi-line edits. Start recording with q{letter}, perform the edits, then stop with q. Replay with @{letter}; repeat the last macro with @@. Macros are just register contents, so they survive across sessions if saved with :wviminfo.
# Recipe: turn each line of CSV into a JSON object
# alice,40
# bob,32
# ...into
# {"name": "alice", "age": 40},
# {"name": "bob", "age": 32},
qa # start recording into register a
I{"name": "<Esc> # insert prefix
f, # jump to the comma
a", "age": <Esc> # replace comma with key
A},<Esc> # append closing brace + comma
j # move to next line
q # stop recording
@a # play once
99@a # play up to 99 times (stops if it errors)
Output:
{"name": "alice", "age": 40},
{"name": "bob", "age": 32},
A macro that errors mid-playback stops the whole loop — useful as a built-in "stop when done" signal. End each iteration with a motion that errors at end of file (like
jpast the last line).
Folding
Folding collapses regions of text into a single line. Vim has several fold methods (syntax, indent, marker, manual, expr); the most portable for ad-hoc folds is marker, which uses {{{ / }}} in comments.
:set foldmethod=indent # fold by indentation level
:set foldmethod=syntax # fold by syntax (per filetype)
:set foldmethod=marker # fold between {{{ and }}}
zo / zc # open / close fold under cursor
za # toggle fold under cursor
zR # open all folds
zM # close all folds
zj / zk # jump to next / previous fold
Output: (none — exits 0 on success)
:vimgrep and quickfix
:vimgrep searches files using Vim's regex engine and stores results in the quickfix list, a navigable list of file:line locations. :copen opens the list in a window; :cnext / :cprev jump between matches.
:vimgrep /TODO/ **/*.py # search recursively for TODO in Python files
:copen # open the quickfix window
:cnext / :cprev # next / previous match
:cfirst / :clast # first / last match
# Use an external tool (faster) and pipe results into quickfix:
:set grepprg=rg\ --vimgrep\ --no-heading\ --smart-case
:grep "TODO" .
:copen
Output (:copen after :vimgrep /TODO/ **/*.py):
src/auth/login.py|42| # TODO: rate-limit
src/api/routes.py|118| # TODO: validate input
src/utils/cache.py|7| # TODO: implement expiry
Command-line ranges
Ex commands (:-commands) accept a range of lines before the command name. Ranges combine numeric lines, marks, search patterns, and special tokens like . (current line), $ (last line), and % (entire file).
| Range | Meaning |
|---|---|
:5 | line 5 |
:5,20 | lines 5–20 |
:.,+10 | current line + next 10 |
:-5,. | five lines back through current |
:% | whole file |
:'<,'> | visual selection |
:'a,'b | from mark a to mark b |
:/start/,/end/ | from line matching /start/ to line matching /end/ |
:10,20d # delete lines 10–20
:.,+5y # yank current + next 5 lines
:%s/old/new/g # substitute in whole file
:'<,'>!sort -u # filter visual selection through sort -u
:/BEGIN/,/END/s/foo/bar/g # substitute only between BEGIN and END markers
Output: (none — exits 0 on success)
Reading and writing
A buffer is only persisted to disk with :w. Use :wa to write all modified buffers; :q quits a window; :wqa writes everything and exits Vim. :r reads a file or command output into the current buffer.
:w # write current buffer
:w newname.txt # save a copy under another name
:wa # write all modified buffers
:q # quit current window
:q! # force-quit, discarding changes
:wq # write + quit
:wqa # write all + quit Vim
:x # like :wq, but only writes if modified
:r README.md # read README.md into the buffer below the cursor
:r !date # insert output of `date` command
:r !git diff --stat # insert a git summary
Output: (none — exits 0 on success)
A high-value baseline ~/.vimrc
Below is a small ~/.vimrc that addresses the most common annoyances of stock Vim: smart search, sane indentation, persistent undo, a visible cursor line, and clipboard integration. Drop this in as a starting point and grow from there.
" ~/.vimrc — minimal but useful baseline
" --- General ---------------------------------------------------------
set nocompatible " don't pretend to be vi
set hidden " allow background buffers with changes
set mouse=a " mouse in all modes
set clipboard=unnamedplus " yank/paste go through system clipboard
set undofile " persistent undo across sessions
set undodir=~/.vim/undo
set updatetime=300 " faster swap / CursorHold
" --- Display ---------------------------------------------------------
syntax on
filetype plugin indent on
set number relativenumber " hybrid line numbers
set cursorline " highlight current line
set scrolloff=5 " keep 5 lines of context
set signcolumn=yes " avoid jitter from gitgutter / LSP
" --- Search ----------------------------------------------------------
set ignorecase smartcase " case-insensitive unless pattern has uppercase
set incsearch hlsearch " incremental + highlight matches
nnoremap <Esc><Esc> :nohlsearch<CR>
" --- Indentation -----------------------------------------------------
set expandtab " spaces, not tabs
set shiftwidth=4 softtabstop=4 tabstop=4
set autoindent smartindent
" --- Splits ----------------------------------------------------------
set splitbelow splitright " new splits open below/right
nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l
" --- Leader-key shortcuts -------------------------------------------
let mapleader = " "
nnoremap <leader>w :w<CR>
nnoremap <leader>q :q<CR>
nnoremap <leader>e :e <C-r>=expand('%:p:h').'/'<CR>
Output: (none — exits 0 on success)
Plugins (vim-plug)
For anything beyond a baseline ~/.vimrc, a plugin manager keeps the install simple. vim-plug is the most common choice — single file, declarative, and parallel installer. Add Plug lines, save, then run :PlugInstall.
# Install vim-plug
curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
Output: (none — exits 0 on success)
" ~/.vimrc — plugin block
call plug#begin('~/.vim/plugged')
Plug 'tpope/vim-surround' " ys/cs/ds to add/change/delete surrounding chars
Plug 'tpope/vim-commentary' " gcc to toggle comment
Plug 'tpope/vim-fugitive' " :Git
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim' " :Files :Rg :Buffers
Plug 'editorconfig/editorconfig-vim'
call plug#end()
Output: (none — exits 0 on success)
Neovim built-in LSP (0.11+)
Neovim 0.11 promoted the LSP client to a first-class API: register a server with vim.lsp.config() and turn it on with vim.lsp.enable() — no plugin manager, no nvim-lspconfig required for common servers. Combined with the async tree-sitter rewrite (highlighting, folding, and injected queries no longer block the UI), this is the biggest reason to prefer Neovim over Vim 9.2 for daily editing of large files.
-- ~/.config/nvim/init.lua
vim.lsp.config('luals', {
cmd = { 'lua-language-server' },
filetypes = { 'lua' },
root_markers = { '.luarc.json', '.git' },
})
vim.lsp.enable('luals')
-- Default LSP keymaps shipped with 0.11
-- grn = rename, gra = code action, grr = references, gri = implementation
-- K = hover, <C-s> in insert = signature help
Output: (none — exits 0 on success)
Helix as an alternative
helix is a post-modern modal editor written in Rust that flips Vim's grammar order: you make the selection first (the noun), then apply an action (the verb) — so w immediately highlights the next word and d deletes the highlight. LSP, tree-sitter, and DAP are built in; there is no plugin system to configure. Reach for it when you want a Vim-like keyboard model without spending a weekend on ~/.vimrc.
hx FILE # open a file
# Inside helix:
# w select to next word (noun first)
# d delete the selection (then verb)
# x select current line
# % select whole file
# space + f file picker
# space + / global search
# :w write
# :q quit
Output: (none — exits 0 on success)
| Feature | Vim 9.2 | Neovim 0.11 | Helix 25.01 |
|---|---|---|---|
| Grammar | verb-noun (dw) | verb-noun (dw) | noun-verb (wd) |
| Scripting | Vimscript, Vim9script, Python | Lua (first-class), Vimscript | TOML config only |
| Built-in LSP | external plugin | yes (vim.lsp.config) | yes |
| Built-in tree-sitter | partial | yes (async) | yes |
| DAP | external plugin | external plugin | experimental built-in |
| Plugin ecosystem | huge (vim-plug, etc.) | huge (lazy.nvim) | none — built-ins only |
| Config file | ~/.vimrc | ~/.config/nvim/init.lua | ~/.config/helix/config.toml |
Common pitfalls
- "How do I quit?" —
:qto quit,:q!to force-quit with unsaved changes,:wqto save and quit. - Stuck in Insert mode — press
Esc(orCtrl-[, which is identical on most terminals). - Paste reformats badly — set
:set pastebefore pasting from outside Vim, then:set nopaste. Modern Vim withset clipboard=unnamedplusmakes this unnecessary. - Caps-lock + accidentally-typed
ZZsaves and quits.ZQdiscards changes and quits. - Substituting forward slashes —
:s/\/usr\/bin/\/opt\/bin/is unreadable. Use a different delimiter::s#/usr/bin#/opt/bin#. :s/.../.../gdoesn't replace across the whole file — by default it acts on the current line only. Prefix with%to target the whole file::%s/foo/bar/g.- Macros that don't quite work — record into a register, then
"apto paste the macro into the buffer and edit it as text. Re-yank with"ay$to save the corrected version. - Two-key chords feel slow — set
set timeoutlen=500to shorten the wait for mapped chord completion.
Real-world recipes
Edit a file picked with fzf
Combine fzf (fuzzy finder) with vim to launch the editor on the result. Useful at the shell prompt to jump straight into a file without typing its path.
vim "$(fzf)"
# Restrict to tracked files in a git repo
vim "$(git ls-files | fzf)"
Output: (none — exits 0 on success)
Search-and-replace across many files
For a project-wide rename, use shell tooling to enumerate files and sed to substitute — or open the files in Vim's quickfix list and run :cdo to apply a Vim substitute across every match.
# In Vim:
:grep "old_name" -r . # populate quickfix
:cdo s/old_name/new_name/g | update
Output: (none — exits 0 on success)
Edit binary files as hex
Use xxd round-trip to view and modify binary content. Open the file, convert to hex, edit, then convert back before saving.
vim -b /home/alice/firmware.bin
# Inside Vim:
:%!xxd " convert buffer to hex dump
" edit the dump...
:%!xxd -r " convert back
:w
Output: (none — exits 0 on success)
Diff two files
Vim's built-in diff mode highlights differences side-by-side and supports per-hunk operations: do (diff obtain — pull change from the other side) and dp (diff put — push change to the other side).
vim -d before.conf after.conf # equivalent: vimdiff before.conf after.conf
# Inside diff mode:
]c / [c # next / previous hunk
do # pull change from other window
dp # push change to other window
:diffupdate # recompute the diff
Output: (none — exits 0 on success)
Open at a specific line from compiler output
When a stack trace or compiler error includes path:line:col, jump straight to that location.
vim +42 src/main.py # open at line 42
vim +/^def\ main src/main.py # open at the first `def main`
# From a grep result like src/app.py:118:42: some text
file=src/app.py; line=118
vim "+$line" "$file"
Output: (none — exits 0 on success)
Use Vim as git's editor
Configure git to use Vim for commit messages, rebases, and merges. The +startinsert argument auto-enters Insert mode so you can start typing immediately.
git config --global core.editor "vim"
# Or, with auto-insert on commit messages:
git config --global core.editor "vim '+startinsert'"
Output: (none — exits 0 on success)
vimtutoris a 30-minute interactive tutorial bundled with Vim. Run it once a year — there's always a motion or text-object you've forgotten about.
[!WARN] Avoid
:set pastemappings to a function key on modern Vim —'paste'disables abbreviations and indent-on-paste, which surprises people who don't toggle it off afterwards.set clipboard=unnamedplusis the modern alternative.