如何生成“您不能在垂直模式下使用 \unskip”?

如何生成“您不能在垂直模式下使用 \unskip”?

我们都知道(或相信)\unskip在主垂直模式下这是不可能的,这个说法可以在网站上的各种答案中找到。是的,LaTeX 做了很多工作来\addvspace解决\addpenalty这个问题。所以当我在在 multicol 环境中,第二列始终低于第一列一个简单的解决方法\unskip

这在主垂直列表中!

因此,查看 TeX 程序本身,条件是如果列表中的最后一项是粘合项,并且该粘合项已经贡献给当前页面,则会触发错误。但是什么时候会发生这种情况?

XXX
\par
\vskip 1cm 
\vskip 5cm
\unskip\unskip
XXX
\bye

这种方法非常完美,并且根据 TeXbook 的说法,只有 5 种情况会将内容从最近的贡献移动到当前页面(第 122 页):

以下是可能发生这种情况的时间列表:(a)在段落的开头或结尾,前提是该段落正在添加到主垂直列表中。(b)在该段落中显示的等式的开头或结尾。(c) \halign在垂直模式下完成后。(d)在向主垂直列表贡献一个框或惩罚或插入之后。(e)在例程\output结束后。

不幸的是,它并不十分准确(可能还有一些其他地方对此进行了进一步讨论,但我忽略了)。例如,如果您\vskip在上面的示例中在后面添加一个空行,那么它会触发错误,即使这\par显然不会触发或结束任何段落。

我可以想象从情况(e)来创建它,例如,通过让输出例程在主垂直列表中添加胶水,尽管我还没有尝试过。

现实中还有哪些其他情况会引发这种情况?

答案1

查看源代码tex.web,我收集了以下内容,但我不确定其中任何一条。从(单独的)行

primitive("unskip",remove_item,glue_node);

any_mode(remove_item): delete_last;

我看到\unskip调用了该过程delete_last,其中有以下注释tex.web

类似地\lastbox,此命令在垂直模式下是不允许的(内部垂直模式除外),因为垂直模式下的当前列表会发送到页面构建器。但如果我们碰巧能够在垂直模式下实现它,我们就会这么做。

换句话说,TeX 会尽最大努力移除某些内容,但有时这是不可能的。事实上,delete_last如果当前模式是,vmode并且(我相信)没有最近的贡献,则“对现在无法执行操作表示歉意”的代码,除非\unskip遵循非粘合节点(在这种情况下\unskip不执行任何操作)。因此,您需要找出何时将内容移出最近的贡献的评估是正确的。

主垂直列表分为两部分:从page_headpage_tail表示当前页面,从contrib_headcontrib_tail表示最近的贡献。搜索contrib_,我发现在几个地方使用了变量:

  • 在程序中show_activitieslink(contrib_head)进行查询,以了解是否有任何最近的贡献;
  • 该程序build_page似乎将材料从最近的贡献移动到当前页面,因此对我们来说至关重要;
  • link(contrib_head):=link(p)在两个地方使用来向最近的贡献添加节点;
  • q:=new_skip_param(top_skip_code)然后link(contrib_head):=q在添加第一个框时将 topskip 添加到页面;
  • 当在给定节点分页时,通过操作contrib_head和,当前页面中后续的内容将放置在最近的贡献之前contrib_tail
  • 默认的输出例程似乎将当前页面放回到最近的贡献中(当然除了已经拆分并放入的页面\box255),然后 shipout \box255
  • 在用户定义的输出例程之后也会发生同样的情况(为业务保存\box255)。

从中我们可以看出,这build_page可能就是你想要的。它在以下情况下被调用(标有与您的列表相对应的字母):

  • (a)当一个段落以 开始vmode(通过水平命令,如\indent、字母\discretionary等)时,插入\everypar到输入流后;
  • (b)\everydisplay在输入流中插入标记列表并设置进入显示模式的各种参数后,如果周围模式为vmode
  • (b) 显示结束后,返回水平模式(并保存语言等),如果周围模式为vmode
  • (a)\par在水平模式下以 结束一个段落后,如果结果模式是vmode
  • (c)当以\halign结尾时vmode
  • (d) 在 中插入惩罚后vmode
  • (d)在程序内box_end,如果完成的箱子(或箱子登记册,或......)非空并且要被添加到主垂直列表中(而不是存储,运出或用作领导者);
  • (d) 当\insert\vadjust以端基字符结尾时,如果结果模式为vmode
  • (e)在 TeX 完成用户的输出例程后,检查是否为\box255空,并将所有当前页面材料放入最近的贡献中(参见上文);
  • 当遇到\parvmode
  • 插入后,\hbox to \hsize{}\vfill\penalty-'10000000000如果遇到原始情况时主垂直列表中仍有一些材料\end

与您的列表相比,出现了一些差异。在默认输出例程之后,build_page似乎没有使用。\end您的列表中缺少的情况。更重要的是,您的列表中没有明确给出不受限制的垂直模式下的情况\par(尽管我猜(a)适合它)。这个案例解释了为什么

XXX\par
\vskip 1cm
%
\unskip

删除 后失败%。与预期相反,\par在垂直模式下不会被忽略:它将材料从最近的贡献移动到当前页面,但也会重置一些参数(、 和\looseness\hangindent。这让我很惊讶。\hangafter\parshape

我发现最后一件事。该程序build_page没有被使用,append_glue因为该程序append_glue“至少在一个地方被使用,而那是一个错误”。我不知道错误在哪里。但这解释了为什么\vskip 1cmTeX 不会将任何材料移动到当前页面。

相关内容