基础概念
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
| "[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.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.sort.enabled": true, "latex-workshop.bibtex-fields.order": [ "author", "title", "journal", "year" ], "latex-workshop.formatting.latex": "latexindent",
|
以及一些自定义快捷键
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
| { { "key": "f5", "command": "latex-workshop.build", "when": "editorLangId =~ /^latex$|^latex-expl3$|^doctex$|^rsweave$|^jlweave$|^pweave$/" }, { "key": "alt+a", "command": "latex-workshop.select-env", "when": "editorTextFocus && !editorReadonly && editorLangId =~ /^latex$|^context$|^latex-expl3$|^doctex$|^rsweave$|^jlweave$|^pweave$/" }, { "key": "alt+n", "command": "latex-workshop.select-envname", "when": "editorTextFocus && !editorReadonly && editorLangId =~ /^latex$|^context$|^latex-expl3$|^doctex$|^rsweave$|^jlweave$|^pweave$/" }, { "key": "alt+i", "command": "latex-workshop.select-envcontent", "when": "editorTextFocus && !editorReadonly && editorLangId =~ /^latex$|^context$|^latex-expl3$|^doctex$|^rsweave$|^jlweave$|^pweave$/" }, { "key": "alt+w", "command": "-toggleSearchWholeWord", "when": "searchViewletFocus" }, { "key": "alt+w", "command": "-toggleFindWholeWord", "when": "editorFocus" }, { "key": "alt+s", "command": "latex-workshop.surround", "when": "editorHasSelection && editorTextFocus && !editorReadonly && editorLangId =~ /^latex$|^context$|^latex-expl3$|^doctex$|^rsweave$|^jlweave$|^pweave$/" }, { "key": "alt+e", "command": "latex-workshop.toggle-equation-envname", "when": "editorTextFocus && !editorReadonly && editorLangId =~ /^latex$|^context$|^latex-expl3$|^doctex$|^rsweave$|^jlweave$|^pweave$/" }, { "key": "alt+v", "command": "latex-workshop.view", "when": "editorTextFocus && !editorReadonly && editorLangId =~ /^latex$|^latex-class$|^latex-package$|^context$|^latex-expl3$|^doctex$|^rsweave$|^jlweave$|^pweave$/" }, { "key": "alt+q", "command": "workbench.action.toggleSidebarVisibility" }, { "key": "alt+w", "command": "workbench.action.toggleAuxiliaryBar" } }
|
智能补全
对于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 文档(文档更新后还是需要手动刷新)