This is because you need to pass a list that conforms to what the builder expects and the callback that you use doesn't do that for you (after all, it also gets hbox content).

Isn't "processors/after" the same as "pre_linebreak_filter"? I thought that only "hpack_filter" gets \hbox content? Anyways, my actual function has this guard at the very start:

if (head.id ~= par_id and context) or -- Ensure that we were actually given a par
        status.output_active or -- Don't run during the output routine
        tex.nest.ptr > 1 -- Don't run inside boxes
    then
        return head
    end

so I think that I'm only processing actual top-level paragraphs here.

There is no 'callback sequence handler' for the par builder (currently i see no need for it, also given the extra overhead involved) but this what what you can do:

\startluacode
     function builders.paragraphs.constructors.methods.preroll_a(head)
         local result, info = tex.linebreak(head)
         tex.prevdepth = info.prevdepth
         tex.prevgraf = info.prevgraf
         return result
     end
     function builders.paragraphs.constructors.methods.preroll_b(head)
         local result, info = tex.linebreak(nodes.nuts.copylist(head))
         inspect(info)
         return true
     end
\stopluacode

\defineparbuilder[preroll_a]
\defineparbuilder[preroll_b]

\starttext
     \setmainparbuilder[default]   \input tufte \par \input tufte \page
     \setmainparbuilder[preroll_a] \input tufte \par \input tufte \page
     \setmainparbuilder[preroll_b] \input tufte \par \input tufte \page
\stoptext

I think that that code is for replacing the linebreaker entirely, like with using "linebreak_filter"? My goal isn't to replace the linebreaker; I just want to be able to inspect the paragraph before it is broken, without modifying anything.

What I'm trying to do *very* roughly looks like the following:

    paragraphs = {}
    attribute = 1234

    function pre_linebreak_filter(head)
        if head.id ~= node.id"par" then
            return head
        end

        local nat_node, nat_info = tex.linebreak(node.copylist(head))
        node.freelist(nat_node)

        local long_node, long_info = tex.linebreak(
            node.copylist(head), {looseness = 1}
        )

        if long_info.prevgraf == nat_info.prevgraf + 1 then
            table.insert(paragraphs, long_node)
        end

        return head
    end

    function post_linebreak_filter(head)
        node.setattribute(head, attribute, #paragraphs)
        node.setattribute(node.slide(head), attribute, #paragraphs)

        return head
    end

    function pre_output_filter(head)
        if tex.outputpenalty ~= tex.widowpenalty then
            return head
        end

        -- Pick a paragraph from `paragraphs` somehow

        -- Replace that paragraph on the page with the one
        -- from `paragraphs`

        -- Move the last line of the page onto the top of
        -- tex.lists.contributehead

        return head
    end

(The full implementation is in the module "lua-widow-control" on CTAN, TeX Live, and modules.contextgarden.net, or directly at "https://github.com/gucci-on-fleek/lua-widow-control/blob/master/source/lua-widow-control.lua";. It's pretty long though, so I'm just trying to summarize here.)

This works pretty well with Plain LuaTeX, LuaLaTeX, OpTeX, MkIV, and MkXL before the latest upload, but something broke with the latest upload in MkXL. I understand that I'm mucking around with volatile interfaces, and I have no problem making a bunch of changes whenever the engine/format changes; the problem is that I'm not too sure what changed in the engine, so I don't know what I need to change in my code.

On the to do is a to add a 'prepare' helper that adds the mandate nodes (par fillers etc)

Maybe that's all that I need? If that's the case, I have no problem coding my own "prepare helper" if you think that it'll be awhile before you get around to it; the problem is that I'm not entirely sure what nodes I would need to add. These new nodes aren't added until after "pre_linebreak_filter", and they're gone after the linebreaker runs, so I can't inspect a "regular" paragraph to see where these nodes belong.

but even then one has to be careful where linebreak hackery is applied.

Oh yes, I'm well aware :) Earlier versions of my module would silently eat entire paragraphs, which was very not good. Luckily that problem is fixed now.

And finally, thanks for all your work with LuaMetaTeX. This new engine is quite nice to work with and has some pretty cool new features.

Thanks,
-- Max
___________________________________________________________________________________
If your question is of interest to others as well, please add an entry to the 
Wiki!

maillist : ntg-context@ntg.nl / https://www.ntg.nl/mailman/listinfo/ntg-context
webpage  : https://www.pragma-ade.nl / http://context.aanhet.net
archive  : https://bitbucket.org/phg/context-mirror/commits/
wiki     : https://contextgarden.net
___________________________________________________________________________________

Reply via email to