Saltar al contenido

Qué trae la 0.12 (y qué no)

Lo que el núcleo absorbió en la serie 0.12 con su versión exacta, los cuatro límites donde el «ya no necesitas plugins» deja de ser cierto, los cambios que rompen configuraciones sin dar ningún error, y la tabla de deprecaciones que te dice de un vistazo si el código que acabas de copiar es de otra época.

Acabas de aprender a leer :help. Esta lección es su primer uso serio, porque la pregunta «¿qué versión tengo y qué significa eso?» es la que decide si el código que encuentras por ahí te va a funcionar. Y en Neovim esa pregunta pesa más que en casi cualquier otra herramienta: en tres versiones —0.10, 0.11 y 0.12— el núcleo se ha tragado el comentado, los atajos de corchete, la configuración del LSP, el gestor de plugins y el completado automático. Todo lo escrito antes sigue publicado, sigue apareciendo en las búsquedas y sigue teniendo buena pinta. La única defensa es saber exactamente qué entró, cuándo, y qué se quedó fuera pese a lo que se repite.

  • Situar cada capacidad del núcleo en la versión exacta en que llegó, sin fiarte del año del artículo.
  • Delimitar los cuatro límites donde «ya no hacen falta plugins» deja de ser verdad.
  • Reconocer los cambios de 0.12 que alteran el comportamiento sin dar error.
  • Usar :h news, :h deprecated y :checkhealth vim.deprecated como rutina de actualización.
  • Decidir si un fragmento de código ajeno es de esta época o de otra.

Primero, qué versión es esta

La 0.12.0 se publicó el 29 de marzo de 2026 y la 0.12.4, la estable de hoy, el 5 de julio. Entre una y otra hay cuatro versiones de parches, y la rama de desarrollo ya va por la 0.13.

Eso importa por una razón práctica: en Neovim, el tercer número también trae funcionalidad. ZR no existía en la 0.12.0 y apareció en la 0.12.2. Cuando algo de esta guía no te funcione, nvim --version completo —los tres números— es la primera comprobación, no solo el 0.12.

Por qué sigue siendo 0.algo

Neovim lleva más de una década publicando versiones y todavía no ha llegado al 1.0, y la pregunta sale siempre. No significa que esté a medias: es un editor que usan millones de personas a diario y que empaquetan todas las distribuciones. Significa que el proyecto no ha querido comprometerse a la promesa que implica un 1.0 —congelar la API pública— mientras siga reformándola, que es exactamente lo que ha hecho en las últimas tres versiones con el LSP, Treesitter y el gestor de plugins.

Lo que sí tiene garantía de estabilidad es la API, que lleva su propia numeración. La de la 0.12 es la nivel 14, y esa es la cifra que le importa a un plugin.

Cómo preguntar la versión desde tu propia configuración

Vas a necesitarlo en cuanto tu config viaje entre máquinas con versiones distintas. Hay dos formas y conviene usar la primera:

LUA
-- La forma corta: ¿tengo al menos esta versión?if vim.fn.has("nvim-0.12") == 1 thenvim.o.autocomplete = trueend-- La forma larga, cuando necesitas los númeroslocal v = vim.version()          -- { major = 0, minor = 12, patch = 4, ... }if vim.version.ge(v, { 0, 12, 2 }) then-- ZR existeend

has("nvim-0.12") es verdadero para 0.12 y superior, así que no hay que actualizarlo cada vez que sale una versión. Es el patrón que verás en cualquier plugin bien escrito, y el que hace que una configuración no se rompa al clonarla en un servidor con una versión más vieja.

La rutina de actualización, en tres comandos

Cada vez que subas de versión, y antes de tocar nada:

VIM
:h news                    " qué entró, qué se rompe:h deprecated              " qué dejó de ser la forma correcta:checkhealth vim.deprecated  " qué de eso estás usando TÚ

Los dos primeros describen el editor; el tercero te audita a ti. La lección entera que estás leyendo cabe en esos tres comandos: lo que sigue es el recorrido comentado de esta versión concreta.

Lo que absorbió el núcleo

Hace dos años era un plugin Hoy Desde
Comment.nvim gc, y gc también como objeto de texto 0.10
LuaSnip para expandir vim.snippet 0.10
vim-unimpaired ]q, [b, ]d, ]<Space>… en el core 0.11
nvim-lspconfig como framework vim.lsp.config() y vim.lsp.enable() 0.11
nvim-ufo para plegar por LSP vim.lsp.foldexpr() 0.11
packer, lazy vim.pack 0.12
nvim-cmp para el menú automático 'autocomplete' 0.12
nvim-treesitter para seleccionar v_an / v_in por defecto 0.12

El error de atribución más común: el LSP no es de la 0.12

vim.lsp.config() y vim.lsp.enable(), la carpeta lsp/ del runtimepath y los atajos grn, gra, grr, gri son de la 0.11. Verás mucho artículo que los vende como la gran novedad de la 0.12, y no lo son.

Lo que sí es nuevo de 0.12 en LSP: el cuarto nivel de fusión after/lsp/, el comando :lsp enable|disable|restart|stop, el atajo grx para ejecutar un code lens, vim.lsp.get_configs(), el color de documento —activado por defecto—, el rango de edición enlazada, el completado en línea con guía para Copilot, el formateo al teclear y los diagnósticos de espacio de trabajo.

vim.pack, el gestor integrado

Cuatro funciones y nada más: vim.pack.add(), update(), del() y get(). La especificación de un plugin tiene cuatro campos, y solo src es obligatorio —tanto que puedes pasar una cadena suelta y se toma como src—. version acepta una rama, una etiqueta, un hash, o vim.version.range('1.0') para quedarte con la mayor etiqueta semántica dentro de un rango.

Clona en stdpath('data')/site/pack/core/opt/, carga con :packadd, regenera los helptags solo, y mantiene un lockfile en nvim-pack-lock.json que el propio manual te recomienda meter en control de versiones. Los eventos PackChangedPre y PackChanged son el sitio donde enganchar lo que haga falta tras instalar o actualizar.

'autocomplete', el completado automático

Es una opción booleana, no una lista de banderas: vim.o.autocomplete = true. La acompañan dos más, 'autocompletedelay' y 'autocompletetimeout'. La receta oficial completa está en :h ins-autocompletion-example, y no llega a cinco líneas.

Lo que ya puedes usar hoy, sin configurar nada

Esto es lo más accionable de la lección, y llega justo en el momento correcto: has terminado el Nivel 0, no has escrito una línea de configuración, y todo esto ya funciona en tu editor.

Comentar

gcc comenta la línea, gc{moción} comenta lo que le digas, gcap un párrafo, y gcgc descomenta el bloque de comentarios en el que estés. Sabe qué símbolo usa cada lenguaje. Desde 0.10, sin plugin.

Saltar por listas con corchetes

La familia entera de vim-unimpaired entró en el núcleo en la 0.11. La regla es constante: [ va hacia atrás, ] hacia adelante, la mayúscula va al extremo de la lista.

Par Recorre
]q [q ]Q [Q la quickfix
]l [l ]L [L la lista de ubicaciones
]b [b ]B [B los buffers abiertos
]t [t las etiquetas
]a [a la lista de argumentos
]d [d ]D [D los diagnósticos
]<Space> [<Space> añade una línea en blanco debajo / encima

]d y [d funcionan desde hoy con los diagnósticos que produzca cualquier cosa; y ]q es la que usarás mañana mismo con los resultados de :helpgrep.

Seleccionar por estructura

En cualquier fichero con parser activo —hoy: Lua, Markdown, la ayuda y los ficheros de consultas— la 0.12 trae selección incremental de serie. Entra en Visual y prueba:

