使用 listings 和 LaTeX 2020-10-01 PL3 执行两次 file/after 钩子

使用 listings 和 LaTeX 2020-10-01 PL3 执行两次 file/after 钩子

今天早上更新 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

LoremZ//ipsumZZ

不幸的是,钩子运行两次的情况似乎很难确定。

相关软件包版本为

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/beforefile/before/\CurrentFile,然后读入文件,然后使用file/after/\CurrentFilefile/after

问题在于,如果在读取文件时宏\CurrentFile发生了更改,无论出于何种原因,file/after/\CurrentFile执行的钩子都会出错。就你的情况而言,正如 Ulrike 发现的那样,一个组从文件外部开始,在文件内部结束,因此本地分配丢失,并被\CurrentFile重置为空,因此使用的钩子是file/after/。除此之外,清理宏的设计不当会丢弃最后的/,因此使用的钩子是file/after,然后file/after再次。

以前的版本已经考虑到了这一点(完成\CurrentFile后一直恢复),但是引入了一个错误\@@input这次提交(PL3 的一部分)延迟恢复\CurrentFile到钩子执行之后,这有点毫无意义。

我修复了这个问题此请求请求,PL4 的一部分。如果您正在阅读本文并遇到此问题,请更新您的 LaTeX。

相关内容