Quien escribe LaTeX en Vim no eligió Vim por LaTeX. Ya vive en Vim o en Neovim y quiere que LaTeX venga a él. Un Vim desnudo sí sabe qué es un archivo .tex —incluye un archivo de sintaxis y un complemento de tipo de archivo—, pero la cabecera de ese complemento, ftplugin/tex.vim, sigue diciendo Last Change: Wed 19 Apr 2006. Ni compilación, ni PDF, ni finalización de \ref, ni lista de secciones. Todo eso llega con vimtex, el complemento de Karl Yngve Lervåg. Esta página trata lo que vimtex añade a un Vim desnudo, la compilación latexmk residente que hay detrás de \ll, los objetos de texto que permiten editar entornos y comandos con la gramática propia de Vim, y los puntos en los que Vim y Neovim difieren de verdad.
Lo que un Vim desnudo ya sabe de LaTeX
Lo que un Vim desnudo sabe de un archivo .tex es color más tres pequeños trucos: [d salta a la definición de un \newcommand o un \def; gf e [i leen el contenido de \include{...} como nombre de archivo; y con matchit activado, % va y viene entre \begin{...} y \end{...}. Toda la implementación cabe en unas cuarenta líneas de ftplugin/tex.vim, que el Vim 9.1 de hoy sigue distribuyendo con el nombre de Benji Fisher y la línea Version: 1.4 / Last Change: Wed 19 Apr 2006. El archivo de sintaxis syntax/tex.vim ha llegado a la Version 121, pero su cabecera dice que ese archivo de runtime busca un nuevo mantenedor.
Un Vim desnudo incluye además una definición de compilador, compiler/tex.vim. Tras :compiler tex, makeprg pasa a ser latex -interaction=nonstopmode y errorformat recibe un patrón largo capaz de leer los registros de LaTeX, de modo que un simple :make llena la lista quickfix con los errores. Es decir, incluso un Vim desnudo llega hasta «escribir, :make, saltar a la línea fallida». Lo que no puede hacer es abrir el PDF, ir y venir entre fuente y PDF, completar \ref o \cite, ni recorrer la estructura del documento. vimtex asume todo eso y, para el tipo de archivo tex, sustituye el complemento TeX interno de Vim por el suyo.
" What bare Vim gives you, without any plugin at all.
packadd! matchit " % jumps between \begin{...} and \end{...}
compiler tex " :make runs latex and fills the quickfix listPor qué un .tex recién creado acaba en plaintex y vimtex no se carga
La respuesta es sencilla: Vim adivina leyendo el contenido del archivo. FTtex(), en autoload/dist/ft.vim de Vim 9.1, mira primero una línea %&formato al principio y después recorre mil líneas desde la primera línea no comentada en busca de \documentclass, \usepackage, \begin{, \newcommand o \renewcommand. Si no aparece ninguna, cae en un valor predeterminado que, mientras g:tex_flavor no esté definido, es plain: el tipo de archivo pasa a ser plaintex y no tex. Un archivo nuevo y vacío, o un fragmento en el que todavía no se ha escrito \documentclass, es exactamente ese caso.
Lo curioso es que el consejo que suele darse para esto —poner let g:tex_flavor = 'latex' en el vimrc— funciona al revés con vimtex. vimtex sobrescribe la propia detección de tipo de archivo en su ftdetect/tex.vim y fija g:tex_flavor en latex por usted. Su documentación lo dice sin rodeos: esa toma de control existe justamente para evitar que los .tex se reconozcan por omisión como plaintex. Con vimtex instalado, pues, no hace falta escribir g:tex_flavor. Al contrario, darle un valor distinto de latex es la manera de rechazar esa toma de control: ahí es donde la opción resulta útil.
Instalar vimtex y por qué no debe cargarse de forma diferida
Sin rodeos: no cargue vimtex de forma diferida. La razón es mecánica, no cuestión de gusto. La búsqueda inversa —volver del PDF a la fuente— depende de :VimtexInverseSearch, un comando global que el visor invoca desde fuera del editor. Si el cuerpo del complemento no se ha cargado, ese comando no existe. Además, vimtex es un complemento de tipo de archivo y usa el mecanismo autoload, de modo que ya se carga solo cuando hace falta; no queda nada que un gestor de complementos pueda diferir. En lazy.nvim eso se escribe lazy = false; en vim-plug, sin cláusula for.
Dos requisitos más. Primero, la versión del editor. Desde vimtex 2.18, publicado en julio de 2026, exige Vim 9.2 o Neovim 0.12.4 y sencillamente no se carga en versiones anteriores. Si uno se queda en un editor más viejo, lo correcto es fijar la etiqueta v2.17; let g:vimtex_version_check = 0 calla la comprobación. Segundo, filetype plugin on y syntax enable. Sin lo primero, vimtex no se carga en absoluto; sin lo segundo, deja de funcionar todo lo que se apoya en la información sintáctica: la detección de zonas matemáticas o el objeto de texto i$. Incluso apostando por Tree-sitter en Neovim, conviene dejar activas las funciones de sintaxis de Vim.
call plug#begin()
Plug 'lervag/vimtex'
" Pin an older tag if you are stuck on Vim < 9.2:
" Plug 'lervag/vimtex', { 'tag': 'v2.17' }
call plug#end()
filetype plugin indent on " required (indent is optional)
syntax enable " required for math zones, i$ and friends
set encoding=utf-8 " needed in Vim, not in Neovim
let maplocalleader = ' ' " Space as <localleader>; default is backslash
let g:vimtex_view_method = 'zathura'En Neovim se escribe lo mismo en Lua, y los ajustes van dentro de init para que surtan efecto antes de que se cargue el cuerpo del complemento. maplocalleader es la puerta de entrada de casi todos los comandos de vimtex —el prefijo predeterminado lo fija g:vimtex_mappings_prefix, cuyo valor por omisión es <localleader>l, y <localleader> es por defecto una barra invertida—, así que declararlo explícitamente ahorra confusiones más adelante. Si se deja la barra invertida, se teclea \ll; si se cambia a Espacio, se pulsa Espacio y luego ll.
return {
"lervag/vimtex",
lazy = false, -- never lazy-load: it breaks :VimtexInverseSearch
init = function()
vim.g.maplocalleader = " "
vim.g.vimtex_view_method = "zathura" -- "skim" on macOS
vim.g.vimtex_compiler_method = "latexmk"
end,
}\ll: latexmk queda residente y el PDF sigue cada guardado
Pulse \ll una vez y latexmk arranca en modo residente; púlselo otra vez y se detiene. Se comporta como un interruptor porque los ajustes por omisión de g:vimtex_compiler_latexmk activan continuous, que por debajo usa la vigilancia continua de latexmk. A partir de ahí cada guardado dispara una recompilación y el PDF del visor se pone al día solo. Para una única pasada está \lS (:VimtexCompileSS), y para parar, \lk (o \lK para todos los proyectos).
| Atajo | Comando | Efecto |
|---|---|---|
\ll | :VimtexCompile | Inicia o detiene la compilación continua (interruptor) |
\lS | :VimtexCompileSS | Compilación de una sola pasada, como en CI |
\lv | :VimtexView | Abre el PDF y hace búsqueda directa hasta el cursor |
\lt | :VimtexTocOpen | Abre el búfer del índice (\lT alterna) |
\le | :VimtexErrors | Lista errores y avisos en la ventana quickfix |
\lo | :VimtexCompileOutput | Muestra la salida en bruto del compilador |
\lc | :VimtexClean | Limpia archivos auxiliares (\lC borra también la salida) |
\li | :VimtexInfo | Muestra el archivo raíz detectado, los paquetes y el estado |
\ls | :VimtexToggleMain | Alterna si el archivo actual cuenta como raíz |
Las opciones que se pasan a latexmk por omisión son cuatro: -verbose, -file-line-error, -synctex=1 e -interaction=nonstopmode. Como -synctex=1 está ahí desde el principio, los datos de sincronización que necesitan la búsqueda directa e inversa descritas más abajo se generan sin que usted configure nada. En cuanto a errores, g:vimtex_quickfix_mode vale 2 por defecto —la ventana quickfix se abre sola pero no roba el foco—, lo que encaja con leer los errores de reojo mientras se escribe. Para cambiar de compilador, se da a g:vimtex_compiler_method uno de estos valores: latexmk (predeterminado), latexrun, tectonic, arara, texpresso o generic.
Cuando \ll llama al motor equivocado: -pdf frente a $pdf_mode
Uno escribe $pdf_mode = 3 en .latexmkrc y la compilación sigue negándose a pasar por DVI. La causa es que vimtex añade cada vez un indicador de motor a la línea de comandos. El motor sale de la tabla g:vimtex_compiler_latexmk_engines, cuya clave por omisión _ apunta a -pdf. Y un -pdf en la línea de comandos gana a $pdf_mode en .latexmkrc, de modo que el archivo de configuración queda anulado sin aviso. vimtex sí deduce el motor a partir de $pdf_mode, pero, como dice su documentación, solo para 1 (pdfLaTeX), 4 (LuaLaTeX) y 5 (XeLaTeX). La vía DVI, la 3, no está incluida.
La corrección adecuada es poner una directiva de programa TeX al principio del archivo principal. Su lado derecho debe ser una clave de esa tabla: lualatex para LuaLaTeX y pdfdvi para la vía DVI (que corresponde a -pdfdvi). Las llamadas reales a upLaTeX y dvipdfmx van después en .latexmkrc: la combinación clásica de los artículos en japonés. La configuración de latexmk en sí pertenece a la página de compilaciones automatizadas; los detalles están allí.
% In the main .tex file, first line: pick the key, not the binary name.
% !TeX program = pdfdvi
# .latexmkrc -- upLaTeX and dvipdfmx do the actual work
$latex = 'uplatex -synctex=1 -interaction=nonstopmode -file-line-error %O %S';
$bibtex = 'upbibtex %O %B';
$biber = 'biber --bblencoding=utf8 -u -U --output_safechars %O %S';
$makeindex = 'upmendex %O -o %D %S';
$dvipdf = 'dvipdfmx %O -o %D %S';
$max_repeat = 5;Pasar -synctex=1 también a $latex es lo esencial: así los datos de sincronización llegan al PDF incluso pasando por un DVI. Si se abandona latexmk el panorama cambia: migrar a Tectonic consiste solo en poner g:vimtex_compiler_method en tectonic, sin selección de motor ni .latexmkrc.
Objetos de texto: editar \begin{...} con la gramática de Vim
Esta es la única razón insustituible para escribir LaTeX en Vim. La edición en Vim se apoya en una gramática de verbo más objeto: d (borrar) o c (cambiar) combinados con iw (el interior de una palabra) o ap (un párrafo entero). vimtex añade a ese vocabulario las estructuras del propio LaTeX. dae borra todo, de \begin{...} a \end{...}; cie sustituye solo el contenido; ci$ reescribe solo el interior de una fórmula en línea. Contar líneas para borrar un entorno align de treinta líneas se acabó.
| Objeto | Alcance | Uso típico |
|---|---|---|
ie / ae | Un entorno (salvo el document de nivel superior) | dae borra el entorno entero; cie sustituye su contenido |
i$ / a$ | Un entorno matemático ($...$, \[...\]) | ci$ reescribe solo el interior de la fórmula |
ic / ac | Un comando y sus argumentos | dac elimina un \textbf{...} completo |
id / ad | Un par de delimitadores | El ci( que entiende LaTeX; también atrapa \left(...\right) |
iP / aP | Una sección | daP mueve o borra una sección entera de una vez |
im / am | Un solo \item | Atrapa exactamente una entrada de la lista |
A eso se añade un trío para reescribir la estructura: ds quita el envoltorio, cs lo cambia, ts lo alterna. dse desnuda un entorno y deja el contenido, cse convierte un itemize en un enumerate (la finalización ofrece los candidatos), dsc/csc hacen lo mismo con un comando y dsd/csd con un delimitador. tse cambia de entorno, tss alterna su forma con asterisco, tsc el asterisco de un comando y tsd va y viene entre (...) y \left(...\right). En cuanto al movimiento, % salta entre los elementos de un par, ]]/[[ van al principio de la sección siguiente y anterior, ][/[] a los finales, ]m/[m a los entornos y ]n/[n a las fórmulas. Con el cursor sobre un comando, K abre la documentación de ese paquete.
Moverse por un documento largo: el búfer del índice y la finalización de \ref
Pulse \lt y el índice de todo el documento se abre como un búfer corriente. Al ser un búfer corriente, se busca en él con /, se recorre con j y k, y Enter salta a esa sección. Incluso en un documento repartido en varios archivos, vimtex sigue \input e \include desde el archivo raíz, de modo que se obtiene un único índice que abarca todos los capítulos. Se abre por omisión en una ventana de cincuenta columnas; aspecto y comportamiento se ajustan con g:vimtex_toc_config. Si el archivo que edita cuenta como raíz se alterna con \ls, y \li muestra cuál ha decidido vimtex que lo es.
La finalización se apoya en la maquinaria propia de Vim. En un búfer tex, omnifunc toma automáticamente el valor vimtex#complete#omnifunc (g:vimtex_complete_enabled está activo por omisión), de modo que Ctrl-X Ctrl-O en modo inserción produce candidatos. Justo después de \cite{ aparecen las claves bibliográficas de los archivos .bib y de los \bibitem; tras \ref{, las \label del documento; tras \usepackage{, los .sty instalados; tras \includegraphics{, nombres de archivo. Pulsar esa combinación cada vez cansa, así que en la práctica se conecta el omnifunc a un motor de finalización: la fuente omni de nvim-cmp en Neovim, o la extensión coc-omni de coc.nvim, que funciona en ambos. El reparto de tareas nunca cambia: vimtex fabrica los candidatos y el motor decide cuándo y cómo mostrarlos.
local cmp = require("cmp")
cmp.setup({
sources = cmp.config.sources({
{ name = "omni" }, -- pulls vimtex candidates through omnifunc
}),
})En qué se diferencian realmente Vim y Neovim
En cuanto a la edición, los objetos de texto, el índice y la finalización son exactamente iguales en ambos. La diferencia está en una sola cosa: si algo externo puede llamar de vuelta al editor. La búsqueda inversa exige que el visor alcance al editor, y en Vim ese canal es la característica +clientserver. La documentación de vimtex dice con claridad que el servidor arranca automáticamente en Windows o en gVim, pero no en un Vim que corre en una terminal de Linux o macOS. Neovim no tiene clientserver en absoluto y usa MessagePack-RPC en su lugar; vimtex trata a ambos igual, y en los dos casos la dirección queda en v:servername.
Y «basta con arrancar un servidor en el Vim de la terminal» tampoco siempre funciona. El /usr/bin/vim que viene con macOS informa -clientserver: la característica está excluida en la compilación, así que remote_startserver() no existe y el fragmento de abajo no hace nada. Ahí la elección se reduce a usar una compilación con +clientserver, como MacVim o el Vim de Homebrew, o pasarse a Neovim. La conclusión práctica de esta sección es la imagen especular: en el lado de Neovim no hace falta configuración alguna. Quedan dos diferencias menores: Vim necesita encoding en utf-8 y Neovim no, y las versiones exigidas se enuncian por separado como Vim 9.2 y Neovim 0.12.4.
" Vim only, and only in a build that has +clientserver.
if empty(v:servername) && exists('*remote_startserver')
call remote_startserver('VIM')
endifElegir visor y la línea de comandos de la búsqueda inversa
Lo que más se malinterpreta aquí es el valor por omisión de g:vimtex_view_method. No se elige con astucia según la plataforma: en todos los sistemas el valor por omisión es general, que recae en un lanzamiento genérico: xdg-open en Linux, open en macOS, SumatraPDF y compañía en Windows. Ese visor genérico se nombra en g:vimtex_view_general_viewer. Los métodos dedicados disponibles son zathura, zathura_simple, skim, mupdf, galley y sioyek; no existe un valor sumatrapdf. Usar SumatraPDF en Windows pasa por general. Cómo funciona SyncTeX en sí se trata en su propia página; lo que sigue es solo configuración.
La búsqueda directa (fuente → PDF) se reduce a \lv y no exige casi configuración. El trabajo está en la búsqueda inversa: hay que enseñar al visor a ejecutar cierto comando al hacer clic. Ese comando es VimtexInverseSearch <línea> <archivo>. Lo único que hay que vigilar es que los marcadores del número de línea y del nombre de archivo se escriben distinto en cada visor: zathura usa %{line} y %{input}, Skim usa %line y %file, y SumatraPDF usa %l y %f. Con g:vimtex_view_method = 'zathura', vimtex lanza zathura con -x y le entrega ese comando, de modo que en la mayoría de los sistemas un Ctrl-clic devuelve a la fuente sin haber escrito nada.
# Linux: zathura. Ctrl-click in the PDF jumps back to the source.
set synctex true
set synctex-editor-command "nvim --headless -c 'VimtexInverseSearch %{line} %{input}'"Para Skim en macOS, abra la pestaña Sync de sus preferencias, ponga el preajuste en Custom y registre el comando con sus argumentos; la búsqueda inversa es entonces Cmd-Mayús-clic. Para SumatraPDF en Windows, coloque una línea de la misma forma en el campo de línea de comandos de búsqueda inversa; se dispara con doble clic. Con gVim, sustituya la parte nvim --headless por vim -v --not-a-term -T dumb.
# macOS, Skim: Preferences > Sync > Preset: Custom
Command: nvim
Arguments: --headless -c "VimtexInverseSearch %line '%file'"
# Windows, SumatraPDF: Settings > Options > inverse search command-line
cmd /c start /min "" nvim --headless -c "VimtexInverseSearch %l '%f'"Los cuatro movimientos que conviene fijar primero
vimtex no es una herramienta que haya que dominar antes de empezar a escribir. Iniciar la compilación continua con \ll, guardar, mirar el punto correcto del PDF con \lv y leer solo los errores con \le: una vez que esos cuatro gestos están en los dedos, el resto se añade de uno en uno el día en que hace falta. Con los objetos de texto conviene lo mismo: empezar solo con dae y cse y ampliar luego a ci$ y tsd; pronto se ve qué operaciones se realizan de verdad a diario.
Antes de repartir el documento en varios archivos conviene comprobar una cosa una sola vez: si pulsar \ll desde un archivo de capítulo sigue produciendo el mismo PDF. Mire \li para ver qué archivo ha tomado vimtex como raíz; si se equivoca, cambie con \ls o señale el archivo principal con % !TeX root = main.tex. Resuelto eso, la compilación se queda quieta mientras se añaden por encima motores de finalización y fragmentos.