Subscribe for free with iTunes, Twitter, or RSS (Ogg or Quicktime).

Vimcasts

Writing a custom fold expression

#38

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.

Download

OGG 18.1 MB

Quicktime 23.8 MB

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 foldexpr

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:

value meaning
"0" the line is not in a fold
"1", "2", ... the line is in a fold with this level
"=" use fold level from the previous line
">1", ">2" 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 :help fold-expr.

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.

Customizing the foldtext

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()

Inside of a foldtext expression, we can use the v:foldstart and v:foldend variables, which reference the line numbers of the first and last lines that make up the current fold.

Further Reading

In preparing this material, I took inspiration from several sources, including: