Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define a new Vim operator with a parameter?

Tags:

I have been looking to map a new operator in Vim that takes an extra parameter.

For example, we know that ciw will “cut inside word” and will put you into Insert mode. What I am looking for is having a custom action to replace c (for example, s) that takes movements like iw, but requires an extra parameter.

A trivial example would be:

Given a line in a text file 

Execute siw* in Normal mode (assuming the cursor is on the first column) for it to surround the first word with * like so:

*Given* a line in a text file 

I know, this is what the most excellent surround.vim plugin does. But I am just giving an example here, and looking for an answer as to how to get the mappings so that the above work.

I tried playing with onoremap and opfunc, but can’t seem to get them to play the way I want.

So, what I am looking for is a combination of motions plus operator pending mappings.

like image 965
alfredodeza Avatar asked Jan 24 '12 21:01

alfredodeza


1 Answers

Here is an example implementation of the command described in the question, for illustrative purposes.

nnoremap <silent> s :set opfunc=Surround<cr>g@ vnoremap <silent> s :<c-u>call Surround(visualmode(), 1)<cr>  function! Surround(vt, ...)     let s = InputChar()     if s =~ "\<esc>" || s =~ "\<c-c>"         return     endif     let [sl, sc] = getpos(a:0 ? "'<" : "'[")[1:2]     let [el, ec] = getpos(a:0 ? "'>" : "']")[1:2]     if a:vt == 'line' || a:vt == 'V'         call append(el, s)         call append(sl-1, s)     elseif a:vt == 'block' || a:vt == "\<c-v>"         exe sl.','.el 's/\%'.sc.'c\|\%'.ec.'c.\zs/\=s/g|norm!``'     else         exe el 's/\%'.ec.'c.\zs/\=s/|norm!``'         exe sl 's/\%'.sc.'c/\=s/|norm!``'     endif endfunction 

To get user input, the function InputChar() is used, assuming that the required argument is a single character.

function! InputChar()     let c = getchar()     return type(c) == type(0) ? nr2char(c) : c endfunction 

If it is necessary to accept a string argument, change the call to InputChar() in Surround() to the call to input(), instead.

like image 89
ib. Avatar answered Sep 20 '22 18:09

ib.