# VS Code as LaTeX editor

Welcome to the most popular page on this blog. No joke, this one is a perennial favourite. I have not updated the content overmuch recently; your feedback is welcome if something is outdated; and you will help hundreds of people.

Visual Studio Code brovides nearly as good a LaTeX writing experience as, say, TeXShop, in that the preview and workflwo is …OK and the actual editing experince is superior, better supported and more integrated into my workflow than some weird-tin-pot specialist LaTeX editor maintained by one quirky academic somewhere. Alexander Zeilmann makes an eloquent argument for this choice in his LaTeX Workflow post, which includes additional tips.

## General

Set up a git .gitignore

## Texlab

The disruptive entrant is texlab for vs code.

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 extensions makes some radical design choices in the name of simplicity and elegance, which hopefully means that the experience will be not too janky because it is simple, which sometimes means fast. 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.

ext install efoerster.texlab

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, the viewer is invoked 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 need Skim apparently. 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 work on multiple OSes, you need to disable sync for these machine-specific settings, or it will constantly be trying to run evince on macos or some such.

## LaTeX Workshop

LaTeX-Workshop is the default VS Code LaTeX editing extension. Originally I was skeptical, 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 much better; I just need to make sure that little TeX sidebar is active and everything becomes apparent. Some things are still fiddly.

### 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:

    "latex-workshop.bind.altKeymap.enabled": true,

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 in your head.

### 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:

"latex-workshop.hover.preview.mathjax.extensions": [
"boldsymbol"
]

UPDATE: At some point this started working for me even with reasonably challenging macros.

### Snippets

LaTeX workshop supports smart snippets with autocomplete.

Reproduced here for my offline reference are the most useful ones.

PrefixEnvironment name
BEQequation
BSEQequation*
BALalign
BSALalign*
BITitemize
BENenumerate
BSPLsplit
BCAScases
BFRframe
BFIfigure
PrefixSectioning level
SPApart
SCHchapter
SSEsection
SSSsubsection
SS2subsubsection
SPGparagraph
SSPsubparagraph
PrefixCommand
@(\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

### 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 or latexmk were available workflows for me. UPDATE: These are now supported There are two ways to do 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.

    "latex-workshop.latex.autoBuild.cleanAndRetry.enabled": false,

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:

    "latex-workshop.latex.recipes": [
{
"name": "latexmk 🔃",
"tools": [
"latexmk"
]
},
{
"name": "xelatexmk 🔃",
"tools": [
"xelatexmk"
]
},
{
"name": "platexmk 🔃",
"tools": [
"platexmk"
]
},
{
"name": "pdflatex ➞ bibtex ➞ pdflatex×2",
"tools": [
"pdflatex",
"bibtex",
"pdflatex",
"pdflatex"
]
},
{
"name": "xelatex ➞ biber ➞ xelatex",
"tools": [
"xelatex",
"biber",
"xelatex"
]
}
],
"latex-workshop.latex.tools": [
{
"name": "latexmk",
"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": {}
},
{
"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": {}
}
]

That is a lot of configurations, no? And they do not look like the other configurations on the internet, do they? Honestly I cannot understand how we all live in parallel universes with slightly different LaTeX configurations, all alike and yet all incompatible.

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 xelatexmk configuration; 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.

### 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 OK; we are somewhat hamstrung because everything is constrained to a single window by VS Code. (Although see VS Code’s dual window hack). 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.
• Sync works in AFAICT one direction only — I can sync from VS Code to the PDF viewer, but the reverse does not work for me.

Since they are unsupported, one needs to guess the config to make them go. 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%"
],
}

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%"
],
}

For macos, use Skim.app.

    "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": [
"-r",
"-b",
"%LINE%",
"%PDF%",
"%TEX%",
],

Backward (i.e. viewer-to-LaTeX) sync, if it worked, which it does not for me, would be by ⇧⌘-Click. Documentation here.

### 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.

tlmgr install latexindent

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:

  {
"name": "latexmk",
"command": "latexmk",
"args": [
"-synctex=1",
"-interaction=nonstopmode",
"-file-line-error",
"-pdf",
"-outdir=%OUTDIR%",
"%DOC%"
],
"env": {"TEXMFHOME": "c:/texlive/2019"} // That's how you do it
}

## Spell checking

Contra my prior VS Code spell checking advice, SpellRight is unsupported for LaTeX.

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 in the field:

LTEX:

LTEX — Grammar/Spell Checker Using LanguageTool with Support for LATEX, Markdown, and Others

LTEX provides offline grammar checking of various markup languages using LanguageTool (LT). LTEX can be used standalone as a command-line tool, as a language server using the Language Server Protocol (LSP), or directly in various editors using extensions.

LTEX currently supports BibTEX, ConTEXt, LATEX, Markdown, Org, reStructuredText, R Sweave, and XHTML documents.

The difference to regular spell checkers is that LTEX not only detects spelling errors, but also many grammar and stylistic errors…

A classic use case of LTEX is checking scientific LATEX papers, but why not check your next blog post, book chapter, or long e-mail before you send it to someone else?

TBC.

### 1 comment

Hi,

Nice description. I tried to use Synctex with Evince and LaTeX-Workshop. Downloaded the script and modified settings.json. The ctrl+alt+v works fine, however, Synctex's forward-backward search doesn't. Any idea? I use ubuntu 22.04.

Thanks