VS Code as LaTeX editor
November 11, 2019 — September 27, 2024
Welcome to the most popular page on this blog. No joke, this one is a perennial favourite. Please leave a comment if you notice something wrong or outdated; you will help hundreds of people.
Visual Studio Code is for me the overall best way of editing LaTeX. Compared to a special-purpose editor (e.g. TeXShop) the preview and build process is inferior but adequate. The actual editing experience is superior, better streamlined and more integrated into my workflow than any weird, tin-pot specialist editor maintained by one quirky academic somewhere. Alexander Zeilmann makes an eloquent argument for choosing VS Code in his LaTeX Workflow post, which includes additional tips.
However, I had to tweak it a bit to get it to work smoothly, and I made some mistakes. Successes and failures both are reproduced here for your delectation and amusement.
A second-best is Overleaf, which is a web-based editor, and whilst the editing experience is inferior, it gets bonus points for being collaborative. Note that Overleaf is also a backend for VS Code LaTeX
OK, LaTeX-in-VS Code. Here we go.
There is one major decision point to start, which is the choice of which extension to use
- LaTeX Workshop or
- texlab.
- Overleaf plugin
- No plugins, just treat this as text.
Texlab is the most aesthetic and elegant to my mind, but it is not as easy or as well-supported by a large community, so in practice I tend not to use it.
Set up a TeX-aware git .gitignore to stop VS Code freaking out about all the auxiliary files.
1 Overleaf plugin
Online LaTeX frontend Overleaf can integrate into VS Code.
Overleaf Workshop is an open-source extension for Overleaf users to manage projects, edit documents, and collaborate in Visual Studio Code. The name of the extension is inspired by the well-known LaTeX Workshop Extension.
The aim of Overleaf Workshop is to provide a seamless experience for Overleaf users to enjoy the service of Overleaf in VS Code just like in the web browser, while benefiting from the powerful features and extensions of VS Code.
Besides the official Overleaf server provided on https://www.overleaf.com, we also support the access to self-hosted Overleaf Community Edition and Overleaf Server Pro Edition servers.
Notice that the official server (with premium features) and Server Pro Edition are neither free nor open-source, the feature support for these servers is limited. All these extra features are marked with Pro in the following sections.
2 Texlab
The disruptive entrant in the crowded field of LaTeX extensions for VS Code Texlab.
A Visual Studio Code extension that provides rich editing support for the LaTeX typesetting system, powered by the TexLab language server. It aims to produce high-quality code completion results by indexing your used packages as you type.
Recommended matching syntax highlighter: latex-syntax.
Neat feature: supported configuration uses the modernised and streamlined tectonic distribution instead of classic LaTeX.
This extension makes some radical design choices in the name of simplicity and elegance, which might mean it is less confusing. On the other hand, it probably means that some features, edge cases and/or misfeatures in classic TeX will be unsupported. For an extension which can handle that weird workflow that you have been working on since 1997, see LaTeX Workshop.
2.1 SyncTeX
The build/preview workflow is jarring; you need to start your own previewer then maintain sync, which requires custom setup depending on which unsatisfactory PDF viewer you use. Which means different settings on each OS. After that… TBH I cannot work out how to invoke the build step from inside VS code. Or invoke the PDF viewer. I cannot work out how to invoke the PDF viewer except via synctex. This means that, unintuitively, I invoke the viewer by the command LaTeX: Forward Search
.
For GNOME desktops, evince-synctex works.
{
"texlab.forwardSearch.executable": "evince-synctex",
"texlab.forwardSearch.args": ["-f", "%l", "%p", "\"code -g %f:%l\""]
}
Installation by one of the following:
pip3 install --user https://github.com/efoerster/evince-synctex/archive/master.zip
pipx install https://github.com/efoerster/evince-synctex/archive/master.zip
On macOS we had best use Skim, apparently. Skim docs on TeX and PDF Synchronization reveal that Skim must be in Check for file changes
mode (see app settings).
{
"texlab.forwardSearch.executable": "/Applications/Skim.app/Contents/SharedSupport/displayline",
"texlab.forwardSearch.args": ["%l", "%p", "%f"]
}
If you, as I, work on multiple OSes, we need to disable sync for these machine-specific settings, or it will constantly be trying to run evince on macOS or some such.
3 LaTeX Workshop
LaTeX-Workshop is the default VS Code LaTeX editing extension. Originally I was sceptical, despite its many features, because it was confusing when things went wrong (Where WAS that syntax error?) which meant it was not good at its main job because syntactically invalid is the normal state of a document I am writing.
However, the new version is better; I just need to make sure that little TeX sidebar is active and everything becomes apparent. Some things are still fiddly.
3.1 Why are all my keymaps borked?
LaTeX-workshop comes with an aggressively intrusive set of keybindings that clash with so many other things that for me at least there is no sense fixing them up one-by-one. Instead, I use the following setting to switch to the alternative keymap:
This is not well documented; see Pull Request #983 or the FAQ entry. The above setting changes all Ctrl-Alt-<key>
shortcuts to Ctrl-L, Alt-<key>
. Translate the versions from the manual in your head.
3.2 Configuration
It seems wise to me to set latex-workshop.latex.build.forceRecipeUsage to false
so that we can also use magic comments for compatibility with our colleagues. In particular, I like to use !TEX program = xelatex
at the top of my documents, and Identify the master document explicitly
3.3 Equation preview
VS Code supposedly can preview individual equations via javascript. This does not work for me on substantial documents, and I cannot work out why, because there is no error dumped anywhere I can see it. I will never find time to work out what is happening. Only simple equations in trivial test documents have preview for me.
It might be something about fancy macros or packages I use? Javascript mathematics are blind to the LaTeX loaded packages, but we can globally fake out some use-cases with some with global MathJax extensions:
3.4 Snippets
LaTeX workshop supports smart snippets with autocomplete.
Reproduced here for my offline reference are the most useful ones.
Prefix | Environment name |
---|---|
BEQ |
equation |
BSEQ |
equation* |
BAL |
align |
BSAL |
align* |
BIT |
itemize |
BEN |
enumerate |
BSPL |
split |
BCAS |
cases |
BFR |
frame |
BFI |
figure |
Prefix | Sectioning level |
---|---|
SPA |
part |
SCH |
chapter |
SSE |
section |
SSS |
subsection |
SS2 |
subsubsection |
SPG |
paragraph |
SSP |
subparagraph |
The next ones are not snippets, apparently, but they look the same to me: @ suggestions:
Prefix | Command |
---|---|
@( |
\left( $1 \right) |
@{ |
\left\{ $1 \right\} |
@[ |
\left[ $1 \right] |
__ |
_{$1} |
** |
^{$1} |
@8 |
\infty |
@6 |
\partial |
@/ |
\frac{$1}{$2} |
@% |
\frac{$1}{$2} |
@_ |
\bar{$1} |
@I |
\int_{$1}^{$2} |
@| |
| |
@\ |
\setminus |
@, |
\nonumber |
3.5 Build recipes
Building using something modern or fancy? The default build workflow is some pdflatex
+BibTeX
system that is ok but outdated. I would prefer a simpler more modern workflow that supports e.g. XeTeX. Out of the box, neither XeTeX nor latexmk
were available workflows for me. UPDATE: These are now supported.
There are two ways to set these up.
Firstly, the old school way that the developers of LaTeX workshop seem to dislike, but which was far and away the easiest for me: Use the Latex Workshop-style TeX magic This looks like, e.g.
% !TEX program = latexmk
% !TEX options = -synctex=1 -pdf -file-line-error -halt-on-error -xelatex -outdir="%OUTDIR%" "%DOC%"
I put that at the start of the master document and things behave as expected. Good. For this particular build tool, latexmk, to actually have any advantage, one would want to disable auto-clean (a.k.a. delete everything and rebuild from scratch all the time) so that latexmk
can be smart about rebuilds. Looks like the following setting does that.
The price one pays for this is needing to manually clean up the detritus from time to time.
The developer-preferred way of configuring the LaTeX build is difficult, verbose and error-prone but supposedly ineffably better. That kind of argument is one that I am curiously susceptible to, in that I occasionally find myself buying biodynamic yoghurt even though biodynamic is definitely nonsense.
Anyway, in the biodynamic configuration method, we make new “recipes” in the configuration JSON. The process is 😴. Here, cargo cult the ones I use, which in practice are all about latexmk
, which is generally easiest and fastest for me.
Q: Are they still necessary, or does modern LaTeX workshop support latexmk
out of the box?
"latex-workshop.latex.recipes": [
{
"name": "latexmk 🔃",
"tools": [
"latexmk"
]
},
{
"name": "xelatexmk 🔃",
"tools": [
"xelatexmk"
]
},
{
"name": "platexmk 🔃",
"tools": [
"platexmk"
]
}
],
"latex-workshop.latex.tools": [
{
"name": "latexmk",
```json
"command": "latexmk",
"args": [
"-synctex=1",
"-file-line-error",
"-pdf",
"-outdir=%OUTDIR%",
"%DOC%"
],
"env": {}
},
{
"name": "platexmk",
"command": "latexmk",
"args": [
"-synctex=1",
"-file-line-error",
"-pdf",
"-outdir=%OUTDIR%",
"%DOC%"
],
"env": {}
},
{
"name": "xelatexmk",
"command": "latexmk",
"args": [
"-synctex=1",
"-file-line-error",
"-xelatex",
"-pdf", // controversial bit
"-outdir=%OUTDIR%",
"-interaction=nonstopmode",
"%DOC%"
],
"env": {}
},
]
Qiita, in VSCode で最高の LaTeX 環境を作る demonstrates how to make the latexmk
workflow more configurable, so that you can essentially always use latexmk
. Alexander Zeilmann demonstrates a more minimalist one. In practice, I do not want to learn another domain-specific language to configure a build system, so I am sticking with the verbose JSON configuration.
Usually I use the platexmk
configuration out of necessity although I prefer xelatexmk
. Occasionally I use vanilla latexmk
when I have to output for some journal who really hates modern character sets.
The disruptive new tectonic build system notionally minimises the amount of configuration we need to do by being smart and defaulting to modern choices. To use tectonic with LaTeX-workshop:
"latex-workshop.latex.tools": [
{
"name": "tectonic",
"command": "tectonic",
"args": [
"--synctex",
"%DOC_EXT%"
],
"env": {}
}
],
"latex-workshop.latex.recipes": [
{
"name": "tectonic",
"tools": [
"tectonic"
]
}
]
See also Using Tectonic with VS Code on the tectonic GitHub forum. pace James Yu, it needs "--synctex"
and "%DOC_EXT%"
to work properly.
Now we can use the tectonic system from LaTeX-workshop! That is, like, biodynamic and ketogenic at the same time, or something.
Advanced: compile scientific workbooks such as knitr. See docs
There are some bonus classic-flavour build recipes at the end.
3.6 SyncTeX
SyncTeX makes discerning what I am typing somewhat easier, by connecting the cursor location in the source code to the viewing location in the PDF (and, on some systems, vice versa). The built-in implementation in Latex-workshop is OK; we are somewhat hamstrung because everything is constrained to a single window by VS Code. 1 External PDF viewers are not officially supported but more-or-less work for me, and are superior for a dual monitor setup, although definitely jankier.
Minuses of external PDF viewers:
- Documentation is perfunctory.
- Occasionally it does not do what I want regarding mouse keyboard focus and I find myself typing LaTeX into a PDF viewer window
NB: I’m no fan of the default PDF viewers on linux desktops (Okular, Evince), if I edit more TeX on linux I will probably move to Sioyek or Zathura.
The default keyboard shortcut for syncing is ⇧⌥⌃J
, or ⌘L⌥J
with the alternate keymap.
3.6.1 Okular
A good example of reverse engineering the config for kubuntu’s PDF viewer okular
is given by Heiko/@miteron.
{
"latex-workshop.view.pdf.viewer": "external",
// @sync host=work-pc
"latex-workshop.view.pdf.external.viewer.command": "okular",
// @sync host=work-pc
"latex-workshop.view.pdf.external.viewer.args": [
"--unique",
"%PDF%"
],
// @sync host=work-pc
"latex-workshop.view.pdf.external.synctex.command": "okular",
// @sync host=work-pc
"latex-workshop.view.pdf.external.synctex.args": [
"--unique",
"%PDF%#src:%LINE%%TEX%"
],
}
3.6.2 Evince
For GNOME doc viewer evince
things are more complicated. Specifically, I needed a bridging script and special config:
{
// @sync host=home-pc
"latex-workshop.view.pdf.external.viewer.command": "evince2",
// @sync host=home-pc
"latex-workshop.view.pdf.external.viewer.args": [
"%PDF%"
],
// @sync host=home-pc
"latex-workshop.view.pdf.external.synctex.command": "evince_forward_search",
// @sync host=home-pc
"latex-workshop.view.pdf.external.synctex.args": [
"%PDF%",
"%LINE%",
"%TEX%"
],
}
3.6.3 Skim.app
For macOS, Skim.app is reliable and popular.
Backward (i.e. viewer-to-LaTeX) sync is by ⇧⌘-Click
. Documentation here. To make it work I had to change the defaults. Skim comes with its own VS Code preset, which uses the command open
to open vscode://file"%urlfile":%line
. We can force VS Code Insiders by using open
with URI vscode-insiders://file"%urlfile":%line
. This did not work for me on one of my machines for no discernible reason. The slightly slower method, telling Skim to use code
to open --goto "%file":%line
, worked in that case. The following was the necessary setup from the VS Code side:
"latex-workshop.view.pdf.viewer": "external",
"latex-workshop.view.pdf.external.viewer.command": "/Applications/Skim.app/Contents/SharedSupport/displayline",
"latex-workshop.view.pdf.external.viewer.args": [
"0",
"%PDF%"
],
"latex-workshop.view.pdf.external.synctex.command": "/Applications/Skim.app/Contents/SharedSupport/displayline",
"latex-workshop.view.pdf.external.synctex.args": [
"-revert", // reload
"-readingbar", // highlight line
"-background", // do not steal focus
"%LINE%",
"%PDF%",
"%TEX%",
],
The background
setting is contentious. Skim.app steals input focus if it comes to the foreground which is often not what we want. But also, having it come to the foreground is a plus, because then we can see it. I recommend avoiding the problem by using it fullscreen on an external display.
3.7 Gotchas
Gotcha: If there are weird “provider errors” in the vscode exthost
log, the problem might be that latexindent
must be installed, and possibly it was not for me because I installed a minimalist TeX distribution.
If I want to switch TeX installations, I can do so by environment variables, so I whack something like the following in my settings.json
:
3.8 Spell checking
Contra my VS Code spell checking advice, SpellRight is unsupported for LaTeX-Workshop.
If I persevere in using spellright, the following exclusions make things tidier:
"spellright.ignoreRegExpsByClass": {
"latex": [
"/\\\\begin\\\\{{equation,align}\\\\}(.*?)\\\\end\\\\{{equation,align}\\\\}/mg",
"/\\\\{autoref,autocites?,cites?}\\\\{(.*?)\\\\}/g",
],
},
But it will still be horrible. Probably better is to disable spellright for .tex
files in favour of cspell instead. Supposedly LanguageTool is good for more diverse languages, but I have not tried it.
Alternatively, here is a new entrant, LTEX, discussed at VS Code for prose. It seems nifty but the memory footprint is large so I tend not to use it..
4 Bonus time: Even more build configurations
Some LaTeX-Workshop build configurations I no longer use (because latexmk is so good), but which might be useful to others.
"latex-workshop.latex.recipes": [
{
"name": "pdflatex ➞ bibtex ➞ pdflatex`×2",
"tools": [
"pdflatex",
"bibtex",
"pdflatex",
"pdflatex"
]
},
{
"name": "xelatex ➞ biber ➞ xelatex",
"tools": [
"xelatex",
"biber",
"xelatex"
]
}
],
"latex-workshop.latex.tools": [
{
"name": "pdflatex",
"command": "pdflatex",
"args": [
"-synctex=1",
"-interaction=nonstopmode",
"-halt-on-error",
"-file-line-error",
"%DOC%"
],
"env": {}
},
{
"name": "xelatex",
"command": "xelatex",
"args": [
"-synctex=1",
"-interaction=nonstopmode",
"-halt-on-error",
"-file-line-error",
"%DOC%"
],
"env": {}
},
{
"name": "bibtex",
"command": "bibtex",
"args": [
"%DOCFILE%"
],
"env": {}
},
{
"name": "biber",
"command": "biber",
"args": [
"%DOCFILE%"
],
"env": {}
}
]
Footnotes
Although see VS Code’s dual window hack).↩︎