\vtop
下面例子中两者的代码看起来非常相似。
不同之处在于:
- 在情况 1 中,您有
\hbox{ccc\hfill}
。由于和之间\hrule
没有\baselineskip
插入 -glue 。TeX 不会进入水平模式。和之间没有插入 -glue 。(和之间根本没有插入垂直胶水。)bbb
ccc
\parskip
bbb
ccc
bbb
ccc
- 在情况 2 中,你有
ccc
。由于和之间\hrule
没有\baselineskip
插入 -glue 。TeX 会进入水平模式。和之间插入 -glue 。bbb
ccc
\parskip
bbb
ccc
现在假设一种情况,你不知道 TeX 是否会在 之后进入水平模式,\hrule
但无论如何你都不想\parskip
在 之后有 -glue/任何垂直粘连\hrule
。无论如何你都希望它看起来像情况 1 中的那样。
有没有一种方法可以取消或防止\parskip
胶水,以防材料在\hrule
切换到水平模式之前不知道这种切换是否会发生?
\parindent=0ex
\parskip=4cm
\baselineskip=2cm
\hbox to\hsize{%
\vtop{\hsize=.3\hsize
\hbox{aaa}
\hbox{bbb}
\hrule height 0mm depth 0mm\relax
\hbox{ccc} %<- TeX stays in restricted vertical mode
\par\hbox to\hsize{This is case 1\hfill}
}\hfill\vrule\hfill
\vtop{\hsize=.3\hsize
\hbox{aaa}
\hbox{bbb}
\hrule height 0mm depth 0mm\relax
ccc %<- TeX switches to horizontal mode
\par\hbox to\hsize{This is case 2\hfill}
}%
}
\bye
答案1
你可以做这样的事情
\parindent=0ex
\parskip=4cm
\baselineskip=2cm
\hbox to\hsize{%
\vtop{\hsize=.3\hsize
\hbox{aaa}
\hbox{bbb}
\hrule height 0mm depth 0mm\relax
\everypar{\setbox0=\lastbox\endgraf\everypar{}\vskip-2\parskip}
\hbox{ccc} %<- TeX stays in restricted vertical mode
\par\hbox to\hsize{This is case 1\hfill}
}\hfill\vrule\hfill
\vtop{\hsize=.3\hsize
\hbox{aaa}
\hbox{bbb}
\hrule height 0mm depth 0mm\relax
\everypar{\setbox0=\lastbox\endgraf\everypar{}\vskip-2\parskip}
ccc %<- TeX switches to horizontal mode
\par\hbox to\hsize{This is case 2\hfill}
}%
}
\bye
答案2
这个答案是进一步发展的尝试大卫·卡莱尔的回答\everypar
它针对的是每当 TeX 由于切换到水平模式而刚刚传递垂直粘合并通过插入宽度\parskip
来启动水平列表时传递其标记的钩子。\hbox
\parindent
由于您关注的是“的代码\vtop
”而不是本身,\vtop
因此我假设所需的方法也是在(非内部)垂直模式下解决,其中可能某些\begingroup
.. \endgroup
-thingie 可能在前面,而更多的段落可能在\hbox{ccc}
// ( ccc
? \noindent ccc
)-thingie 之后。
也许您可以摆弄\everypar
、\everyhbox
、、以确保不仅下一段而且通常接下来排版的内容都会取消对 的\everyvbox
更改。 \everymath
\everydisplay
\everyar
我还没有想过关于“下一步排版的东西”是否还有更模糊的情况需要考虑。
在下面的示例中,token\skiprestore
被\resetskiprestore
永久地添加到上述每个钩子上。通常这些宏是无操作的。
宏\makemydamnverticalgap
重新定义
\resetskiprestore
重新定义\skiprestore
并将\resetskiprestore
其设为无操作。\skiprestore
应用重新定义\resetskiprestore
并做一些负垂直跳过以取消垂直\parskip
粘合,以防\noindent
插入\hbox
的用于启动水平列表的宽度为0pt
。
我决定将标记永久地添加到钩子前面,因为这样就可以重新定义这些标记,这意味着\global
所需的更改将在包装成组后继续存在。
我不知道在 LaTeX 2ε 中实现这种事情的最佳方法,其中内核本身会处理所有这些\every...
-hooks。
在 LaTeX 中也有这样的包一切钩子这允许您随意使用\every...
-hooks。请注意,当前版本(everyhook v1.2,发布日期为 2014/11/26)有一个错误,每当执行 、、等操作时,连续哈希值的数量就会减半,例如,########
减半为。####
\PushPreHook
\PopPreHook
\PushPostHook
\PopPostHook
(几个月前我在该软件包的 GitHub 存储库上解决了这个问题。)
\parindent=3ex
\parskip=.5cm
\long\def\exchange#1#2{#2#1}
\long\def\firstoftwo#1#2{#1}
\long\def\secondoftwo#1#2{#2}
\newbox\mybox
\long\gdef\prependtohook#1#2{%
#1=\expandafter{\romannumeral0\expandafter\exchange\expandafter{\the#1}{ #2}}
}%
\prependtohook\everypar{\skiprestore}
\prependtohook\everyhbox{\resetskiprestore}
\prependtohook\everyvbox{\resetskiprestore}
\prependtohook\everymath{\resetskiprestore}
\prependtohook\everydisplay{\resetskiprestore}
% I am not sure whether \resetskiprestore should be done with other hooks also.
\newbox\mybox
\gdef\skiprestore{}%
\gdef\resetskiprestore{}%
\long\def\makemydamnverticalgap#1{%
\endgraf
\hrule height 0mm depth 0mm\relax\nobreak
\kern#1\nobreak
\hrule height 0mm depth 0mm\relax
\gdef\resetskiprestore{\gdef\skiprestore{}\gdef\resetskiprestore{}}%
\gdef\skiprestore{%
\resetskiprestore
\setbox\mybox=\lastbox
\vskip-2\parskip
\endgraf\ifdim\wd\mybox>0pt \else\expandafter\noindent\fi
}%
\ignorespaces
}%
\noindent This is some paragraph.\xleaders\hbox{This is some paragraph.}\hfill This is some paragraph.
\begingroup
\makemydamnverticalgap{2cm}
\endgroup
\hbox{This does not switch to horizontal mode. There should be a vertical 2cm gap above this.}
This is another paragraph.
\noindent This is some paragraph.\xleaders\hbox{This is some paragraph.}\hfill This is some paragraph.
\begingroup
\makemydamnverticalgap{2cm}
\endgroup
\leavevmode This does switch to horizontal mode. There should be a vertical 2cm gap above this.
This is another paragraph.
\noindent This is some paragraph.\xleaders\hbox{This is some paragraph.}\hfill This is some paragraph.
\begingroup
\makemydamnverticalgap{2cm}
\endgroup
\noindent This does switch to horizontal mode. There should be a vertical 2cm gap above this.
This is another paragraph.
\xleaders\vbox{\hrule height 0pt width 0pt\par This is another paragraph.}\vfill\break
\parindent=1cm
\parskip=4cm
\baselineskip=2cm
\hbox to\hsize{%
\vtop{\hsize=.25\hsize
\hbox{aaa}
\hbox{bbb}
\makemydamnverticalgap{0cm}%
\hbox{ccc} %<- TeX stays in restricted vertical mo\-de
\par\vtop{\noindent This is case 1 - \TeX{} staying in restricted vertical mo\-de}
}\hfill\vrule\hfill
\vtop{\hsize=.25\hsize
\hbox{aaa}
\hbox{bbb}
\makemydamnverticalgap{0cm}%
ccc %<- TeX switches to horizontal mo\-de
\par\vtop{\noindent This is case 2 - \TeX{} switching to horizontal mo\-de and inserting {\tt\string\par\-in\-dent}}
}\hfill\vrule\hfill
\vtop{\hsize=.25\hsize
\hbox{aaa}
\hbox{bbb}
\makemydamnverticalgap{0cm}%
\noindent ccc %<- TeX switches to horizontal mo\-de
\par\vtop{\noindent This is case 3 - \TeX{} switching to horizontal mo\-de and not inserting {\tt\string\par\-in\-dent}}
}
}
\bye