18

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
15

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 followed by a comment character. Note that this is fairly naïve and may not work for all languages since commentstring can be more complex than just a single character. 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
| improve this answer | |
  • 1
    @JackFrost if you need to tell someone the code in their answer doesn't work, comments or your own answer is a better spot. (Martin, there was a suggested edit to escape \s in one of the sets. Unsure if needed or not, but I suspect it might be.) – D. Ben Knoble May 8 at 0:17
  • 1
    With just one \ the pattern just get ignored, guess I only tested the case where # is at the start of the line. Thanks for the edit! – Martin Tournoij May 8 at 0:48
  • @D.BenKnoble Yes you need two due to :help option-backslash. I tend to prefer to define a function and set options that take an expression (and autocmds, etc.) to the function call, in order to avoid too many levels of escaping. – filbranden May 8 at 1:55
3

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.

| improve this answer | |
0

You can visually select commented block with vac and then create a manual fold zf.

Comment text object may be language extension to set of standard vim text objects. Tested it with Go syntax.

| improve this answer | |
  • 2
    Indeed, ac is not a builtin. But with tpope’s commentary gc is a text object. So better solutions are zfac, zfgc, or zfip at worst – D. Ben Knoble Jul 25 '19 at 3:57

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.