How do I create a custom operator that works with any motion in Vim?
Answer
:set operatorfunc=MyFunc<CR>g@{motion}
Explanation
Vim's operatorfunc and g@ let you define custom operators that accept any motion or text object, just like built-in operators d, c, and y. This is one of Vim's most powerful extensibility features, allowing you to create reusable operations that integrate seamlessly with Vim's grammar.
How it works
operatorfuncis set to a function name that will process the operated-on regiong@{motion}invokes that function over the given motion or text object- The function receives a
typeargument:'line','char', or'block' - Inside the function, the
'[and']marks delimit the operated region
Example
Define an operator that wraps text in parentheses:
function! WrapInParens(type)
let sel_save = &selection
let &selection = 'inclusive'
if a:type ==# 'char'
normal! `[v`]c()
normal! P
elseif a:type ==# 'line'
normal! `[V`]c()
normal! P
endif
let &selection = sel_save
endfunction
nmap <silent> gs :set operatorfunc=WrapInParens<CR>g@
vmap <silent> gs :<C-u>call WrapInParens(visualmode())<CR>
Now gsiw wraps a word in parentheses, gs$ wraps to end of line, and gsip wraps a paragraph.
Tips
- Always use
nmap(notnnoremap) for theg@mapping sinceg@is itself a mapping - Map the visual mode version separately to handle visual selections
- The pattern
set opfunc=... g@is idiomatic — it is how most plugin authors implement custom operators - See
:help :map-operatorfor the full documentation and more examples