答案

答案

编辑:下面给出了可能的答案的摘要。

在我当前的 LuaTeX 项目中,我使用用户定义的 whatsit 节点在 LuaTeX 运行的不同阶段之间传输信息。关于这个主题,手册中说明了以下内容:

LUATEX 引擎将简单地跨过这些内容而不查看其内容。

我对此的解释是,我可以添加用户定义的 whatsit 节点,而在节点列表的实际处理中不应发生任何变化(即,无论有没有它们,文档都应该看起来相同)。

但是,我遇到了以下问题。在我的例子中,某个段落,我们称之为,将溢出页面并移至下一页。因此,上一页剩余段落之间的空白将被拉伸以填充页面(分别填充列)。

如果我添加一个用户定义的 whatsit 节点作为,段落内容被移至下一页(与之前一样),但 whatsit 节点仍保留在上一页。随后,在上一页最后一列的底部添加空格,以确保段落间距正确。

在我看来,这不是正确的行为,我有以下两个问题

  1. 我可以强制 whatsit 节点保留在其段落中吗?(但最好不要将其打包到额外的水平或垂直列表中。)
  2. 如果不行,我至少可以抑制列底部段落间空白的产生吗?

附加信息

一个插图它看起来是这样的:

         Without whatsit                  With whatsit

Page n  |text          |        Page n  |text          |
        |text          |                |              |
        |              |                |text          |
        |text          |                |text          |    Incorrect
        |text__________|                |______________| <- inter-paragraph
                                                            glue
         ______________                  ______________
Page n+1|text of P     |        Page n+1|text of P     |
        |text of P     |                |text of P     |
        |              |                |              |
        |text          |                |text          |

详细我执行以下操作:

使用post_linebreak_filter回调,我将用户定义的 whatsit 节点添加为垂直段落列表的新头(通过使用node.insert_before(head, head, my_whatsit))。此节点在 shipout 阶段仍然可见,在此阶段,它将集成到当前列的垂直列表中。如果段落移动到下一页(如我上面的例子所示),则可以在页面的垂直列列表中找到 whatsit 节点n,而段落的其余部分将移动到页面n+1。我需要它与段落保持一致。


答案

纯乳胶

Dan 的回答解释了如何使用\penalty和将 whatsit 对接到段落\nobreak

LuaTeX

David Carlisle 和 topskip 给出了两种不同的方法来实现此行为,即在回调中改变 whatsit 节点的插入位置post_linebreak_filter。topskip 的解决方案以递归方式搜索段落中的第一个 hlist,并将 whatsit 节点插入其中。David 的方法旨在将 whatsit 节点插入到第一个节点(通常是粘合节点)之后,从而将其锚定到段落。在我的例子中,这可以通过简单地更改node.insert_before(head, head, my_whatsit)为来实现node.insert_after(...)。这使 whatsit 节点与段落的 hlist 保持在同一个 vlist 中,这就是我选择它作为解决方案的原因。正如 David 已经提到的,最好将 whatsit 节点插入到所有可丢弃节点之后(而不仅仅是第一个节点之后)。

答案1

从 topskip 的答案中随意窃取(虽然我也投票支持它:-)他展示了如何将 whatsit 推入水平列表(这基本上\textcolor{}..与相反\color)但如果您希望 whatsit 位于垂直列表中但在下一段之前没有断点,您可以按照我在评论中的建议进行操作,并将其添加到列表的下方。

\documentclass{article}
\usepackage{luacode,luatexbase}
\begin{document}

jj

\begin{luacode*}
w = node.new("whatsit","user_defined")
w.type=100

function foo(head)
  new_head = node.insert_before(head, head.next, w)
  return new_head
end

luatexbase.add_to_callback("post_linebreak_filter",foo,"foo")    
\end{luacode*}

Hello 
\showoutput

\end{document}

