On Tue, 2022-03-15 at 18:16 +0100, Javier Bezos wrote: > How can I process every single letter in math? Processing > glyph nodes in text is more or less trivial, and to some > extent even in-line math (surrounded by 'math' type nodes), > but processing math, including displays, sub/superscripts, > fractions, radicals. etc.? From the manual I think the > solution must be the node.mlist_to_hlist and the > corresponding callback, and this is what I’ve achieved > so far: > > ----------------------- > \directlua{ > > function math_tweak(head, d, p) > head = node.mlist_to_hlist(head, d, p) > for item in node.traverse(head) do > if item.id == node.id'glyph' then > item.char = 88 > end > end > return head, d, p > end > > callback.register('mlist_to_hlist', math_tweak) > > } > > $a$ ${b\over c}$ $\sqrt{d}$ $e$ > > $$f$$ > > \bye > ------------------------ > > Here, only ‘a’, ‘e’ and ‘f’ are converted to ‘X’ (= 88). > > With a branch for item.id == 0 calling recursively the > function sub/superscripts are processed, but that’s not > quite correct.
You want to process the nodes *before* converting the mlist to a hlist. Once the conversion has been done there is lots of layouting stuff that gets in the way of sensibly processing the formula. The mlist representation is much more structured and easier to work with. But also then you have to take care that you treat all nodes correctly and descend into sublists: \directlua{ local converters = {} local function convert(n) local id = n.id local type = node.type(id) local typeconv = converters[type] if typeconv then typeconv(n) else texio.write_nl("Warning: no conversion available for " .. type) end end function converters.noad(n) if not (n.nucleus.head or n.nucleus.char) then % This is a thing, e.g. ${}$ is just an empty noad return end convert(n.nucleus) if n.sub then convert(n.sub) end if n.sup then convert(n.sup) end end function converters.math_char(n) n.char = utf8.codepoint("X") end function converters.sub_mlist(n) for n in node.traverse(n.head) do convert(n) end end function converters.fraction(n) convert(n.num) convert(n.denom) end function converters.radical(n) convert(n.nucleus) if n.sub then convert(n.sub) end if n.sup then convert(n.sup) end end function converters.accent(n) convert(n.nucleus) if n.accent then convert(n.accent) end if n.bot_accent then convert(n.bot_accent) end if n.sub then convert(n.sub) end if n.sup then convert(n.sup) end end local function math_tweak(head, style,penalties) for n in node.traverse(head) do convert(n) end return node.mlist_to_hlist(head, style, penalties) end callback.register('mlist_to_hlist', math_tweak) } $a \left(b\right)$ $a$ ${b\over c}$ $\sqrt{d}$ $e$ $$\hat{f}$$ \bye Cheers, Henri > > Javier >