Tu init.lua desde cero (Lua para Neovim)
Crea tu configuración modular en Lua: estructura de archivos, las opciones esenciales, la tecla leader y tus primeros keymaps. Sin distribuciones, todo tuyo.
Nada de LazyVim ni distribuciones prefabricadas. Vas a construir tu configuración pieza a pieza. Entender cada línea es lo que te da el control total: cuando algo falle (y fallará), sabrás exactamente dónde mirar.
- Estructurar la config en módulos Lua limpios y mantenibles.
- Lo mínimo de Lua que necesitas:
vim.opt,vim.g,vim.keymap.set. - Configurar las opciones esenciales de un buen entorno.
- Definir la tecla
leadery tus primeros atajos.
La estructura modular
Neovim carga ~/.config/nvim/init.lua al arrancar. Podrías meter todo ahí, pero una config de nivel dios se organiza en módulos. Esta es la estructura que usaremos toda la guía:
~/.config/nvim/
├── init.lua # punto de entrada: requiere el resto
└── lua/
└── config/
├── options.lua # opciones (vim.opt)
├── keymaps.lua # atajos globales
└── autocmds.lua # automatizaciones
Eso es todo por ahora. En la lección siguiente aparecerán los plugins, y ahí decidirás con qué gestor: vim.pack, que viene dentro de Neovim 0.12 y no añade ningún archivo, o lazy.nvim, que sí añade un lua/config/lazy.lua y una carpeta lua/plugins/. No lo des por hecho todavía.
Cualquier archivo dentro de lua/ se importa con require("ruta.sin.extension"), usando puntos en vez de barras. Crea el init.lua raíz así:
-- 1) leader ANTES de cargar plugins (importante)
vim.g.mapleader = " "
vim.g.maplocalleader = " "
-- 2) opciones y atajos base
require("config.options")
require("config.keymaps")
require("config.autocmds")
-- 3) Los plugins entran aquí en la lección 1.2.
vim.g.mapleader debe definirse antes de que se carguen los plugins, o algunos atajos se registrarán con el leader equivocado. Por eso está en la primera línea del init.lua.
Lua mínimo para Neovim
No necesitas dominar Lua para configurar Neovim. Con estas cuatro cosas te mueves en el 95% de los casos:
-- Variables globales de Vim (flags de plugins, leader...)
vim.g.mapleader = " "
-- Opciones del editor
vim.opt.number = true -- activar
vim.opt.tabstop = 4 -- con valor
vim.opt.clipboard:append("unnamedplus") -- métodos sobre opciones de lista
-- Atajos: vim.keymap.set(modo, teclas, acción, opciones)
vim.keymap.set("n", "<leader>w", ":w<CR>", { desc = "Guardar" })
-- Llamar funciones de la API
vim.api.nvim_create_autocmd("BufWritePre", { callback = function() end })
Usa vim.opt (soporta métodos como :append, tablas y es el idioma moderno). vim.o existe pero es más limitado. Para variables usa vim.g; para atajos, vim.keymap.set.
Opciones esenciales
Crea lua/config/options.lua. Estas son las opciones que todo buen setup activa, comentadas:
local opt = vim.opt
-- Números de línea (híbrido: relativo + absoluto en la actual)
opt.number = true
opt.relativenumber = true
-- Indentación
opt.tabstop = 2 -- ancho visual de un tab
opt.shiftwidth = 2 -- ancho de una indentación
opt.expandtab = true -- tabs -> espacios
opt.smartindent = true -- indentación inteligente
-- Búsqueda
opt.ignorecase = true -- ignora mayúsculas...
opt.smartcase = true -- ...salvo que escribas alguna
opt.hlsearch = false -- no resaltar tras buscar
opt.incsearch = true -- resaltar mientras escribes
-- Interfaz
opt.termguicolors = true -- colores de 24 bits (imprescindible para temas)
opt.signcolumn = "yes" -- columna de signos siempre visible (evita saltos)
opt.cursorline = true -- resalta la línea actual
opt.scrolloff = 8 -- deja 8 líneas de margen al hacer scroll
opt.wrap = false -- no partir líneas largas
-- Splits (donde aparecen las ventanas nuevas)
opt.splitright = true
opt.splitbelow = true
-- Archivos y undo
opt.swapfile = false
opt.undofile = true -- historial de deshacer persistente entre sesiones
-- Portapapeles del sistema
opt.clipboard = "unnamedplus"
-- Experiencia
opt.updatetime = 250 -- respuesta más ágil (diagnósticos, etc.)
opt.timeoutlen = 400 -- ventana para secuencias de teclas
opt.mouse = "a" -- el ratón, por si acaso (opcional)
Con números relativos ves “3 líneas abajo, 5 arriba”. Combinado con un conteo, 5j o 3dd se vuelven inmediatos: lees el número al lado de la línea y saltas exacto.
La tecla leader y tus primeros keymaps
La tecla leader es un prefijo para tus atajos personalizados. La convención moderna es la barra espaciadora: cómoda y no colisiona con nada. Ya la pusimos en init.lua.
Crea lua/config/keymaps.lua:
local map = vim.keymap.set
-- Volver a Normal cómodo
map("i", "jk", "<Esc>", { desc = "Salir a Normal" })
-- Guardar y salir
map("n", "<leader>w", "<cmd>w<cr>", { desc = "Guardar archivo" })
map("n", "<leader>q", "<cmd>q<cr>", { desc = "Cerrar ventana" })
-- Limpiar el resaltado de búsqueda
map("n", "<Esc>", "<cmd>nohlsearch<cr>", { desc = "Quitar resaltado" })
-- Moverse entre ventanas (splits) con Ctrl + hjkl
map("n", "<C-h>", "<C-w>h", { desc = "Ventana izquierda" })
map("n", "<C-j>", "<C-w>j", { desc = "Ventana abajo" })
map("n", "<C-k>", "<C-w>k", { desc = "Ventana arriba" })
map("n", "<C-l>", "<C-w>l", { desc = "Ventana derecha" })
-- Redimensionar ventanas
map("n", "<C-Up>", "<cmd>resize +2<cr>", { desc = "Más alto" })
map("n", "<C-Down>", "<cmd>resize -2<cr>", { desc = "Más bajo" })
-- Mover líneas seleccionadas en modo Visual
map("v", "J", ":m '>+1<cr>gv=gv", { desc = "Bajar selección" })
map("v", "K", ":m '<-2<cr>gv=gv", { desc = "Subir selección" })
-- Mantener el cursor centrado al saltar
map("n", "<C-d>", "<C-d>zz")
map("n", "<C-u>", "<C-u>zz")
map("n", "n", "nzzzv")
map("n", "N", "Nzzzv")
-- Pegar sin perder lo copiado (en Visual)
map("x", "<leader>p", [["_dP]], { desc = "Pegar sin sobrescribir registro" })
El campo { desc = "..." } no es decorativo: en el Nivel 1.2 instalaremos which-key, que lee esas descripciones y te muestra un menú flotante con todos tus atajos al pulsar <leader>. Documenta cada keymap desde el principio y tendrás una config que se explica sola.
Automatizaciones básicas (autocmds)
Los autocmd ejecutan acciones ante eventos. Crea lua/config/autocmds.lua con dos clásicos:
local aug = vim.api.nvim_create_augroup
local au = vim.api.nvim_create_autocmd
-- Resaltar brevemente el texto que copias
au("TextYankPost", {
group = aug("resaltar_yank", { clear = true }),
callback = function() vim.hl.on_yank({ timeout = 200 }) end,
})
-- Quitar espacios en blanco al final al guardar
au("BufWritePre", {
group = aug("limpiar_espacios", { clear = true }),
pattern = "*",
command = [[%s/\s\+$//e]],
})
- Crea la estructura de carpetas y los tres archivos (
options,keymaps,autocmds). - Escribe el
init.luaraíz con sus tresrequire. Todavía no hay plugins: eso es la lección siguiente. - Reinicia con
:restart. Deberías ver números relativos, la línea actual resaltada y<leader>wguardando. - Verifica que no haya errores con
:messages.
Cuando tu propia config arranque limpia, estás listo para instalar plugins.