1

I'm trying to write a function + map that works on a visual selection. My function just prints out the marks right now:

let g:count = 0
function! s:plink(...) abort
    let g:count = g:count + 1
    echomsg printf("%d %s %d %s %d", g:count, a:1, line(a:1), a:2, line(a:2))
endfunction
vnoremap <Leader>r :call <SID>plink("'<", "'>")<CR>

I was surprised to find out that my function is being called once per line when I invoke it as shift-V, select lines, \r:

1 '< 80 '> 84
2 '< 80 '> 84
3 '< 80 '> 84
4 '< 80 '> 84
5 '< 80 '> 84

How do I make this snippet call my code only once when I invoke it?

1

When you start an ex-command (:) from visual mode, Vim automatically prepends '<,'> to the command.

Function calls can accept ranges, of which the above is an example: when given them, they are called once for each line.

One fix is to get rid of the range when the function is called:

xnoremap <Leader>r :<C-u>call ...

(Note that I’ve switched to xnoremap to only map in visual mode—vnoremap includes select mode, which generally is undesirable.)


The alternative is to declare the function with the range attribute (see :help func-range).

Then the mapping is unchanged, but the declaration must take two arguments (a:firstline and a:lastline).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.