Writing a custom fold expression
With a little bit of Vimscript, you can create a custom folding expression for any filetype. We’ll start by looking at the mechanics of folding with markers, then go on to create a folding expression for markdown documents.
I’ll be running my Core Vim Class online on Monday, January 27th. Tickets cost £160, but you can get the earlybird discount of £145 if you buy yours before January 24th. The price includes an exclusive screencast that summarises the material from the class.
Here’s a gist of the markdown folding expression that was created in the video.
Creating an ftplugin
Create a filetype plugin for markdown files as follows:
mkdir -p ~/.vim/after/ftplugin/markdown vim ~/.vim/after/ftplugin/markdown/folding.vim
You can replace
markdown with the name of any other language to create a filetype plugin for that language instead.
The mechanics of a
Here’s the boilerplate fold expression that we used to begin with:
function! MarkdownFolds() return "0" endfunction setlocal foldmethod=expr setlocal foldexpr=MarkdownFolds()
It works like this: the
MarkdownFolds() function is called one time for each line in the document. If the function returns
"0", it indicates that the line is not part of a fold. If the function returns
"1", it indicates that the line has a fold level of one. Here are a few more values that can be returned from a fold expression, with their meanings:
||the line is not in a fold|
||the line is in a fold with this level|
||use fold level from the previous line|
||a fold with this level starts at this line|
For a complete list of values that can be returned by a fold expression, look up
Inside of a fold expression, we can use the
v:lnum variable to access the line number of the current line that is being evaluated. This can easily be combined with the
getline() function to get the contents of the current line that’s being evaluated.
We can customize the way that a fold looks by way of the
foldtext option. Here’s the boilerplate foldtext expression that we used to begin with:
function! MarkdownFoldText() return getline(v:foldstart) endfunction setlocal foldtext=MarkdownFoldText()
In preparing this material, I took inspiration from several sources, including: