Sfoglia il codice sorgente

update vim fold text WIP

Made cleaner, diff fold now handled differently, fold descriptions still work in
progress. Taking stuff from lokaltog's foldtext as is useful (though a fair
amount of it is also a bit disorganised).
Weiyi Lou 12 anni fa
parent
commit
36609b1e73
1 ha cambiato i file con 170 aggiunte e 49 eliminazioni
  1. 170 49
      vim/settings/folding.vim

+ 170 - 49
vim/settings/folding.vim

@@ -1,11 +1,11 @@
 " Folding - Modeline and Notes {{{
-" vim: set sw=2 ts=2 sts=2 et tw=78 foldmarker={{{,}}} foldlevel=0 foldmethod=marker spell:
+" vim: set sw=2 ts=2 sts=2 et tw=78 foldmarker={{{,}}} foldlevel=0 foldmethod=marker:
 "
 "   cinaeco/dotfiles Folding Settings
 "
 "   These are settings to make folding easier to use and look at:
 "    - Indented Folds to match their first line.
-"    - Stat box to right displays line count and fold level.
+"    - Statbox to right displays line count and fold level.
 "    - Coloured distinctly red!
 "        (sounds harsh, but actually works well with solarized-dark!)
 "    - Fillchar is forced to '.' rather than '-'.
@@ -13,7 +13,7 @@
 "    - SpaceBar toggles folds, if any.
 "        (much more convenient than the 'z' commands)
 "    - SPF13-VIM provides quick foldlevel setting map: <Leader>f[0-9]
-"        (useful with stat box lvl)
+"        (useful with statbox lvl)
 "
 "   Note that custom foldtext will only work for vim 7.3+. For earlier
 "   versions of vim, only the colouring and spacebar mapping will take effect.
@@ -46,79 +46,200 @@ if has('folding')
   " }}}
 
   " Fold Highlighting {{{
-  " Red fold text! (Pretty good with solarized-dark)
-  highlight Folded term=none cterm=none ctermfg=darkred ctermbg=none guifg=darkred guibg=none
+  highlight Folded term=none cterm=none ctermfg=darkgrey ctermbg=none guifg=darkgrey guibg=none
   " }}}
 
   " Fold Text {{{
   set foldtext=CustomFoldText()
 
-  function! CustomFoldText()
+  function! CustomFoldText(...)
 
-    " At least vim 7.3. {{{
-    "  - Requirement for strdisplaywidth.
+    " At least vim 7.3 {{{
+    "  - Requirement for strdisplaywidth().
+    "  - strdisplaywidth() seems to work. If multi-byte characters start to give
+    "  trouble, consider checking the more primitive solution in strlen() help.
     if v:version < 703
       return foldtext()
     endif
     " }}}
 
-    " Force dot fillchar. {{{
-    "  - The complicated line is to ensure we replace the fold fillchar only.
+    " Common variables for all foldmethods {{{
+    let lineCount = v:foldend - v:foldstart + 1
+    let displayWidth = winwidth(0) - &foldcolumn
+    if (&number || &relativenumber)
+      let displayWidth -= &numberwidth
+    endif
+    let foldChar = '┄'
+    " }}}
+
+    " Set fold fillchar {{{
+    "  - This complicated line is to ensure we replace the fold fillchar only.
     let &l:fillchars = substitute(&l:fillchars,',\?fold:.','','gi')
-    setlocal fillchars+=fold:.
+    exec 'setlocal fillchars+=fold:' . foldChar
     " }}}
 
-    " Prepare script variables. {{{
-    let foldChar = matchstr(&fillchars, 'fold:\zs.')
-    let currWinWidth = winwidth(0)
+    " Handle diff foldmethod {{{
+    "  - Display a centre-aligned statbox with the number of lines.
+    if &foldmethod == 'diff'
+
+      " Prepare the statbox {{{
+      let statBox = printf('[ %s matching lines ]', lineCount)
+      " }}}
+
+      " Prepare filler lines {{{
+      let filler = repeat(foldChar, (displayWidth - strchars(statBox)) / 2)
+      " }}}
+
+      " Output the combined fold text {{{
+      return filler.statBox
+      " }}}
+
+    endif
     " }}}
 
