在 LuaTeX 中,“标识” linebreak_filter 是什么?(或者:我们如何使用 `tex.linebreak` 来匹配默认的换行算法?)

在 LuaTeX 中,“标识” linebreak_filter 是什么?(或者:我们如何使用 `tex.linebreak` 来匹配默认的换行算法?)

考虑以下 LaTeX 文档(将用 进行编译lualatex):

\documentclass{article}
\usepackage{lipsum}
\begin{document}
\directlua{
  function shouldbenoop(head, isDisplay)
    return tex.linebreak(head)
  end
}
% \directlua{luatexbase.add_to_callback('linebreak_filter', shouldbenoop, 'This should be same as the default?')}

\lipsum
\end{document}

无论该行是否add_to_callback被注释掉,输出似乎都相同,那就是我们覆盖的换行过滤器,它调用tex.linebreak,似乎执行与 TeX 默认执行相同的操作。

然而,当我们尝试使用普通的 TeX (将用 进行编译luatex) 进行相同操作时:

\input ltluatex % For luatexbase.add_to_callback
\input plipsum
\directlua{
  function shouldbenoop(head, isDisplay)
    return tex.linebreak(head)
  end
}
% \directlua{luatexbase.add_to_callback('linebreak_filter', shouldbenoop, 'This should be same as the default?')}

\lipsum{1-20}
\bye

并使用换行符过滤器(取消注释上面的注释行),结果看起来很糟糕,之间段落:

段落连在一起

这些段落看起来几乎重叠,我们需要设置更高的值\parskip才能获得“正确”的结果(当然,它们并不正确,因为它们与不使用换行过滤器的结果不同)。

问题不在于ltluatex纯文本加载,因为结果与此相同:

\input plipsum
\directlua{
  function shouldbenoop(head, isDisplay)
    return tex.linebreak(head)
  end
}
\directlua{callback.register('linebreak_filter', shouldbenoop)}

\lipsum{1-20}
\bye

它也与没有任何关系plipsum,因为只需输入段落而无需加载包即可重现它。

发生了什么事?更重要的是,我们可以linebreak_filter在纯 TeX 中编写什么来完美重现默认换行的效果(即与没有 相同linebreak_filter)?

答案1

您需要(至少)重置\prevdepth类似这样的内容,否则\prevdepth将获得 -1000pt 的“列表开始”值,并且下一段之前没有空格。

\directlua{
  function shouldbenoop(head, isDisplay)
    h,t =tex.linebreak(head)
    tex.prevdepth= t.prevdepth
   return h
  end
}
\directlua{callback.register('linebreak_filter', shouldbenoop)}

\hsize3cm
\parindent0pt

g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g 

\showthe\prevdepth
g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g


a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a

a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a

\bye

答案2

我删除此帖并非出于感情原因,而是出于知情评论评论并从回答@FrankMittlebach 和 @DavidCarlisle 预计\prevdepth(并且\prevgraf) 设置必须通过回调恢复。我没有阅读手册,但从那以后似乎评论@ShreevatsaR 表示,人们还需要从其他来源收集信息。


这太长了,但这是一条注释:在 LaTeX 的情况下,也出现了问题。这是我的测试文件:

\documentclass{article}

\begin{document}
\directlua{
  function shouldbenoop(head, isDisplay)
    return tex.linebreak(head)
  end
}
%\directlua{luatexbase.add_to_callback('linebreak_filter', shouldbenoop, 'This should be same as the default?')}

\parskip 0pt

\def\x{\rule{2cm}{5pt} }

\def\y{\x\x\x\x}
\def\z{\y\y}

\z

\z g g g 

\z

\thispagestyle{empty}
\showoutput

\end{document}

当执行时,第二段g g g中的 导致第三段向下移动\directlua。TeX 计算的基线跳粘应该是 4.94pt,但结果却是 7pt(使得 底部g到下一个基线的距离正好是 7pt+5pt=12pt)。

这是日志的差异,已精简到相关内容。每个部分的顶部是\directlua执行的结果,底部是注释掉的结果。显然,前一种情况下最后一段的位置较低,这是由于字母的下行线g:TeX 维持恒定基线的机制已损坏。

*** 84,90 ****
  ...\hbox(0.0+0.0)x345.0, direction TLT
  ..\glue 25.0
  ..\glue(\lineskip) 0.0
! ..\vbox(550.0+0.0)x345.0, glue set 477.88895fil, direction TLT
  ...\write-{}
  ...\glue(\topskip) 5.0
  ...\hbox(5.0+0.0)x345.0, glue set - 1.0, direction TLT
--- 83,89 ----
  ...\hbox(0.0+0.0)x345.0, direction TLT
  ..\glue 25.0
  ..\glue(\lineskip) 0.0
! ..\vbox(550.0+0.0)x345.0, glue set 479.94873fil, direction TLT
  ...\write-{}
  ...\glue(\topskip) 5.0
  ...\hbox(5.0+0.0)x345.0, glue set - 1.0, direction TLT
***************
*** 168,174 ****
  ....\glue(\parfillskip) 0.0 plus 1.0fil
  ....\glue(\rightskip) 0.0
  ...\glue(\parskip) 0.0
! ...\glue(\baselineskip) 7.0
  ...\hbox(5.0+0.0)x345.0, glue set - 1.0, direction TLT
  ....\localpar
  .....\localinterlinepenalty=0
--- 167,173 ----
  ....\glue(\parfillskip) 0.0 plus 1.0fil
  ....\glue(\rightskip) 0.0
  ...\glue(\parskip) 0.0
! ...\glue(\baselineskip) 4.94
  ...\hbox(5.0+0.0)x345.0, glue set - 1.0, direction TLT
  ....\localpar
  .....\localinterlinepenalty=0
***************

执行后的输出图像\directlua

在此处输入图片描述

最后一段向下移动。


并且\the\prevdepth确实0.0pt在 lua 过滤器的情况下和2.06pt没有它的情况下都会产生结果。(人们期望使用 会产生附带损害\special,就像使用 等时发生的那样\color……但这里的\showoutput并没有显示这样的事情,所以一定更多地是在 luatex 的内部)。

相关内容