Tecla Hace
an amplía la selección al nodo padre
in la reduce al hijo
]n / [n salta al nodo hermano siguiente / anterior
]N / [N amplía la selección al hermano

Ponte dentro de una función en un fichero .lua, pulsa v y luego an varias veces: la selección va creciendo por la estructura real del código, no por líneas. Es lo que hasta la 0.11 exigía instalar nvim-treesitter.

Lo que aparece solo cuando hay un servidor

Estos no funcionan hoy porque aún no has instalado ningún servidor de lenguaje, pero no habrá que mapearlos cuando lo hagas en el Nivel 3: vienen puestos desde la 0.11.

Tecla Acción
K documentación del símbolo bajo el cursor
grn renombrar
gra acciones de código
grr referencias
gri implementaciones
grt ir al tipo
grx ejecutar el code lens (nuevo en 0.12)
gO esquema de símbolos del fichero
Ctrl-s en Insertar firma de la función

Merece la pena mirar esa tabla dos veces, porque contradice a la mitad de las guías que encontrarás: no hace falta escribir treinta líneas de keymaps en un on_attach. Eso era necesario hasta la 0.10.

Y unos cuantos sueltos

gx abre en el navegador la URL bajo el cursor. :Man ls lee páginas de manual dentro del editor. :Inspect te dice qué grupos de resaltado tiene el carácter del cursor, y :InspectTree te enseña el árbol sintáctico. Y copia hasta el final de la línea, no la línea entera. :Undotree y :DiffTool son de la 0.12. Y editorconfig y matchit están encendidos.

Los cuatro límites

Se lee mucho «ya no necesitas plugins». Cuatro precisiones, todas comprobables en :help, y todas cosas que te ahorrarán una tarde.

El completado nativo son dos sistemas, no uno. La opción 'autocomplete' levanta el menú con las fuentes de 'complete' —buffer, ventanas, etiquetas—, y vim.lsp.completion es un módulo aparte que aporta los candidatos del servidor y los efectos secundarios: expandir el snippet, aplicar ediciones adicionales, ejecutar comandos. La documentación oficial no trae ninguna receta que combine los dos. Y con 'autocomplete' activo solo cinco de las once banderas de 'completeopt' tienen efecto, cosa que el manual dice en una sola línea fácil de pasar por alto. Para Lua, shell, Markdown o texto llano sobra. Se queda corto en emparejado difuso tolerante a erratas, en mezclar fuentes en el orden que tú decidas y en snippets con saltos entre campos.

Treesitter no indenta, y no colorea todo. El resaltado y el plegado por árbol sí están en el núcleo, con seis parsers compilados —C, Lua, Markdown, Vimscript, Vimdoc y el de las propias consultas—. Pero no existe vim.treesitter.indentexpr(), y en todo el runtime de Neovim no hay un solo fichero indents.scm: la indentación por árbol la aporta el plugin, que además la marca como experimental. Y el resaltado por árbol viene encendido por defecto solo en cuatro tipos de fichero: ayuda, Lua, Markdown y las consultas. Para C —cuyo parser viene incluido— hay que activarlo.

El núcleo no instala nada. vim.treesitter.language.add() carga un parser que ya esté en el disco; descargarlo y compilarlo es cosa del plugin. No existe ningún comando :TS* en el core. Y los servidores de lenguaje son programas externos que alguien tiene que poner en el PATH.

vim.pack no es lazy.nvim. Su propia documentación lo llama experimental: «todavía se considera experimental, aunque debería ser lo bastante estable para el uso diario». No tiene carga perezosa por evento o por tipo de fichero, ni campo de dependencias, ni hooks de compilación, ni perfilado de arranque. Y trae tres limitaciones declaradas: si el plugin ya está en disco no comprueba su revisión, añadirlo dos veces en la misma sesión no hace nada, y no se entera si el repositorio cambia su rama por defecto.

Lo de «se acabaron los Press ENTER» tiene letra pequeña

La 0.12 trae ui2, un rediseño del área de mensajes y de la línea de comandos que elimina el aviso de continuar y colapsa los mensajes largos. No está activo por defecto: es experimental y vive en un espacio de nombres privado. Se enciende con require('vim._core.ui2').enable().

Si lo leíste como una novedad automática de la versión, no lo es todavía. El propio código lleva una nota de sus autores sobre qué haría falta para activarlo de serie.

Lo que se rompe sin dar error

Esta es la categoría peligrosa: no falla, cambia de comportamiento.

i_CTRL-R inserta literal

Insertar un registro desde Insertar ya no simula tecleo, pega. Es más rápido y no destroza la indentación, pero si dependías de que se reformateara, cambió. El comportamiento viejo: <C-R>=@x.

«buffer» pasó a «buf»

En nvim_create_autocmd() y familia, y en vim.keymap.set/del. La clave vieja sigue aceptada, pero la documentación ya usa la nueva.

‘shelltemp’ ahora es false

Los comandos de shell dejan de pasar por ficheros temporales por defecto.

TOhtml es opt-in

Hay que pedirlo: :packadd nvim.tohtml.

Y tres eliminaciones de verdad, que sí dan error: vim.diagnostic.disable(), vim.diagnostic.is_disabled() y definir los signos de diagnóstico con sign_define(). Si tu config —o una que copies— hace cualquiera de las tres, no arranca.

En Treesitter, dos cambios que muerden a quien escribe queries

El linter de consultas ya no se activa solo al abrir un fichero .scm: ahora se pide con vim.g.query_lint_on. Y la directiva offset! escribe su resultado en metadata[id].offset en vez de en .range. Las dos rompen en silencio código que funcionaba, y las dos las verás de cerca en el Nivel 17.

La tabla que detecta un tutorial viejo

Esto es lo que más te va a servir del nivel entero. Cuando encuentres código por internet, búscale estas cosas: si aparece alguna, sabes sin más contexto que es de otra época y que probablemente lo demás también lo sea.

Si ves esto Es de antes de Hoy se escribe
vim.loop 0.10 vim.uv
vim.tbl_flatten() 0.10 Iter:flatten()
nvim_buf_set_option() 0.10 nvim_set_option_value()
vim.lsp.get_active_clients() 0.10 vim.lsp.get_clients()
vim.highlight 0.11 vim.hl
vim.diagnostic.goto_next() 0.11 vim.diagnostic.jump({ count = 1 })
termopen() 0.11 jobstart({ term = true })
client.request(), client.stop() 0.11 métodos Client:*
vim.diff() 0.12 vim.text.diff()
vim.lsp.semantic_tokens.start() 0.12 …semantic_tokens.enable()
require('lspconfig').X.setup{} 0.11 vim.lsp.config() + vim.lsp.enable()
require('nvim-treesitter.configs') — ya no existe
:TSInstall presentado como comando del core — es del plugin, nunca fue del core
Vimscript9 (vim9script, def) — Neovim no lo soporta

Deprecado no es eliminado

Casi todo lo de 0.9, 0.10 y 0.11 sigue funcionando en la 0.12, con un aviso. No tienes que arreglarlo todo el día de la actualización.

Pero sí conviene saber que la cuenta atrás existe: vim.lsp.semantic_tokens.start(), por ejemplo, lleva marcada en el código su retirada para la 0.13. :checkhealth vim.deprecated te da tu lista personal, ordenada por urgencia real.

Lo demás que trajo la 0.12

Sin entrar en detalle, para que sepas que existe cuando lo necesites:

  • Editor: :restart y ZR, :connect, :detach, :Undotree, :DiffTool, :uniq, :help! con búsqueda inteligente, :wall ++p para crear directorios padre.
  • Interfaz: barras de progreso nativas en el terminal, la opción 'busy' para marcar un buffer ocupado, ventanas flotantes con 'statusline' propia y movibles entre pestañas, y errores más cortos —«Error in:» en vez de «Error detected while processing:»—.
  • Defaults: 'diffopt' incluye indent-heuristic e inline:char; la 'statusline' por defecto pasó a ser una expresión que muestra diagnósticos y progreso; 'exrc' busca también en los directorios padre; shada excluye /tmp y /private.
  • Librería estándar: vim.net.request(), vim.list.unique(), vim.list.bisect(), vim.version.intersect(), vim.fs.ext(), y vim.json.encode() con sangrado y claves ordenadas.

Deprecar bien es la parte difícil, y casi nadie la hace

Vale la pena detenerse en el fichero deprecated.txt, porque dice más sobre este proyecto que cualquier lista de funcionalidades.

Un editor con cincuenta años de compatibilidad hacia atrás y un ritmo de cambio como el de estas tres versiones tiene un problema que parece irresoluble: si no rompe nada, se queda con la basura acumulada de medio siglo; si rompe, castiga a los usuarios que lo eligieron precisamente por su estabilidad. La respuesta habitual de la industria son los dos extremos, y los dos son malos. Un extremo es congelar: nunca se retira nada, cada función mala convive con su sustituta para siempre, y el resultado es una superficie de API donde hay seis maneras de hacer lo mismo y ninguna documentación te dice cuál. El otro extremo es romper y avisar en las notas de la versión, que en la práctica significa que se entera el que las lee.

Lo que hace Neovim es una tercera cosa, y tiene tres piezas que solo funcionan juntas. La primera: la deprecación es un estado con nombre y con fecha, no una opinión —la función sigue funcionando, avisa, y lleva anotada la versión en que desaparecerá—. La segunda: existe un documento único que lista qué sustituye a qué, así que la migración no es un ejercicio de arqueología por foros. Y la tercera, que es la que casi nadie implementa: el proyecto te da una herramienta que audita tu propio código y te dice qué de todo eso te afecta a ti. :checkhealth vim.deprecated convierte un documento genérico en una lista personal de tres líneas.

Fíjate en lo que esa tercera pieza resuelve. El problema real de una deprecación nunca fue enterarse de que existe; fue averiguar si te toca. Un CHANGELOG te obliga a leer cincuenta cambios para descubrir que dos te afectan, y por eso nadie los lee. Invertir la dirección de la pregunta —de «qué cambió» a «qué de lo que cambió estoy usando»— es una diferencia pequeña en implementación y enorme en cuánta gente acaba migrando.

Llévatelo fuera del editor, porque es un patrón que puedes aplicar a lo que construyas: si tu librería deprecia algo, la parte valiosa no es el aviso en el CHANGELOG, es el codemod, el lint o el comando que le dice a cada usuario qué le toca a él. Las migraciones que salen bien no son las que se comunican mejor: son las que le ahorran al usuario el trabajo de averiguar si le importan.

Auditar tu propia versión

  1. Ejecuta nvim --version y anota los tres números. Comprueba en :h news si tu versión de parche trajo algo.
  2. Abre :h news y localiza la sección de cambios que rompen. Encuentra qué le pasó a i_CTRL-R y explica con tus palabras en qué cambia pegar un registro.
  3. Ejecuta :checkhealth vim.deprecated. Hoy, sin configuración, debería estar limpia. Vuelve a este comando el día que copies tu primer bloque de código de internet.
  4. Verifica el límite de Treesitter: abre un .c y ejecuta :lua print(vim.treesitter.highlighter.active[0] ~= nil). Dirá false pese a que el parser de C viene incluido. Repítelo en un .lua y compara.
  5. Verifica el otro: :lua print(vim.treesitter.indentexpr) imprime nil. Esa función no existe en el núcleo, por mucho que aparezca en configuraciones ajenas.
  6. Comprueba que 'autocomplete' es booleana: :set autocomplete? y luego :lua vim.o.autocomplete = true. Escribe en un buffer con varias palabras repetidas y observa el menú sin haber instalado nada.
  7. Busca en :h deprecated tres de las entradas de la tabla de arriba y comprueba que la doc te da la sustituta exacta.
  8. Sin configurar nada: abre un .lua, ponte dentro de una función, pulsa v y luego an tres veces. La selección crece por la estructura, no por líneas.
  9. Sin configurar nada: comenta un párrafo con gcap y descoméntalo con gcgc. Añade una línea en blanco encima con [<Space>.
  10. Ejecuta :lua print(vim.fn.has("nvim-0.12"), vim.inspect(vim.version())). Esas dos formas son las que usarás para que tu configuración no se rompa en una máquina con otra versión.