Improving the text displayed in a Vim fold.

I have just recently got irritated enough with the current way that folds appear in Vim that I decided to roll my own custom foldtext function.

In particular I wanted the top (non-blank) line to be displayed clearly and cleanly. I also wanted to know not just how many lines were folded but what percentage of the file this accounts for. This is often useful for quickly glancing at to see where most of the document resides. I also wanted a nice easy way of visualising the fold level and how that compares to the folds surrounding a fold.

This is the end result.

 1 fu! CustomFoldText()
 2     "get first non-blank line
 3     let fs = v:foldstart
 4     while getline(fs) =~ '^\s*$' | let fs = nextnonblank(fs + 1)
 5     endwhile
 6     if fs > v:foldend
 7         let line = getline(v:foldstart)
 8     else
 9         let line = substitute(getline(fs), '\t', repeat(' ', &tabstop), 'g')
10     endif
12     let w = winwidth(0) - &foldcolumn - (&number ? 8 : 0)
13     let foldSize = 1 + v:foldend - v:foldstart
14     let foldSizeStr = " " . foldSize . " lines "
15     let foldLevelStr = repeat("+--", v:foldlevel)
16     let lineCount = line("$")
17     let foldPercentage = printf("[%.1f", (foldSize*1.0)/lineCount*100) . "%] "
18     let expansionString = repeat(".", w - strwidth(foldSizeStr.line.foldLevelStr.foldPercentage))
19     return line . expansionString . foldSizeStr . foldPercentage . foldLevelStr
20 endf

And these are the folds that it produces.

Leave a Reply


Responses to “Improving the text displayed in a Vim fold.”

  1. Pretty beautiful, thanks!
    For those readers who didn’t know how to set up the fold text function, set foldtext=CustomFoldText() below the function definition does the trick.

  2. Ah yes, thank you for pointing that out.

  3. Thanks for the tip (and for your excellent plugin Gitv). However, it seems you unintentionally ignored the situation of double-width characters (e.g. Chinese characters). As a result, strlen(line) returns wrong number and the generated fold text appears unaligned. My solution is simple: just use strwidth() to replace strlen(). Hope it helps.

    • Thanks for drawing my attention to this. I’ve fixed the code with an update. It now also handles tab characters (if you don’t use ‘expandtab’). This ‘strlen’ bug was present in gitv also, so I’ve fixed that too. Look for an update in the github repo.

  4. Thanks. I git-pull’ed the Gitv code. Nice job!

  5. Been using this fold function for a week, and never want to go back to the original again. It’s way more clever! Thanks for sharing <3

  6. This is very nice. Thanks.

  7. Heya i’m for the first time here. I found this board and I find It really helpful & it helped me out a lot. I’m hoping to provide one thing back and aid others such as you aided me.|

  8. Hey awesome!!!

    I modified a bit to clean up trailing characters i use in my foldmarker setup.

    ” folding setup
    set foldmarker={{{,}}}
    autocmd Syntax c,cpp,tcl,xml set foldmethod=marker

    ” custom fold display
    fu! CustomFoldText()
    “get first non-blank line
    let fs = v:foldstart
    while getline(fs) =~ ‘^\s*$’ | let fs = nextnonblank(fs + 1)
    if fs > v:foldend
    let line = getline(v:foldstart)
    let line = substitute(getline(fs), ‘\t’, repeat(‘ ‘, &tabstop), ‘g’)
    ” for c type commenting remove the foldmarker
    let line = substitute(line, “{ \/\/ {{{“, “”, ‘g’)
    let line = substitute(line, “{ \/\/{{{“, “”, ‘g’)
    let line = substitute(line, “\/\/ {{{“, “”, ‘g’)
    let line = substitute(line, “\/\/{{{“, “”, ‘g’)
    let w = winwidth(0) – &foldcolumn – (&number ? 8 : 0)
    let foldSize = 1 + v:foldend – v:foldstart
    let foldSizeStr = ” ” . foldSize . ” lines ”
    let foldLevelStr = repeat(“+–”, v:foldlevel)
    let lineCount = line(“$”)
    let foldPercentage = printf(“[%.1f", (foldSize*1.0)/lineCount*100) . "%] ”
    let expansionString = repeat(“.”, w – strwidth(foldSizeStr.line.foldLevelStr.foldPercentage))
    return line . expansionString . foldSizeStr . foldPercentage . foldLevelStr
    set foldtext=CustomFoldText()

  9. Thanks for sharing, much appreciated!

    But I like more how the fold text looks from left, like in this:

    With neat closing on the right, with some +—.

    Any chance to integrate it into your code?