How do I create a custom Vim operator that works with any motion or text object?
Answer
g@
Explanation
Vim lets you define your own operators — commands that compose with any motion or text object just like d, y, or c. Set the operatorfunc option to a function name, then trigger it with g@ followed by any motion. The function receives the selection type ("char", "line", or "block") and can operate on the '[ and '] marks that Vim sets to the start and end of the motion's range.
How it works
:set operatorfunc=FuncName— designate the function to callg@{motion}— apply the operator over the motion (e.g.,g@w,g@ip,g@t>)- Inside the function,
'[and']are the start/end of the operated-on text - The
.(dot) command can repeat the lastg@invocation with the same motion
Example
Define a "comment-out" operator that prepends # to the operated lines:
function! CommentOut(type) abort
if a:type ==# 'line'
'[,']s/^/# /
else
'[,']s/^/# /
endif
endfunction
nnoremap <silent> gc :set operatorfunc=CommentOut<CR>g@
xnoremap <silent> gc :call CommentOut('line')<CR>
Now gcip comments out the inner paragraph, gc3j comments out 3 lines, and . repeats the last operation.
Tips
g@@repeats the lastg@call — useful for applying the operator a second time- For charwise operations, use
`[and`](backtick marks) instead of'[and']to get exact character positions - Always use
<silent>in the mapping to avoid echoing:set operatorfunc=...to the command line - Combine with
nmap <leader>x :set operatorfunc=MyFunc<CR>g@andnmap <leader>xx V:call MyFunc('line')<CR>for a line-shortcut