Personalizar LazyVim sin romperlo
Override de plugins y opciones, tus propios keymaps, añadir y desactivar plugins, cambiar el tema y deshacer los choques de teclas que la distro trae de fábrica.
Aquí está la habilidad clave del Arquitecto: tomar una base ajena y hacerla tuya sin romperla. LazyVim está diseñada para que la modifiques con elegancia — override, no parche. Estas son las operaciones que necesitas, incluida la menos glamurosa y la más urgente: recuperar las teclas que la distro repartió por ti.
- Sobreescribir las
optsde un plugin de LazyVim. - Entender el caso especial de Treesitter, donde casi todo el mundo copia API muerta.
- Añadir tus propios plugins y desactivar los que no quieras.
- Poner tus opciones y keymaps que ganan a los de la distro.
- Resolver el choque de
s,Sy<C-Space>que LazyVim te deja servido. - Cambiar el tema (colorscheme).
La regla de oro: override, no editar la distro
Nunca edites los archivos internos de LazyVim. En su lugar, crea un archivo en lua/plugins/ con una spec del mismo plugin: LazyVim fusiona tu configuración con la suya. Tus cambios sobreviven a las actualizaciones.
1) Sobreescribir las opciones de un plugin
Devuelve una spec con el mismo plugin y tus opts. Se hace un deep merge con las de LazyVim:
return {
-- Referencia el plugin por su nombre corto: si el repo cambia de owner,
-- tu override sigue apuntando al sitio correcto.
{
"gitsigns.nvim",
opts = {
signs = { add = { text = "┃" }, change = { text = "┃" } },
},
},
}
¿Necesitas lógica, no solo fusionar? Usa opts como función y recibes las opciones actuales para modificarlas:
return {
{
"nvim-lualine/lualine.nvim",
opts = function(_, opts)
-- modifica lo que LazyVim ya configuró
table.insert(opts.sections.lualine_x, " " .. os.date("%H:%M"))
return opts
end,
},
}
2) El caso especial: Treesitter
La rama main de nvim-treesitter es una reescritura incompatible. El módulo nvim-treesitter.configs desapareció, y con él highlight, indent e incremental_selection. El plugin hoy hace una sola cosa: instalar parsers y aportar queries, con require("nvim-treesitter").install { "lua", "rust" }. El resaltado lo enciende vim.treesitter.start() desde un autocomando FileType, y el plegado sale de vim.wo[0][0].foldexpr = 'v:lua.vim.treesitter.foldexpr()' con foldmethod = 'expr'. Si un tutorial te enseña require("nvim-treesitter.configs").setup(...), está escrito para la rama congelada.
Dicho eso, dentro de LazyVim sí escribes ensure_installed, y aquí es donde se confunde casi todo el mundo:
return {
{
"nvim-treesitter/nvim-treesitter",
opts = { ensure_installed = { "swift", "zig" } }, -- se AÑADEN a las de LazyVim
},
}
ensure_installed no es una opción del plugin: es una opción de la spec de LazyVim, que la lee, la extiende como lista y luego llama por ti a la API real de la rama main. Por eso funciona aquí y por eso no hace absolutamente nada en la config a mano que montaste en el Nivel 2 — allí llamas tú directamente a require("nvim-treesitter").install.
No cambies el branch ni intentes reconfigurar cuándo carga: LazyVim ya gobierna esa spec en la rama main y sabe lo que hace. Limítate a añadir lenguajes por ensure_installed. Y si algún día sacas Treesitter de la distro, recuerda que fuera de aquí la rama main no admite carga perezosa: va con lazy = false, branch = "main" y build = ":TSUpdate".
3) Añadir tus propios plugins
Igual que en tu config a mano: la spec en lua/plugins/, y se suma a la base de LazyVim.
return {
{
"folke/zen-mode.nvim",
cmd = "ZenMode",
opts = {},
keys = {
{ "<leader>uz", "<cmd>ZenMode<cr>", desc = "Modo zen" },
},
},
}vim.pack.add({ { src = "https://github.com/folke/zen-mode.nvim" } })
require("zen-mode").setup({})
vim.keymap.set("n", "<leader>uz", "<cmd>ZenMode<cr>", { desc = "Modo zen" })Dentro de una config de LazyVim lo normal es la vía lazy. La de vim.pack te sirve si lo montas fuera de la distro o si mantienes también una config propia.
4) Desactivar un plugin de LazyVim
Ponle enabled = false:
return {
{ "folke/flash.nvim", enabled = false }, -- fuera flash, prefiero otra cosa
}
5) Opciones y keymaps que ganan
LazyVim carga tus lua/config/options.lua y keymaps.lua después de los suyos, así que lo tuyo prevalece:
-- se fusiona con las opciones de LazyVim; lo tuyo manda
vim.opt.relativenumber = true
vim.opt.scrolloff = 10
vim.g.snacks_animate = false
local map = vim.keymap.set
map("n", "<leader>ww", "<cmd>w<cr>", { desc = "Guardar rápido" })
-- ¿quitar un keymap que pone LazyVim? bórralo:
-- vim.keymap.del("n", "<leader>xx")
LazyVim trae which-key configurado: pulsa <leader> y espera para ver TODO su mapa de atajos, con sus grupos (<leader>f buscar, <leader>g git, <leader>c código…). Antes de crear un keymap, comprueba si ya existe uno; así no duplicas ni pisas nada sin querer.
6) El reparto de teclas: el conflicto que viene de fábrica
Esta es la personalización que de verdad importa, porque no falla con un error sino con silencio. Empieza por el diagnóstico, siempre:
:map s
:map <C-Space>
:map <Tab>
En una LazyVim recién instalada, :map s te responde que s y S son de flash.nvim, y :map <C-Space> te dice que esa tecla también. La buena noticia es que en lo primero LazyVim coincide con esta guía; la mala, que lo segundo hay que arreglarlo.
Lo que LazyVim hace bien: s para flash, gs para surround
Es exactamente el reparto de la lección 2.3, así que aquí no tienes que tocar nada. LazyVim cede s y S a flash porque un salto es una moción y merece dos teclas, y en su extra coding.mini-surround mueve surround al prefijo gs (gsa, gsd, gsr), que nativamente significa “dormir N segundos” y por tanto está libre. Se pierden s y S de Vim, que son cl y cc — coste casi nulo.
El choque aparece cuando tú añades mini.surround con sus valores por defecto encima, por ejemplo trayendo tu archivo del Nivel 2 sin adaptarlo. Entonces hay dos plugins reclamando s y gana el que cargue último. Si eso te pasa, la solución es la misma que ya usas: fijar el prefijo gs explícitamente.
return {
{
"mini.surround",
opts = {
mappings = {
add = "gsa", -- añadir delimitadores
delete = "gsd", -- borrarlos
replace = "gsr", -- cambiarlos
find = "gsf",
find_left = "gsF",
highlight = "gsh",
},
},
},
}
O más simple: activa el extra con :LazyExtras y no escribas nada, porque hace justo esto.
Lo que sí hay que quitarle: <C-Space>
Esta no se negocia. En este track <C-Space> está reservado para el autocompletado —el nativo de 0.12 se enciende con vim.o.autocomplete y se afina con vim.opt.completeopt— y <Tab> para moverse por su menú. LazyVim se la da a flash, y el síntoma es que tu completado deja de responder sin dar ningún error.
-- Ctrl-Espacio es del autocompletado. Punto.
pcall(vim.keymap.del, { "n", "x", "o" }, "<C-Space>")
Si además prefieres quedarte solo con los mapeos de flash que tú elijas y descartar el resto de los suyos (r, R y <C-Space> incluidos), pasa keys como función: lazy descarta las teclas heredadas y usa únicamente lo que devuelvas.
return {
"folke/flash.nvim",
-- keys como función DESCARTA las de LazyVim (s, S, r, R y Ctrl-Espacio)
keys = function()
return {
{ "s", mode = { "n", "x", "o" }, function() require("flash").jump() end, desc = "Flash: saltar" },
{ "S", mode = { "n", "x", "o" }, function() require("flash").treesitter() end, desc = "Flash: nodo" },
}
end,
}
Reinicia y vuelve a ejecutar :map s y :map <C-Space>. :map s debe mostrar un solo dueño, flash, y :map <C-Space> debe salir vacío en modo normal. Si :map s te lista dos entradas, todavía tienes la bomba puesta: solo que hoy ha cargado en el orden que te favorece.
7) Cambiar el tema
LazyVim usa Tokyo Night por defecto. Para poner Catppuccin (o cualquier otro), instala el tema y dile a LazyVim que lo use:
return {
{ "catppuccin/nvim", name = "catppuccin", opts = { flavour = "mocha" } },
{
"LazyVim/LazyVim",
opts = { colorscheme = "catppuccin" },
},
}vim.pack.add({ { src = "https://github.com/catppuccin/nvim" } })
require("catppuccin").setup({ flavour = "mocha" })
vim.cmd.colorscheme("catppuccin")Dentro de LazyVim usa la vía lazy: la distro necesita saber el nombre del tema para cargarlo en el momento correcto.
Todo en LazyVim se personaliza declarando lo que quieres distinto, no reescribiendo lo que ya funciona. Un archivo por cambio, cada uno diciendo “de este plugin, cambia esto”. Tu carpeta lua/plugins/ se convierte en la lista de tus decisiones sobre la base, y cuando la distro se actualice tus overrides seguirán en pie porque nunca tocaste sus tripas. Pero fíjate en cuál ha sido el override más importante de esta lección: no una opción bonita, sino repartir el teclado. Una config con cuarenta plugins tiene un presupuesto de teclas finito, y el conflicto no avisa con un error — una función simplemente deja de responder y crees que el plugin está roto. Por eso :map y :checkhealth son las dos primeras cosas que miras cuando algo “no funciona”.
- Ejecuta
:map sy:map <C-Space>y anota quién los tiene ahora mismo. - Elige la opción A o la B y aplícala. Vuelve a ejecutar
:map s: debe haber un solo dueño. - Borra el mapeo de
<C-Space>y confirma que tu autocompletado responde otra vez. - Cambia el tema a Catppuccin con un override.
- Añade un plugin nuevo (por ejemplo zen-mode) en
lua/plugins/. - Desactiva un plugin que no uses con
enabled = false. - Añade
swiftaensure_installedde Treesitter y comprueba que se suma a los de LazyVim en vez de sustituirlos.