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?