[NTG-context] Callbacks in LuaMetaTeX

Max Chernoff mseven at telus.net
Mon May 2 06:08:27 CEST 2022


Hi list,

I've been playing around with some of the Lua callbacks in LuaMetaTeX,
and I have a few questions/comments.

Context: I'm writing a Plain/LaTeX/ConTeXt module called
"lua-widow-control" that uses Lua callbacks to automatically remove
widows and orphans from documents. The relevant Lua code is at:

     https://github.com/gucci-on-fleek/lua-widow-control/blob/master/source/lua-widow-control.lua

in case you're curious about how I'm using these callbacks, but you
shouldn't need to look there since this email is self-contained.

1. In LMTX, calling "tex.linebreak" produces a
    
        luatex warning  > tex: left parfill skip is gone

    warning. I don't get this warning in Plain LuaTeX, LuaLaTeX, or MkIV,
    so I think that it's specific to LuaMetaTeX. The LuaMetaTeX manual
    hardly mentions "left parfill skip"/"parfillleftskip", so I'm not too
    sure what to do to avoid this warning.

    You can reproduce the warning with this code (but any call to
    "tex.linebreak" also works):

        \startluacode
            function test(head)
                tex.linebreak(node.copylist(head))
        
                return head
            end
        
            nodes.tasks.appendaction("processors", "after", "test")
        \stopluacode
        
        \starttext
            Hello!
        \stoptext

2. The LuaMetaTeX manual says that "pre_linebreak_filter" is called
    after the parfillskip glue has been added, but this doesn't seem to
    be the case. With LuaLaTeX/Plain LuaTeX, this is true, but the node
    list passed to the callback in MkXL is missing the parfillskip. (I
    don't have an MkIV installation to test here.)

    This MkXL code:

        \startluacode
            function test(head)
                local last = node.slide(head)
        
                print "START"
                for i=1,3 do
                    print(last)
                    print(
                        node.type(last.id),
                        node.subtypes(last.id)[last.subtype],
                        last.width,
                        last.stretchorder,
                        last.stretch
                    )
        
                    last = last.prev
                end
                print "STOP"
        
                return head
            end
        
            nodes.tasks.appendaction("processors", "after", "test")
        \stopluacode
        
        \starttext
            Hello!
        \stoptext

    produces:

        START
        <node :   2521 <=   2258 =>    nil : glue spaceskip>
        glue    spaceskip       341648  0       384354
        <node :   2509 <=   2521 =>   2258 : glyph unset>
        glyph   nil     213792  nil     nil
        <node :   2497 <=   2509 =>   2521 : glyph unset>
        glyph   nil     385140  nil     nil
        STOP
        START
        <node :   2611 <=   2357 =>    nil : glue userskip>
        glue    userskip        0       2       65536
        <node :   2274 <=   2611 =>   2357 : glyph unset>
        glyph   nil     385140  nil     nil
        <node :   2239 <=   2274 =>   2611 : rule strut>
        rule    strut   0       nil     nil
        STOP

    while this (presumably) equivalent Plain LuaTeX code:

        \directlua{
            function test(head)
                local last = node.slide(head)
        
                print "START"
                for i=1,3 do
                    print(last)
                    print(
                        node.type(last.id),
                        node.subtypes(last.id)[last.subtype],
                        last.width,
                        last.stretch_order,
                        last.stretch
                    )
        
                    last = last.prev
                end
                print "STOP"
        
                return head
            end
        
            callback.register("pre_linebreak_filter", test)
        }
        
        Hello!
        
        \bye

    produces:

        START
        <node     82 <    298 >    nil : glue 15>
        glue    parfillskip     0       2       65536
        <node    291 <     82 >    298 : penalty 2>
        penalty linepenalty     nil     nil     nil
        <node    284 <    291 >     82 : glyph 0>
        glyph   unset   182045  nil     nil
        STOP

    I'm not sure if this is a doc bug, an engine bug, or if I'm just
    doing something wrong.

3. The LuaTeX/LuaMetaTeX engine manuals say that for node callbacks, you
    can return "true" if you don't need to replace the passed node list.
    This works fine with raw LuaTeX callbacks and the luatexbase
    wrappers, but it doesn't work with the ConTeXt "nodes.tasks" wrapper
    functions.

    This Plain example works:

        \directlua{
            callback.register("pre_linebreak_filter", function ()
                return true
            end)
        }
        
        Hello!
        
        \bye

    But this MkXL example doesn't:

        \startluacode
            function test(head)
                return true
            end
        
            nodes.tasks.appendaction("processors", "after", "test")
        \stopluacode
        
        \starttext
            Hello!
        \stoptext

    I'm not sure if this behaviour is expected or not. Saving the node
    passed to the callback then returning it at the end works just fine,
    but being able to just return "true" would be slightly more
    convenient sometimes.

4. Would it be possible to add a ConTeXt-level interface ("nodes.tasks")
    to the "pre_output_filter" callback? Right now I'm using the
    low-level engine interface ("callback.register"), but this is pretty
    fragile since any format update could block this. Plus, it would be
    more convenient for me if I could register all of the callbacks the
    same way. The way I'm doing it right now seems to work well enough
    though, so this doesn't matter too much.

5. Off-topic, but is there a good way to trace node memory leaks?
    Documents larger than ~1600 pages run out of node memory when I load
    lua-widow-control, so I know that I'm leaking nodes somewhere, but
    it's pretty tricky to trace. Are there any "tricks" to find leaked
    nodes, or do I just need to watch my allocations very carefully?

Sorry if any of these points don't make much sense or have already been
answered elsewhere.

Thanks in advance.
-- Max
    
Versions used for test documents:
     ConTeXt  ver: 2022.04.20 19:18 LMTX  fmt: 2022.5.1  int: english/english

     This is LuaTeX, Version 1.13.2 (TeX Live 2021/W32TeX)


More information about the ntg-context mailing list