wandres.dev
MAESTRO · Dominio profundo del editor

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.

⏱ 12 min

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.

🎯 Al terminar esta lección sabrás
  • 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
💡
foldlevelstart = 99 es clave

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
El flujo de lectura de un archivo nuevo

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

kevinhwang91/nvim-ufo
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.

🗂️
nvim-ufokevinhwang91/nvim-ufo

Plegado moderno con proveedores LSP + Treesitter y un foldtext que dice cuántas líneas oculta cada fold. El estándar para folds bonitos.

opt
⛳ DRILL Entra en un archivo de 400 líneas y localiza una función concreta sin hacer scroll ciego.
Ver solución
zM · zj/zk · za

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.

⚔️ Pliega como un maestro
  1. Activa el plegado por Treesitter con el autocomando de FileType (o instala nvim-ufo, pero no las dos cosas).
  2. Abre un archivo grande y pulsa zM: ¿ves el esqueleto?
  3. Navega con zj/zk y abre uno con za.
  4. Vuelve a expandir todo con zR.