如何在编译时自动加载已安装的包?

如何在编译时自动加载已安装的包?

这更像是一个假设性问题。它不是要安装和加载已声明但未安装的缺失包,例如 MiKTeX 所做的那样。

假设有人正在编写报告或文章。在输入代码时,例如

\documentclass[a4paper,12pt,onecolumn]{scrartcl}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[english]{babel}

%\usepackage{lipsum} %<--- forgot to actually load resp. make clear the package is needed. Or was commented out in an earlier session.

\title{a nice title}
\author{John Doe}
\date{\today}


\begin{document}

\maketitle

\chapter{Why the sun is hot}
\section{About the sun}
\lipsum %<--- first call of macro, but it's unknown to the compiler so an error is thrown. the usual behaviour.

\chapter{Why it's a bad idea to touch the sun}
\section{The temperature of the sun}
\lipsum

\end{document}

在这种情况下,包lipsum被忘记告知。在这种情况下的常见行为:抛出错误。

这种行为导致作者修复问题并重新开始编译,所有这些都很耗时。

现在:如何才能让编译器在第一次解析关键字时(在我们的示例中:)方便地加载缺少的包,\lipsum并继续编译而不会引发错误并中断编译文档?

答案1

由于这个问题已经开放了一个月,我想我会尝试一下。从问题中的描述来看:

这种行为导致作者修复问题并重新开始编译,所有这些都很耗时。

我认为真正的问题是关于人类必须付出的代价手动修复并重新编译。(“编译”仅指用户可见的行为,即调用某个程序 — 例如latexmkarara— 而不一定是 pdfTeX(或任何)程序本身。)根据这种解释,原则上绝对可以为用户节省一些时间。

(当然,只要你愿意改变 *TeX 程序本身,一切皆有可能,但无论好坏,在 TeX 世界中这样的事并不多。)

这个答案的底部是一个概念验证 Python 脚本。假设你把它放入一个名为的文件中invoke.py。然后pdflatex bad.tex你可以执行python3 invoke.py bad.tex,你会在终端中看到以下输出:

The control sequence \lipsum was undefined
Adding package lipsum to the file.
Great, nothing was undefined this time. This was the output:
This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./bad.tex
LaTeX2e <2017-04-15>
Babel <3.10> and hyphenation patterns for 84 language(s) loaded.
(/usr/local/texlive/2017/texmf-dist/tex/latex/base/article.cls
Document Class: article 2014/09/29 v1.4h Standard LaTeX document class
(/usr/local/texlive/2017/texmf-dist/tex/latex/base/size10.clo)) (/usr/local/texlive/2017/texmf-dist/tex/latex/lipsum/lipsum.sty) (./bad.aux) [1{/usr/local/texlive/2017/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] [2] [3] (./bad.aux) )</usr/local/texlive/2017/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx12.pfb></usr/local/texlive/2017/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb>
Output written on bad.pdf (3 pages, 36350 bytes).
Transcript written on bad.log.

前三行来自 Python 脚本。运行此脚本后,文件bad.tex将更改为包含\usepackage{lipsum}其中的行。由于整个过程需要 0.47 秒(而且现在 TeX 总体来说非常快),我认为它真正解决了问题(允许用户避免手动将包添加到文件的耗时步骤),即使在幕后,TeX 程序已被调用多次。(实际上,即使 TeX 需要很长时间,事实是程​​序可以比人类更快地添加缺失的包,而人类无论如何都必须重新运行该程序,所以它总是更快。)

这是 Python 脚本invoke.py

import subprocess
import sys

giant_map_of_macros_to_packages = {
    'lipsum': 'lipsum',
    # ...
}

def add_package(package, filename):
    """Inserts a usepackage line into the file."""
    with open(filename) as f:
        contents = f.read()
    where = contents.find('\\begin{document}')
    with open(filename, 'w') as f:
        f.write(contents[:where])
        f.write('\\usepackage{%s}\n' % package)
        f.write(contents[where:])

if __name__ == '__main__':
    filename = sys.argv[1]
    run_again = True
    while run_again:
        run_again = False
        completed = subprocess.run(['pdflatex', '-halt-on-error', filename],
                                   stdout=subprocess.PIPE)
        lines = completed.stdout.decode('utf-8').splitlines()
        try:
            where = lines.index('! Undefined control sequence.')
            line = lines[where + 1]
            undefined = line[line.rfind('\\') + 1:]
            print('The control sequence \\%s was undefined' % undefined)
            package = giant_map_of_macros_to_packages[undefined]
            print('Adding package %s to the file' % package)
            add_package(package, filename)
            run_again = True
        except ValueError:
            print('Great, nothing was undefined this time. This was the output:')
            print('\n'.join(lines))
        except KeyError:
            print('Not sure what package defines %s. Add it to giant_map_of_macros_to_packages' % undefined)

明显地:

  • 这只是一个概念证明(表明它是可能的);正确的位置可能是标准 LaTeX 构建工具之一,例如latexmkarara
  • [在我看来,更好的办法是将这样的功能添加到 TeX 程序本身中,但这永远不会发生。]
  • \begin{document}这假设了一些事情(通常是正确的),例如文件中存在一行,在该行之前可以安全地插入\usepackage{...}一行,未定义的宏是消息\\后面行的最后一行之后的所有内容! Undefined control sequence.,等等。
  • 有人必须维护giant_map_of_macros_to_packages— 尽管原则上这也是 TeX 内部可自动化的。(例如使用 LuaTeX:对于每个包,比较加载包之前和之后的宏哈希表。)当多个包定义相同的宏时,优雅地处理这种情况也是很好的。

相关内容