枚举中缺少项目编号

枚举中缺少项目编号

你可能会认为我不会惹恼egreg 解决方案,但为了辩护,我使用了 DavidCarlisle 的解决方案\setbox 与 \sbox 和 \savebox - 我需要了解哪些区别?使 egreg 的解决方案适应检测空文本的正确方法到目前为止,这对我来说一直很好,但是当我尝试在enumerate环境中使用它时,它会导致它吞噬产品编号:

在此处输入图片描述

请注意,如果没有可用的标题(第三项),则不会吞噬项目编号。

如果我\sbox0{\begingroup\vbox{#1}\endgroup}按照原始解决方案替换:

\sbox0{#1}

这个特定的 MWE 起作用,但在其他地方引起了问题(此处未显示)。

问题:

那么,我可以对现有解决方案做出哪些最小改变,\sbox0以使产品编号不被吞噬?

我正在禁用其中的某些宏\begingroup以消除任何副作用,因此需要分组。

代码:

\documentclass{article}
\usepackage{enumitem}

\makeatletter
\newcommand{\DoIfNonEmptyText}[1]{% Actually takes two parameters
    %\sbox0{#1}%
    \sbox0{\begingroup\vbox{#1}\endgroup}%
    \ifdim\wd0=\z@\relax% 
        \expandafter\@gobble%
    \else%
        \expandafter\@firstofone%
    \fi%
}%
\makeatother

\newcommand{\QuotableText}[3][]{%
    % [#1] = optional title
    % #2   = name for this (not relevant for this example)
    % #3   = the content
    \DoIfNonEmptyText{#1}{\textit{#1}:~}%
    #3%
}%


\begin{document}
\begin{enumerate}
    \item First Item
    \item \QuotableText[Sub title]{Text One}{Second Item}
    \item \QuotableText{Text Two}{Third Item}
    \item Fourth Item
\end{enumerate}
\end{document}

更新:

根据 Frank Mittelbach 的回答,我尝试使用我自己的\savebox,但它仍然显示与上面相同的输出:

\makeatletter
\newsavebox{\@DoIfNonEmptyTextBox}%
\newcommand{\DoIfNonEmptyText}[1]{% Actually takes two parameters
    \begingroup
    \savebox{\@DoIfNonEmptyTextBox}{\vbox{#1}}% -- This still gobbles the item number!
    %\savebox{\@DoIfNonEmptyTextBox}{#1}%        -- This works
    \ifdim\wd\@DoIfNonEmptyTextBox=\z@\relax% 
        \endgroup\expandafter\@gobble%
    \else%
        \endgroup\expandafter\@firstofone%
    \fi%
}%
\makeatother

但如果我删除\vbox{},那么它就可以正常工作。那么,如何使用\vbox(注意:这里不使用\sbox0)导致枚举项消失?

答案1

当项目标签消失时,一个好的经验法则是添加\leavevmode;但在这种情况下(感谢 Frank 指出这一点)设置\everypar为空应该可以解决问题。

\makeatletter
\newcommand{\DoIfNonEmptyText}[1]{% Actually takes two parameters
  \begingroup\sbox0{\vbox{\everypar{}#1}}%
  \ifdim\wd0=\z@\relax
    \endgroup
    \expandafter\@gobble
  \else
    \endgroup
    \expandafter\@firstofone
  \fi
}
\makeatother

内容\everypar将在结束时恢复\vbox并且这将保持enumerate快乐。

答案2

错误的答案(尽管它偶然解决了这个问题)

答案很简单,不要使用框 0,或者确保使用它不会造成任何伤害。这是一个临时框,但\itemLaTeX 的命令也会使用它来存储其项目一小段时间(在遇到命令\item和段落开始后排版标签之间),\QuotableText在此期间会执行您的命令。

现在您对 box0 的更改不是本地的,因此您会覆盖内容。

解决方案 1:使用\newbox获取您的私人盒子注册您的测试

解决方案 2:对 box0 进行本地更改。启动一个组,然后在进行测量后立即将其关闭(这意味着在两个分支中都将其关闭):

\makeatletter
\newcommand{\DoIfNonEmptyText}[1]{% Actually takes two parameters
\begingroup
    \sbox0{#1}%
    \ifdim\wd0=\z@\relax% 
\endgroup
        \expandafter\@gobble%
    \else%
\endgroup
        \expandafter\@firstofone%
    \fi%
}%
\makeatother

你有过

\sbox0{\begingroup\vbox{#1}\endgroup}%

但那里的组设置错了。框 0 的设置仍然在组之外。组内只有正在排版的内容,因此组没有任何效果。

更新(为什么\vbox物品标签会消失)

这是个棘手的问题。我们必须仔细查看列表环境如何将项目标签附加到项目段落。

基本上,内部发生的事情是标签被构造并存储在一个盒子里(它不是我之前声称的盒子 0,而实际上是一个私人盒子(\@labels)所以感谢你的信任投票,但我的答案完全是错误的。

现在,通过使用,框已附加到\everypar,实际使用的定义是

\everypar={\@minipagefalse \global \@newlistfalse \if@inlabel \global \@inlabel
false {\setbox \z@ \lastbox \ifvoid \z@ \kern -\itemindent \fi }\box \@labels 
\penalty \z@ \fi \if@nobreak \@nobreakfalse \clubpenalty \@M \else \clubpenalty 
\@clubpenalty \everypar {}\fi }

因此,当从垂直模式切换到水平模式时,就会执行上述操作。

现在,如果我们只是使用测试,\sbox 那么这将构建一个 h-box,因此\everypar不会执行。但是,如果我们\vbox在内部使用,那么任何文本#1都会触发\everypar。如果你仔细观察,标签只会在@inlabel为真时设置,并且此开关是全球在真实情况下设置为 false。

因此基本上标签放入此处\vbox进行测试,之后就不会再进行排版。

因此,总结一下上述最初的论点错误的(我没有仔细看,列表环境确实使用了框 0,但这是无害的)并且我的重新定义只起作用,因为我\vbox同时取出了。

相关内容