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

How do I create a Vim mapping where the keys it produces are computed dynamically at runtime?

Answer

:nnoremap <expr> {key} {expression}

Explanation

The <expr> argument to any map command (:nmap, :inoremap, etc.) tells Vim to evaluate the right-hand side as a Vimscript expression each time the mapping is triggered, rather than using it as a literal key sequence. This enables mappings that change behavior based on context.

How it works

  • <expr> must appear before the key and expression in the :map command
  • The expression is evaluated as Vimscript and must return a string of keys to execute
  • The returned string is used exactly as if you had typed those keys — it can include mode-switching characters, function calls, or conditionals

Example

A smarter j that moves by display lines when the line is wrapped, or by real lines otherwise:

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

With no count prefix, j maps to gj (moves by visible line). With a count like 5j, it falls back to real-line j.

A mapping that inserts different text based on the current filetype:

:inoremap <expr> <Tab> (&filetype == 'python') ? '    ' : '\t'

Tips

  • Use <expr> with <silent> to suppress command-line echo: :nnoremap <silent> <expr> ...
  • The expression is not executed as an Ex command — return a key sequence string, not a command
  • Access Vim state freely: v:count, &option, mode(), col('.'), etc.
  • This is the clean alternative to using has('patch') guards or if statements around multiple mappings

Next

How do I quickly evaluate and print a Lua expression in Neovim without calling print()?