今天早上更新 LaTeX 2020-10-01 PL3 后,我的测试套件因神秘错误而失败。
该错误可以追溯到以下形式的不太最小的 WE
\documentclass{scrartcl}
\usepackage[listings]{tcolorbox}
\lstset{escapeinside = {(*@}{@*)},}
\newtcblisting{mylisting}{listing only}
\begin{document}
\begin{mylisting}
(*@1@*)
\end{mylisting}
\begin{mylisting}
(*@2@*)
\end{mylisting}
\begin{mylisting}
(*@3@*)
\end{mylisting}
\begin{mylisting}
(*@4@*)
\end{mylisting}
\begin{mylisting}
(*@5@*)
\end{mylisting}
\begin{mylisting}
(*@6@*)
\end{mylisting}
\begin{mylisting}
(*@7@*)
\end{mylisting}
\end{document}
失败了
Package scrlfile-hook Warning: More file names popped from stack than put to.
(scrlfile-hook) This should never happen. However, it could
(scrlfile-hook) happen if scrlfile-hook is loaded by another
(scrlfile-hook) package or class. In this case some packages or
(scrlfile-hook) classes are not recognised correctly.
(./scrlfile-escaped-listings-tcolorbox.listing)
\openout4 = `scrlfile-escaped-listings-tcolorbox.listing'.
(./scrlfile-escaped-listings-tcolorbox.listing)
! LaTeX3 Error: Message 'to-much-pops' for module 'scrlfile-hook' already
(LaTeX3) defined.
For immediate help type H <return>.
...
l.39 \end{mylisting}
?
Package scrlfile-hook Warning: More file names popped from stack than put to.
(scrlfile-hook) This should never happen. However, it could
(scrlfile-hook) happen if scrlfile-hook is loaded by another
(scrlfile-hook) package or class. In this case some packages or
(scrlfile-hook) classes are not recognised correctly.
起初我以为这是 KOMA-Script 的问题,所以我在https://komascript.de/node/2362但事实证明,尽管该问题只是由于 KOMA-Script 中的一个小疏忽(目前已经修复)而变得明显;但问题的核心却更深。
以下 MWE 显示file/after
在某些情况下钩子代码可能会被执行多次。由于 KOMA-Script 的filehook
模块用于file/after
弹出文件名堆栈,因此钩子可能会一次弹出多个文件,从而导致警告并最终导致上述错误。
\documentclass{article}
\usepackage{listings}
\lstset{escapeinside = {(*@}{@*)},}
\usepackage{etoolbox}
\AddToHook{file/before}{\AfterPreamble{A [\CurrentFile]}}
\AddToHook{file/after}{\AfterPreamble{Z}}
\begin{filecontents*}{\jobname-normal.tex}
Lorem
\end{filecontents*}
\begin{filecontents*}{\jobname-escaped.tex}
(*@ipsum@*)
\end{filecontents*}
\begin{document}
\lstinputlisting{\jobname-normal.tex}
\lstinputlisting{\jobname-escaped.tex}
\lstinputlisting{\jobname-normal.tex}
\lstinputlisting{\jobname-escaped.tex}
\end{document}
代码运行时没有错误,但在输出中我们可以看到file/after
对于包含序列的列表,代码执行了两次escapeinside
。
不幸的是,钩子运行两次的情况似乎很难确定。
相关软件包版本为
LaTeX2e <2020-10-01> patch level 3
L3 programming layer <2020-12-07> xparse <2020-03-03>
listings 2020/03/24 1.8d
所有示例均可在我的 MikTeX 系统(运行 LaTeX 2020-10-01 PL2)上正常运行。
为什么文件钩子在这里执行了两次?我怎样才能阻止它这样做?
答案1
当使用 输入文件时\InputIfFileExists
(基本上是 LaTeX 中到处使用的,除了一些特殊情况,如普通语法\input <file>
),它会设置\CurrentFile
,使用钩子file/before
和file/before/\CurrentFile
,然后读入文件,然后使用file/after/\CurrentFile
和file/after
。
问题在于,如果在读取文件时宏\CurrentFile
发生了更改,无论出于何种原因,file/after/\CurrentFile
执行的钩子都会出错。就你的情况而言,正如 Ulrike 发现的那样,一个组从文件外部开始,在文件内部结束,因此本地分配丢失,并被\CurrentFile
重置为空,因此使用的钩子是file/after/
。除此之外,清理宏的设计不当会丢弃最后的/
,因此使用的钩子是file/after
,然后file/after
再次。
以前的版本已经考虑到了这一点(完成\CurrentFile
后一直恢复),但是引入了一个错误\@@input
这次提交(PL3 的一部分)延迟恢复\CurrentFile
到钩子执行之后,这有点毫无意义。
我修复了这个问题此请求请求,PL4 的一部分。如果您正在阅读本文并遇到此问题,请更新您的 LaTeX。