基础概念
LaTeX WorkShop 插件的编译逻辑分为两层:第一层为 recipe,第二层为 tool,具有如下特点:
- 一个 recipe 由若干个 tool 组成;
- 在配置文件中可以提供多个 recipe 和多个 tool;
- 直接点击编译按钮会自动选择第一个(或上一次使用的)recipe 来执行编译;
- 一个 tool 通常包括一个单独的编译命令加上若干参数,例如 xelatex,lualatex 和 pdflatex 等,还可能是处理参考文献需要的 bibtex 或 biber;
- 一个 recipe 会依次执行它所包含的 tool,例如:
1
| xelatex -> bibtex -> xelatex -> xelatex
|
LaTeX WorkShop 插件其实只是对原本在命令行操作的 LaTeX 编译命令以及格式化命令进行了封装。
此外,LaTeX WorkShop 插件会在命令中传递特殊变量%DOC%或%DOCFILE%代表当前文件,第一个是文件名(含完整路径,不含后缀),第二个则是文件名(不含后缀),略有区别。
由于插件也只是调用了pdflatex、latexmk等编译命令,如果环境中存在.latexmkrc等配置文件,可能会对插件的编译行为造成影响。
但是因为插件的选项是通过命令行参数传递的,优先级更高,影响应该不大。
LaTeX WorkShop 插件并不推荐使用例如% !TEX program = xelatex的魔法命令来指定编译命令,但是考虑到向后兼容性会为其提供有限的支持,需要在设置中开启相关选项。
编译配置(一)
第一种配置是使用 latexmk 分别调用 xelatex,lualatex 和 pdflatex,配置如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| "latex-workshop.latex.tools": [ { "name": "xelatexmk", "command": "latexmk", "args": [ "-pdfxe", "-file-line-error", "-halt-on-error", "-interaction=nonstopmode", "-synctex=1", "-auxdir=%DIR%/.aux", "-outdir=%OUTDIR%", "%DOC%" ] }, { "name": "lualatexmk", "command": "latexmk", "args": [ "-pdflua", "-file-line-error", "-halt-on-error", "-interaction=nonstopmode", "-synctex=1", "-outdir=%OUTDIR%", "-auxdir=%DIR%/.aux", "%DOC%" ] }, { "name": "latexmk", "command": "latexmk", "args": [ "-pdf", "-file-line-error", "-halt-on-error", "-interaction=nonstopmode", "-synctex=1", "-outdir=%OUTDIR%", "-auxdir=%DIR%/.aux", "%DOC%" ] } ], "latex-workshop.latex.recipes": [ { "name": "XeLaTeXmk", "tools": [ "xelatexmk" ] }, { "name": "LuaLaTeXmk", "tools": [ "lualatexmk" ] }, { "name": "LaTeXmk", "tools": [ "latexmk" ] } ], "latex-workshop.latex.clean.args": [ "-outdir=%OUTDIR%", "-c", "%TEX%", "-auxdir=%DIR%/.aux" ],
|
这里使用.aux/辅助目录存储编译过程中生成的各种杂项文件,在清理时也需要指定。
在使用某些宏包时,可能需要加上 "-shell-escape" 选项才能成功编译。
编译配置(二)
第二种配置是不使用 latexmk,直接使用 xelatex 等编译命令,
此时由于参考文献(bibtex 或 biber)和双向引用等原因,需要配置 recipe 进行多次编译,配置如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| "latex-workshop.latex.tools": [ { "name": "xelatex", "command": "xelatex", "args": [ "-file-line-error", "-halt-on-error", "-interaction=nonstopmode", "-synctex=1", "%DOC%" ] }, { "name": "pdflatex", "command": "pdflatex", "args": [ "-file-line-error", "-halt-on-error", "-interaction=nonstopmode", "-synctex=1", "%DOC%" ] }, { "name": "bibtex", "command": "bibtex", "args": [ "%DOCFILE%" ] } ], "latex-workshop.latex.recipes": [ { "name": "xelatex->xelatex", "tools": [ "xelatex", "xelatex" ] }, { "name": "xelatex", "tools": [ "xelatex" ] }, { "name": "pdflatex", "tools": [ "pdflatex" ] }, { "name": "BibTeX", "tools": [ "bibtex" ] }, { "name": "xe->bib->xe*2", "tools": [ "xelatex", "bibtex", "xelatex", "xelatex" ] }, { "name": "pdf->bib->pdf*2", "tools": [ "pdflatex", "bibtex", "pdflatex", "pdflatex" ] } ],
|
这组配置并没有使用.aux/子目录存放辅助文件,因为这些编译命令虽然支持指定输出目录,但是无法自动创建目录。
VSCode 与 SumatraPDF 双向跳转
除了 tools 和 recipes 这两个主要的配置,还有一个重要的功能是双向跳转,
通过 VSCode 内部预览 PDF 时,可以直接进行双向跳转,无需任何配置。
默认的双向跳转操作是:
ctrl + 单击 PDF 相应位置,从 PDF 跳转到源文件对应位置
ctrl+alt+j,从源文件跳转到 PDF 对应位置
由于内部预览无法拆分窗口,在外部使用 SumatraPDF 进行 PDF 预览可能更加方便,下面考虑配置支持 VSCode 和 SumatraPDF 之间的双向跳转。
VSCode 也可以把 PDF 预览页面单独拆开了,因此也可以直接用 VSCode 预览,但是有时内置预览页面的清晰度实在太差了,例如截图时最好还是使用外部的 PDF 浏览器。
参考 LaTeX-Workshop 的 wiki
以及 SumatraPDF 的相关讨论。
对于 VSCode 的配置如下:
1 2 3 4 5 6 7 8 9 10 11
| "latex-workshop.view.pdf.viewer": "external", "latex-workshop.view.pdf.external.synctex.command": "<path-to-SumatraPDF>/SumatraPDF.exe", "latex-workshop.view.pdf.external.synctex.args": [ "-forward-search", "%TEX%", "%LINE%", "-reuse-instance", "-inverse-search", "\"<path-to-vscode>/Code.exe\" \"<path-to-vscode>/resources/app/out/cli.js\" --ms-enable-electron-run-as-node -r -g \"%f:%l\"", "%PDF%" ],
|
对于 SumatraPDF 的高级选项配置为:
1 2
| InverseSearchCmdLine = "<path-to-vscode>/Code.exe" "<path-to-vscode>/resources/app/out/cli.js" --ms-enable-electron-run-as-node -r -g "%f:%l" EnableTeXEnhancements = true
|
如果打开 SumatraPDF 的设置面板找不到Set inverse command-line这个项,
需要在高级选项中首先打开 Tex 增强选项:EnableTeXEnhancements = true,
Set inverse command-line在配置文件中实际上是 InverseSearchCmdLine = ... 这一项。
注意配置中的参数顺序,如果跳转中断在 cli.js 文件,可以尝试将 --ms-enable-electron-run-as-node 移动到 cli.js 之前。
如果 VS Code 始终无法打开 SumatraPDF,可以试着把 SumatraPDF.exe 的路径添加到环境变量 PATH。
测试发现,上面的这个配置仍然只能在受限的条件下正常工作,
如果在 VSCode 中通过源文件跳转的方式启动 SumatraPDF,很可能对于 PDF 文件无法进行跳转回到源文件,
这个问题可能和 SumatraPDF 的启动方式有关,通过 VSCode 启动时继承了 VSCode 的某些上下文,使得双向跳转失败。
最好的使用方式是:单独使用 vscode 打开 tex 文件(或者对应的文件夹),使用 SumatraPDF 打开 PDF 文件,然后在两者之间可以进行双向跳转。
VSCode 补充配置
除了最主要的编译部分和双向跳转,还有一些可能有用的,与 LaTeX 相关的辅助性配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| "[latex]": { "editor.defaultFormatter": "James-Yu.latex-workshop", "editor.wordWrap": "on", "editor.unicodeHighlight.allowedLocales": { "zh-hans": true, "zh-hant": true }, "editor.formatOnSave": false, }, "latex-workshop.showContextMenu": true, "latex-workshop.view.pdf.internal.synctex.keybinding": "double-click", "latex-workshop.latex.autoBuild.cleanAndRetry.enabled": false, "latex-workshop.latex.recipe.default": "lastUsed", "latex-workshop.message.error.show": false, "latex-workshop.message.warning.show": false, "latex-workshop.latex.build.rootfileInStatus": true, "latex-workshop.latex.build.clearLog.everyRecipeStep.enabled": false, "latex-workshop.bibtex-fields.order": [ "author", "title", "journal", "year" ], "latex-workshop.formatting.latex": "latexindent", "latex-workshop.latex.autoClean.run": "onFailed", "latex-workshop.bibtex-fields.sort.enabled": true, "latex-workshop.intellisense.citation.backend": "biblatex", "latex-workshop.bibtex-format.sort.enabled": true,
|
以及定义快捷键,这里只定义了 F5 编译
1 2 3 4 5 6 7
| { { "key": "f5", "command": "latex-workshop.build", "when": "editorLangId =~ /^latex$|^latex-expl3$|^doctex$|^rsweave$|^jlweave$|^pweave$/" } }
|
还有常用环境的 snippets
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| { "latex-table": { "prefix": "\\table", "body": [ "\\begin{table}[htbp]", " \\centering", " % \\caption{XXX} % \\label{tab:XXX}", " \\vspace{3mm}", " \\begin{tabular}{ccc}", " \\toprule", " \\$N\\$ & Error & Order \\\\\\", " \\midrule", " 10 & 3.99e-02 & - \\\\\\", " 20 & 6.12e-03 & 2.71 \\\\\\", " 40 & 5.45e-04 & 3.49 \\\\\\", " 80 & 2.57e-05 & 4.41 \\\\\\", " 160 & 1.03e-06 & 4.65 \\\\\\", " 320 & 3.23e-08 & 4.99 \\\\\\", " \\bottomrule", " \\end{tabular}", "\\end{table}" ] }, "latex-figure": { "prefix": "\\figure", "body": [ "\\begin{figure}[htbp]", " \\centering", " \\includegraphics[width=0.8\\textwidth]{$1}", " % \\caption{XXX} % \\label{fig:XXX}", "\\end{figure}" ] }, "latex-figures": { "prefix": "\\figures", "body": [ "\\begin{figure}[htbp]", " \\centering", " \\begin{subfigure}[c]{0.47\\textwidth}", " \\centering", " \\includegraphics[width=\\textwidth]{$1}", " \\end{subfigure}", " \\begin{subfigure}[c]{0.47\\textwidth}", " \\centering", " \\includegraphics[width=\\textwidth]{$2}", " \\end{subfigure}", " % \\caption{XXX} % \\label{fig:XXX}", "\\end{figure}", "" ] }, "beamer-columns": { "prefix": "\\columns", "body": [ "\\begin{columns}[T]", " \\begin{column}{0.4\\textwidth}", "", " \\end{column}", "", " \\begin{column}{0.6\\textwidth}", "", " \\end{column}", "\\end{columns}", "$0" ], } }
|
智能补全
对于 LaTeX 来说,智能补全还是非常有必要的,LaTeX workshop 插件在这方面提供了很多支持,可以查看对应的 官方文档。
首先,对于一些最常见的公式环境,可以使用BXY(或BSXY代表加星号版本,不区分大小写)的 prefix 来自动补全完整的环境,这里的XY取自公式环境名称的缩写,如下表:
| prefix |
name |
BEQ, BSEQ |
equation, equation* |
BAL, BSAL |
align, align* |
BGA, BSGA |
gather, gather* |
除了公式,常见的列表环境和浮动体环境也是支持的:
| prefix |
name |
BIT |
itemize |
BEN |
enumerate |
对于数学公式中的常用字体也有支持(可以选中需要改变字体的片段后再输入),如下表
| prefix |
command |
MRM |
\mathrm{${1}} |
MSF |
\mathsf{${1}} |
MBF |
\mathbf{${1}} |
MBB |
\mathbb{${1}} |
MCA |
\mathcal{${1}} |
MIT |
\mathit{${1}} |
MTT |
\mathtt{${1}} |
实际上插件还提供了一组快捷键对应上述命令,例如 ctrl+M,ctrl+B 对应 \mathbf{},完整列表可以在快捷键绑定中查看。
插件还对一些常见的数学元素进行了自动替换,例如
| prefix |
command |
__ |
_{$1} |
** |
^{$1} |
... |
\dots |
对于很多的数学符号,插件还提供了@X方式的快捷输入方式,其中X与数学符号的对应关系很有意思,例如
| prefix |
command |
@%,@/ |
\frac{}{} |
@2 |
\sqrt{} |
@6 |
\partial |
@8 |
\infty |
@( |
\left( \right) |
@[ |
\left[ \right] |
@{ |
\left\{ \right\} |
@| |
\left| \right| |
@a |
\alpha |
@b |
\beta |
@d |
\delta |
@D |
\Delta |
@ve |
\varepsilon |
@vf |
\varphi |
@vq |
\vartheta |
这些智能补全只会在编辑 LaTeX 文档时触发,对于其它文档的编辑不会造成干扰。
补充
.gitignore
当前 LaTeX 项目使用的。gitignore 如下
1 2 3 4 5 6
| .aux/
*.pdf *.synctex.gz *.synctex.gz.sum.synctex indent.log
|
含义为忽略.aux/文件夹、所有 PDF 文件以及相关的辅助文件。注意如果需要插入 PDF 格式的图片,还需要加上其它规则将其包含,例如
主文件查找
对于多文件项目,在非主文件中点击编译按钮,LaTeX Workshop 插件需要找到对应的主文件,这涉及到对主文件的查找策略(wiki of LaTeX-Workshop),
当打开新文档、更改活动编辑器或执行任何 LaTeX Workshop 命令时,LaTeX Workshop 会自动进行主文件查找。
主文件的查找规则:
- 使用魔法注释指定,例如
% !TEX root = ../main.tex,但是需要修改插件的对应选项,因为默认不会使用这些魔法注释;
- 如果当前文件包含
\documentclass[...]{...},就会被视作主文件;
- 遍历当前 VSCode 打开的文件夹中的所有
.tex 文件。第一个包含 \documentclass[...]{...} 且包含当前编辑器中的文件的 .tex 文件将被设置为根文件。
主文件必须位于 VSCode 打开的当前文件夹中。可以通过设置把查找主文件使用的指示器从 \documentclass[...]{...} 改成 \begin{document}。
因此,如果插件找错了主文件(例如当前文件实际被多个主文件共用,当然这种做法并不建议),最简单的做法就是打开一下正确的主文件。
其他方案
目前主流的 LaTeX 解决方案包括:
- local:
- VSCode + LaTeX Workshop
- TeXstudio
- remote:
下面提供一种比较折腾的方案,纯 Linux 风格,绕过 VSCode,适合基于 vim/nvim 在无图形界面的远程服务器使用,包括如下步骤:
- ssh 登陆远程服务器
- Tmux 开启如下创建
- vim/nvim 编辑文档
- latexmk 持续编译:
latexmk -xelatex -pvc -interaction=nonstopmode main.tex
- 在服务器上持续开启 http 服务器,监听本地 8000 端口:
python3 -m http.server 8000
- 在本地持续开启 ssh 端口转发:
ssh -N -L 8000:127.0.0.1:8000 user@server
- 在浏览器打开
http://127.0.0.1:8000,打开 PDF 文档(文档更新后还是需要手动刷新)