How do I enable LSP and treesitter-powered code folding in Neovim with nvim-ufo?
Answer
:lua require('ufo').openAllFolds()
Explanation
nvim-ufo is a Neovim plugin that replaces the built-in fold system with one powered by LSP (textDocument/foldingRange) or treesitter. The result is accurate, language-aware folds that reflect real code structure — functions, classes, blocks — rather than just indentation levels.
How it works
nvim-ufo provides fold providers that query LSP or treesitter for fold ranges. A minimal setup:
vim.o.foldcolumn = '1'
vim.o.foldlevel = 99 -- start with all folds open
vim.o.foldlevelstart = 99
vim.o.foldenable = true
require('ufo').setup({
provider_selector = function(bufnr, filetype, buftype)
return { 'treesitter', 'indent' } -- fallback chain
end
})
The standard Vim fold keybindings (za, zo, zc, zR, zM) work unchanged. nvim-ufo also adds:
zR— open all folds (overridden by ufo to use its provider)zM— close all foldsK/ a custom keymap — peek into a closed fold without opening it:vim.keymap.set('n', 'K', function() local winid = require('ufo').peekFoldedLinesUnderCursor() if not winid then vim.lsp.buf.hover() end end)
Example
With LSP as the provider, a TypeScript file gets folds at function and class boundaries even if the indentation is inconsistent. A fold on a 200-line class shows a summary line with the number of folded lines, making large files far easier to navigate.
With treesitter fallback, languages without an LSP (shell scripts, config files) still get structural folds based on the grammar.
Tips
- Use
{ 'lsp', 'treesitter', 'indent' }as the provider chain to maximize coverage across file types peekFoldedLinesUnderCursor()opens a floating preview window — useful for reading function bodies without disrupting the current fold layout- Set
foldlevel = 99andfoldlevelstart = 99so files open fully expanded by default; close folds manually withzMorzm - nvim-ufo works alongside plugins like
statuscol.nvimfor a cleaner fold column display - The plugin respects
foldenable— disable per-buffer with:set nofoldenablewhen you want a flat view