当 LuaTeX 创建节点时,我怎样才能告诉它当时的心理状态?

当 LuaTeX 创建节点时,我怎样才能告诉它当时的心理状态?

在开始之前要绝对清楚,这是一个关于 LuaTeX 的问题,因此该问题中的“节点”是指 LuaTeX 的节点概念,而不是任何其他 TeX 包的概念。

最终,我想检测 TeX 何时更改组并将该信息记录在节点列表中,以便当我稍后处理该节点列表时(通过pre_linebreak_filter),我可以找出每个节点创建时存在的组级别。

我现有的方法是使用设置attribute为 的tex.currentgrouplevel。但是,由于属性是静态的,每次 TeX 更改组时我都需要重置它。似乎没有针对该特定事件的回调,因此我习惯于每次token_filter读取标记时都设置它。它效率不高,但我一次只希望它用于短片段,因此我会在需要时安装回调,并在完成后再次将其删除。

具体来说,我的回调的 lua 代码是:

local function setlevel ()
   tex.attribute[1] = tex.currentgrouplevel
   return token.get_next()
end

我已经在 TeX 中设置了属性。

但是,LuaTeX 的当前版本已删除了token_filter回调,因此这不再有效!建议似乎是使用token库的功能,特别是扫描仪。但是,我看到的这个示例暗示必须明确调用它。因此,为了检查读取的每个标记以查看它是否进行了组更改,我必须不断重新调用扫描仪,而且这似乎只能通过将标记插入输入流来完成。这变得很棘手,因为某些标记可​​能需要经过 TeX 的嘴和胃的处理,然后将东西插回到输入流中。

另一种策略是调整节点创建代码。但是,我尝试更改该node.new函数(当然是使用早期版本的 LuaTeX),结果表明 LuaTeX 为自己创建节点时不会调用该函数,只有运行用户编写的代码时才会调用(我猜出于实现原因,这样做是有道理的)。

那么,有没有办法用当前版本的 LuaTeX 实现我想要的功能?也就是说,每个创建的节点都知道创建它的 TeX 组级别。

(在“类似问题”中在 LuaTeX 中跟踪组级别和位置作为一个问题,这将是重复的,但对该问题的接受答案存在与它使用的相同的问题token_filter。)

答案1


数学


对于从数学节点生成的节点(例如注释中的a b^2/{a b}^2示例),情况更简单,因为{}组映射到水平列表,就像\hbox因此在节点树中直接可见一样。

以此为例

\documentclass{article}


\begin{document}


\directlua{
function foo(n,s)
  print "\string\n callback\string\n"
  local typ=node.types()
  local nn=n
  while(nn \string~= nil) do
    print(typ[nn.id] ..'(' .. nn.id .. ')')
    if(nn.id==0 and nn.list \string~= nil) then
      local nnn=nn.list
      while(nnn \string~= nil) do
        print('..' .. typ[nnn.id] ..'(' .. nnn.id .. ')')
        nnn=nnn.next
      end
    end
    nn=nn.next
  end
  return n
end
luatexbase.add_to_callback("pre_linebreak_filter",foo,"foo")
}
$ a b ^2$

${a b}^2$

\end{document}

因此a b ^2产生

math(11)
glyph(29)
glyph(29)
hlist(0)
..glyph(29)
math(11)

因此,数学从顶层开始,然后是 a 和 b,上标的嵌套列表具有字形 2,然后是数学结束。

反之则{a b}^2产生

math(11)
hlist(0)
..glyph(29)
..glyph(29)
hlist(0)
..glyph(29)
math(11)

所以这是一个数学开始,然后是一个嵌套的 hlist,对应于{} 包含字形 a 和 b,然后是另一个对应于上标的 hlist,包含列表 2,然后是数学结束。


文本


要处理文本模式,您需要更加努力,这使用输入缓冲区回调来插入\zz每个{重要的内容,\zz因为它将插入到一些棘手的地方,例如\begin{itemize}仍然\begin{\zz itemize}有效......

在 Lua 代码中,将属性\zz设置\grpdepth为当前分组深度。

最后,我们在回调中选择这些,pre_linebreak只是为了调试构造的节点列表。

输入

{{{{{{{{{a{b{c{d{e}}}}}}}}}}}}}

产生控制台输出

..glyph a[depth=9]
..glyph b[depth=10]
..kern  [depth=-1]
..glyph c[depth=11]
..glyph d[depth=12]
..glyph e[depth=13]

完整测试文档为

\documentclass{article}

\newattribute\grpdepth
\edef\grpdepthnum{\the\allocationnumber}

\def\zz{\directlua{%
tex.attribute.grpdepth=tex.currentgrouplevel
print('\string\nCURRENT LEVEL = ' .. tex.attribute.grpdepth)
}}

\def\startattributing{\directlua{%
function flaggroup (s)
 return string.gsub(s,'{','{\string\\zz ')
end
  local zzz='}}'
luatexbase.add_to_callback(
  'process_input_buffer',
  flaggroup,
  'flaggroup')
}}

\def\endattributing{\directlua{%
luatexbase.remove_from_callback(
  'process_input_buffer',
  'flaggroup')
}}


\directlua{
function foo(n,s)
  print "\string\n callback\string\n"
  local typ=node.types()
  local nn=n
  while(nn \string~= nil) do
        na=node.get_attribute(nn,\grpdepthnum) or -1
        print('..' .. 
              typ[nn.id] .. ' ' ..
              string.char(nn.char or 32) ..
              '[depth=' .. na .. ']'
              )
    if(nn.id==0 and nn.list \string~= nil) then
      local nnn=nn.list
      while(nnn \string~= nil) do
        na=node.get_attribute(nnn,\grpdepthnum) or -1
        print('..' .. 
              typ[nnn.id] .. ' ' ..
              string.char(nnn.char or 32) ..
              '[depth=' .. na .. ']'
              )
        nnn=nnn.next
      end
    end
    nn=nn.next
  end
  return n
end
luatexbase.add_to_callback("pre_linebreak_filter",foo,"foo")
}
\begin{document}


\startattributing

\def\f{a}\meaning\f

aaa \emph{bbb}  \mbox{jjj} {ccc ddd} {{{x}}}

{{{{{{{{{a{b{c{d{e}}}}}}}}}}}}}

\begin{itemize}
\item zzz
\end{itemize}

\endattributing

\end{document}

相关内容