-    " Prepare fold indent. {{{
-    "  - Indent taken from first line in fold.
-    let indentLevel = indent(v:foldstart)
-    let indent = repeat(' ', indentLevel)
+    " Handle all other foldmethods {{{
+
+      " Prepare fold indent and indicator {{{
+      "  - If indent allows, build the indicator into it.
+      let foldIndicator = '▸ '
+      let indLen = strdisplaywidth(foldIndicator)
+      if indent(v:foldstart) >= indLen
+        let indent = repeat(' ', indent(v:foldstart) - indLen) . foldIndicator
+      else
+        let indent = repeat(' ', indent(v:foldstart))
+      endif
+      " }}}
+
+      " Prepare the statbox {{{
+      "  - Fixed statbox width at 18 characters.
+      "  - Count width by display cells instead of bytes if at least vim 7.4
+      if v:version >= 704
+        let countType = 'S'
+      else
+        let countType = 's'
+      endif
+      let statBox = '[ ' . printf('%14'.countType, lineCount.' lns, lv '.v:foldlevel) . ' ]'
+      " }}}
+
+      " Prepare fold description {{{
+      "  - Remove fold markers and comment markers.
+      "  - Truncate to 1/3 of the current window width.
+
+        " Use function argument as line text if provided {{{
+        let line = a:0 > 0 ? a:1 : getline(v:foldstart)
+        " }}}
+
+        " Remove fold markers {{{
+        let foldmarkers = split(&foldmarker, ',')
+        let line = substitute(line, '\V' . foldmarkers[0] . '\%(\d\+\)\?\s\*', '', '')
+        " }}}
+
+        " Remove surrounding whitespace {{{
+        let line = substitute(line, '^\s*\(.\{-}\)\s*$', '\1', '')
+        " }}}
+
+        " Add an extra space at the end {{{
+        let foldDesc = line.' '
+        " }}}
+
+      " }}}
+
+      " Prepare filler lines {{{
+      "  - midFiller is the fill between the description and statbox.
+      "  - midFiller compensates for column widths generated by foldcolumn, number
+      "  and relativenumber.
+      let endFiller = repeat(foldChar, 1)
+      let midFillerLength = displayWidth - strdisplaywidth(indent.foldDesc.statBox.endFiller)
+      let midFiller = repeat(foldChar, midFillerLength)
+      " }}}
+
+      " Output the combined fold text {{{
+      return indent.foldDesc.midFiller.statBox.endFiller
+      " }}}
+
     " }}}
 
-    " Prepare fold description. {{{
-    "  - Truncated to 1/3 of the current window width.
-    let allFoldMarkers = split(&foldmarker, ',')
-    let frontFoldMarker = allFoldMarkers[0]
-    let lineRaw = substitute(getline(v:foldstart), '^\s*"\?\s*\|\s*"\?\s*'.frontFoldMarker.'\d*\s*', '', 'g')
-    let line = '+ '.lineRaw.' '
-    let foldDesc = strpart(line, 0, currWinWidth / 3)
+  endfunction
+  " }}}
+
+  " Lokaltog's Fold Text for learning more stuff about fold description preparation {{{
+  function! FoldText(...)
+    " This function uses code from doy's vim-foldtext: https://github.com/doy/vim-foldtext
+    " Prepare fold variables {{{
+    " Use function argument as line text if provided
+    let l:line = a:0 > 0 ? a:1 : getline(v:foldstart)
+
+    let l:line_count = v:foldend - v:foldstart + 1
+    let l:indent = repeat(' ', indent(v:foldstart))
+
+    let l:w_win = winwidth(0)
+    let l:w_num = getwinvar(0, '&number') * getwinvar(0, '&numberwidth')
+    let l:w_fold = getwinvar(0, '&foldcolumn')
     " }}}
+    " Handle diff foldmethod {{{
+    if &fdm == 'diff'
+      let l:text = printf('┤ %s matching lines ├', l:line_count)
 
