Plegado (folds): domar archivos enormes
Colapsa y expande secciones de código para navegar archivos grandes. Folds por Treesitter, atajos esenciales y nvim-ufo para un plegado moderno y bonito.
Un archivo de 800 líneas es inmanejable si lo ves todo a la vez. Los folds te dejan colapsar funciones, clases y bloques para ver solo la estructura, y expandir justo lo que necesitas. Es como un mapa plegable de tu código.
- Entender los métodos de plegado y elegir el bueno (Treesitter).
- Los atajos esenciales para plegar y desplegar.
- Configurar folds por Treesitter en tu init.lua.
- nvim-ufo para un plegado moderno con texto informativo.
Métodos de plegado
Neovim puede decidir qué plegar de varias formas (foldmethod):
| Método | Cómo decide los folds |
|---|---|
manual |
los creas tú a mano |
indent |
por nivel de indentación (rápido y decente) |
expr |
por una expresión — aquí entra Treesitter |
marker |
por marcadores en comentarios |
El mejor con diferencia es expr con Treesitter: pliega por la estructura real del código (funciones, clases, bloques), no por indentación aproximada.
Configurar folds por Treesitter
Antes de copiar nada, aclaremos el malentendido más extendido: el plegado por Treesitter lo da Neovim, no el plugin. La función es vim.treesitter.foldexpr() y vive en el core desde hace varias versiones. nvim-treesitter (rama main, la única viva) solo instala parsers y queries: no configura ningún plegado por ti, así que si un tutorial te enseña a activar folds desde su setup, está escrito para la rama muerta.
Además, foldmethod y foldexpr son opciones de ventana, no globales: si las pones para todo el editor también se aplican a buffers sin parser. Actívalas por tipo de archivo, junto al resaltado (lección 2.3):
vim.api.nvim_create_autocmd("FileType", {
callback = function(args)
-- Nada de lista de lenguajes: pregunta si hay parser para este buffer.
-- Si no lo hay, no toca foldexpr y el plegado nativo sigue intacto.
local lang = vim.treesitter.language.get_lang(vim.bo[args.buf].filetype)
if not lang or not vim.treesitter.language.add(lang) then return end
vim.treesitter.start(args.buf, lang) -- resaltado
vim.wo[0][0].foldexpr = "v:lua.vim.treesitter.foldexpr()" -- plegado
vim.wo[0][0].foldmethod = "expr"
end,
})
Fíjate en que el guard resuelve justo el problema del párrafo anterior: en un buffer sin parser la función sale antes de tocar nada, así que foldmethod se queda como estaba. Y al instalar un parser nuevo funciona solo, sin editar ninguna lista.
El resto de opciones de plegado sí son globales y van con las demás:
vim.o.foldtext = "" -- pinta la línea plegada con su resaltado normal
vim.o.foldlevelstart = 99 -- abre todo al entrar (no empieces todo plegado)
vim.o.foldnestmax = 4
Sin él, abres un archivo y todo aparece plegado — molesto. Con foldlevelstart = 99 entras con todo desplegado y pliegas solo cuando quieres. Es la configuración que espera casi todo el mundo.
Los atajos esenciales
Todos en modo Normal, sobre una línea plegable:
| Tecla | Acción |
|---|---|
za |
alterna el fold bajo el cursor (el más usado) |
zo / zc |
abrir / cerrar el fold |
zR / zM |
abrir todos / cerrar todos |
zr / zm |
abrir / cerrar un nivel en todo el archivo |
zj / zk |
saltar al siguiente / anterior fold |
zv |
abre justo lo necesario para ver el cursor |
Abres un archivo desconocido, pulsas zM para plegarlo todo y ver solo las firmas de funciones y clases: el esqueleto del archivo de un vistazo. Localizas la parte que te interesa, za para abrirla, y trabajas. Es la forma más rápida de orientarte en código ajeno: primero el mapa, luego el detalle.
nvim-ufo: el plegado moderno
El plegado nativo funciona, pero nvim-ufo lo lleva a otro nivel: pide los folds a un proveedor (el LSP, Treesitter o la indentación como respaldo) y muestra un texto de fold informativo (cuántas líneas hay plegadas, con resaltado).
return {
"kevinhwang91/nvim-ufo",
dependencies = { "kevinhwang91/promise-async" },
event = "BufReadPost",
init = function()
vim.o.foldcolumn = "1"
vim.o.foldlevel = 99
vim.o.foldlevelstart = 99
vim.o.foldenable = true
end,
opts = {
provider_selector = function(bufnr, filetype, buftype)
return { "treesitter", "indent" }
end,
},
keys = {
{ "zR", function() require("ufo").openAllFolds() end, desc = "Abrir todos los folds" },
{ "zM", function() require("ufo").closeAllFolds() end, desc = "Cerrar todos los folds" },
},
}vim.pack.add({
{ src = "https://github.com/kevinhwang91/promise-async" },
{ src = "https://github.com/kevinhwang91/nvim-ufo" },
})
vim.o.foldcolumn = "1"
vim.o.foldlevel = 99
vim.o.foldlevelstart = 99
vim.o.foldenable = true
require("ufo").setup({
provider_selector = function(bufnr, filetype, buftype)
return { "treesitter", "indent" }
end,
})
vim.keymap.set("n", "zR", function() require("ufo").openAllFolds() end, { desc = "Abrir todos los folds" })
vim.keymap.set("n", "zM", function() require("ufo").closeAllFolds() end, { desc = "Cerrar todos los folds" })ufo gestiona los folds él mismo, así que si lo usas NO pongas también el foldexpr de Treesitter de la sección anterior: elige uno de los dos. Y necesita foldlevel alto antes de arrancar, por eso las opciones van primero.
zR y zM hay que remapearlos porque ufo mantiene su propio foldlevel: las versiones nativas lo cambiarían y volverías a pelearte con folds que se cierran solos.
Plegado moderno con proveedores LSP + Treesitter y un foldtext que dice cuántas líneas oculta cada fold. El estándar para folds bonitos.
Ver solución
zM pliega todo → ves solo firmas. zj/zk saltan entre folds hasta la función objetivo. za la abre. zR cuando quieras volver a ver todo. Más rápido que scrollear a ojo.
- Activa el plegado por Treesitter con el autocomando de
FileType(o instala nvim-ufo, pero no las dos cosas). - Abre un archivo grande y pulsa
zM: ¿ves el esqueleto? - Navega con
zj/zky abre uno conza. - Vuelve a expandir todo con
zR.