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

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 call
  • g@{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 last g@ 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 last g@ 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@ and nmap <leader>xx V:call MyFunc('line')<CR> for a line-shortcut

Next

How do I build a macro programmatically using Vimscript instead of recording it?