sponsor Vim development Vim logo Vim Book Ad

intermediate Tip #271: easy (un)commenting out of source code

 tip karma   Rating 214/73, Viewed by 14507 

Read and edit this tip on the Vim tip wiki. The wiki may have a more recent version of this tip.

created:   June 30, 2002 22:57      complexity:   intermediate
author:   [email protected]      as of Vim:   5.7

Something that I do quite alot is comment out blocks of text, only to uncomment that same block later. The following mappings have proven useful to me. They can be applied using visually selected blocks, or with motion keys.

" lhs comments
map ,# :s/^/#/<CR>
map ,/ :s/^/\/\//<CR>
map ,> :s/^/> /<CR>
map ," :s/^/\"/<CR>
map ,% :s/^/%/<CR>
map ,! :s/^/!/<CR>
map ,; :s/^/;/<CR>
map ,- :s/^/--/<CR>
map ,c :s/^\/\/\\|^--\\|^> \\|^[#"%!;]//<CR>

" wrapping comments
map ,* :s/^\(.*\)$/\/\* \1 \*\//<CR>
map ,( :s/^\(.*\)$/\(\* \1 \*\)/<CR>
map ,< :s/^\(.*\)$/<!-- \1 -->/<CR>
map ,d :s/^\([/(]\*\\|<!--\) \(.*\) \(\*[/)]\\|-->\)$/\2/<CR>

The commands to comment a selection of text are as follows, begining with begining-of-line comments:

    ,#    shell, perl, etc
    ,/     c++
    ,>    email quote
    ,"     vim
    ,%    latex, prolog
    ,!      assembly?... add single !
    ,;      scheme
    ,-      don't remember this one... add --
    ,c     clears any of the previous comments

Here are the wrapping comments, each line wrapped individually:

    ,*      c
    ,(       Standard ML
    ,<      html
    ,d      clears any of the wrapping comments

 rate this tip  Life Changing Helpful Unfulfilling 

<< Insert a single character | automaticaly formating pasted text (p=`]) >>

Additional Notes

Anonymous, July 1, 2002 6:28
After executing this tip, the content of "/ is highlighted in my gvim; which is rather annoying.
In e.g. MapBasic which I'm trying to figure out right now, I use:
map ,' :s/^/'/<CR> :let @/=""<CR>
Leo
alinets<at>yahoo.com, July 1, 2002 13:26
I am having the same problem,
I have hlsearch option on (highlight search) and when I use one of the mappings to add comment it leaves me with a lot of hihjlighting that is not required/intended. Is there a way to turn off highlight search for these command only ?
alinets<at>yahoo.com, July 1, 2002 14:40
OK, figured it out.
Just add :nohlsearch <CR> at the end of the mapping and it would remove the highlight.
Highlighting would be reenabled when you do the next search. I checked it out it works

" lhs comments
map ,# :s/^/#/<CR> <Esc>:nohlsearch <CR>
map ,/ :s/^/\/\//<CR> <Esc>:nohlsearch <CR>
map ,> :s/^/> /<CR> <Esc>:nohlsearch<CR>
map ," :s/^/\"/<CR> <Esc>:nohlsearch<CR>
map ,% :s/^/%/<CR> <Esc>:nohlsearch<CR>
map ,! :s/^/!/<CR> <Esc>:nohlsearch<CR>
map ,; :s/^/;/<CR> <Esc>:nohlsearch<CR>
map ,- :s/^/--/<CR> <Esc>:nohlsearch<CR>
map ,c :s/^\/\/\\|^--\\|^> \\|^[#"%!;]//<CR> <Esc>:nohlsearch<CR>

" wrapping comments
map ,* :s/^\(.*\)$/\/\* \1 \*\//<CR> <Esc>:nohlsearch<CR>
map ,( :s/^\(.*\)$/\(\* \1 \*\)/<CR><Esc>:nohlsearch <CR>
map ,< :s/^\(.*\)$/<!-- \1 -->/<CR> <Esc>:nohlsearch<CR>
map ,d :s/^\([/(]\*\\|<!--\) \(.*\) \(\*[/)]\\|-->\)$/\2/<CR> <Esc>:nohlsearch<CR>
[email protected], July 1, 2002 14:50
Adding :nohlsearch<cr> to the end of each pattern clears up the highlighting. Note that this doesn't turn off search highlighting, it just removes the highlighting that's there. Here are the ammended regexs:

" lhs comments
map ,# :s/^/#/<CR>:nohlsearch<CR>
map ,/ :s/^/\/\//<CR>:nohlsearch<CR>
map ,> :s/^/> /<CR>:nohlsearch<CR>
map ," :s/^/\"/<CR>:nohlsearch<CR>
map ,% :s/^/%/<CR>:nohlsearch<CR>
map ,! :s/^/!/<CR>:nohlsearch<CR>
map ,; :s/^/;/<CR>:nohlsearch<CR>
map ,- :s/^/--/<CR>:nohlsearch<CR>
map ,c :s/^\/\/\\|^--\\|^> \\|^[#"%!;]//<CR>:nohlsearch<CR>

" wrapping comments
map ,* :s/^\(.*\)$/\/\* \1 \*\//<CR>:nohlsearch<CR>
map ,( :s/^\(.*\)$/\(\* \1 \*\)/<CR>:nohlsearch<CR>
map ,< :s/^\(.*\)$/<!-- \1 -->/<CR>:nohlsearch<CR>
map ,d :s/^\([/(]\*\\|<!--\) \(.*\) \(\*[/)]\\|-->\)$/\2/<CR>:nohlsearch<CR>
[email protected], July 1, 2002 14:52
Jinx!
[email protected], July 3, 2002 2:53
A more intelligent way is to save the search pattern highlighted.
let hls=@/|s ... |let @/=hls
[email protected], July 3, 2002 5:52
The problem with that is that it thwarts motion keys. The way it stands you can do something like '3,#' and it will comment 3 lines. Ranges don't work with 'let ...', unfortunately.
[email protected], July 3, 2002 12:16
This function is based on the various comments here, and seems to work.
fun CppstyleQuote()
   let hls=@/
   s/^/\/\//
   let @/=hls
endfun
map ,/ :call CppstyleQuote()<CR>

Leo
[email protected], July 6, 2002 17:23
" I use a single mapping, which can comment/uncomment line:
function! C_CommentLine()
if getline(".") =~ '/\*.*\*/'
normal ^2x$xx
else
normal I/*A*/
endif
endfunction
nmap <buffer> <Esc>d :call C_CommentLine()<LF>

" <Esc>d on my term means <M-D> or Alt-D

" This mapping comments the visual selection, You have to perform a selection from left to
" right or from top to bottom. If you do a linewise selection, the cursor
" position, not the end of selection matters.
vmap <buffer> <Esc>d a*/gvoi/*

[email protected], September 23, 2002 19:22
i use the mouse the select the lines i want to comment/uncomment and have this on the right click menu
to insert/delete // at the start of the line:

:vmenu PopUp.Comments.Add  :s/^/\/\//<CR>
:vmenu PopUp.Comments.Remove  :s/^..//<CR>

seems to work ok
[email protected], September 28, 2002 16:02
The comment whose language you forgot (in your notes), ,-, is for SQL comments....
[email protected], October 12, 2002 11:30
hi all!!
those are great, but i don't like the highlighted search and also i like my //  allways at the very begining of the line, so i've wrote this function (very newbie and unoptimized, but it works XD )

it comments and uncomments the current line:

"""""""""""""""""""""""""""""""""""""""""""""""""
function! MyComm()
    let linenum= line('.')
    let line = getline('.')

    let commpos= match(line, "//")
    let n = 0
    while n< commpos
        if line[n]!= " " && line[n]!= "\t"
            break
        endif
        let n= n+1
    endwhile
    if n== commpos && commpos!= -1
        let line= strpart(line, 0, commpos).strpart(line, commpos+2)
    else
        let line= "//".line
    endif

    let err= setline(linenum, line)
endfunction
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"and use this keybindings:

map <M-c> :call MyComm()<CR>
imap <M-c> <esc>:call MyComm()<CR>i

" for the /* */ pair, i use visual mode, an then alt-v:

vmap <M-v> v`<I<CR><esc>k0i/*<ESC>`>I<CR><esc>k0i*/<ESC>

hope u find useful :)
[email protected], October 25, 2002 3:04
Using visual block selection at the start of the lines you want to comment, along with 'I' (CAPS-EYE), and the
comment character is also very handy. Decommenting would be (ofcourse!) to select the comments in a visual
block and delete them.
[email protected], February 8, 2003 13:37
the '--' comments are also for ADA95 if anyone has has the pleasure of coding in it.
[email protected], March 19, 2003 23:02
A few people have said something like this, but I have found it more useful to not need to remember a different mapping for each language I'm editing. To this end, I have several different functions that set up commands based on which language I'm editing. Like so:

" Define functions
function! PoundComment()
   map - :s/^/# /<CR>
   map _ :s/^\s*# \=//<CR>
   set comments=:#
endfunction

function! SlashComment()
   map - :s/^/\/\/ /<CR>
   map _ :s/^\s*\/\/ \=//<CR>
endfunction

" And then later...
autocmd FileType perl      call PoundComment()
autocmd FileType cgi       call PoundComment()
autocmd FileType csh       call PoundComment()
autocmd FileType sh        call PoundComment()
autocmd FileType java      call SlashComment()

You get the idea. Now, I can always comment a line/range of lines with - (hyphen), and uncomment it with _ (underscore).

There's More Than One Way To Do It.
Anonymous, November 10, 2003 14:07
-- is also for sql, silly boy
Anonymous, November 10, 2003 16:35
Ok, my turn:

These will handle the :nohl search highlighting case nicely (nothing's changed, it's automatic)

map \# :call Comment()<CR>
map \-# :call Uncomment()<CR>
map \--# :call UncommentBlock()<CR>

" Comments range (handles multiple file types)
function! Comment() range
  if &filetype; == "c" || &filetype; == "php" || &filetype; == "css"
    execute ":" . a:firstline . "," . a:lastline . 's/^\(.*\)$/\/\* \1 \*\//'
  elseif &filetype; == "html" || &filetype; == "xml" || &filetype; == "xslt" || &filetyle; == "xsd"
    execute ":" . a:firstline . "," . a:lastline . 's/^\(.*\)$/<!-- \1 -->/'
  else
    if &filetype; == "java" || &filetype; == "cpp" || &filetype; == "cs"
      let commentString = "//"
    elseif &filetype; == "vim"
      let commentString = '"'
    else
      let commentString = "#"
    endif
    execute ":" . a:firstline . "," . a:lastline . 's,^,' . commentString . ','
  endif
endfunction

" Uncomments range (handles multiple file types)
function! Uncomment() range
  if &filetype; == "c" || &filetype; == "php" ||| &filetype; == "css" || &filetype; == "html" || &filetype; == "xml" || &filetype; == "xslt" || &filetyle; == "xsd"
    " https://www.vim8.org/tips/tip.php?tip_id=271
    execute ":" . a:firstline . "," . a:lastline . 's/^\([/(]\*\|<!--\) \(.*\) \(\*[/)]\|-->\)$/\2/'
  else
    if &filetype; == "java" || &filetype; == "cpp" || &filetype; == "cs"
      let commentString = "//"
    elseif &filetype; == "vim"
      let commentString = '"'
    else
      let commentString = "#"
    endif
    execute ":" . a:firstline . "," . a:lastline . 's,^' . commentString . ',,'
  endif
endfunction

" Uncomments from current line up to last line that's commented
function! UncommentBlock()
  if &filetype; == "c" || &filetype; == "php" ||| &filetype; == "css" || &filetype; == "html" || &filetype; == "xml" || &filetype; == "xslt" || &filetyle; == "xsd"
    echoerr "TODO: haven't implemented UncommentBlock; use Uncomment instead"
  else
    if &filetype; == "java" || &filetype; == "cpp" || &filetype; == "cs"
      let commentString = '\/\/'
      let firstChar = '/'
    elseif &filetype; == "vim"
      let commentString = '"'
      let firstChar = '"'
    else
      let commentString = '#'
      let firstChar = '#'
    endif
    if version < 600 && strlen( commentString ) > 1
      echoerr "TODO: haven't implemented multi-character comment block"
    else
      " TODO: doesn't handle case where the block ends at end of file
      execute ':.,/^\(\(' . commentString . '\)\@!\|[^' . firstChar . ']\|$\)/-1s/^' . commentString . "//"
    endif
  endif
endfunction

[email protected], November 12, 2003 19:04
Your script works well, but has little bugs:
1. mistype some 'filetype' to 'filetyle'
2. mistype some '||' to '|||"
Dani, January 30, 2004 6:27
All this was very useful, thanks!
Based on the above and having 4 things in mind: (1) single keystroke (2) no highlighting (3) C language (4) being simple - my version became:

function! Komment()
if getline(".") =~ '\/\*'
let hls=@/
s/^\/\*//
s/*\/$//
let @/=hls
else
let hls=@/
s/^/\/*/
s/$/*\//
let @/=hls
endif
endfunction

map k :call Komment()<CR>

So pressing k will comment out the current line if it is not already so and will uncomment it if it is commented already. Really handy :)
Dani
Anonymous, March 31, 2004 0:31
[email protected], i love you
[email protected], April 6, 2004 9:32
You might have a look at vimscript #955. I "improved" the original tip a little:
- no "remove comment" key, but the comment-status of a line is toogled
- no hlsearch-problem
- commenting uses the original indentation, not the first column
Anonymous, November 25, 2005 5:57
I found the Nerd commenter script very valuable: vimscript #1218
Anonymous, December 21, 2005 23:10
I settled on using vimscript #23, called Enhanced Commentify

It has a lot of functionality and options.
If you want simplicity, vimscript #4 is available.
[email protected], February 7, 2006 19:08
Dani, that tip worked for me in 30 seconds- thanks!
Anonymous, March 16, 2006 18:32
! is used for X resources
Anonymous, May 17, 2006 3:23
To do this quickly with a visual selection you could just type shift-i and then the comment character(s) followed by Esc or ctrl-c which will insert the characters at the start of the selection at every line.
If you have questions or remarks about this site, visit the vimonline development pages. Please use this site responsibly.
Questions about Vim should go to the maillist. Help Bram help Uganda.
   
SourceForge.net Logo