Ceux qui écrivent du LaTeX dans Vim n’ont pas choisi Vim pour LaTeX. Ils habitent déjà Vim ou Neovim et souhaitent que LaTeX vienne à eux. Un Vim nu sait pourtant ce qu’est un fichier .tex — il livre un fichier de syntaxe et un greffon de type de fichier —, mais l’en-tête de ce greffon, ftplugin/tex.vim, porte encore la mention Last Change: Wed 19 Apr 2006. Aucune compilation, aucun PDF, aucune complétion de \ref, aucune liste des sections. Tout cela n’arrive qu’avec vimtex, le greffon de Karl Yngve Lervåg. Cette page traite de ce que vimtex ajoute à un Vim nu, de la compilation latexmk résidente derrière \ll, des objets texte qui permettent de manipuler environnements et commandes dans la grammaire propre de Vim, et des points où Vim et Neovim diffèrent réellement.
Ce qu’un Vim nu sait déjà de LaTeX
Ce qu’un Vim nu sait d’un fichier .tex, c’est la couleur plus trois petites astuces : [d saute à la définition d’un \newcommand ou d’un \def ; gf et [i lisent le contenu de \include{...} comme un nom de fichier ; et avec matchit activé, % fait l’aller-retour entre \begin{...} et \end{...}. Toute l’implémentation tient dans une quarantaine de lignes de ftplugin/tex.vim, que le Vim 9.1 d’aujourd’hui livre encore avec le nom de Benji Fisher et la ligne Version: 1.4 / Last Change: Wed 19 Apr 2006. Le fichier de syntaxe syntax/tex.vim a bien atteint la Version 121, mais son en-tête indique que ce fichier de runtime cherche un nouveau mainteneur.
Un Vim nu livre en outre une définition de compilateur, compiler/tex.vim. Après :compiler tex, makeprg vaut latex -interaction=nonstopmode et errorformat reçoit un long motif capable de lire les journaux LaTeX : un simple :make remplit alors la liste quickfix avec les erreurs. Même un Vim nu permet donc d’« écrire, faire :make, sauter à la ligne fautive ». Ce qu’il ne sait pas faire : ouvrir le PDF, circuler entre la source et le PDF, compléter \ref ou \cite, parcourir la structure du document. vimtex prend tout cela en charge et, pour le type de fichier tex, remplace le greffon TeX interne de Vim par le sien.
" 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 listPourquoi un .tex tout neuf devient plaintex et vimtex ne se charge pas
La réponse est simple : Vim devine en lisant le contenu du fichier. FTtex(), dans autoload/dist/ft.vim de Vim 9.1, examine d’abord une ligne %&format tout en haut, puis parcourt mille lignes à partir de la première ligne non commentée à la recherche de \documentclass, \usepackage, \begin{, \newcommand ou \renewcommand. Si rien de tout cela n’apparaît, il retombe sur une valeur par défaut qui, tant que g:tex_flavor n’est pas défini, vaut plain : le type de fichier devient alors plaintex et non tex. Un fichier neuf et vide, ou un fragment où l’on n’a pas encore tapé \documentclass, relève exactement de ce cas.
Le plus curieux est que le conseil que l’on rencontre d’ordinaire — mettre let g:tex_flavor = 'latex' dans son vimrc — fonctionne à l’envers avec vimtex. vimtex écrase lui-même la détection de type de fichier dans son propre ftdetect/tex.vim et positionne g:tex_flavor à latex à votre place. Sa documentation l’explique sans détour : cette prise de contrôle sert précisément à éviter que les .tex soient reconnus par défaut comme plaintex. Avec vimtex installé, il est donc inutile d’écrire g:tex_flavor. À l’inverse, lui donner une valeur autre que latex est la manière de refuser cette prise de contrôle — c’est là que l’option devient utile.
Installer vimtex, et pourquoi il ne faut pas le charger paresseusement
Sans détour : ne chargez pas vimtex paresseusement. La raison est mécanique, pas affaire de goût. La recherche inverse — revenir du PDF vers la source — repose sur :VimtexInverseSearch, une commande globale que la visionneuse appelle depuis l’extérieur de l’éditeur. Si le corps du greffon n’est pas chargé, cette commande n’existe pas. De plus, vimtex est un greffon de type de fichier et utilise le mécanisme autoload : il n’est déjà chargé qu’au moment utile, et il ne reste rien à différer pour un gestionnaire de greffons. Avec lazy.nvim, cela s’écrit lazy = false ; avec vim-plug, pas de clause for.
Deux autres prérequis. D’abord la version de l’éditeur. Depuis vimtex 2.18, publié en juillet 2026, il exige Vim 9.2 ou Neovim 0.12.4 et ne se charge tout simplement pas sur plus ancien. Si l’on reste sur un éditeur plus vieux, la bonne solution est d’épingler l’étiquette v2.17 ; let g:vimtex_version_check = 0 fait taire la vérification. Ensuite filetype plugin on et syntax enable. Sans le premier, vimtex ne se charge pas du tout ; sans le second, tout ce qui repose sur l’information syntaxique — détecter les zones mathématiques, l’objet texte i$ — cesse de fonctionner. Même en misant sur Tree-sitter dans Neovim, mieux vaut laisser les fonctions de syntaxe de Vim actives.
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'Dans Neovim, on écrit la même chose en Lua, et les réglages ont leur place dans init afin de prendre effet avant le chargement du corps du greffon. maplocalleader est la porte d’entrée de presque toutes les commandes de vimtex — le préfixe par défaut est fixé par g:vimtex_mappings_prefix, dont la valeur par défaut est <localleader>l, et <localleader> vaut lui-même une barre oblique inverse. Le déclarer explicitement évite bien des confusions. Si on garde la barre oblique inverse, on tape \ll ; si on choisit Espace, on presse Espace puis 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 reste résident et le PDF suit chaque enregistrement
Une pression sur \ll et latexmk démarre en mode résident ; une seconde pression l’arrête. Ce comportement de bascule vient de ce que les réglages par défaut de g:vimtex_compiler_latexmk activent continuous, qui s’appuie sur la surveillance continue de latexmk. Dès lors, chaque enregistrement déclenche une nouvelle compilation et le PDF de la visionneuse se met à jour tout seul. Pour un passage unique, il y a \lS (:VimtexCompileSS) ; pour arrêter, \lk (ou \lK pour tous les projets).
| Raccourci | Commande | Effet |
|---|---|---|
\ll | :VimtexCompile | Démarre ou arrête la compilation continue (bascule) |
\lS | :VimtexCompileSS | Compilation en un seul passage, comme en CI |
\lv | :VimtexView | Ouvre le PDF et effectue une recherche avant vers le curseur |
\lt | :VimtexTocOpen | Ouvre le tampon de table des matières (\lT bascule) |
\le | :VimtexErrors | Liste erreurs et avertissements dans la fenêtre quickfix |
\lo | :VimtexCompileOutput | Affiche la sortie brute du compilateur |
\lc | :VimtexClean | Nettoie les fichiers auxiliaires (\lC supprime aussi la sortie) |
\li | :VimtexInfo | Affiche le fichier racine détecté, les packages et l’état |
\ls | :VimtexToggleMain | Bascule la prise en compte du fichier courant comme racine |
Les options transmises par défaut à latexmk sont au nombre de quatre : -verbose, -file-line-error, -synctex=1 et -interaction=nonstopmode. Comme -synctex=1 y figure d’emblée, les données de synchronisation nécessaires aux recherches avant et inverse décrites plus bas sont produites sans aucune configuration. Côté erreurs, g:vimtex_quickfix_mode vaut 2 par défaut — la fenêtre quickfix s’ouvre seule mais ne prend pas le focus —, ce qui convient à une lecture du coin de l’œil pendant la rédaction. Pour changer de compilateur, on donne à g:vimtex_compiler_method l’une des valeurs latexmk (défaut), latexrun, tectonic, arara, texpresso ou generic.
Quand \ll lance le mauvais moteur : -pdf contre $pdf_mode
On écrit $pdf_mode = 3 dans .latexmkrc et la compilation refuse toujours de passer par le DVI. La cause : vimtex ajoute chaque fois un drapeau de moteur sur la ligne de commande. Le moteur provient de la table g:vimtex_compiler_latexmk_engines, dont la clé par défaut _ renvoie -pdf. Or un -pdf en ligne de commande l’emporte sur $pdf_mode dans .latexmkrc : le fichier de configuration est écrasé sans un mot. vimtex déduit bien le moteur de $pdf_mode, mais, comme l’indique sa documentation, uniquement pour 1 (pdfLaTeX), 4 (LuaLaTeX) et 5 (XeLaTeX). La voie DVI, la 3, n’en fait pas partie.
La bonne correction consiste à placer une directive de programme TeX en tête du fichier principal. Sa partie droite doit être une clé de cette table : lualatex pour LuaLaTeX, pdfdvi pour la voie DVI (qui correspond à -pdfdvi). Les appels réels à upLaTeX et dvipdfmx vont ensuite dans .latexmkrc — la combinaison classique des articles en japonais. La configuration de latexmk elle-même relève de la page sur les compilations automatisées ; les détails s’y trouvent.
% 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;Passer -synctex=1 à $latex aussi est l’essentiel : les données de synchronisation parviennent alors jusqu’au PDF même en passant par un DVI. En quittant latexmk, le tableau change : passer à Tectonic revient à donner à g:vimtex_compiler_method la valeur tectonic, sans choix de moteur ni .latexmkrc.
Objets texte : manipuler \begin{...} dans la grammaire de Vim
C’est là l’unique raison irremplaçable d’écrire du LaTeX dans Vim. L’édition dans Vim repose sur une grammaire verbe plus objet : d (supprimer) ou c (changer) combinés à iw (l’intérieur d’un mot) ou ap (un paragraphe entier). vimtex ajoute à ce vocabulaire les structures de LaTeX elles-mêmes. dae supprime tout, de \begin{...} à \end{...} ; cie ne remplace que le contenu ; ci$ ne retape que l’intérieur d’une formule en ligne. Compter les lignes pour supprimer un environnement align de trente lignes, c’est fini.
| Objet | Portée | Usage typique |
|---|---|---|
ie / ae | Un environnement (hors document de premier niveau) | dae supprime tout l’environnement ; cie en remplace le contenu |
i$ / a$ | Un environnement mathématique ($...$, \[...\]) | ci$ ne retape que l’intérieur de la formule |
ic / ac | Une commande et ses arguments | dac retire un \textbf{...} entier |
id / ad | Une paire de délimiteurs | Le ci( qui connaît LaTeX ; il attrape aussi \left(...\right) |
iP / aP | Une section | daP déplace ou supprime une section entière d’un coup |
im / am | Un seul \item | Attrape exactement une entrée de liste |
S’y ajoute un trio pour réécrire la structure : ds supprime l’enveloppe, cs la change, ts la bascule. dse déshabille un environnement en gardant le contenu, cse transforme un itemize en enumerate (la complétion propose les candidats), dsc/csc font de même pour une commande et dsd/csd pour un délimiteur. tse change d’environnement, tss bascule sa forme étoilée, tsc l’étoile d’une commande, et tsd fait la navette entre (...) et \left(...\right). Côté déplacement, % saute d’un élément d’une paire à l’autre, ]]/[[ vont au début de la section suivante et précédente, ][/[] aux fins, ]m/[m aux environnements et ]n/[n aux formules. Le curseur sur une commande, K ouvre la documentation du package correspondant.
Circuler dans un long document : le tampon de table des matières et la complétion de \ref
Une pression sur \lt et la table des matières de tout le document s’ouvre comme un tampon ordinaire. Puisque c’est un tampon ordinaire, on y cherche avec /, on s’y déplace avec j et k, et Entrée saute à la section. Même dans un document réparti sur plusieurs fichiers, vimtex suit \input et \include depuis le fichier racine : on obtient donc une table unique couvrant tous les chapitres. Elle s’ouvre par défaut dans une fenêtre de cinquante colonnes ; apparence et comportement se règlent via g:vimtex_toc_config. \ls bascule la prise en compte du fichier courant comme racine, et \li indique quel fichier vimtex considère comme tel.
La complétion s’appuie sur la mécanique propre de Vim. Dans un tampon tex, omnifunc prend automatiquement la valeur vimtex#complete#omnifunc (g:vimtex_complete_enabled est actif par défaut) : Ctrl-X Ctrl-O en mode insertion produit donc des candidats. Juste après \cite{ apparaissent les clés de citation issues des fichiers .bib et des \bibitem ; après \ref{, les \label du document ; après \usepackage{, les fichiers .sty installés ; après \includegraphics{, des noms de fichiers. Frapper cette combinaison à chaque fois lasse, aussi relie-t-on en pratique l’omnifunc à un moteur de complétion : la source omni de nvim-cmp sous Neovim, ou l’extension coc-omni de coc.nvim, qui fonctionne dans les deux. La répartition des rôles ne change jamais : vimtex fabrique les candidats, le moteur décide quand et comment les montrer.
local cmp = require("cmp")
cmp.setup({
sources = cmp.config.sources({
{ name = "omni" }, -- pulls vimtex candidates through omnifunc
}),
})Ce qui distingue réellement Vim de Neovim
Du point de vue de l’édition, les objets texte, la table des matières et la complétion sont rigoureusement identiques dans les deux. La différence tient à une seule chose : la possibilité pour l’extérieur de rappeler l’éditeur. La recherche inverse suppose que la visionneuse atteigne l’éditeur ; dans Vim, ce canal est la fonctionnalité +clientserver. La documentation de vimtex indique nettement qu’un serveur démarre automatiquement sous Windows ou dans gVim, mais pas pour un Vim lancé dans un terminal sous Linux ou macOS. Neovim ne possède pas de clientserver et emploie MessagePack-RPC ; vimtex traite les deux de la même façon, et l’adresse se retrouve dans v:servername dans les deux cas.
Et « il suffit de lancer un serveur dans le Vim du terminal » ne tient pas toujours. Le /usr/bin/vim livré avec macOS annonce -clientserver : la fonctionnalité est absente à la compilation, remote_startserver() n’existe donc pas et l’extrait ci-dessous ne fait rien. Le choix se réduit alors à une compilation dotée de +clientserver, comme MacVim ou le Vim de Homebrew, ou à un passage à Neovim. La conclusion pratique de cette section en est le reflet : du côté de Neovim, aucune configuration n’est requise. Restent deux différences plus légères : Vim veut encoding à utf-8, pas Neovim, et les versions exigées sont énoncées séparément — Vim 9.2 et 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')
endifChoisir une visionneuse et la ligne de commande de la recherche inverse
Le point le plus mal compris ici est la valeur par défaut de g:vimtex_view_method. Elle n’est pas choisie finement selon la plate-forme : sur tout système, la valeur par défaut est general, qui retombe sur un lancement générique — xdg-open sous Linux, open sous macOS, SumatraPDF et consorts sous Windows. Cette visionneuse générique se nomme dans g:vimtex_view_general_viewer. Les méthodes dédiées proposées sont zathura, zathura_simple, skim, mupdf, galley et sioyek ; il n’existe pas de valeur sumatrapdf. Utiliser SumatraPDF sous Windows passe par general. Le fonctionnement de SyncTeX lui-même fait l’objet d’une page distincte ; ce qui suit ne concerne que la configuration.
La recherche avant (source → PDF) se réduit à \lv et ne demande presque aucune configuration. Le travail est du côté de la recherche inverse : il faut apprendre à la visionneuse à exécuter une commande précise au clic. Cette commande est VimtexInverseSearch <ligne> <fichier>. La seule chose à surveiller est que les substituants du numéro de ligne et du nom de fichier s’écrivent différemment selon la visionneuse : zathura emploie %{line} et %{input}, Skim %line et %file, SumatraPDF %l et %f. Avec g:vimtex_view_method = 'zathura', vimtex lance zathura avec -x et lui transmet cette commande : sur la plupart des systèmes, un Ctrl-clic ramène à la source sans qu’on ait écrit quoi que ce soit.
# 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}'"Pour Skim sous macOS, ouvrez l’onglet Sync des préférences, choisissez le préréglage Custom et enregistrez la commande avec ses arguments ; la recherche inverse se fait alors par Cmd-Maj-clic. Pour SumatraPDF sous Windows, placez une ligne de même forme dans le champ de ligne de commande de recherche inverse ; elle se déclenche par double-clic. Avec gVim, remplacez la partie nvim --headless par 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'"Les quatre gestes à fixer en premier
vimtex n’est pas un outil qu’il faudrait maîtriser avant de commencer à écrire. Lancer la compilation continue avec \ll, enregistrer, regarder le bon endroit du PDF avec \lv, ne lire que les erreurs avec \le — une fois ces quatre gestes dans les doigts, le reste s’ajoute un à un le jour où il devient nécessaire. Pour les objets texte aussi, mieux vaut partir de dae et cse seulement, puis élargir à ci$ et tsd ; on découvre vite quelles opérations on effectue réellement chaque jour.
Avant de répartir le document sur plusieurs fichiers, une vérification unique s’impose : \ll depuis un fichier de chapitre produit-il toujours le même PDF ? \li indique quel fichier vimtex tient pour racine ; s’il se trompe, on bascule avec \ls ou l’on désigne le fichier principal par % !TeX root = main.tex. Une fois ce point réglé, la compilation reste stable pendant qu’on empile moteurs de complétion et snippets.