我先介绍一些背景信息。也许这有助于找到替代解决方案。
我制作了一些用于简单缩进列表的宏,文本编辑器效率高(只需添加或删除x
即可更改缩进)。所有这些都通过更改来实现\leftskip
,效果很好。但后来我决定通过将描述文本附加\descr
到它前面的项目来节省一些空间 - 不结束段落,但我仍然希望此描述的延续具有更大的缩进。下面的代码做错了。\desc
实际上增加了它附加到的段落的缩进。
这是我当前的代码。我正在使用 LaTeX,尽管它可能看起来不像:
\newdimen\ListSkip\ListSkip=1cm
\def\nox{\par\bigskip\leftskip=0pt\normalsize\rm\relax}
\def\x{\par\leftskip=0pt\Large\rm\bfseries\relax}
\def\xx{\par\leftskip=1\ListSkip\normalsize\rm\bfseries\relax}
\def\xxx{\par\leftskip=2\ListSkip\normalsize\rm\relax}
\def\desc{\quad\leftskip=3\ListSkip\footnotesize\sf\relax}
\x First Chapter.
\xx A few words from our sponsor.
\xx Theory of ABC explained in detail.
\xxx The scientifical world just a few years back.
\xxx First important discovery.
\desc Here I will describe how professor Humblegoat made the miraculous discovery of the relation behind this theory while he was electroshocked in his bathtub.
\xxx Ground-breaking changes in physical concepts.
\nox Normal text again here.
渲染结果如下:
问题是,第一个重要发现现在比科学界…… \leftskip
显然不是合适的工具\desc
。如果我使用它,\hangindent=1\ListSkip\hangafter=1
结果是正确的,但是我如何知道段落中的当前行我可以使用\hangafter
?
答案1
如果我使用它,
\hangindent=1\ListSkip\hangafter=1
结果是正确的,但是我如何知道我可以在段落中使用的当前行\hangafter
?
简单的答案是:你不能。TeX 在实际将段落分成一行之前不知道段落中的哪个元素属于哪一行,而这发生在它反对命令\par
或结束段落的空行时。然而,到那时段落内的所有宏处理都已完成,因此这些信息对宏处理不可用。
因此,如果描述之前的材料不止一行,例如
\xxx First important discovery. And it takes more than a line in the document. Or perhaps more.
\desc Here I will describe how professor Humblegoat ...
如果这一切都发生在一个段落中,那么就没有办法检测到这种情况。而且这种设置还有另一个问题:您\baselineskip
在更改描述的字体大小时更改了中间部分。但 TeX 只会在\baselineskip
一个段落中查看一次(当它遇到时\par
)。因此,您的前两行已经在较小的 baselineskip 中,但字体较大。
说了这么多,还是有一个巧妙的方法可以让它发挥作用:将内容分成两段,并确保第二段的第一行有正确的缩进。诀窍是使用数学显示功能,该功能允许我们获取显示前最后一行的长度。因此,在开始时,\desc
我们用数学显示中断当前段落,记录宝贵行的大小。然后返回空白显示为页面添加的任何空间。然后设置生成新段落并继续。
相当糟糕的代码如下:
\newdimen\lastlinewidth
\def\desc{%
\begingroup
\predisplaypenalty=10000
\postdisplaypenalty=10000
\abovedisplayskip=0pt
\abovedisplayshortskip=0pt
\belowdisplayskip=-\baselineskip
\belowdisplayshortskip=-\baselineskip
$$\global\lastlinewidth\predisplaysize
\global\advance\lastlinewidth by -2em
$$%
\endgroup
\footnotesize\sf\relax
\vskip-\baselineskip % backup by the baselineskip about to come for the new text (depends on new font size!)
\vskip-\parskip % and the parskip being added
\noindent\kern\lastlinewidth % start new paragraph for "description"
\leftskip=0pt % cancel any \leftskip
\hangindent=3\ListSkip % but instead use \hangindent from the start
\quad
}
如果我们将这个定义应用到例子中(后面有一行\xxx First ...
),我们会得到以下结果:
这应该是预期的结果。
如果查看最终页面上生成的材料(通过),就可以看到幕后发生的事情\showoutput
。 这里的相关部分是:
....\OT1/cmr/m/n/10 m
....\OT1/cmr/m/n/10 o
....\OT1/cmr/m/n/10 r
....\OT1/cmr/m/n/10 e
....\OT1/cmr/m/n/10 .
....\penalty 10000
....\glue(\parfillskip) 0.0 plus 1.0fil
....\glue(\rightskip) 0.0
...\penalty 10000
...\glue(\abovedisplayskip) 0.0
...\glue(\baselineskip) 10.05556
...\hbox(0.0+0.0)x0.0, shifted 172.5, display
...\penalty 10000
...\glue(\belowdisplayskip) -12.0
...\glue -9.5
...\glue 0.0 plus -1.0
...\glue(\parskip) 0.0 plus 1.0
...\glue(\baselineskip) 3.94444
...\hbox(5.55556+1.55556)x345.0, glue set 0.09123
....\glue(\leftskip) 85.35823
....\kern 183.98907
....\kern -85.35823
....\glue 8.50012
....\OT1/cmss/m/n/8 H
....\OT1/cmss/m/n/8 e
....\OT1/cmss/m/n/8 r
....\OT1/cmss/m/n/8 e
您可以看到显示器添加的各种惩罚和跳过(以及代表显示器的空框)以及为平衡这些惩罚和跳过而添加的字距和跳过。您还可以看到由于字体大小不同而导致的不同的基线跳过。
最后一条评论:
以这种方式拆分段落可能会产生副作用,尤其是如果此类代码嵌入到 LaTeX 机制中,而 LaTeX 机制在段落处理方面有自己的一套特性(例如\everpar
在某些地方进行内部重新定义等)。因此,需要小心谨慎,并且必须准备好深入研究 LaTeX2e 内核代码,以防万一。
值得一提的一个一般副作用是:TeX 拆分段落时,段落的最后一行始终不进行任何拉伸,而段落中间的行则可能根据情况设置得稍微松散或紧密一些。这意味着以这种方式人为地拆分段落会减少 TeX 寻找最佳换行符的选项,并且可能会改变段落,即使其他所有内容都保持不变(即没有边距变化等)。特别是,第一个段落的最后一行和最后一个段落的第一行不一定具有相同的“松散度”,后者可能设置得非常松散或紧密,而前者始终具有自然宽度的空格。
答案2
非常感谢 Frank Mittelbach。这是确切地我想要的。显示数学技巧真的很有用。我已经根据我的列表的需求调整了 Frank 的答案中的代码,以便描述适用于所有级别的缩进,并且在放入新段落时也能很好地间隔开(然后不需要任何技巧,因此\ifhmode
在命令中添加了检查)。我还从四边形移动到使用此列表的标准缩进\ListSkip
,以避免不同 em 大小的不同水平跳过。这是更新后的代码:
\newdimen\lastlinewidth
\newdimen\ListSkip\ListSkip=1cm
\def\nox{\par\bigskip\leftskip=0pt\normalsize\rm\relax}
\def\x{\par\noindent\leftskip=0pt\Large\rm\bfseries\relax}
\def\xx{\par\noindent\leftskip=1\ListSkip\normalsize\rm\bfseries\relax}
\def\xxx{\par\noindent\leftskip=2\ListSkip\normalsize\rm\relax}
\def\desc{\ifhmode
\begingroup\predisplaypenalty=10000 \postdisplaypenalty=10000
\abovedisplayskip=0pt \abovedisplayshortskip=0pt
\belowdisplayskip=-\baselineskip
\belowdisplayshortskip=-\baselineskip
$$\global\lastlinewidth\predisplaysize
\global\advance\lastlinewidth by -2em$$%
\endgroup
\footnotesize\sf\relax
\vskip-\baselineskip % backup by the baselineskip about to come for the new text (depends on new font size!)
\vskip-\parskip % last unmodified line, rest is modified
\advance\leftskip by \ListSkip
\advance\lastlinewidth by -\leftskip
\advance\lastlinewidth by \ListSkip
\noindent\kern\lastlinewidth
\else
\noindent\advance\leftskip by \ListSkip\footnotesize\sf\relax % in case we already were in a new paragraph
\fi
}
% Let's test it!
\x First Chapter. \desc Gotta start somewhere, right?
\xx Thanks to my family, friends and everybody else I barely know. \desc The usual crap.
\xx A few words from our sponsor. \desc Spam, spam, spam, lovely spam, spam, spam, spam, spam, spam bacon and eggs, spam, spam, spam, spam, spam, spam, spam, eggs, spam, spam, spam, spam, spam, spam, spam, spam, spam, spam, spam, spam, spam, spam, spam, spam!
\xx Theory of ABC explained in detail.
\xxx The scientifical world just a few years back. \desc Short description.
\xxx First important discovery.
\desc Here I will describe how professor Humblegoat made the miraculous discovery of the relation behind this theory while he was electroshocked.
\xxx First important discovery. And it takes more than a line in the document. Or perhaps a lot more than that.
\desc Here I will describe how professor Humblegoat made the miraculous discovery of the relation behind this theory while he was electroshocked while taking a bath in his house.
\xxx Ground-breaking changes in physical concepts.
\desc Description explicitly placed in new paragraph.
\nox Normal text again here.
现在渲染效果看起来和我想要的完全一样:
再次感谢!
答案3
\leftskip
适用于段落(据我所知)。对于您,\desc
您只能使用\quad
或\hspace*{}
或其他东西将其向右移动一点。
当您在描述中找到新行(之后的文本\desc
)时,它不会与上一行左对齐,但这是由中第一行的正常缩进造成的\par
。
以下内容能解决您的问题吗?
\newdimen\ListSkip\ListSkip=1cm
\def\nox{\par\bigskip\leftskip=0pt\normalsize\rm\relax}
\def\x{\par\leftskip=0pt\Large\rm\bfseries\relax}
\def\xx{\par\leftskip=1\ListSkip\normalsize\rm\bfseries\relax}
\def\xxx{\par\noindent\leftskip=2\ListSkip\normalsize\rm\relax}
\def\desc{\quad\footnotesize\sf\relax}