是否可以从盒子中移除(或以其他方式使之无效)某个 whatsit 节点?

是否可以从盒子中移除(或以其他方式使之无效)某个 whatsit 节点?

我知道一般来说不可能修改盒子里的内容(根据https://tex.stackexchange.com/a/49903/17427),尽管我相信有时可以“拆箱”材料并对其进行破解(但我对此并不熟悉)。

不过,我目前的兴趣在于\write从框中删除(或禁用)节点,这不会影响它的外观等。这样做的动机主要是我的“答案”在这里关于将幻灯片的缩小副本放入注释页中的方式beamer以及由此导致的多重定义标签。为了 MWE 的目的,假设我正在创建一个包含 的框\label,但我想显示该框两次,一次显示\label生效,一次不显示,并且我想防止出现多重标签问题,而不会破坏标签机制的其他功能,也不会收集框中的原始代码并对其进行两次处理。

我确信使用 LuaTeX 可以实现这一点,并且我对使用和不使用 LuaTeX 的解决方案都很感兴趣(因此我没有将其标记为 {luatex})。

与 MWE 一起玩:

\documentclass{article}
\tracingonline2
\showboxdepth\maxdimen
\showboxbreadth\maxdimen

\newbox\boxa
\newbox\boxb

\newcommand{\showtwo}[2]{\showtokens{^^J^^J#1, #2^^J^^J}}
\begin{document}
\section{Hello}

{
\setbox\boxa\hbox{abc\label{hi}def}
\showbox\boxa
\setbox\boxb=\copy\boxa
\box\boxa

\let\write\showtwo
% edit \boxb somehow
\showbox\boxb
\box\boxb

}

\end{document}

我目前尝试采用的方法不是从框中删除节点(因为我不知道从哪里开始),而是在节点\write进入框之前通过添加一个额外的间接层\latelua,然后理论上我应该能够在不编辑框的情况下更改间接层的行为。这可能不是一个好主意(想法?),但它表明我已经做出了一些努力!但是,根据手册,“从回调内部使用的结果未定义tex.print”,我不确定是否\latelua被视为回调。无论如何,我设法从 中执行的唯一操作(\latelua而不会让我的命令被默默忽略)是tex.errortex.sprint([[\noexpand\undefinedcs]]),当然没有像 这样的操作tex.sprint([[\unexpanded{\immediate\write\@auxout{...}}]])

Lua 间接尝试(但请注意,在我禁用写入之前,我的标签不会写入文件aux):

\documentclass{article}
\tracingonline2
\showboxdepth\maxdimen
\showboxbreadth\maxdimen

\newbox\boxa
\newbox\boxb

\directlua{tex.enableprimitives('',tex.extraprimitives())}
\setcounter{errorcontextlines}{\maxdimen}

\usepackage{etoolbox}
\makeatletter
\patchcmd{\label}{\protected@write}{\protected@labelwrite}{}{\showtokens{patching \label failed}}
\let\protected@labelwrite\protected@write
\patchcmd{\protected@labelwrite}{\write#1}{\latelabelwritehelper{#1}}{}{\showtokens{patching \protected@labelwrite failed}}

\newcommand*{\latelabelwritehelper}[2]{%
    \latelua{tex.sprint([[\noexpand\latelabelwrite{#1}{#2}]])}}
\newcommand*{\latelabelwrite}[2]{\immediate\write#1{#2}}
\newcommand*{\disablelatelabelwrite}{\let\latelabelwrite\@gobbletwo}
\makeatother

\begin{document}

\section{Hello}

\setbox\boxa\hbox{abc\label{hi}def}
\showbox\boxa
\setbox\boxb=\copy\boxa
\box\boxa

\disablelatelabelwrite
\showbox\boxb
\box\boxb

\end{document}

(还请注意,这是我第一次真正尝试用 Lua 做某事!)

答案1

如果您只是想摆脱写入的 whatsits,则输出带有\leaders忽略写入 whatsits 的框。

所以,\setbox\boxb=\hbox{\leaders\copy\boxa\hskip\wd\boxa}这可能是一个解决方案。

答案2

在经典 TeX 中,您无法删除 whatsit 节点,但是如果您可以控制宏层并可以控制原始框的构造,则可以安排 whatsit 永远不会出现在顶级列表中,并且始终受到可以删除的框的保护。这是 LaTeX3 xgalley 代码需要完全控制所有垂直命令的主要原因之一,以便它可以在之后调整垂直列表。

在这种情况下你可以

\documentclass{article}
\tracingonline2
\showboxdepth\maxdimen
\showboxbreadth\maxdimen

\let\oldlabel\label
\def\label#1{\hbox{\oldlabel{#1}}}
\newbox\boxa
\newbox\boxb

\newcommand{\showtwo}[2]{\showtokens{^^J^^J#1, #2^^J^^J}}
\begin{document}
\section{Hello}

{
\setbox\boxa\hbox{abc\label{hi}}
\showbox\boxa
\setbox\boxb=\copy\boxa
\box\boxa

\let\write\showtwo
% edit \boxb somehow
\setbox\boxb\hbox{\unhbox\boxb\setbox0\lastbox}
\showbox\boxb
\box\boxb

}

\end{document}

制作

> \box26=
\hbox(6.94444+0.0)x15.27782
.\OT1/cmr/m/n/10 a
.\OT1/cmr/m/n/10 b
.\kern0.27779
.\OT1/cmr/m/n/10 c
.\hbox(0.0+0.0)x0.0
..\write1{\newlabel{hi}{{1}{\thepage }}}

! OK.
l.17 \showbox\boxa

? 
> \box27=
\hbox(6.94444+0.0)x15.27782
.\OT1/cmr/m/n/10 a
.\OT1/cmr/m/n/10 b
.\kern0.27779
.\OT1/cmr/m/n/10 c

! OK.
l.24 \showbox\boxb

相关内容