othree / html5.vim

HTML5 omnicomplete and syntax
http://www.vim.org/scripts/script.php?script_id=3236
934 stars 76 forks source link

Code folding support #56

Open zanona opened 9 years ago

zanona commented 9 years ago

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

othree commented 9 years ago

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 commented 8 years ago

Not sure what should be fold. Any idea?

zanona commented 8 years ago

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

othree commented 8 years ago

How about use fold-indent

othree commented 8 years ago

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>
zanona commented 8 years ago

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 :)

nhooyr commented 8 years ago

@zanona thanks for the folding function.

nhooyr commented 8 years ago

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

nhooyr commented 8 years ago

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

zanona commented 8 years ago

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.

nhooyr commented 8 years ago

@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.

rifazn commented 10 months ago

@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.