Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code folding support #56

Open
zanona opened this issue Jan 23, 2015 · 12 comments
Open

Code folding support #56

zanona opened this issue Jan 23, 2015 · 12 comments

Comments

@zanona
Copy link

zanona commented Jan 23, 2015

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
Copy link
Owner

othree commented Jan 23, 2015

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
Copy link
Owner

othree commented Jan 29, 2016

Not sure what should be fold. Any idea?

@zanona
Copy link
Author

zanona commented Jan 29, 2016

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
Copy link
Owner

othree commented Jan 29, 2016

How about use fold-indent

@othree
Copy link
Owner

othree commented Jan 29, 2016

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
Copy link
Author

zanona commented Jan 29, 2016

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
Copy link
Contributor

nhooyr commented Feb 17, 2016

@zanona thanks for the folding function.

@nhooyr
Copy link
Contributor

nhooyr commented Feb 17, 2016

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

@nhooyr
Copy link
Contributor

nhooyr commented Feb 17, 2016

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
Copy link
Author

zanona commented Feb 17, 2016

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
Copy link
Contributor

nhooyr commented Feb 17, 2016

@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
Copy link

rifazn commented Jan 22, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants