在开始之前要绝对清楚,这是一个关于 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}