当前垂直列表中的第一个框?

当前垂直列表中的第一个框?

是否有可能获取当前垂直列表中的第一个框?如果不可能,是否可以定义一个宏来获取一个参数并返回该参数的第一行(垂直列表的第一个框)。抱歉我的英语不好。谢谢

编辑

为了澄清我的问题,请查看这个 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}

在此处输入图片描述

相关内容