是否有可能获取当前垂直列表中的第一个框?如果不可能,是否可以定义一个宏来获取一个参数并返回该参数的第一行(垂直列表的第一个框)。抱歉我的英语不好。谢谢
编辑
为了澄清我的问题,请查看这个 wme 及其输出。
\documentclass{article}
\usepackage{lipsum}
\def\gettfirstline#1{I want this macro return\par Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel, wisi. Morbi auctor
}
\setlength\parindent{0pt}
\begin{document}
\lipsum[2]
\vspace{1.5cm}
\gettfirstline{\lipsum[2]}
\end{document}
答案1
您可以将数据分配给 a \vbox
,然后使用 提取第一个框\vsplit
。这很不靠谱,如果您的框不是以文本开头,它只会给您框,则可能会失败。因此,与 中的解决方案相比更改段落第一行*排版*的样式您无法再更改格式,但间距会保留:
\documentclass{article}
\usepackage{lipsum}
\newbox\mylocalbox
\newbox\myglobalbox
\def\Ggetfirstline{%
\vfuzz\maxdimen
\setbox\mylocalbox=\vsplit0to1sp
\setbox\mylocalbox\vbox{%
\unvbox\mylocalbox
\global\setbox\myglobalbox\lastbox
}%
\endgroup
\box\myglobalbox
}
\def\Getfirstline{\aftergroup\Ggetfirstline}
\def\getfirstline{\begingroup\afterassignment\Getfirstline\setbox0\vbox}
\setlength\parindent{0pt}
\begin{document}
\lipsum[2]
\vspace{1.5cm}
\getfirstline{\lipsum[2]}
\end{document}
此代码将第一行插入为与原始类型相同的框,通常是\hbox
。您还可以将框包裹在 vbox 中,以保持水平位移不变:
\documentclass{article}
\usepackage{lipsum}
\newbox\mylocalbox
\newbox\myglobalbox
\def\Ggetfirstline{%
\vfuzz\maxdimen
\setbox\mylocalbox=\vsplit0to1sp
\global\setbox\myglobalbox\vbox{\unvbox\mylocalbox}
\endgroup
\box\myglobalbox
}
\def\Getfirstline{\aftergroup\Ggetfirstline}
\def\getfirstline{\begingroup\afterassignment\Getfirstline\setbox0\vbox}
\setlength\parindent{0pt}
\begin{document}
\lipsum[2]
\vspace{1.5cm}
\getfirstline{\lipsum[2]}
\end{document}
如果您愿意使用 LuaTeX,则可以使用 Lua 创建一个更通用、更强大的宏,即使您位于主垂直列表中,它也会始终为您提供当前垂直列表中的第一个框:(这是纯 LaTeX,如果您更喜欢 LuaLaTeX,只需添加\documentclass
, \begin{document}
, )\end{document}
\def\setboxtovhead{\directlua{
local vlistid, hlistid = node.id'vlist', node.id'hlist';
local vlistlevel = tex.nest.ptr;
while math.abs(tex.nest[vlistlevel].mode) \csstring~= 1 do
vlistlevel = vlistlevel - 1
end
local nest = tex.nest[vlistlevel]
local head = nest.mode == 1 and tex.lists.page_head or nest.head.next;
while head and head.id \csstring~= vlistid and head.id \csstring~= hlistid do
head = head.next
end
tex.box[token.scan_int()] = node.copy(head)
}}
\parindent0pt\parskip1em
abc\hfil\break def\hfil\break ghi
\setboxtovhead0
The first line was:\par
\box0
\end
答案2
一个技巧是设置无限\clubpenalty
,这样一个\vsplit
操作就会捕获那个惩罚并且盒子会在那里被分割:
\documentclass{article}
\usepackage{lipsum}
\newsavebox\mainbox
\newsavebox\firstbox
\newcommand{\getfirstline}[1]{%
\begingroup
\setbox\mainbox=\vbox{%
\clubpenalty=-10000
\predisplaypenalty=-10000
#1%
}%
\vbadness=10000 % don't be bothered with underfull boxes
\setbox\firstbox=\vsplit\mainbox to \maxdimen
\setbox\firstbox=\vbox{\unvbox\firstbox}
\box\firstbox
\endgroup
}
\begin{document}
\lipsum[2]
\getfirstline{\lipsum[2]}
\lipsum[2]
\end{document}