It seems expression mappings are evaluated in advance of a macro being executed rather than being evaluated at the time that the mapped left hand side is encountered. Consider the following example:
function! X()
let line = line('.')
let col = col('.')
echomsg "Pressed x at (".l:line.", ".l:col.")"
return "x"
endfunction
nnoremap <expr> x X()
After sourcing this script, place your cursor at the start of the last line and record the macro fpx
. If you look in :messages
you’ll see “Pressed x at (8, 8).” If you then undo the change, return your cursor to the start of the last line, and play the recorded macro, you’ll see “Pressed x at (8, 1),” which shows the function is evaluated before the macro is executed.
This creates a surprising difference between behavior during recording and behavior during replay. Is it possible to circumvent this while still using an expression mapping?