Duplicate tip
This tip is very similar to the following:
These tips need to be merged – see the merge guidelines.
created June 30, 2002 · complexity intermediate · author jmpatton · version 5.7
Something that I do quite a lot 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, beginning with beginning-of-line comments:
,# shell, perl, etc ,/ c++ ,> email quote ," vim ,% latex, prolog ,! assembly/X-resources ,; scheme ,- sql, ada ,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
Comments[]
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>
Just add :nohlsearch <CR> at the end of the mapping and it would remove the highlight. Highlighting would be re-enabled 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>
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 amended 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>
A more intelligent way is to save the search pattern highlighted. let hls=@/|s ... |let @/=hls
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.
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>
" 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/*
I use the mouse to 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>
those are great, but I don't like the highlighted search and also i like my // always at the very beginning of the line, so I've wrote this function (very newbie and unoptimized, but it works)
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 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>
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 to select the comments in a visual block and delete them.
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).
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" || &filetype == "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" || &filetype == "xsd" " [[VimTip271]] 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" || &filetype == "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
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 :)
See script#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
I found the Nerd commenter script very valuable: Nerd Commenter
I like Enhanced Commentify. It has a lot of functionality and options.
If you want simplicity, ToggleCommentify is available.
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.