html5.vim icon indicating copy to clipboard operation
html5.vim copied to clipboard

Code folding support

Open zanona opened this issue 10 years ago • 12 comments

I have foldmethod=syntax and it seems there is not code-folding support for html files? Is this correct? perhaps I am missing something

zanona avatar Jan 23 '15 15:01 zanona

Yes, I don't have any folding setting now. I don't use fold at all so no idea what tag could be fold and won't break user editing.

othree avatar Jan 23 '15 15:01 othree

Not sure what should be fold. Any idea?

othree avatar Jan 29 '16 06:01 othree

Hey @othree, to be honest I saw myself needing to fold all tags that had more than one line of content inside, I believe it is a good option to have.

A few months ago, I have written a script that would allow me to fold html tags, however, the it is quite buggy and it doesn't play well when changing buffers having other syntax declarations (ie: html <-> less), causing the fold structure to be lost when swapping.

Please have a look on the demo below and also the source here: https://github.com/zanona/dotfiles/blob/master/.vim/ftplugin/html.vim

Additionally, you can see that on Line 2 I am hard-coding all the tags I want to allow the script to fold.

I am certain that you can create something much better that integrates nicely with other syntax files when swapping buffers ;)

If you have any questions please let me know.

asciicast

zanona avatar Jan 29 '16 09:01 zanona

How about use fold-indent

othree avatar Jan 29 '16 10:01 othree

Another question is, you want to fold every level? Or just the upper level?

ex:

<div> <!-- fold -->
  <div> <!-- fold -->
    <div> <!-- fold -->
    </div>
  </div>
</div>

or:

<div> <!-- fold -->
  <div> 
    <div> 
    </div>
  </div>
</div>

othree avatar Jan 29 '16 10:01 othree

The problem is that with HTML, indentation would not really be a requirement and could fail for those who don't use it?

In regards the fold level, I believe the ideal is to be able to ident every level as per the first example. I believe indentation bring many benefits when organising code and focusing on a single area of the code, specially now with single-page apps/websites everywhere :)

zanona avatar Jan 29 '16 10:01 zanona

@zanona thanks for the folding function.

nhooyr avatar Feb 17 '16 05:02 nhooyr

@zanona don't you get annoyed that as you type, all the folds open up and then close?

nhooyr avatar Feb 17 '16 06:02 nhooyr

This is a syntax solution

syn sync fromstart
set foldmethod=syntax

syn region TagFold start=+^<\%(html\|heade\@!\|body\)\@!\([^/?!><]*[^/]>\)\&.*\(<\1\|[[:alnum:]]\)$+ end=+^</.*[^-?]>$+ fold transparent keepend extend

syn match CommentFold "<!--\_.\{-}-->" fold transparent extend

Just pop it into after/syntax/html.vim. Its based on XMLFolding

nhooyr avatar Feb 17 '16 06:02 nhooyr

Thanks for the suggestion @nhooyr. I have tried to use this syntax plugin, however I wasn't able to fold nested tags which I found a bit strange?

In regards your question to all folds opening up once typing? I am using this:

function! s:OnInsertModeEnter()
  if !exists('w:last_fdm')
    let w:last_fdm = &foldmethod
    setlocal foldmethod=manual
  endif
endfunction

function! s:OnInsertModeLeave()
  if exists('w:last_fdm')
    let &l:foldmethod = w:last_fdm
    unlet w:last_fdm
  endif
endfunction

autocmd       InsertEnter             *        call <SID>OnInsertModeEnter()
autocmd       InsertLeave,WinLeave    *        call <SID>OnInsertModeLeave()

This will change the foldmethod to manual when editing maintaining the current state and switch back to the previous mode when going into normal mode allowing you to perform file updates as expected.

This has helped me not only on this case but many other cases where performance is drastically affected when foldmethod=syntax once editing large files.

zanona avatar Feb 17 '16 20:02 zanona

@zanona thanks for that snippet, gonna be really useful.

Don't know how I overlooked the folding of the nested tags, my bad.

Thanks for the folding script. I personally prefer specifying the tags that I don't want folded. Thus I modified it a bit.

let s:exclude_tags_list = [
      \ '\/',
      \ '!',
      \ 'html',
      \ 'head\>',
      \ 'body',
      \ 'area',
      \ 'base',
      \ 'br',
      \ 'col',
      \ 'embed',
      \ 'hr',
      \ 'img',
      \ 'input',
      \ 'keygen',
      \ 'link',
      \ 'menuitem',
      \ 'meta',
      \ 'param',
      \ 'source',
      \ 'track',
      \ 'wbr',
      \ ]
let s:exclude_tags = join(s:exclude_tags_list, '\|')

function! HTMLFolds()
  let line = getline(v:lnum)

  " Ignore tags that open and close in the same line
  if line =~# '<\(\w\+\).*<\/\1>'
    return '='
  endif

  if line =~# '<\%(' . s:exclude_tags . '\)\@!'
    return 'a1'
  endif

  if line =~# '<\/\%(' . s:exclude_tags . '\)\@!'
    return 's1'
  endif

  return '='
endfunction

setlocal foldmethod=expr
setlocal foldexpr=HTMLFolds()

I also changed the regexes to normal vim regexes and removed the s:level variable.

nhooyr avatar Feb 17 '16 22:02 nhooyr

@nhooyr @zanona Any updates to the above snippets you have made? I tried them in Vim 9.0 and it was erroneous. The ending of the tags wasn't being shown... For instance: pic1, pic2.

Though I must admit, I just copy pasted @nhooyr snippet above verbatim, not exactly know what it does.

I tried with the indent foldmethod and have this in after/syntax/html.vim:

set foldlevel=2
set foldmethod=indent

Which gives this.

After about 5 minutes of browsing the code base, I think it's not bad for a workaround.

rifazn avatar Jan 22 '24 14:01 rifazn