14

The syntax foldmethod is great, but sometimes I just want to fold the comments in a source file.

Also syntax folding of comments only works for C-Style comments like:

/*
 ...
 */

But not for comment boilerplate like:

//
//
// ...
//

Or even for comment blocks in non-C-like languages like:

#
#
# ...
#

How can I configure this with vim?

  • Do you want to use syntax folding and comment folding? Or only comment folding? – Martin Tournoij Jun 4 '15 at 8:25
  • @Carpetsmoker, syntax folding + comment folding would be ok if one could say 'open all folds, except for comments'. Otherwise, comment folding without syntax folding would be fine as well. – maxschlepzig Jun 4 '15 at 9:38
14

Folding only the comments is fairly easy by using foldmethod=expr:

set foldmethod=expr foldexpr=getline(v:lnum)=~'^\s*'.&commentstring[0]

This will simply check if the line starts with any amount of whitespace + a comment character. Note that this is fairly naive, and may not work for all languages. So you may want to use a autocmd to be more specific:

autocmd FileType c setlocal foldmethod=expr foldexpr=getline(v:lnum)=~'^\s*//'
autocmd FileType python setlocal foldmethod=expr foldexpr=getline(v:lnum)=~'^\s*#'

For more information about fold-expr, see:


Using syntax folding and comment folding is more involved; this would require modifing the syntax file in /usr/share/vim/vim74/syntax/*.vim, and will be specific to the language you're using.

Note that some filetypes already do this! For example from ruby.vim:

if !exists("ruby_no_comment_fold")
  syn region rubyMultilineComment start="\%(\%(^\s*#.*\n\)\@<!\%(^\s*#.*\n\)\)\%(\(^\s*#.*\n\)\{1,}\)\@=" end="\%(^\s*#.*\n\)\@<=\%(^\s*#.*\n\)\%(^\s*#\)\@!" contains=rubyC
  syn region rubyDocumentation    start="^=begin\ze\%(\s.*\)\=$" end="^=end\%(\s.*\)\=$" contains=rubySpaceError,rubyTodo,@Spell fold
else
  syn region rubyDocumentation    start="^=begin\s*$" end="^=end\s*$" contains=rubySpaceError,rubyTodo,@Spell
endif
2

I like folding with indent but including the comments in the fold (I mean each comment get the same level of fold as the previous line).

Unfortunately, foldignore keyword just works for one line comments. So I fold with expr in vimrc:

set foldmethod=expr
set foldexpr=FoldMethod(v:lnum)

function! FoldMethod(lnum)
  "get string of current line
  let crLine=getline(a:lnum)

  " check if empty line 
  if empty(crLine) "Empty line or end comment 
    return -1 " so same indent level as line before 
  endif 

  " check if comment 
  let a:data=join( map(synstack(a:lnum, 1), 'synIDattr(v:val, "name")') )
  if a:data =~ ".*omment.*"
    return '='
  endif

  "Otherwise return foldlevel equal to indent /shiftwidth (like if
  "foldmethod=indent)
  else  "return indent base fold
    return indent(a:lnum)/&shiftwidth
endfunction

The last block :

indent(a:lnum)/&shiftwidth

Returns a foldlevel base on indent.

And the other one :

join( map(synstack(a:lnum, 1), 'synIDattr(v:val, "name")') )

Checks if the first character of the line is consider as a comment with the syntax. So it is a good way to merge indent and syntax folding with expression, the most advanced folding.

Note that you can also "set foldtext" depending on how you want the result to look like.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.