Ouvrez un fichier .tex dans un Visual Studio Code fraîchement installé et il est déjà coloré, sans la moindre extension — car VS Code livre une grammaire LaTeX d'origine, et cette grammaire a été extraite de l'extension LaTeX Workshop. La couleur est pourtant tout ce que VS Code sait de LaTeX. La compilation, l'affichage du PDF, les allers-retours entre la source et le PDF : tout cela revient à LaTeX Workshop, et la composition elle-même est faite par la distribution TeX installée sur la machine, lancée comme processus fils. Cette page traite du modèle à deux niveaux qui décrit une compilation — outils et recettes —, de la raison pour laquelle la recette par défaut lance un autre moteur que celui dont une grande partie des documents ont besoin, et de la visionneuse PDF intégrée qui réduit SyncTeX à un ctrl-clic.
Ce que VS Code sait de LaTeX tout seul
Un VS Code nu enregistre trois identifiants de langage et une grammaire pour chacun, rien de plus : tex pour .sty et .cls, latex pour .tex, bibtex pour .bib. Aucune commande de compilation, aucune visionneuse PDF, aucune complétion, aucun saut vers un \ref. Ces fichiers de grammaire viennent du dépôt jlelong/vscode-latex-basics, dont le README indique que les fichiers faisaient à l'origine partie de LaTeX Workshop ; VS Code les livre depuis sa version de janvier 2022. Les couleurs qui apparaissent dès l'ouverture d'un .tex sont donc déjà le travail de l'extension, des mois avant qu'on ne l'installe.
Tout le reste est fourni par LaTeX Workshop (de James Yu, identifiant Marketplace James-Yu.latex-workshop) — tout sauf TeX. L'extension lance des exécutables tels que latexmk, pdflatex ou biber comme processus fils et relit leur sortie ; elle ne peut donc jamais être en meilleure santé que la distribution qui la sous-tend : TeX Live, MiKTeX ou MacTeX. Une règle de diagnostic en découle : compiler le projet une fois dans un terminal avant de toucher au moindre réglage. Si latexmk échoue là, aucune ligne de settings.json ne sauvera la situation ; s'il réussit là et que l'extension prétend malgré tout ne pas trouver la commande, le suspect est l'environnement hérité par VS Code, pas l'extension.
L'installation n'a rien de remarquable — la vue Extensions (Ctrl/Cmd+Shift+X), rechercher « LaTeX Workshop ». Ce qui arrive avec elle, c'est presque toute la surface de travail : commandes de compilation, aperçu du PDF, complétion, saut d'un \ref ou d'un \cite vers sa cible, plan du document, et un arbre des fichiers du projet assemblé en suivant \input et \include — c'est aussi la liste des fichiers que surveille la compilation automatique. Si vous avez modifié votre PATH pour installer TeX, redémarrez VS Code, idéalement en vous déconnectant puis reconnectant, afin que le nouvel environnement soit pris en compte. Vérifiez ensuite depuis un terminal que la distribution répond.
# does the TeX distribution answer at all?
latexmk --version
# does the project build outside the editor?
latexmk -pdf main.tex
# with a .latexmkrc that already picks the engine, no flags are needed
latexmk main.tex
# is the extension looking at the same PATH you are?
which latexmkUne fois la compilation au terminal réussie, tout ce qui reste se situe du côté de VS Code et se ramène à trois questions : quelle recette s'exécute, quel fichier est la racine, et où apparaît le PDF. Le reste de cette page traite de ces trois points.
Outils et recettes : lire latex-workshop.latex.recipes
Une compilation s'écrit sur deux niveaux. Un outil (latex-workshop.latex.tools) définit une commande à lancer : un name, une command (l'exécutable) et un tableau args. Une recette (latex-workshop.latex.recipes) est une liste ordonnée de noms d'outils. latexmk est une recette d'un seul outil ; pdflatex -> bibtex -> pdflatex * 2 en compte quatre. La séparation existe parce que le même exécutable est réclamé avec des arguments différents selon les cas : les outils livrés comprennent latexmk, lualatexmk, xelatexmk, latexmk_rconly, pdflatex, bibtex et tectonic, et les recettes les recombinent au lieu de dupliquer les définitions de commandes.
{
"name": "latexmk",
"command": "latexmk",
"args": [
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"-pdf",
"-outdir=%OUTDIR%",
"%DOC%"
],
"env": {}
}Lire les arguments un à un révèle la conception. -synctex=1 réclame la table SyncTeX évoquée plus bas ; -interaction=nonstopmode va jusqu'au bout au lieu de s'arrêter à une erreur pour attendre une saisie ; -file-line-error affiche les erreurs sous la forme main.tex:42: Undefined control sequence, et c'est ce dernier drapeau qui permet à l'extension de sauter du panneau Problèmes directement à la ligne. -pdf demande à latexmk de produire le PDF directement avec pdfLaTeX — le drapeau qui posera problème plus loin. Les jetons %…% sont des espaces réservés que l'extension substitue juste avant le lancement.
| Espace réservé | Se substitue en |
|---|---|
%DOC% | chemin du fichier racine, sans son extension |
%DOC_EXT% | chemin du fichier racine, avec son extension |
%DOCFILE% | le seul nom du fichier racine, sans extension |
%DIR% | le répertoire du fichier racine ; valeur par défaut de outDir |
%OUTDIR% | le répertoire de sortie fixé par latex-workshop.latex.outDir |
%TMPDIR% | un répertoire temporaire pour les fichiers auxiliaires ; laisse la source propre |
%WORKSPACE_FOLDER% | le chemin de l'espace de travail actuellement ouvert |
Le choix de la recette revient à latex-workshop.latex.recipe.default. Sa valeur par défaut est "first" — la première entrée de la liste l'emporte — et la régler sur "lastUsed" fait mémoriser la dernière recette choisie. Une compilation se lance par Ctrl+Alt+B (Cmd+Alt+B sur Mac). Pour exécuter une recette précise une seule fois, utilisez « LaTeX Workshop: Build with recipe » dans la palette de commandes ; pour en fixer une à un fichier, écrivez %!LW recipe=latexmk (lualatex) en première ligne. Cette directive est ignorée dès qu'on choisit la recette à la main dans le panneau.
Pourquoi la recette par défaut lance un autre moteur que le vôtre
La réponse est dans la définition d'outil ci-dessus : -pdf est l'argument qui demande à latexmk de produire le PDF directement avec pdfLaTeX. Ce seul mot explique une bonne part des signalements « ça compile au terminal mais pas dans VS Code ». Si le préambule charge fontspec — tout ce qui emploie des polices OpenType, tout ce qui emploie unicode-math, la plupart des modèles récents —, la compilation s'arrête sur ! Fatal Package fontspec Error: The fontspec package requires either XeTeX or LuaTeX. Si vous saisissez du japonais, du chinois ou du coréen directement, vous obtenez plutôt ! LaTeX Error: Unicode character こ (U+3053) not set up for use with LaTeX. Aucun des deux messages ne mentionne VS Code, car VS Code n'est pas en cause.
Le correctif consiste simplement à choisir une autre recette, et il y a quatre voies, par permanence croissante. Juste cette fois : « Build with recipe » dans la palette de commandes. Juste ce fichier : %!LW recipe=… en première ligne. Désormais, celle que j'ai choisie en dernier : régler latex-workshop.latex.recipe.default sur "lastUsed". Fixée pour tout le projet : réordonner latex-workshop.latex.recipes dans settings.json pour que la recette voulue arrive en tête, puisque la valeur par défaut est "first". La liste livrée contient déjà latexmk (lualatex), latexmk (xelatex) et latexmk (latexmkrc) : la plupart du temps, on choisit au lieu d'écrire.
Mettre le moteur dans .latexmkrc, pas dans settings.json
Un choix de moteur inscrit dans les réglages de l'éditeur ne quitte jamais la machine où il a été écrit. Inscrit dans un .latexmkrc, il voyage avec le projet : le TeXstudio du coauteur, un conteneur d'intégration continue et un simple latexmk main.tex aboutissent au même résultat. La recette livrée latexmk (latexmkrc) existe précisément pour cela : elle exécute latexmk %DOC% sans ajouter d'argument. Voici une configuration upLaTeX + dvipdfmx, longtemps la combinaison classique des articles japonais :
$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';
$pdf_mode = 3;
$max_repeat = 5;Le point pivot est $pdf_mode. 3 signifie « produire un DVI, puis le convertir en PDF avec $dvipdf » ; 1 correspond à pdfLaTeX en direct, 4 à LuaLaTeX. L'index passe par upmendex, capable de trier le japonais, et la bibliographie par upbibtex. %S, %O, %D et %B sont les espaces réservés propres à latexmk — source, options supplémentaires, cible de sortie et nom de base sans extension — d'une autre famille que le %DOC% de l'extension : ne les mélangez pas. Discret mais capital : $latex porte -synctex=1. Sans lui, le saut par clic décrit plus bas cesse de fonctionner sans le moindre message.
À l'inverse, pour tout garder dans settings.json et se passer du .latexmkrc, écrivez votre propre outil et votre propre recette, et placez la recette en tête. Voici un exemple autonome pour LuaLaTeX, qui compose le japonais via luatexja et les ltjsclasses, sans détour par dvipdfmx :
{
"latex-workshop.latex.tools": [
{
"name": "lualatexmk",
"command": "latexmk",
"args": [
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"-lualatex",
"-outdir=%OUTDIR%",
"%DOC%"
],
"env": {}
}
],
"latex-workshop.latex.recipes": [
{ "name": "lualatexmk", "tools": ["lualatexmk"] }
]
}Les trois réglages à fixer en premier : sortie, build auto, visionneuse
Les réglages vivent dans settings.json. Ouvrez l'écran de réglages par Ctrl/Cmd+, et utilisez « Ouvrir les paramètres (JSON) » en haut à droite ; vous pouvez modifier soit le fichier utilisateur global, soit un .vscode/settings.json dans le projet. Tout ce que des coauteurs ou un serveur de compilation doivent partager va obligatoirement dans le second. Sur plusieurs dizaines de réglages, trois méritent d'être tranchés d'emblée :
latex-workshop.latex.outDir— où vont les fichiers intermédiaires et le PDF. La valeur par défaut est%DIR%, à côté du.tex. En réglant%DIR%/out, les.aux,.loget.flscessent de joncher le dossier source et le.gitignoretient en une ligne.latex-workshop.latex.autoBuild.run— ce qui déclenche une compilation automatique. Par défautonFileChange, qui surveille les dépendances sur le disque et réagit donc aussi aux modifications faites hors de l'éditeur. Les autres valeurs sontonSave(à l'enregistrement seulement) etnever(manuel uniquement). Si vous perdez le fil de ce qui a déclenché une compilation,onSaveest le choix lisible.latex-workshop.view.pdf.viewer— où apparaît le PDF :tab(par défaut, un onglet dans VS Code),browser(navigateur par défaut) ouexternal(autre programme, considéré comme expérimental). Pour un SyncTeX sans friction :tab.
{
"latex-workshop.latex.outDir": "%DIR%/out",
"latex-workshop.latex.autoBuild.run": "onSave",
"latex-workshop.view.pdf.viewer": "tab",
"latex-workshop.latex.recipe.default": "lastUsed"
}Séparer le répertoire de sortie comporte un piège : modifier outDir change du même coup l'endroit où l'extension cherche les .aux et .fls. Si cela ne correspond plus à l'endroit où la compilation les écrit réellement, vous vous retrouvez avec un PDF bel et bien produit mais introuvable pour l'extension, et des renvois qui ne se résolvent jamais. Gardez les deux alignés — surtout si votre .latexmkrc fixe aussi $out_dir. Le ménage des fichiers intermédiaires revient à latex-workshop.latex.autoClean.run, mais dès lors que tout atterrit dans out/, supprimer le dossier suffit.
Compiler main.tex en éditant un chapitre : % !TEX root
Placez % !TEX root = ../main.tex en première ligne du fichier enfant. Cela suffit pour que la compilation démarre au document principal même si seul le chapitre est ouvert. Cela fonctionne parce que LaTeX Workshop cherche la racine en cinq étapes, dont ce commentaire magique est la première : (1) % !TEX root ; (2) le fichier ouvert contient-il lui-même \documentclass ou \begin{document} ; (3) parcourir les .tex à la racine de l'espace de travail à la recherche d'une déclaration de classe ; (4) l'organisation du package subfiles ; (5) l'analyse des fichiers .fls. La devinette tombe souvent juste — mais dans une thèse aux dizaines de fichiers de chapitres, c'est justement le fait de deviner qui est risqué.
% !TEX root = ../main.tex
% !TEX program = lualatex
\section{Method}
% Building from inside this chapter still starts at main.tex.- Outre
% !TEX root, l'extension lit aussi% !TEX program,% !TEX optionset% !BIB program. Pour désactiver toute la famille, mettezlatex-workshop.latex.build.enableMagicCommentsàfalse. - Ouvrez l'espace de travail à la racine du projet qui contient
main.tex. Si vous n'ouvrez que le dossier du chapitre, l'étape (3) de la recherche n'atteint jamais le document principal. - Le chemin de
% !TEX rootest relatif au fichier qui le porte : déplacer un chapitre dans un autre dossier oblige à corriger la ligne. - Un choix de recette en désaccord avec
% !TEX programest le meilleur moyen de s'égarer. En équipe, poussez la décision dans le.latexmkrcet normalisez la recette surlatexmk (latexmkrc).
La visionneuse PDF intégrée et SyncTeX au ctrl-clic
La visionneuse PDF qu'ouvre tab est une page web bâtie autour de PDF.js de Mozilla, servie par un petit serveur que l'extension fait tourner en local. D'où le fait que browser donne exactement la même visionneuse, et que le rendu ne varie ni avec le système d'exploitation ni avec un lecteur PDF installé. Seul external sort du lot : il confie le fichier à un autre programme, d'où son statut expérimental — la recherche avant avec une visionneuse externe doit être câblée à part, via des clés telles que latex-workshop.view.pdf.external.synctex.command.
Ce qu'il faut retenir ici : SyncTeX n'est pas une fonction de l'éditeur. Ce qui écrit la correspondance entre les lignes de la source et les positions dans le PDF, c'est le moteur TeX, et son interrupteur est -synctex=1. Si l'extension peut lire un .synctex.gz, c'est uniquement parce que la recette a transmis ce drapeau. Définissez votre propre outil en l'oubliant : la compilation réussit, le PDF apparaît, et seul le saut par clic cesse silencieusement de fonctionner, sans la moindre erreur. Si le saut marchait hier et plus aujourd'hui, soupçonnez d'abord les arguments de la recette.
Deux gestes suffisent. La recherche avant (source → PDF) saute du curseur à l'endroit correspondant du PDF : Ctrl+Alt+J, ou Cmd+Alt+J sur Mac ; dans la palette de commandes, c'est « LaTeX Workshop: SyncTeX from cursor ». Pour sauter automatiquement après chaque compilation, mettez latex-workshop.synctex.afterBuild.enabled à true. La recherche inverse (PDF → source) est un Ctrl-clic (Cmd-clic sur Mac) dans la visionneuse intégrée ; le geste se choisit par latex-workshop.view.pdf.internal.synctex.keybinding, soit ctrl-click (défaut), soit double-click. Au passage : compiler, c'est Ctrl+Alt+B, et ouvrir le PDF, Ctrl+Alt+V.
SyncTeX survit aussi à la route par le DVI. Passez -synctex=1 à $latex comme dans le .latexmkrc ci-dessus et la table écrite par upLaTeX traverse dvipdfmx jusqu'au PDF ; il n'est pas nécessaire d'aller droit au PDF avec pdfLaTeX pour pouvoir sauter. La mécanique elle-même — ce que contient un .synctex.gz, et le fait qu'une valeur négative produise à la place un fichier texte non compressé et lisible — relève de la page SyncTeX.