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

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

  1. Write a Vimscript function that accepts a single string argument ("char", "line", or "block"), describing the selection type
  2. Vim sets marks '[ and '] to the start and end of the operated region before calling your function
  3. Map a key to :set opfunc=YourFunc<CR>g@ — the g@ 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 opfunc immediately before g@ 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 need getpos("'[")/getpos("']") to work character-precisely
  • This is the technique behind popular plugins like vim-commentary (gc), vim-surround (ds, cs), and vim-exchange (cx)

Next

How do I match a pattern only when it is preceded or followed by another pattern, without including that context in the match?