[NTG-context] upload

Max Chernoff mseven at telus.net
Fri Jul 8 09:40:33 CEST 2022

> 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
         return head

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

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

         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)

         return head

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

         return head

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

         -- 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

(The full implementation is in the module "lua-widow-control" on CTAN, 
TeX Live, and modules.contextgarden.net, or directly at 
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.

-- Max

More information about the ntg-context mailing list