How do I create a key mapping that behaves differently depending on context?
Answer
:nnoremap <expr> j (v:count == 0 ? 'gj' : 'j')
Explanation
Expression mappings use the <expr> flag to evaluate a Vimscript expression at the time the key is pressed. The expression's return value becomes the actual key sequence executed. This lets you create context-sensitive mappings that adapt their behavior based on mode, count, cursor position, or any other condition.
How it works
:nnoremap <expr>— creates a non-recursive normal mode mapping that evaluates an expressionj— the key being remapped(v:count == 0 ? 'gj' : 'j')— if no count is given, usegj(move by display line); if a count is given (e.g.,5j), use regularj(move by actual line)
The expression must return a string of key sequences. Vim evaluates it fresh on every keypress.
Example
Add these to your vimrc:
" Move by display lines when no count, by actual lines with count
nnoremap <expr> j (v:count == 0 ? 'gj' : 'j')
nnoremap <expr> k (v:count == 0 ? 'gk' : 'k')
Now j and k move visually through wrapped lines, but 5j still jumps exactly 5 actual lines — useful with relativenumber.
Tips
- Use
<expr>withpumvisible()to make Tab behave differently during completion::inoremap <expr> <Tab> pumvisible() ? '<C-n>' : '<Tab>' - Access
mode(),col('.'),line('.'), or any Vimscript function in the expression - Return
"\<Ignore>"to make the mapping do nothing under certain conditions - Works with all mapping commands:
nnoremap,inoremap,vnoremap,cnoremap