(New page: If you want to treat commenting lines of code just like deleting, whatever keystrokes you use should act just like the 'd' command. Defining a custom operator with the opfunc setting lets...) |
(Change <tt> to <code>, perhaps also minor tweak.) |
||
(3 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
+ | {{TipNew |
||
− | If you want to treat commenting lines of code just like deleting, whatever keystrokes you use should act just like the 'd' command. Defining a custom operator with the opfunc setting lets you do that. With the set of commands below, you can use ,c (here mapleader is set to ,) just like d in normal mode. |
||
+ | |id=1570 |
||
+ | |previous=1569 |
||
+ | |next=1571 |
||
+ | |created=2008 |
||
+ | |complexity=basic |
||
+ | |author=Jlepak |
||
+ | |version=7.0 |
||
+ | |subpage=/200806 |
||
+ | |category1= |
||
+ | |category2= |
||
+ | }} |
||
+ | This tip uses the <code>opfunc</code> option to define two operators. Assuming the default backslash leader key, the operators are: |
||
+ | *<code>\c</code> to comment lines (insert a comment string before each line) |
||
+ | *<code>\C</code> to uncomment lines |
||
+ | ==Usage== |
||
− | As an added bonus, the funny business in the first function with the c-v visual-block command formats things pretty nicely, with the comment signifiers lined up at the point of indentation of the first line of the commented block. |
||
⚫ | |||
− | |||
⚫ | |||
<pre> |
<pre> |
||
⚫ | |||
− | ,cip |
||
⚫ | |||
− | will transform |
||
⚫ | |||
⚫ | |||
− | def f(self,x): |
+ | def f(self, x): |
if x < 5: |
if x < 5: |
||
print "Pointless function." |
print "Pointless function." |
||
return 0 |
return 0 |
||
</pre> |
</pre> |
||
+ | |||
− | to |
||
+ | The command <code>yip</code> (yank inner paragraph) would copy the block. In a similar manner, the command <code>\cip</code> will comment-out the block, resulting in: |
||
<pre> |
<pre> |
||
− | class |
+ | class Example: |
− | # def f(self,x): |
+ | # def f(self, x): |
# if x < 5: |
# if x < 5: |
||
# print "Pointless function." |
# print "Pointless function." |
||
Line 26: | Line 36: | ||
</pre> |
</pre> |
||
+ | Later, you could remove the comment signifiers with <code>\Cip</code>. |
||
− | Here's the code (pretty short, but could certainly be made cleaner by someone who knows better). It only handles linewise comments. |
||
+ | 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: |
||
+ | *<code>\ciB</code> comment inner block (between braces) |
||
+ | *<code>\c}</code> comment to end paragraph |
||
+ | *<code>\cG</code> comment to end buffer |
||
+ | *<code>Vjjj\c</code> comment visually-selected lines |
||
+ | |||
+ | ==Script== |
||
+ | Here's the code. It only handles linewise comments. |
||
<pre> |
<pre> |
||
− | " Comment lines from mark a to mark b |
+ | " Comment or uncomment lines from mark a to mark b. |
+ | function! CommentMark(docomment, a, b) |
||
− | fun DoCommentMark(a,b) |
||
− | + | if !exists('b:comment') |
|
⚫ | |||
− | endfun |
||
⚫ | |||
− | " Handles the opfunc call |
||
+ | if a:docomment |
||
⚫ | |||
⚫ | |||
⚫ | |||
+ | else |
||
− | endfun |
||
+ | exe "'".a:a.",'".a:b . 's/^\(\s*\)' . escape(b:comment,'/') . '/\1/e' |
||
− | " Handles visual mode |
||
+ | endif |
||
− | fun DoCommentV() |
||
+ | endfunction |
||
− | call DoCommentMark('<', '>') |
||
− | endfun |
||
− | " |
+ | " Comment lines in marks set by g@ operator. |
⚫ | |||
− | fun UnCommentMark(a,b) |
||
⚫ | |||
⚫ | |||
+ | endfunction |
||
− | endfun |
||
− | fun UnCommentOp(...) |
||
⚫ | |||
− | endfun |
||
− | fun UnCommentV() |
||
− | call UnCommentMark('<', '>') |
||
− | endfun |
||
+ | " Uncomment lines in marks set by g@ operator. |
||
⚫ | |||
− | + | function! UnCommentOp(type) |
|
⚫ | |||
− | vmap <leader>c <Esc>:call DoCommentV()<CR> |
||
+ | endfunction |
||
− | vmap <leader>C <Esc>:call UnCommentV()<CR> |
||
+ | " Return string used to comment line for current filetype. |
||
− | " There's probably a better way to set the commenting character ... |
||
+ | function! CommentStr() |
||
− | au BufEnter * call SetComment() |
||
⚫ | |||
− | fun SetComment() |
||
+ | return '//' |
||
⚫ | |||
⚫ | |||
⚫ | |||
+ | return '"' |
||
⚫ | |||
− | + | elseif &ft == 'python' || &ft == 'perl' || &ft == 'sh' || &ft == 'R' |
|
+ | return '#' |
||
− | let b:comment = '"' |
||
+ | elseif &ft == 'lisp' |
||
− | elseif &ft == 'python' || &ft == 'perl' || &ft == 'sh' || &ft == 'R' |
||
+ | return ';' |
||
− | let b:comment = '#' |
||
+ | endif |
||
⚫ | |||
+ | return '' |
||
− | let b:comment = ';' |
||
+ | endfunction |
||
⚫ | |||
+ | |||
− | endfun |
||
⚫ | |||
+ | 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> |
||
</pre> |
</pre> |
||
+ | |||
+ | ==Explanation== |
||
+ | A custom operator can be defined using visual-mode maps (to apply the operator to a selection), and using the <code>operatorfunc</code> (<code>opfunc</code>) option (to apply the operator to a movement). |
||
+ | |||
+ | The <code>g@</code> operator can be used in a map to define your own operator. When <code>g@</code> is invoked, the function defined by the <code>opfunc</code> option is called with an argument indicating the type of motion ("line", "char" or "block"). In addition, the <code>'[</code> and <code>']</code> 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 <code>comment</code>, for example: |
||
⚫ | |||
⚫ | |||
⚫ | |||
+ | |||
+ | ==See also== |
||
+ | *[[VimTip1555|Creating new text objects]] |
||
+ | *[[VimTip1516#Operator pending mode maps|Operator pending mode maps]] |
||
+ | *[[VimTip271|Easy (un)commenting out of source code]] |
||
+ | |||
+ | ==References== |
||
+ | *{{help|'opfunc'}} |
||
+ | |||
+ | ==Comments== |
Latest revision as of 06:34, 13 July 2012
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='#---'