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 bufferVjjj\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='#---'