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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With