与 topskip 代码(猜测)的唯一区别是,我将其改为headhead.nextwhatsit 移到 lineskip 粘合之后。(更仔细的代码可以测试节点类型并进行迭代,直到找到第一个不可丢弃的节点,但这演示了效果。如果比较带有或不带有的版本的日志文件,.next您会看到

*** 143,150 ****
  ....\glue(\parfillskip) 0.0 plus 1.0fil
  ....\glue(\rightskip) 0.0
  ...\glue(\parskip) 0.0 plus 1.0
- ...\glue(\baselineskip) 3.11111
  ...\whatsit0=0
  ...\hbox(6.94444+0.0)x345.0, glue set 307.49994fil, direction TLT
  ....\whatsit
  .....\localinterlinepenalty=0
--- 143,150 ----
  ....\glue(\parfillskip) 0.0 plus 1.0fil
  ....\glue(\rightskip) 0.0
  ...\glue(\parskip) 0.0 plus 1.0
  ...\whatsit0=0
+ ...\glue(\baselineskip) 3.11111
  ...\hbox(6.94444+0.0)x345.0, glue set 307.49994fil, direction TLT
  ....\whatsit
  .....\localinterlinepenalty=0

这意味着,如果你不习惯 unix diff 格式,那么

  ...\whatsit0=0
 ...\glue(\baselineskip) 3.11111

已交换顺序,显示基线跳过粘合(这是示例中分页符发生的位置)现在出现在 whatsit 之前。

答案2

任何内容(无论是否由用户定义)始终是不可丢弃的。因此,如果粘连在它后面,那么该粘连就构成了一个断点。如果粘连在它前面,那么它可能会与页面的其余部分一起延伸。要使它遵循以下段落,您可以将其作为段落的一部分。LaTeX 方法是将其放在\leavevmode它前面。这样可以将任何内容定位在该段落第一行的基线处。如果这种定位会产生影响,并且您希望它在段落之前处于垂直模式,那么您可以在任何内容之前和/或之后放置一个稍微更有利的断点\nobreak

\par
\penalty 10
<my whatsit>
\nobreak
<start of paragraph>

文档的分页方式并不总是相同的,当包含特殊内容时,段落的分页方式也并不总是相同的。众所周知的例子是彩色特殊内容。如果您在\color{red}段落开始之前说,那么它就会在粘连\special之前发生\parskip。这可能会导致分页符,彩色特殊内容位于上一页的底部,而段落位于下一页。

另一个众所周知的例子是,某个东西会导致位置改变:带有选项的 parbox 开头的颜色特殊[t]。该 parbox 的基线位于此处,\special而不是位于第一个文本行的底部。

答案3

您应该将内容添加到段落本身(即水平列表)。

我猜你有类似这样的情况:

\documentclass{article}
\usepackage{luacode,luatexbase}
\begin{document}

\begin{luacode*}
w = node.new("whatsit","user_defined")
w.type=100

function foo(head)
  new_head = node.insert_before(head, head, w)
  return new_head
end

luatexbase.add_to_callback("post_linebreak_filter",foo,"foo")    
\end{luacode*}

Hello 

\end{document}

这会导致垂直列表内出现 whatsit(如其他人所写)。请参阅以下表示:

在此处输入图片描述

也许你应该(我真的不知道你的这个东西是干什么用的)把它添加到段落本身。例如,你可以这样做:

\documentclass{article}
\usepackage{luacode,luatexbase}
\begin{document}

\begin{luacode*}
w = node.new("whatsit","user_defined")
w.type=100

function foo(head)
  while head do
    if head.id == 0 then
      -- hlist
      node.insert_after(head.list,head.list,w)
      return true
    end
    if head.id == 1 then
      -- vlist
      foo(head.list)
    end
    head = head.next
  end
end

Hello
luatexbase.add_to_callback("post_linebreak_filter",foo,"foo")
\end{luacode*}

\end{document}

这使

在此处输入图片描述

现在,whatsit 是 hlist 的一部分。

相关内容