-    " Prepare the stat box. {{{
-    "  - Fixed stat box width at 18 characters.
-    "  - Count width by display cells instead of bytes if at least vim 7.4
-    let lineCount = v:foldend - v:foldstart + 1
-    if v:version >= 704
-      let formatForm = 'S'
-    else
-      let formatForm = 's'
+      " Center-align the foldtext
+      return repeat('┄', (l:w_win - strchars(l:text) - l:w_num - l:w_fold) / 2) . l:text
     endif
-    let statBox = '| ' . printf('%18'.formatForm, lineCount.' lines, lvl '.v:foldlevel) . ' |'
     " }}}
+    " Handle other foldmethods {{{
+    let l:text = l:line
+    " Remove foldmarkers {{{
+    let l:foldmarkers = split(&foldmarker, ',')
+    let l:text = substitute(l:text, '\V' . l:foldmarkers[0] . '\%(\d\+\)\?\s\*', '', '')
+    " }}}
+    " Remove comments {{{
+    let l:comment = split(&commentstring, '%s')
 
-    " Prepare filler lines. {{{
-    "  - endFiller is the fill after the stat box. Fixed at 5 characters.
-    "  - midFiller is the fill between the description and stat box.
-    "  - midFiller compensates for column widths generated by foldcolumn, number
-    "  and relativenumber.
-    "  - strdisplaywidth() seems to work. If multi-byte characters start to give
-    "  trouble, consider checking the more primitive solution in strlen() help.
-    let endFiller = repeat(foldChar, 5)
-    let midFillerLength = winwidth(0) - strdisplaywidth(indent.foldDesc.statBox.endFiller) - &foldcolumn
-    if (&number || &relativenumber)
-      let midFillerLength -= &numberwidth
+    if l:comment[0] != ''
+      let l:comment_begin = l:comment[0]
+      let l:comment_end = ''
+
+      if len(l:comment) > 1
+        let l:comment_end = l:comment[1]
+      endif
+
+      let l:pattern = '\V' . l:comment_begin . '\s\*' . l:comment_end . '\s\*\$'
+
+      if l:text =~ l:pattern
+        let l:text = substitute(l:text, l:pattern, ' ', '')
+      else
+        let l:text = substitute(l:text, '.*\V' . l:comment_begin, ' ', '')
+
+        if l:comment_end != ''
+          let l:text = substitute(l:text, '\V' . l:comment_end, ' ', '')
+        endif
+      endif
     endif
-    let midFiller = repeat(foldChar, midFillerLength)
     " }}}
-
-    " Output the combined fold text. {{{
-    return indent.foldDesc.midFiller.statBox.endFiller
+    " Remove preceding non-word characters {{{
+    let l:text = substitute(l:text, '^\W*', '', '')
+    " }}}
+    " Remove surrounding whitespace {{{
+    let l:text = substitute(l:text, '^\s*\(.\{-}\)\s*$', '\1', '')
+    " }}}
+    " Make unmatched block delimiters prettier {{{
+    let l:text = substitute(l:text, '([^)]*$',   '⟯ ⋯ ⟮', '')
+    let l:text = substitute(l:text, '{[^}]*$',   '⟯ ⋯ ⟮', '')
+    let l:text = substitute(l:text, '\[[^\]]*$', '⟯ ⋯ ⟮', '')
     " }}}
+    " Add arrows when indent level > 2 spaces {{{
+    if indent(v:foldstart) > 2
+      let l:cline = substitute(l:line, '^\s*\(.\{-}\)\s*$', '\1', '')
+      let l:clen = strlen(matchstr(l:cline, '^\W*'))
 
+      let l:indent = repeat(' ', indent(v:foldstart) - 2)
+      let l:text = '▸ ' . l:text
+    endif
+    " }}}
+    " Prepare fold text {{{
+    let l:fnum = printf('┤ %s ⭡ ', printf('%4s', l:line_count))
+    let l:ftext = printf('%s%s ', l:indent, l:text)
+    " }}}
+    return l:ftext . repeat('┄', l:w_win - strchars(l:fnum) - strchars(l:ftext) - l:w_num - l:w_fold) . l:fnum
+    " }}}
   endfunction
   " }}}