Simon
Simon

Reputation: 77

Using execute for visual command in vim

I know this must be something simple.

Why does vnoremap <leader>rl di[<esc>pa] wrap selected text in brackets, but:

vnoremap <leader>rl :call VisAddRefLink()<CR>

function! VisAddRefLink()
    execute "normal! di[\<esc>pa]"
endfunction

doesn't?!

Any help appreciated!

Upvotes: 2

Views: 254

Answers (2)

Ingo Karkat
Ingo Karkat

Reputation: 172530

Try this:

vnoremap <leader>rl :<C-u>call VisAddRefLink()<CR>

function! VisAddRefLink()
    execute "normal! gvdi[\<esc>pa]"
endfunction

The <C-u> in front of the call avoids that the mapping inserts the '<,'> visual range in front of it; we want the function called only one time, not once for every line in the range.

Inside the function, we need to re-establish the visual selection first before operating on it; the gv does that.

Upvotes: 2

Conner
Conner

Reputation: 31040

You need to make your function handle a range. One way of accomplishing this would be like this:

vnoremap <leader>rl :call VisAddRefLink()<CR>

function! VisAddRefLink() range
   exe a:firstline . "normal! ^i["
   exe a:lastline . "normal! $a]"
endfunction

The reason your example isn't working is because the exe doesn't operate on a visual selection per say. For example, try visually selection something and then doing :norm d. You'll notice it doesn't delete. If you add a range to your function like :help function-range-example it helps with visual selections by operating in a similar fashion (line by line). However, it still isn't a true visual selection. The range addition does allow you the a:firstline and a:lastline variables though, which can be used to accomplish this. You can also accomplish this with a single like in this manner:

vnoremap <leader>rl <esc>:norm! '<^x2Phr['>$x2pr]<cr>

This first uses <esc> to end the visual selection. Then it executes a normal command that will only run once. If the visual selection was left then it would run once for each line in the visual selection. Once it's run once it

'<^ jumps to the first line of the visual selection and to the first non-blank space on that line.

x2Phr[ deletes that character, pastes it twice in front, moves to the left so we're over the new character, and replaces it with the opening [

'>$ move to the last character on the last line of the visual selection

x2pr] same as before but in the opposite direction

As usual, there's more than one way to skin a cat, especially with vimscript. As you learn more you see a lot of possibilities for accomplishing things.

Upvotes: 2

Related Questions