diff options
Diffstat (limited to 'ftplugin/svelte/fold.vim')
-rw-r--r-- | ftplugin/svelte/fold.vim | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/ftplugin/svelte/fold.vim b/ftplugin/svelte/fold.vim new file mode 100644 index 00000000..2732660a --- /dev/null +++ b/ftplugin/svelte/fold.vim @@ -0,0 +1,131 @@ +if polyglot#init#is_disabled(expand('<sfile>:p'), 'svelte', 'ftplugin/svelte/fold.vim') + finish +endif + +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" +" Config {{{ +" +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +let s:use_foldexpr = exists("g:vim_svelte_plugin_use_foldexpr") + \ && g:vim_svelte_plugin_use_foldexpr == 1 +"}}} + +if !s:use_foldexpr | finish | endif + +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" +" Settings {{{ +" +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +setlocal foldmethod=expr +setlocal foldexpr=GetSvelteFold(v:lnum) +"}}} + +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" +" Variables {{{ +" +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +let s:empty_line = '\v^\s*$' +let s:block_end = '\v^\s*}|]|\)' +let s:svelte_tag_start = '\v^\<\w+' +let s:svelte_tag_end = '\v^\<\/\w+' +let s:svelte_internal_blocks = '\v:(else|then|catch)' +"}}} + +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" +" Functions {{{ +" +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" see :h fold-expr +" value meaning +" 0 the line is not in a fold +" 1, 2, .. the line is in a fold with this level +" -1 the fold level is undefined, use the fold level of a +" line before or after this line, whichever is the +" lowest. +" "=" use fold level from the previous line +" "a1", "a2", .. add one, two, .. to the fold level of the previous +" line, use the result for the current line +" "s1", "s2", .. subtract one, two, .. from the fold level of the +" previous line, use the result for the next line +" ">1", ">2", .. a fold with this level starts at this line +" "<1", "<2", .. a fold with this level ends at this line +function! GetSvelteFold(lnum) + let this_line = getline(a:lnum) + let next_line = getline(a:lnum + 1) + + " Handle empty lines + if this_line =~ s:empty_line + return -1 + endif + + " Handle start/end tags + if this_line =~ s:svelte_tag_start + return '>1' + endif + if this_line =~ s:svelte_tag_end + " If return '<1', fold will get incorrect with prev line + return 1 + endif + + " Fold by indent + if a:lnum > 1 + let prev_indent = s:IndentLevel(a:lnum - 1) + else + let prev_indent = 0 + endif + let this_indent = s:IndentLevel(a:lnum) + let next_indent = s:IndentLevel(s:NextNonBlankLine(a:lnum)) + + " Fold separately on blocks + if this_line =~ s:svelte_internal_blocks + return '>'.next_indent + endif + + if GetSvelteTag(a:lnum) == 'script' + " Handle closing '}' + if this_line =~ '\v^\s*},?\s*$' + return '<'.prev_indent + endif + + " --this + " ----next + if this_indent < next_indent + return '>'.next_indent + endif + + " ----this + " --next + if this_indent >= next_indent + return this_indent + endif + else + " Template or style + return this_indent + endif +endfunction + +function! s:IndentLevel(lnum) + " Add 1 to indentLevel, so start/end tags can fold properly + return indent(a:lnum) / &shiftwidth + 1 +endfunction + +function! s:NextNonBlankLine(lnum) + let next_line = a:lnum + 1 + let last_line = line('$') + + while next_line <= last_line + if getline(next_line) =~ '\v\S' + return next_line + endif + + let next_line += 1 + endwhile + + return 0 +endfunction +"}}} +" vim: fdm=marker |