fold.vim 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. let s:config = vue#GetConfig('config', {})
  2. let s:enable_foldexpr = s:config.foldexpr
  3. if !s:enable_foldexpr | finish | endif
  4. " Useful for debugging foldexpr
  5. " set debug=msg
  6. function! VueFoldMain(...)
  7. if line('$') < 1000
  8. let s:empty_line = '^\s*$'
  9. let s:vue_tag_start = '^<\w\+'
  10. let s:vue_tag_end = '^<\/\w\+'
  11. setlocal foldexpr=GetVueFold(v:lnum)
  12. setlocal foldmethod=expr
  13. endif
  14. endfunction
  15. " see :h fold-expr
  16. " value meaning
  17. " 0 the line is not in a fold
  18. " 1, 2, .. the line is in a fold with this level
  19. " -1 the fold level is undefined, use the fold level of a
  20. " line before or after this line, whichever is the
  21. " lowest.
  22. " "=" use fold level from the previous line
  23. " "a1", "a2", .. add one, two, .. to the fold level of the previous
  24. " line, use the result for the current line
  25. " "s1", "s2", .. subtract one, two, .. from the fold level of the
  26. " ">1", ">2", .. a fold with this level starts at this line
  27. " "<1", "<2", .. a fold with this level ends at this line
  28. function! GetVueFold(lnum)
  29. let this_line = getline(a:lnum)
  30. let value = s:FoldForSpecialLine(this_line)
  31. if value == -2
  32. " Fold by indent
  33. let this_indent = s:IndentLevel(a:lnum)
  34. " For <script> block
  35. if GetVueTag(a:lnum) == 'script'
  36. let value = s:FoldForScript(a:lnum, this_line, this_indent)
  37. else
  38. let value = this_indent
  39. endif
  40. endif
  41. call vue#LogWithLnum('foldlevel '.value)
  42. return value
  43. endfunction
  44. function! s:FoldForScript(lnum, this_line, this_indent)
  45. let value = -2
  46. if a:lnum > 1
  47. let prev_indent = s:IndentLevel(a:lnum - 1)
  48. else
  49. let prev_indent = 0
  50. endif
  51. let next_indent = s:IndentLevel(nextnonblank(a:lnum + 1))
  52. if a:this_line =~ '^\s*[]})]\+,\?\s*$'
  53. " Closing ']})'
  54. let value = '<'.prev_indent
  55. elseif a:this_indent < next_indent
  56. " --this
  57. " ----next
  58. let value = '>'.next_indent
  59. else
  60. " ----this
  61. " --next
  62. let value = a:this_indent
  63. endif
  64. return value
  65. endfunction
  66. function! s:FoldForSpecialLine(this_line)
  67. if a:this_line =~ s:empty_line
  68. return '='
  69. elseif a:this_line =~ s:vue_tag_start
  70. return '>1'
  71. elseif a:this_line =~ s:vue_tag_end
  72. " If return '<1', fold will get incorrect with prev line
  73. return 1
  74. else
  75. return -2
  76. endif
  77. endfunction
  78. function! s:IndentLevel(lnum)
  79. " Add 1 to indentLevel, so start/end tags can fold properly
  80. return indent(a:lnum) / &shiftwidth + 1
  81. endfunction
  82. "}}}
  83. call VueFoldMain()