Vim Tips Wiki

Commenting with opfunc

Redirected from VimTip1570

1,624pages on
this wiki
Add New Page
Talk0 Share
Tip 1570 Printable Monobook Previous Next

created 2008 · complexity basic · author Jlepak · version 7.0

This tip uses the opfunc option to define two operators. Assuming the default backslash leader key, the operators are:

  • \c    to comment lines (insert a comment string before each line)
  • \C    to uncomment lines


For example, put the cursor anywhere in the def block in the following Python code:

class Example:

    def f(self, x):
        if x < 5:
            print "Pointless function."
        return 0

The command yip (yank inner paragraph) would copy the block. In a similar manner, the command \cip will comment-out the block, resulting in:

class Example:

    # def f(self, x):
    #     if x < 5:
    #         print "Pointless function."
    #     return 0

Later, you could remove the comment signifiers with \Cip.

An operator can be used in two ways:

  • Invoke the operator, then enter a movement command. or
  • Visually select a block, then invoke the operator.


  • \ciB    comment inner block (between braces)
  • \c}    comment to end paragraph
  • \cG    comment to end buffer
  • Vjjj\c    comment visually-selected lines


Here's the code. It only handles linewise comments.

" Comment or uncomment lines from mark a to mark b.
function! CommentMark(docomment, a, b)
  if !exists('b:comment')
    let b:comment = CommentStr() . ' '
  if a:docomment
    exe "normal! '" . a:a . "_\<C-V>'" . a:b . 'I' . b:comment
    exe "'".a:a.",'".a:b . 's/^\(\s*\)' . escape(b:comment,'/') . '/\1/e'

" Comment lines in marks set by g@ operator.
function! DoCommentOp(type)
  call CommentMark(1, '[', ']')

" Uncomment lines in marks set by g@ operator.
function! UnCommentOp(type)
  call CommentMark(0, '[', ']')

" Return string used to comment line for current filetype.
function! CommentStr()
  if &ft == 'cpp' || &ft == 'java' || &ft == 'javascript'
    return '//'
  elseif &ft == 'vim'
    return '"'
  elseif &ft == 'python' || &ft == 'perl' || &ft == 'sh' || &ft == 'R'
    return '#'
  elseif &ft == 'lisp'
    return ';'
  return ''

nnoremap <Leader>c <Esc>:set opfunc=DoCommentOp<CR>g@
nnoremap <Leader>C <Esc>:set opfunc=UnCommentOp<CR>g@
vnoremap <Leader>c <Esc>:call CommentMark(1,'<','>')<CR>
vnoremap <Leader>C <Esc>:call CommentMark(0,'<','>')<CR>


A custom operator can be defined using visual-mode maps (to apply the operator to a selection), and using the operatorfunc (opfunc) option (to apply the operator to a movement).

The g@ operator can be used in a map to define your own operator. When g@ is invoked, the function defined by the opfunc option is called with an argument indicating the type of motion ("line", "char" or "block"). In addition, the '[ and '] marks identify the start and end positions of the motion.

You can let the script determine the comment string from the filetype, or you can define the buffer-local variable comment, for example:

:let b:comment='#---'

See alsoEdit



Ad blocker interference detected!

Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.

Also on Fandom

Random Wiki