vimtricks.wiki Concise Vim tricks, one at a time.

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

  • operatorfunc is set to a function name that will process the operated-on region
  • g@{motion} invokes that function over the given motion or text object
  • The function receives a type argument: '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 (not nnoremap) for the g@ mapping since g@ 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-operator for the full documentation and more examples

Next

How do I return to normal mode from absolutely any mode in Vim?