How do I create a normal mode mapping that correctly captures and passes a count prefix to a function?
Answer
nnoremap <key> :<C-u>call MyFunc(v:count)<CR>
Explanation
When writing custom mappings that call Vimscript functions, a common pitfall is that any count you type before the key (e.g., 5<Leader>j) gets prepended to the command line as a number, corrupting the command. The fix is <C-u>, which clears the command line before the : command runs, while v:count still holds the count you typed.
How it works
v:count— set by Vim to whatever count was typed before the mapping key (0 if none)v:count1— same but defaults to 1 instead of 0 when no count is given<C-u>in command mode — deletes everything from the cursor to the start of the line, clearing any numeric prefix that Vim inserted- Without
<C-u>: typing5<key>produces:5call MyFunc(5)which is a range command — not what you want
Example
" Scroll down N half-pages, defaulting to 1
nnoremap <Leader>d :<C-u>call ScrollHalf(v:count1)<CR>
function! ScrollHalf(count)
execute 'normal! ' . (a:count * &lines / 2) . 'j'
endfunction
Pressing 3<Leader>d calls ScrollHalf(3). Pressing <Leader>d alone calls ScrollHalf(1).
Tips
- Use
v:count1(minimum 1) instead ofv:count(minimum 0) when the count should default to 1 - This pattern is essential for plugin mappings that accept counts
- The same issue applies when calling
execute 'normal! ...'— use<C-u>consistently