Search code examples
vimmarkdownfolding

VIM change folding markdown to show lines and number of words using vimrc


I'm using GVIM on windows for writing sf novels and I fold the chapters so I can hide them away. When folded the chapter 'lines' show something like this:

##1 – Spaceman Spoof Encounters the Watterson........ 115 lines [2.4%] +--+--

This is useful but only a little bit. Some lines may be just a few words and others might be well over a 100 words. What I'd prefer is a line count and a word count like this:

##1 – Spaceman Spoof Encounters the Watterson........ l:115 w:1032 [4.4%] +--+--

with the percentage being that for the words and not for the lines. Any help would sure be appreciated.

Here's the folding section of my _vimrc:

function! MarkdownFolds()
    let thisline = getline(v:lnum)
    if match(thisline, '^##') >= 0
        return ">2"
    elseif match(thisline, '^#') >= 0
        return ">1"
    else
        return "="
    endif
endfunction

setlocal foldmethod=expr
setlocal foldexpr=MarkdownFolds()

function! MarkdownFoldText()
    "get first non-blank line
    let fs = v:foldstart
    while getline(fs) =~ '^\s*$' | let fs = nextnonblank(fs + 1)
    endwhile
    if fs > v:foldend
        let line = getline(v:foldstart)
    else
        let line = substitute(getline(fs), '\t', repeat(' ', &tabstop), 'g')
    endif

    let w = winwidth(0) - &foldcolumn - (&number ? 8 : 0)
    let foldSize = 1 + v:foldend - v:foldstart
    let foldWords = v:foldend,v:foldstart!wc -w
    let foldSizeStr = " " . foldSize . " lines "
    let foldWordsStr = " " . foldWords . " w "
    let foldLevelStr = repeat("+--", v:foldlevel)
    let lineCount = line("$")
    let foldPercentage = printf("[%.1f", (foldSize*1.0)/lineCount*100) . "%] "
    " let expansionString = "."
    let expansionString = repeat(".", w - strwidth(foldSizeStr.line.foldLevelStr.foldPercentage))
    return line . expansionString . foldSizeStr . foldPercentage . foldLevelStr
    " return line . expansionString . foldSizeStr . foldPercentage . foldWordsStr . foldLevelStr
    " return line . "......" . foldSizeStr . foldPercentage . foldLevelStr
endfunction

setlocal foldtext=MarkdownFoldText()

Solution

  • Here is a solution:

    function! MarkdownFoldText()
        "get first non-blank line
        let fs = v:foldstart
        while getline(fs) =~ '^\s*$' | let fs = nextnonblank(fs + 1)
        endwhile
        if fs > v:foldend
            let line = getline(v:foldstart)
        else
            let line = substitute(getline(fs), '\t', repeat(' ', &tabstop), 'g')
        endif
    
        let w = winwidth(0) - &foldcolumn - (&number ? 8 : 0)
        let foldSize = 1 + v:foldend - v:foldstart
    
        let i = 0
        let foldWords=0
        let wordCount=0
        while (i<line('$'))
          let lineWords = len(split(getline(i)))
          if (i<=v:foldend && i>= v:foldstart)
            let foldWords = foldWords + lineWords
          endif
          let wordCount += lineWords
          let i += 1
        endwhile
    
        let foldWordsStr = " " . foldWords . " w,"
        let foldSizeStr = foldWordsStr . foldSize . " lines "
        let foldLevelStr = repeat("+--", v:foldlevel)
        let foldPercentage = printf("[%.1f", (foldWords*1.0)/wordCount*100) . "%] "
        let expansionString = repeat(".", w - strwidth(foldSizeStr.line.foldLevelStr.foldPercentage))
        return line . expansionString . foldSizeStr . foldPercentage . foldLevelStr
    endfunction
    

    The idea is to count the global word count, and the one that is just in the selected region at the same time.

    Then we replace the percentage with the word count as requested.