whexy1999

复杂 LaTeX 项目中几个插件的使用心得

Whexy /
May 06, 2021
5 min read

本文总结了一些在写论文期间遇到的较为复杂的 LaTeX 问题。其中包括 latexdiff 在多文件环境的使用技巧,以及如何解决 latexindent 的依赖冲突。

准备工作

由于 macOS 11 自带的 perl 环境缺少重要头文件 (macOS 12 已经完全移除 perl 环境了),很多 LaTeX 相关的依赖无法安装。在进行环境配置的时候,需要安装一个完整的 perl 环境。

brew install perl
brew link --overwrite perl

Revision 利器 latexdiff

在论文被打回重写的阶段,我们可以用 latexdiff 工具生成一个带批注版本的 PDF,方便讨好 reviewer。

Latexdiff 是一个 LaTeX 编译环境自带的二进制文件。通过 brew 安装的 LaTeX 已经将它加入了 PATH 环境变量。使用也是非常的简单:

latexdiff a.tex b.tex > difference.tex

多文件处理

论文通常不止一个文件。在多文件项目里使用 latexdiff 是一个比较麻烦的事情。latexdiff 自带的 --flatten 参数可以用于压平多文件,但如果项目用 BibTeX 管理引用,则会在压平后报错。

在这篇博客Multiple-file LaTeX diff 中,博主用 Python 写了一个压平多 LaTeX 文件的脚本 flatten.py

#!/usr/bin/python
import sys
import os
import re

inputPattern = re.compile('\\input{(.*)}')

def flattenLatex( rootFilename ):
    dirpath, filename = os.path.split(rootFilename)
    with open(rootFilename,'r') as fh:
        for line in fh:
            match = inputPattern.search( line )
            if match:
                newFile = match.group(1)
                if not newFile.endswith('tex'):
                    newFile += '.tex'
                flattenLatex( os.path.join(dirpath,newFile) )
            else:
                sys.stdout.write(line)

if __name__ == "__main__":
    flattenLatex( sys.argv[1] )

比如如下的文件目录:

$ tree | grep -e "\.tex"

├── main.tex
│   ├── abstract.tex
│   ├── appendix.tex
│   ├── background.tex
│   ├── conclusion.tex
│   ├── design.tex
│   ├── discuss.tex
│   ├── evaluation.tex
│   ├── implementation.tex
│   ├── introduction.tex
│   └── relatedwork.tex

只需要用flatten.py main.tex > flatten_main.tex就可以生成一个压平过的文件。最好检查一下以保证这个文件可编译通过。

忽略嵌套上下文

latexdiff 命令生成的代码通常无法直接通过编译。这是因为很多 LaTeX 环境不支持嵌套它声明的格式。例如section, subsection, subsubsection, table, cite等。需要在 latexdiff 中加入参数跳过它们。

我用的参数是:

latexdiff old.tex new.tex --disable-citation-markup --exclude-textcmd="section,subsection,subsubsection" --config="PICTUREENV=(?:picture|DIFnomarkup|table)[\w\d*@]*"

这套参数跳过 citation markup,忽略段落名称,并且不保留旧版本表格。经过测试,这是我论文库中可编译的最小参数集

自动化

使用 latexdiff 时最好保留所有版本的编译中间件。我展示一下我自用的 Makefile,自动生成比较结果 DIFF.pdf。

TARGETS = main

LATEX	= xelatex
BIBTEX	= bibtex

all:    $(TARGETS) debug

$(TARGETS):
	$(LATEX) $@
	-$(BIBTEX) $@ > $(BIBTEX)_out.log
	$(LATEX) $@
	$(LATEX) $@
	$(LATEX) $@

debug:
	-grep Dialoging *.log

diff:
	rm -rf ./_diff ./_env
	# Checkout Old version
	mkdir _diff
	git archive 5dc07a9 | tar x -C ./_diff
	# Checkout Current version
	mkdir _env
	git archive master | tar x -C ./_env
	# Flatten Old version
	cp ./_diff/main.tex ./_diff/main.tex.bak
	./utils/flatten.py ./_diff/main.tex.bak > ./_diff/main.tex
	cd ./_diff && make
	# Flatten Current version
	cp ./_env/main.tex ./_env/main.tex.bak
	./utils/flatten.py ./_env/main.tex.bak > ./_env/main.tex
	cd ./_env && make
	# LaTeX Diff
	latexdiff _diff/main.tex _env/main.tex --disable-citation-markup --exclude-textcmd="section,subsection,subsubsection" --config="PICTUREENV=(?:picture|DIFnomarkup|table)[\w\d*@]*" > _env/diff.tex
	cp _env/diff.tex _env/main.tex
	cd ./_env && make
	cp ./_env/main.pdf ./DIFF.pdf
	# Cleanup
	rm -rf ./_diff ./_env

clean:
	rm -f images/*.aux images/*.log *.aux *.bbl *.blg *.log *.dvi *.bak *~ $(TARGETS:%=%.pdf)
	rm -f diff*

源码格式化 Latexindent

LaTeX 源码总是杂乱的,其中充斥着各种注释、宏、表格、图片与代码。在多人协作时,会出现巨大的代码风格差异。Latexindent 是一个格式化 LaTeX 源码的工具。还你一篇干净整洁的源码。心情变好,工作效率也会增加。

利用 perl 包管理器 CPAN 安装 Latexindent 的依赖。

sudo cpan Log::Log4perl
sudo cpan Log::Dispatch
sudo cpan YAML::Tiny
sudo cpan File::HomeDir
sudo cpan Unicode::GCString

安装完毕后就可以正常使用 Latexindent 了。VSCode 的 LaTeX Workshop 插件直接调用 Latexindent,按下代码格式化快捷键即可使用。

© LICENSED UNDER CC BY-NC-SA 4.0