Mappings โ :map, :noremap, and Friends
How to bind a keystroke to a command in every mode, and what the modifiers actually do.
Vim has one mapping system with a per-mode entry point. :nnoremap is the workhorse โ non-recursive normal-mode map. <silent>, <expr>, and <buffer> are the three modifiers that cover 90% of real mappings.
Mappings
A mapping binds a keystroke (or short sequence) to a command. It's how you build a personal layer on top of Vim's grammar โ leader shortcuts, plugin bindings, language-specific helpers. The mapping system has more knobs than most people realize, and most of the bugs in handwritten vimrcs come from picking the wrong knob.
Per-mode commands
Mappings are scoped to a mode. Picking the right command (instead of bare :map) is the single most important habit.
| Command | Mode it affects | When to use |
|---|---|---|
| :nmap | Normal | Bindings that act on the buffer from rest. The default for almost every leader mapping. |
| :imap | Insert | Live-while-typing shortcuts โ autopairs, abbreviation-like helpers, completion triggers. |
| :vmap | Visual and Select | Rarely what you want; the Select half eats keystrokes meant as text. Prefer xmap. |
| :xmap | Visual only (not Select) | Visual-mode bindings (e.g. > to indent and re-select). |
| :smap | Select only | Almost never. Select mode behaves like a text-replacing selection (think other editors). |
| :omap | Operator-pending | Custom motions and text objects. After d/c/y, your map fires. |
| :cmap | Command-line | Bindings on the : / / / ? prompt. |
| :tmap | Terminal-job | Bindings inside :terminal buffers (Neovim and newer Vim). |
| :map | Normal + Visual + Select + Op-pending | The bare form. Almost always too broad. |
| :map! | Insert + Command-line | The other broad form. Sometimes useful for Ctrl-chords you want everywhere you type. |
map vs noremap โ the one you almost always want
Every mode has a nore variant: :nnoremap, :inoremap, :vnoremap, etc. The nore prefix means non-recursive: the right-hand side is interpreted using Vim's built-in commands, not other mappings.
Without nore, your mapping can be re-mapped by another mapping. :nmap j gj then :nmap gj jjj will loop. With :nnoremap j gj, the gj on the right is the built-in gj, and the mapping is safe. Use nore everywhere unless you have a specific reason not to. "Specific reason" is almost always: you want to invoke another plugin's mapping deliberately.
The three modifiers that matter
| Modifier | What it does | When to use |
|---|---|---|
<silent> |
Don't echo the right-hand side on the command line as the mapping runs. | Almost always for mappings that call commands. Without it, the :somecmdEnter flicker is visible every keystroke. |
<expr> |
Evaluate the right-hand side as a Vimscript expression; the result is what gets typed. | Conditional mappings โ "if the popup menu is visible, do X; otherwise do Y." The classic <expr> use-case is wiring Tab for completion. |
<buffer> |
Mapping applies only in the current buffer. Stored on the buffer, gone when the buffer is wiped. | Filetype-specific mappings set from ftplugin/. Keeps your Python bindings out of your Markdown buffers. |
Modifiers go before the keystroke, in any order:
nnoremap <silent> <leader>w :write<CR>
inoremap <silent> <expr> <Tab> pumvisible() ? "\<C-n>" : "\<Tab>"
nnoremap <silent> <buffer> <leader>r :!python %<CR>
See also: Operator-Pending Mode, Vim Configuration, Setting Options ({key::set})