使用 Neovim 和 vimtex 高效撰写 LaTeX 学术论文
Matrix 是少数派的写作社区,我们主张分享真实的产品体验,有实用价值的经验与思考。我们会不定期挑选 Matrix 最优质的文章,展示来自用户的最真实的体验和观点。
文章代表作者个人观点,少数派仅对标题和排版略作修改。
LaTeX,作为学术界 de facto 的排版利器,其编辑器可谓是百花齐放。VS Code、TeXstudio、Texmaker,甚至在线的 Overleaf,虽然都可以拿来撰写 LaTeX 文档,但是它们的界面都相对臃肿,编译和预览速度上也不是「业内最快」。经历了近一个月的英文学术论文撰写,我发现直接使用被誉为「编辑器之神」的 Vim(实际上我使用的是 Neovim)来撰写 LaTeX,就我而言最为合适。使用 Neovim 编写 LaTeX 文献,不仅编译飞快、预览方便,还有着几乎无限的可定制性,唯一的缺点,可能就是 Vim 自己相对陡峭的学习曲线。
在这篇文章里,我将不重点叙述 Vim 本身的使用方法,而是主要介绍使用 Vim 配合 LaTeX 发行版 TeX Live 和专为 Vim 设计的 LaTeX 插件 vimtex 来撰写 LaTeX 文献的配置技巧和方法。这一套技巧需要对 Vim 及其操作有着一定的了解,因此建议已经在使用 Vim 编辑文档或项目的同学,或者了解 Vim 的基础用法、希望使用 Vim 撰写 LaTeX 的同学参考本文。
在正文开始之前,我先来简要的介绍一下 Vim 以及 LaTeX 的基础知识。
Vim 是一个在命令行环境下最能发光发热的纯文本编辑器,因此不论是 Linux、macOS 还是 Windows,只要我们安装了 Vim,那么我们只需要打开终端、使用命令 vim
,即可进入 Vim 编辑器。Neovim 是一个 Vim 的社区分支版本,比原版 Vim 有一些新增功能和喜人特性,我个人更喜欢使用 Neovim。
Vim 是一个命令行环境下的编辑器,因此 Vim 自己并没有我们熟悉的 GUI 图形界面。如果在 Linux 和 macOS 下,那么使用各自系统的终端即可调用 Vim。如果在 Windows 上,我们则需要使用更为现代的终端,比如 Windows Terminal,或者使用专为 Neovim 开发的 GUI 前端程序(也就是我们所称呼的 Neovim 前端),比如 neovim-qt、FVim 等,才能提升使用 Vim 编辑的体验。在参考本文前,我们应该至少拥有一个完整的 Neovim 环境,包括 Neovim 本身以及 Neovim 前端。作为参考,我使用的是 Ubuntu 20.04.1 LTS、Neovim v0.5.0-dev 以及 kitty 终端。
LaTeX 是一个专业的排版引擎,其中包含有众多的宏包(撰写 LaTeX 文档时使用的依赖库)与编译器(比如输出 PDF 的 pdflatex
、能够处理 UTF-8 与东亚字符的 xelatex
、支持增量编译的 latexmk
等)。在参考本文前,我们需要在本机上安装 TeX Live 发行版才能完整拥有 LaTeX 环境,并用来编译、撰写 LaTeX 文档。我们将主要使用 latexmk
来编译 LaTeX 文档,latexmk
能够按需调用其他编译引擎,来根据文档内容(比如文档是否包含中文、文档中是否需要编译参考文档等)动态调整编译指令和编译内容。
很多集成度很高的编辑器(比如 TeXstudio)将编译 LaTeX 文档的整个过程隐藏在复杂的界面背后,实际上不易于我们理解 LaTeX 的完整编译闭环。因此,当我们在使用 Neovim 或者其他编辑器来撰写 LaTeX 文档时,我们实际上是做这样的一件事情:
.tex
文件的文本内容,也就是 LaTeX 文档本身;latexmk
发现我们的 .tex
文件内容发生了变化,于是开始编译新增内容:latexmk
会根据我们的 .tex
文件具体更改内容动态的调整编译命令和编译次数;biber
编译,或是增加了新的图表以及相应的引用,则需要两次至四次的调用 pdflatex
编译文档…….pdf
文件来给我们预览,我们使用合适的 PDF 阅读器打开即可;整个编译过程就如图示所示,我们不论是使用 Neovim,还是使用其他集成度高的编辑器,背后实际上执行的都是这样的一套完整的流程。熟悉了整个 LaTeX 编译过程,我们接下来正式开始配置 Neovim 的 LaTeX 撰写环境。
Neovim 和 Vim 一样,都是极为可拓展的纯文本编辑器,有着社区无数的插件支持,我们将使用专业、极简的插件管理器 —— vim-plug 来管理安装 Neovim 的插件。专为 LaTeX 编写设计的 vimtex 插件是 Neovim 撰写 LaTeX 的绝佳搭档,我们将使用 vimtex 来辅助我们在 Neovim 中撰写 LaTeX 项目。默认安装情况下,在 Linux 与 macOS 中的 Neovim 配置文件位于 ~/.config/nvim/init.vim
,在 Windows 中位于 %LOCALAPPDATA%\\nvim\\init.vim
,我们后续的配置操作都将会直接更改这一配置文件。
首先我们安装插件管理器 vim-plug,对于 Neovim,在 Linux 或 macOS 中执行:
sh -c 'curl -fLo "${XDG_DATA_HOME:-$HOME/.local/share}"/nvim/site/autoload/plug.vim --create-dirs \
<https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim>'
或在 Windows 中执行:
iwr -useb <https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim> |`
ni "$(@($env:XDG_DATA_HOME, $env:LOCALAPPDATA)[$null -eq $env:XDG_DATA_HOME])/nvim-data/site/autoload/plug.vim" -Force
之后,我们需要在配置文件 init.vim
中添加 vim-plug 的插件定义部分:
call plug#begin()
Plug 'xxx' # 这里即是安装某个插件的定义位置
Plug '...' # 可以继续定义其他需要安装的插件
# ……
call plug#end()
接下来,我们在定义安装插件的位置添加安装 vimtex 的定义字段。在 init.vim
中 vim-plug 插件定义部分添加:
Plug 'lervag/vimtex
之后,退出并重新进入 Neovim,执行命令 :PlugInstall
,即可安装 vimtex 插件。
在开始使用 vimtex 前,我们还需要配置一些设置项目。下面的全部配置内容都是需要写入配置文件 init.vim
的。首先,我们需要设置撰写的 TeX 文档是 LaTeX 语法风格的文档:
let g:tex_flavor = 'latex'
接下来,我们将编译报错自动弹出错误窗口(quickfix window)设置为 0(即不自动弹出)。我们可以使用命令 :copen
来手动打开错误窗口:
let g:vimtex_quickfix_mode = 0
为了能够让 vimtex 自动在编译完成后启动 PDF 阅读器,我们需要指定所使用的 PDF 阅读器,不同操作系统使用的 PDF 阅读器也不尽相同,因此这里我会提供 Linux、Windows 以及 macOS 三种不同的 PDF 阅读器推荐配置,同学们按照自己的需要选择一种配置即可。
Windows 与 macOS 的配置项目参考自:A Complete Guide on Writing LaTeX with Vimtex in Neovim。
在 Linux 下我个人偏好使用 Zathura 阅读器,我们这样定义即可:
let g:vimtex_view_general_viewer = 'zathura'
let g:vimtex_view_method = 'zathura'
# 这一项目默认即为 nvr,但是如果由于种种原因无法实现 SyncTeX 同步位置,可以考虑手动指定这一项目
let g:vimtex_compiler_progname = 'nvr'
此外我们还需要:
nvr
):pip3 install neovim-remote
~/.config/zathura/zathurarc
中加入下面内容:# ~/.config/zathura/zathurarc
set synctex true
set synctex-editor-command "nvr --remote-silent %f -c %l"
在 Windows 上我们可以安装使用 SumatraPDF,并在 init.vim
为 vimtex 配置如下内容:
let g:vimtex_view_general_viewer = 'SumatraPDF'
let g:vimtex_view_general_options
\ = '-reuse-instance -forward-search @tex @line @pdf'
let g:vimtex_view_general_options_latexmk = '-reuse-instance'
在 macOS 上我们可以安装使用 Skim,并在 init.vim
为 vimtex 配置如下内容:
let g:vimtex_view_general_viewer
\ = '/Applications/Skim.app/Contents/SharedSupport/displayline'
let g:vimtex_view_general_options = '-r @line @pdf @tex'
" This adds a callback hook that updates Skim after compilation
let g:vimtex_compiler_callback_hooks = ['UpdateSkim']
function! UpdateSkim(status)
if !a:status | return | endif
let l:out = b:vimtex.out()
let l:tex = expand('%:p')
let l:cmd = [g:vimtex_view_general_viewer, '-r']
if !empty(system('pgrep Skim'))
call extend(l:cmd, ['-g'])
endif
if has('nvim')
call jobstart(l:cmd + [line('.'), l:out, l:tex])
elseif has('job')
call job_start(l:cmd + [line('.'), l:out, l:tex])
else
call system(join(l:cmd + [line('.'), shellescape(l:out), shellescape(l:tex)], ' '))
endif
endfunction
这样配置后,我们就可以通过 vimtex 默认的 \lv
快捷键(在按住 \
的时候,连续点击 l
和 v
)来正向同步当前 Neovim 光标位置到 PDF 预览位置,也可以通过「Ctrl
+ 点击 PDF 预览相应位置」来反向同步 Neovim 光标位置了。
调用 vimtex 的编译预览以及其他相关命令,往往都会通过 vimtex 默认快捷键来进行操作。前面在配置同步 PDF 的时候,我们已经使用了一个常用的 vimtex 快捷键 \lv
,实际上包括编译与自动唤起 PDF 阅读器、同步光标、停止编译以及清理中间无用文件的快捷键都是类似的操作:按住 \
键,并连续点击后续快捷键。下面是 vimtex 常见的默认快捷键:
\ll
:使用默认编译器(latexmk)开始监听 .tex
文件的变化,编译 LaTeX 项目并打开 PDF 预览界面;\lk
或第二次 \ll
:停止编译器监听文件变动,停止编译;\lv
:正向从 Neovim 光标位置同步 PDF 显示区域;\lc
:清理编译生成的中间文件;其中,需要注意的一点是,前面提到的 \
键实际上是我们 Neovim 中设定的 local leader 键,如果没有特殊设置的话那么默认就是 \
键,但是如果有同学修改了这一键,那么需要按照自己的定义调整快捷键。
此外, vimtex 还包含有:
[[
、]]
、][
、[]
;dse
(Delete surrounding environment);cse
(Change surrounding environment);*
和无 *
的环境标签(比如将 equation*
更换为 equation
、将 figure*
更换为 figure
等)tse
(Toggle starred environment):等等一系列快捷键,用来提升我们的 LaTeX 项目编辑效率。上面是我自己常用的快捷键和快捷指令,更多快捷键请参考:Features - lervag/vimtex。
vimtex 还有自动生成的 TOC 文章目录窗口,非常方便。我个人喜欢将 TOC 放置于左侧窗口,并移除一些非必要的信息板块,同时设定 TOC 窗口默认的宽度。我的 TOC 窗口配置如下:
let g:vimtex_toc_config = {
\ 'name' : 'TOC',
\ 'layers' : ['content', 'todo', 'include'],
\ 'split_width' : 25,
\ 'todo_sorted' : 0,
\ 'show_help' : 1,
\ 'show_numbers' : 1,
\}
这样,我们使用命令 :VimtexTocToggle
即可唤出 vimtex 自动生成的 TOC:
虽然 vimtex 很优秀,但是许多比如自动补全、LaTeX 代码错误提示以及自定义 LaTeX 代码段等功能,还需要依赖其他插件的配合。coc.nvim 全称为 Conquer of Completion,是我在 Neovim 中偏好的自动补全引擎。由于 coc.nvim 支持了 VS Code 的 LSP 协议(Language Server Protocol),因此 coc.nvim 实际上能够做到类似 VS Code 级别的自动补全功能,这也是我使用 coc.nvim 的主要原因。
我们可以使用 vim-plug 来安装 coc.nvim,在 init.vim
的 vim-plug 部分加入如下内容,重新加载 init.vim
并执行 :PlugInstall
即可安装 coc.nvim。
Plug 'neoclide/coc.nvim', {'branch': 'release'}
此外,为了更好的配置 coc.nvim,我们还需要再额外添加一些 coc.nvim 的配置。coc.nvim 的 GitHub 主页给出了一个可以直接拿来使用的配置样例:Example vim configuration - coc.nvim,我们可以直接粘贴这部分代码进入 init.vim
之中。
最后,我们需要安装专为 vimtex 设计的 coc.nvim 插件:coc-vimtex,在 Neovim 中执行 :CocInstall coc-vimtex
即可。这样,我们在撰写 LaTeX 文档时,就可以拥有如 VS Code 一样强大的自动补全功能了。
UltiSnips 是 Neovim 的 snippet 插件,也就是我们所说的「自定义代码段」。借助 snippet,我们可以快速输入预设代码段,包括常见的 LaTeX 代码。
我们可以使用 vim-plug 来安装 UltiSnips,在 init.vim
的 vim-plug 部分加入如下内容,重新加载 init.vim
并执行 :PlugInstall
即可安装 UltiSnips 以及配套的 snippet 库 vim-snippets,前者提供输入 snippet 的必要框架,后者提供多种语言的 snippet 预设代码块。
Plug 'SirVer/ultisnips'
Plug 'honza/vim-snippets
默认情况下我们在 insert 模式下可以使用 Tab
来自动扩展 snippet,常见的 LaTeX 代码块比如:
Tab
来自动扩展;Tab
来自动扩展;Tab
来自动扩展;相信很多使用 LaTeX 的同学都可能读过一篇叫做《How I'm able to take notes in mathematics lectures using LaTeX and Vim》的文章,在这篇文章中,作者详细的介绍了自己是如何通过熟练的 Vim 技巧,加上合适的 snippet 以及自动补全,来使用 LaTeX 和讲座进度几乎同步的记录总结,最终得到格式严格、排版整洁,却无需任何课后额外时间整理的完美笔记。
我就是因为这样的一篇文章,才意识到使用 Vim 来撰写 LaTeX 是能够如此的提升我的文献撰写效率。虽然本文的配置远远没有那位作者的复杂,但是我相信我的配置方案能够帮助许多同学在初次配置自己撰写 LaTeX 项目的 Vim 或 Neovim 时少走很多弯路。感谢阅读。
> 下载少数派 客户端 、关注 少数派公众号 ,了解更妙的数字生活 🍃
> 想申请成为少数派作者?冲!
© 本文著作权归作者所有,并授权少数派独家使用,未经少数派许可,不得转载使用。