Closely related to the previous chapter's topic of navigating vertically in a buffer, Neovim's fold feature takes a different approach to simplifying vertical navigation, while also providing some additional benefits. Rather than define how the cursor navigates over buffer content, folds temporarily collapse groups of lines in buffer down to a single line so that they can be navigated over, yanked, deleted, etc. This not only simplifies navigation, many users leverage folds to create a more distraction-free editing environment by hiding content that is not their present focus of editing.
As a conceptual example of how folds can simplify navigation, one might configure Neovim to open Markdown documents so that only the section headings are visible, while the section bodies are all folded By doing so, the user can quickly navigate to a specific section with just a few keystrokes, "unfold" the content of that section, then begin editing.
Background
Before we get into how to work with folds, let's quickly get a high-level review of how folds work. When Neovim opens a buffer it applies the fold-method that is defined in your configuration. Fold-methods define how a particular document should be folded, and there are a variety of fold-methods available, but we will get into that a bit later.
Each fold-method defines one or more fold-levels, which are a numerical indication of "how much"
folding should occur. Fold-levels start from 0
, meaning fully-folded, then increment as
portions of the content are unfolded, up to the number of fold-levels defined for the current
fold-method.
Going back to our conceptual Markdown example, when the document was opened only the top-level H1
headings were visible and the content of each section was folded. This represents the "deepest"
fold state, since all but the top-level content is contained within folds. Now, suppose we
navigate to a section then unfold it one level by pressing zr. At this point, the direct
content of the H1
sections including any H2
headers might appear, while
pressing it again might display the direct content of the H2
sections, plus any H3
headers.
Opening and Closing Folds
Fold-related commands start with z
, which is appropriate since it looks a bit like a folded
piece of paper. This z
is followed by a second letter that defines the fold action to be
taken. In almost all cases the second letter can be specified in two ways, lower-case and
upper-case, where specifying the lower-case option asserts the specified action a single time, while
the upper-case option asserts the specified action recursively.
We think of Neovim's fold commands as being grouped into two scopes, where "global" fold commands apply to the entire buffer, while "local" fold commands apply to the section that currently contains the cursor. Let's look at both separately.
Global Folding and Unfolding
Global folds apply to to an entire buffer, which can be very useful when opening a new document to "get a feel" for the structure, locate certain sections, etc. The global fold commands are:
Command | Action |
---|---|
zr | Decrease folding by one level (reduce folding) |
zm | Increase folding by one level (more folding) |
zR | Open (Remove) all folds |
zM | Close all folds (More folding) |
To get a quick feel for these commands, open a file then hit zR to make sure all folds are open, then hit zM to quickly close all folds. Now, hit zr a few times to decrease the level of folding one step at a time. This may or may not do much, depending on the file type and how you currently have folds configured, but this should give most readers a quick feel for global folding.
Local Folding and Unfolding
Next, lets take a look at the fold commands that operate on only the portion of the document that contains the cursor.
Command | Action |
---|---|
zo | open fold |
zO | open folds recursively |
zc | close a fold |
zC | close folds recursively |
za | open a closed fold, close an open fold |
zA | open a closed fold or close an open fold recursively |
zv | open enough folds to view the cursor line |
To get a quick feel for how these commands differ from the global commands discussed previously, go back to the file you opened previously, then hit zM to close all of the folds in the document, as you did before. Now move the cursor over to some folded content, hit zo to open only the fold that contains the cursor, then zc to close it again. Toggling fold state is quite common, so there this can also be achieved by hitting za once to open the current fold, then hitting it again to toggle it closed again.
Fold-Methods
Set your fold-method in your Lua configuration file like this:
vim.opt.foldmethod = "fold-method"
where "fold-method" is the name of the method that you would like to use.
Neovim supports each of the legacy Vim fold-methods:
- manual
- Folds are manually opened and closed by executing the previously-discussed commands
- indent
- Folds are automatically created based upon indentation level
- syntax
- Folds are automatically created based on the current syntax highlighting
- marker
- Folds are automatically created based upon markers in the text
- diff
- Folds are automatically created for changed/unchanged text, when operating in a diff window.
- expr
- Folds are automatically created based upon the specified expression
We find the manual method to be useful in many cases, but otherwise we find that Neovim's built-in Treesitter support provides much more accurate, language-specific folding that are superior to the legacy fold methods.
Tree-sitter based folds leverage the expr
fold-method, and use
nvim-treesitter's foldexpr
function to
define the folds for each supported language. Setup instructions are included at the
nvim-treesitter website, but in most cases is simple:
vim.wo.foldmethod = 'expr'
vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()'
Navigating Between Folds
Before we leave the topic of folds, we should also mention that Neovim provides convenient function that allow users to quickly navigate buffers quickly by jumping between the folds similar to how we might do for marks and text objects:
Command | Action |
---|---|
]z | move to end of open fold |
[z | move to start of open fold |
zj | move to the start of the next fold |
zk | move to the end of the previous fold |