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

How do I create a mapping that does different things based on context?

Answer

nnoremap <expr> j (v:count == 0 ? 'gj' : 'j')

Explanation

The <expr> map modifier turns a mapping's right-hand side into a Vimscript expression that is evaluated at the time the key is pressed, with its return value used as the actual keystrokes to execute. This enables smart, context-sensitive mappings without writing a full function.

How it works

  • <expr> is placed between the map command and the lhs key
  • The rhs is any Vimscript expression that returns a string
  • The returned string is fed back to Vim as if you typed those characters
  • v:count holds the count prefix typed before the key (0 if none)

The classic example remaps j and k to move by display lines (gj/gk) when no count is given, but reverts to logical-line movement when a count is provided (so 5j still jumps 5 real lines, enabling relative line numbers to work correctly):

nnoremap <expr> j (v:count == 0 ? 'gj' : 'j')
nnoremap <expr> k (v:count == 0 ? 'gk' : 'k')

Example

Another common use: a smart <CR> in the command window vs. normal buffers:

nnoremap <expr> <CR> &buftype ==# 'quickfix' ? '<CR>' : 'o<Esc>'

This opens a new line with o in normal buffers, but lets <CR> jump to the quickfix entry in the quickfix window.

Tips

  • The expression must return a string (or an empty string '' to do nothing)
  • Use mode() inside the expression to branch on the current mode when using map (without n/i/v prefix)
  • Combine with has() or exists() to guard against missing features
  • For more complex logic, call a function: nnoremap <expr> <Tab> MyTabKey()

Next

How do I build a macro programmatically using Vimscript instead of recording it?