EDIT: A summary of the possible answers is given below.
In my current LuaTeX project I am using user-defined whatsit nodes to transfer information between the different stages of a LuaTeX run. On this topic, the manual states the following:
The LUATEX engine will simply step over such whatsits without ever looking at the contents.
My interpretation of this is, that I can add user-defined whatsit nodes and nothing should change in the actual processing of the node lists (i.e. the document should look the same with or without them).
I am encountering the following problem, however. In my case, a certain paragraph, let's call it P, would overflow the page and is moved to the next page. Accordingly, the white space between the remaining paragraphs on the previous page is stretched to fill the page (resp. column).
If I add a user-defined whatsit node as first node of P, the content of the paragraph is moved to the next page (as before), BUT the whatsit node STAYS on the previous page. Subsequently, whitespace is added at the bottom of the last column on the previous page, the ensure correct inter-paragraph spacing.
In my opinion, this is not the correct behavior and I have the following two questions:
- Can I force the whatsit node to stay with its paragraph? (But preferably not by packing it into additional horizontal or vertical lists.)
- If not, can I at least suppress the generation of inter-paragraph white space at the bottom of the column?
Additional Information
An illustration of how it looks like:
Without whatsit With whatsit
Page n |text | Page n |text |
|text | | |
| | |text |
|text | |text | Incorrect
|text__________| |______________| <- inter-paragraph
glue
______________ ______________
Page n+1|text of P | Page n+1|text of P |
|text of P | |text of P |
| | | |
|text | |text |
In detail I do the following:
With a post_linebreak_filter
callback, I add my user-defined whatsit node as new head of the vertical paragraph list (by using node.insert_before(head, head, my_whatsit)
). This node is still visible at the shipout stage, where it gets integrated into the vertical list of the current column.
In the case of a paragraph that gets moved to the next page (as in my example above), the whatsit node can be found in the vertical column list of page n
, while the rest of the paragraph is moved to page n+1
. I would need it to stay with the paragraph.
Answers
Pure LaTeX
The answer of Dan explains how to dock the whatsit to the paragraph by the use of \penalty
and \nobreak
.
LuaTeX
David Carlisle and topskip gave two different ways to achieve this behavior by altering the insertion location of the whatsit node in the post_linebreak_filter
callback.
topskip's solution recursively searches for the first hlist in the paragraph and inserts the whatsit node into it.
David's approach aims to insert the whatsit node after the first node (usually a glue node) and thus anchors it to the paragraph. In my case this can be achieved by simply changing node.insert_before(head, head, my_whatsit)
to node.insert_after(...)
. This keeps the whatsit node in the same vlist as the paragraph's hlists, which is the reason why I selected this as my solution. As David already mentioned, it would be better to insert the whatsit node after all discardable nodes (and not just after the first one).