排版文学程序:如何启用段落中间分页,但不启用代码中间分页?

排版文学程序:如何启用段落中间分页,但不启用代码中间分页?

我正在写一本书,这是识字计划. 文学程序被划分为“块”或“部分”,每个部分都有文档部分和代码部分。(也可以有一个只有文档而没有代码的块,这在我的应用程序中非常有用。)

我的问题是如何管理排版以便代码的任何部分都不会被分页符分割,同时确保任何文档部分都可以在段落中间拆分文档部分的最后几行与其所记录的代码出现在同一页面上。

我现在使用的技术并不令人满意。它避免了拆分代码部分,但它将文档与代码放在同一页上的方式是完全避免拆分文档部分。

该实施方案的突出特点如下:

  • 每个文档部分都用\nwbegindocs和括起来\nwenddocs。这些宏几乎不做任何事情 — 只是对缩进进行一些小改动。

  • 新的文档部分通常以 开始\nwdocspar。此宏让 LaTeX 知道新部分即将开始,并且可以在此处设置分页符。目前 的默认定义是\nwdocspar\filbreak目标是尽量让文档部分与其后的代码部分保持在同一页上。

  • 您可以将 视为\nwbegincode设置一种特殊的代码排版环境。在标准环境中,它与 最为相似\begin{alltt}。它使用\trivlist,然后要求 LaTeX 尊重换行符,如下所示:

    \@@par
    \def\par{\leavevmode\null \@@par \penalty\nwcodepenalty}%
    \obeylines
    

    默认\nwcodepenalty值为\@highpenalty

如果每个代码块都足够小,可以放在一页上,则此设置足以防止代码块跨页拆分。但此设置不会导致文档块内出现分页符——分页符仅出现在\nwdocspar。这种情况通常会在页面底部留下大量空白,我目前通过\nwdocspar在整个文本中或多或少地随机散布空白来处理这种情况。

下面是一个简单的工作示例,可以更好地说明该问题:

\nwbegindocs{0}
\begin{itemize}
\item
The list of integers shows a recursive type;
its~representation is immutable and uses both a record type and a sum
type.
\end{itemize}
\nwenddocs{}%
\nwbegindocs{1}%
\nwdocspar   %   <------------- this is important!

\subsubsection{Two-dimensional points: a mutable abstraction}

Two-dimensional points are a simple abstraction, but even the simplest
cluster demonstrates many of \clu's important features:
\begin{itemize}
\item
The structure of a cluster includes an \emph{export list} in which
each public operation is given a \emph{type}.
\item
Each cluster defines the {\Tt{}rep\nwendquote} type, which is the
representation of the abstract type that is introduced by the cluster.
\item
This cluster uses one of \uclu's built-in \emph{record types}.
\item
The operations of the cluster use \uclu's {\Tt{}seal\nwendquote} and
{\Tt{}unseal\nwendquote} operations, which convert a representation to
an abstraction and vice versa.
\end{itemize}
To~show you something that is not possible in \uscheme\ or \uml,
I~make the points \emph{mutable}: a point can be mutated by rotating
it 90 degrees counterclockwise, or by reflecting it through the origin.
Also, I~can interrogate a point to ask what quadrant of the plane it
is~in.

In cluster {\Tt{}2Dpoint\nwendquote}, a point is represented by a
mutable record containing its $x$ and $y$ coordinates, which are
integers.  This representation need not satisfy any invariants; all
pairs of coordinages are meaningful.
\nwenddocs{}%
%
\nwbegincode{2}%
\moddef{2dpoint.clu}\endmoddef\nwstartdeflinemarkup\nwenddeflinemarkup
(cluster 2Dpoint
  [exports
     [new      : (int int -> 2Dpoint)]
     [get-x    : (2Dpoint -> int)]
     [get-y    : (2Dpoint -> int)]
     [reflect  : (2Dpoint -> )]
     [rotate+  : (2Dpoint -> )]
     [quadrant : (2Dpoint -> sym)]
     [print    : (2Dpoint -> )]]

  \LA{}definition of the \code{}rep\edoc{} of a \code{}2Dpoint\edoc{}\RA{}

  \LA{}definitions of the operations of cluster \code{}2Dpoint\edoc{}\RA{}
)
\nwendcode{}%
%
\nwbegindocs{3}%
The types of operations {\Tt{}reflect\nwendquote},
{\Tt{}rotate+\nwendquote}, and {\Tt{}print\nwendquote} are types you
couldn't write in \timpcore\ or \tuscheme---they are functions that
return no results.  In~\clu, just as a function may take any number of
arguments, it may return any number of results.  A~function that
returns no results has no types between the arrow and the closing
bracket.
\nwenddocs{}

TeX 实际放置分页符的唯一位置是命令\nwdocspar前的右侧\subsubsection。为了获得合适的分页符,我必须插入额外的分页符\nwdocspar,例如,在每个分页符前插入一个,\item在段落分隔符处插入一个。即便如此,我也无法在段落中间插入分页符——但至少我可以更有效地使用页面。

这种方法效果不太好,而且由于我的手稿大小接近 800 页,我害怕尝试手动调整每一个分页符。

你看到的 LaTeX 代码是由我控制的预处理器生成的,我也控制宏的定义。所以我想问的问题是我可以在文件中放置什么标记,以及如何定义宏,以便通过有限的手动调整来实现以下三种好处?

  • 代码块不会分散到多个页面

  • 当代码块跟在文档块之后且中间没有 时\nwdocspar,文档块的结尾将出现在与代码块相同的页面上。 (我使用\clubpenalty=10000\widowpenalty=10000,并将文档的最后两行与代码放在同一页面上就足够了。)

  • 否则,按照典型的默认设置,文档块可能会在段落中间跨页拆分。


编辑添加: 我想知道是否可以对和标记做些什么\vsplit?虽然对于 800 页的文本,我有点担心速度。

答案1

暂时,我采用标准解决方案,以防止任何代码块被破坏。但为了在段落中间启用换行符,我\stdbreak在段落中随意散布,其中\stdbreak定义如下:

\newcommand\vfilbreak[2][200]{%
  \vskip 0pt plus #2 \penalty -#1 \vskip 0pt plus -#2 \relax}
\newcommand\stdbreak{\vadjust{\vfilbreak[2000]{0.5in}}}

答案2

这是一个老问题,没有公认的答案,但你已经找到了一种解决方案。但由于它尚未结束,我想分享我的想法。

命令\filbreak不是你的朋友。

TeXbook状态

\TeXplain提供的用于页面排版的最有趣的宏称为\filbreak。它的大致含义是“在此处分页并用空白填充底​​部,除非还有空间容纳后面跟着 的更多副本\filbreak。”

\filbreak因此,正如您在设置中观察到的那样,多个 s 之间的文本被放置在一页上。该命令\vfilbreak或多或少是\filbreak伪装的;\filbreak可以直接使用\stdbreak

我认为,除此之外,该设置看起来不错,可以实现项目符号列表中的三项。第二项还可以,如果将\filbreak替换为 之类的东西,则可以实现第三项\stdbreak (尽管罚款 $-2000$ 似乎太“高/低”了)。 \goodbreak如果段落、块、文档和代码部分等之间有足够的可伸缩性, A 可能就足够了。

只有第一项可能会导致问题,因为代码块可能需要跨页中断。\nwcodepenalty行与行之间必须有空格,并且空格必须为 10000 才能防止分页,但这样可能会出现页面过满的情况。例如,如果将值设置为 9000,TeX 可能会在紧急情况下中断,但中断可能在代码部分的第一行或倒数第二行之后。

相关内容