vimtricks.wiki Concise Vim tricks, one at a time.

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 expression
  • j — the key being remapped
  • (v:count == 0 ? 'gj' : 'j') — if no count is given, use gj (move by display line); if a count is given (e.g., 5j), use regular j (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> with pumvisible() 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

Next

How do I ignore whitespace changes when using Vim's diff mode?