Vim Tips Wiki
Advertisement
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
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

Usage

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.

Examples:

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

Script

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() . ' '
  endif
  if a:docomment
    exe "normal! '" . a:a . "_\<C-V>'" . a:b . 'I' . b:comment
  else
    exe "'".a:a.",'".a:b . 's/^\(\s*\)' . escape(b:comment,'/') . '/\1/e'
  endif
endfunction

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

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

" 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 ';'
  endif
  return ''
endfunction

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>

Explanation

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 also

References

Comments

Advertisement