获取宏中包含的下一段文本(指定大小)

获取宏中包含的下一段文本(指定大小)

假设我们有很多文本需要排版,包含在一个宏中,我们称之为\myverylongtext

\newcommand{\myverylongtext}{
    This is some really long text: \blindtext[4].

    And it continues even more: \blindtext[1].
}

为简单起见,我们假设 中没有 sectioning/newpage 命令\myverylongtext,但它可以有换行命令和多个段落(段落分隔命令?)。此外,假设字体大小和行距始终保持不变,但文本中允许使用所有其他 LaTeX 排版命令(\textbf 等)并且应该生效。

是否可以定义一个有效的*宏,当遇到时,获取指定维度的下一段文本?例如:

\newcommand{\getnextchunk}[4]{
    % #1 is name of macro (in our case \myverylongtext) 
    % #2 width of text box
    % #3 height of text box in lines
    % #4 draftmode: optional boolean argument that, when set, instead of typesetting contents returns the actual height (in lines), and width (in length units) of the chunk. (useful in making dynamic layout decisions)
    % returns/typesets a box of shape width * height
}

对此宏的新调用\getnextchunk应该获取下一块文本,就好像其中包含的文本\myverylongtext从前一块重新流动到这一块一样。

* 这\myverylongtext可能很长,而且可能有许多这样的块,因此需要提高效率。您不能\myverylongtext多次排版剩余部分。我对此类问题的解决方案的一个设想是迭代填充一个大小为 0 的框,直到它增长到指定的度量:宽度(长度维度)、高度(行数)和所需的对齐方式;尽管我对低级 tex/luatex/expl3 缺乏了解,无法自己编写它。

此外,要么像 raggedright/raggedleft/full-justified 中指定的对齐命令\myverylongtext应该神奇地生效,要么我们可以设置一个限制,我们不会在 & 中使用这样的命令,\myverylongtext而是将其作为第 4 个参数传递\getnextchunk(我认为后者更可取,并且可以使编码/使用更容易和/或更干净)。

另一种可视化问题的方法是想象我们有多个矩形文本框(宽度和高度不同),当我们在文档中遇到它们时,它们会按顺序流入彼此(不必担心这些文本框的位置,*tex 已经有多个优雅的解决方案)。此外,我们不知道何时以及在文档中会遇到多少这样的文本框。在我看来,从多年使用 *tex 的经验来看,解决这个问题将带来无数的可能性,并使 tex 作为面向设计的布局的排版工具在价值上无与伦比(与 InDesign 等相比)。InDesign 和 Affinity Publisher 等工具允许链接最终以流的形式流入彼此的文本框,这对于旨在满足现代表现排版和多种设计的排版系统来说是必不可少的。这可以让 *tex 作为排版工具面向更广泛的排版/设计社区。

答案1

我的解决方案并不完全符合您的要求,但所有信息都在一个地方管理。我希望接受三次参数传递不会有问题。

数据看起来应如下:

%          lines  width
\declchunk    5     10cm ;
\declchunk    6     12cm ;
\declchunk   12     13cm ;
\declchunk    9     10cm ;
\declchunk    9     10cm ;
\declchunk    9     10cm ;
\declchunk    7      8cm ;
\declchunk    5     10cm ;

\formatchunks \myverylongtext

\setbox101 = \getnextchunk
\setbox102 = \getnextchunk  \rebox 102:{\raggedright}
\setbox103 = \getnextchunk
\setbox104 = \getnextchunk  \rebox 104:{\raggedleft} 
\setbox105 = \getnextchunk

% you can place these boxes everywhere. the following code is only for testing:

box 101: \par \box101 \bigskip
box 102: \par \box102 \bigskip
box 103: \par \box103 \bigskip
box 104: \par \box104 \bigskip
box 105: \par \box105 \bigskip

\bye

首先,我们缩小所有块的尺寸(按行数确定高度,按尺寸确定宽度)。其次,我们格式化给定的文本。最后,我们可以获取数据片段并将它们保存到框中。默认情况下,它们与块对齐。如果我们需要进行其他设置,则可以重新对这些框进行装箱。我们的示例显示第二个框在右侧不齐,第四个框在左侧不齐。此外,您可以执行

\vbox to<dimension>{\unvbox103} \vtop to12mm{\unvbox105} etc. 

例如,因为线与线之间存在可拉伸性和可收缩性。

实现:我们\parshape通过 s 列表获取所有参数\declchunk,然后使用这些参数(仅一次)格式化文本,\vbox\allchunks然后执行调用\vsplit时的\getnextcunk操作。最后,如果用户需要稍微不同的表单块对齐方式,我们可以进行一些重新装箱。

我的实现仅适用于纯 TeX 和经典 TeX。我们不需要任何 TeX 扩展,并且(当然)我们不需要 LaTeX:)。

\newcount\tmpnum
\newcount\shapenum
\newcount\globpar
\newbox\allchunks
\newif\ifrepeat

\splittopskip=\baselineskip

\def\formatchunks#1{\setbox\allchunks=\vbox{%
   \def\par{\ifhmode\shapepar\fi}
   \def\shapepar{\prevgraf=\globpar 
      \parshape\shapenum\shapelist \endgraf
      \globpar=\prevgraf
      \ifnum\prevgraf>\shapenum \let\par=\endgraf \fi}
   \dimen0=\baselineskip \baselineskip=\dimen0 plus2pt minus2pt
   \widowpenalty=0 \clubpenalty=0 \brokenpenalty=0
   \penalty0 #1\vfil}
   \setbox0=\vsplit\allchunks to0pt % \splittopskip added
   \expandafter \renewsize \sizelist \relax
}

\def\shapelist{} \def\sizelist{}
\splittopskip=\baselineskip

\def\shapelist{} \def\sizelist{}

\def\declchunk #1 #2;{\edef\sizelist{\sizelist#1\space}
   \tmpnum=0
   \loop  \advance\tmpnum by1 \advance\shapenum by1
          \edef\shapelist{\shapelist 0pt#2}%
          \ifnum\tmpnum<#1 \repeat
}
\def\getnextchunk{\vsplit\allchunks to\size
   \ifx\sizelist\empty \def\size{\baselineskip}%
   \else \expandafter \renewsize \sizelist \relax \fi 
}
\def\renewsize #1 #2\relax{%
   \def\size{#1\baselineskip}\def\sizelist{#2}%
}

\def\rebox#1:#2{\setbox#1=\vbox{%
   \setbox0=\hbox{}%
   \repeattrue
   \def\raggedright{\rightskip=0pt plus1fill minus1em \relax}%
   \def\raggedleft{\leftskip=0pt plus1fill minus1em \relax}%
   \hsize=\wd#1 
   \unvbox#1
   \loop
      \setbox2=\lastbox
      \ifvoid2 \repeatfalse
      \else \setbox0=\hbox{\hbox{\unhbox2}\penalty-10000 \unhbox0 }
            \unskip\unskip\unpenalty
      \fi
      \ifrepeat \repeat
   \null
   #2\noindent \hfil \unhbox0 \par
}}

\def\myverylongtext{%
  Lorem ipsum dolor sit amet, consectetuer
  ...
  purus eget enim. Nunc vitae tortor. Proin tempus nibh sit amet nisl.
  Vivamus quis tortor vitae risus porta vehicula.
}

相关内容