How do I create a custom Vim operator that works with any motion or text object?
Answer
:set opfunc and g@
Explanation
Vim's operatorfunc option lets you define your own operators — just like the built-in d, y, or c — that accept any motion or text object. Setting opfunc to a function name and then pressing g@ triggers that function with information about the selected region.
How it works
- Write a Vimscript function that accepts a single string argument (
"char","line", or"block"), describing the selection type - Vim sets marks
'[and']to the start and end of the operated region before calling your function - Map a key to
:set opfunc=YourFunc<CR>g@— theg@awaits the next motion
Example
An operator that sorts lines in the motion:
function! SortLinesOp(type) abort
'[,']sort
endfunction
nmap <silent> gs :set opfunc=SortLinesOp<CR>g@
vmap <silent> gs :<C-u>call SortLinesOp('line')<CR>
Now gsip sorts the current paragraph, gs3j sorts the next 3 lines, and gsG sorts from here to end of file. The same operator works with any motion without writing separate logic for each one.
Tips
- Always set
opfuncimmediately beforeg@in the same mapping (as shown), so the function name is fresh for each invocation - Inside the function, use
'[and']marks with:norm,:execute, or direct range commands to act on the text - For
"char"operations you may needgetpos("'[")/getpos("']")to work character-precisely - This is the technique behind popular plugins like
vim-commentary(gc),vim-surround(ds,cs), andvim-exchange(cx)