I'm trying to create a simple, fast folding method for large markdown files. I'm using the fold-expr
method in vim. For example, if I wanted to start folds on H1
and H2
markdown entries, my vimscript code is:
function! MarkdownLevel()
if getline(v:lnum) =~ '^# '
" begin a fold of level one here
return ">1"
elseif getline(v:lnum) =~ '^## '
" begin a fold of level two
return ">2"
else
return "="
endif
endfunction
This works perfectly, and I get nested folds. However, when I have a large markdown file, vim slows down considerably. This is unsurprising and is, in fact, indicated in the fold-expr help in vim. It's because the =
sign tells vim to scan backwards in the file until the first line with an explicitly defined foldlevel can be found; this could be thousands of lines away.
I tried to replace the last line with
else
" set foldlevel to foldlevel of previous line
return foldlevel(v:lnum-1)
endif
But this doesn't work as expected. Does anyone know how to fix this? It's clear I'm not understanding how the foldlevel function works, or how the folding algorithm in vim is implemented.
I figured out how to fix the slowdown and learned somethings about how
fold-expr
works in vim. I tested the performance issues on a 3000 line md file.I was relying on the following automatic folding functionality that
fold-expr
is supposed to have: it starts a fold if foldlevel of the current line is smaller than the foldlevel of the next. It ends a fold if the foldlevel of the current line is larger than the foldlevel of the next. Turns out that this does not work as intended, as far as I can tell.What worked was to explicitly tell vim that a fold starts here using
return ">1"
, where1
is replaced by the appropriate number.After learning how to profile vim scripts from @PeterRinker, I figured out that the
return "="
statement was being evaluated many, many times when I was editing line (for example) 3000.This was my fix: if the foldlevel of the current line does not fall into any of the heading types and the foldlevel of the previous line has already been defined, the current line should just inherit the foldlevel of the previous line. This is an obvious solution, but it does not work if I used
return "1"
instead ofreturn ">1"
above. It needs thereturn "="
statement on the first pass to figure out the foldlevel.So my startup times are a little big (about 1 second) for a 3000 line file, but now editing is very smooth. The following is the finished, simplistic code. Other more elaborate markdown projects do not have this useful simplification.