> Also, for a quite complex project, I need to assign different penalties > to discretionaries of the same paragraph. I've asked on [3], but it > doesn't seem possible with PdfTeX. Is there currently a way to do so in > LuaTeX (by hacking the nodes)? If not, would it be doable, like by > adding a 'penalty' field to disc nodes, with \hyphenpenalty (or any > other relevant value) assigned to it be default, but changeable?
Attached is a patch for this feature. It is very small and non-intrusive: it basically just sets a new "penalty" field to disc nodes, always set to 0. If the field value is 0 while line breaking, it is ignored and the penalty associated to the disc is hyphenpenalty or exhyphenpenalty. But if the field value is non-zero, then line breaking uses it as the penalty associated to the disc. The value needs to be set in a pre_linebreak_filter callback. Attached is also a small Plain TeX example demonstrating the new feature. It would be a huge help for me as it unlocks totally new possibilities. What do you think? Thank you, -- Elie
Index: manual/luatexref-t.tex
===================================================================
--- manual/luatexref-t.tex (révision 5187)
+++ manual/luatexref-t.tex (copie de travail)
@@ -9516,10 +9516,16 @@
\NC pre \NC \syntax{<node>} \NC pointer to the pre|-|break text\NC\NR
\NC post \NC \syntax{<node>} \NC pointer to the post|-|break text\NC\NR
\NC replace \NC \syntax{<node>} \NC pointer to the no|-|break text\NC\NR
+\NC penalty \NC number \NC penalty associated with the discretionary\NC\NR
\stoptabulate
The subtype numbers~4 and~5 belong to the \quote{of-f-ice} explanation given elsewhere.
+The penalty field is always 0 by default. When it is 0, line breaking will use
+hyphenpenalty or exhyphenpenalty (default behaviour). When it is set to a
+non-zero value, line breaking will use the specified value. You can only change
+this field on the Lua side.
+
A warning: never assign a node list to the pre, post or replace field
unless you are sure its internal link structure is correct, otherwise
an error may be result.
Index: source/texk/web2c/luatexdir/lua/lnodelib.c
===================================================================
--- source/texk/web2c/luatexdir/lua/lnodelib.c (révision 5187)
+++ source/texk/web2c/luatexdir/lua/lnodelib.c (copie de travail)
@@ -2853,6 +2853,8 @@
fast_metatable_or_nil(vlink(post_break(n)));
} else if (lua_key_eq(s, replace)) {
fast_metatable_or_nil(vlink(no_break(n)));
+ } else if (lua_key_eq(s, penalty)) {
+ lua_pushnumber(L, disc_penalty(n));
} else {
lua_pushnil(L);
}
@@ -3603,6 +3605,8 @@
nodelib_pushdirect_or_nil(vlink(post_break(n)));
} else if (lua_key_eq(s, replace)) {
nodelib_pushdirect_or_nil(vlink(no_break(n)));
+ } else if (lua_key_eq(s, penalty)) {
+ lua_pushnumber(L, disc_penalty(n));
} else {
lua_pushnil(L);
}
@@ -4798,6 +4802,8 @@
set_disc_field(post_break(n), nodelib_getlist(L, 3));
} else if (lua_key_eq(s, replace)) {
set_disc_field(no_break(n), nodelib_getlist(L, 3));
+ } else if (lua_key_eq(s, penalty)) {
+ disc_penalty(n) = (halfword) lua_tointeger(L, 3);
} else {
return nodelib_cantset(L, n, s);
}
@@ -5544,6 +5550,8 @@
set_disc_field(post_break(n), nodelib_popdirect(3));
} else if (lua_key_eq(s, replace)) {
set_disc_field(no_break(n), nodelib_popdirect(3));
+ } else if (lua_key_eq(s, penalty)) {
+ disc_penalty(n) = (halfword) lua_tointeger(L, 3);
} else {
return nodelib_cantset(L, n, s);
}
Index: source/texk/web2c/luatexdir/tex/linebreak.w
===================================================================
--- source/texk/web2c/luatexdir/tex/linebreak.w (révision 5187)
+++ source/texk/web2c/luatexdir/tex/linebreak.w (copie de travail)
@@ -1950,10 +1950,12 @@
int actual_penalty = hyphen_penalty;
if (subtype(cur_p) == automatic_disc)
actual_penalty = ex_hyphen_penalty;
+ if (disc_penalty(cur_p) != 0)
+ actual_penalty = (int) disc_penalty(cur_p);
s = vlink_pre_break(cur_p);
do_one_seven_eight(reset_disc_width);
if (s == null) { /* trivial pre-break */
Index: source/texk/web2c/luatexdir/tex/texnodes.h
===================================================================
--- source/texk/web2c/luatexdir/tex/texnodes.h (révision 5187)
+++ source/texk/web2c/luatexdir/tex/texnodes.h (copie de travail)
@@ -151,7 +151,7 @@
pointers are not really needed (8 instead of 10).
*/
-# define disc_node_size 10
+# define disc_node_size 11
typedef enum {
discretionary_disc = 0,
@@ -162,13 +162,14 @@
select_disc, /* second of a duo of syllable_discs */
} discretionary_types;
-# define pre_break_head(a) ((a)+4)
-# define post_break_head(a) ((a)+6)
-# define no_break_head(a) ((a)+8)
+# define pre_break_head(a) ((a)+5)
+# define post_break_head(a) ((a)+7)
+# define no_break_head(a) ((a)+9)
-# define pre_break(a) vinfo((a)+2)
-# define post_break(a) vlink((a)+2)
-# define no_break(a) vlink((a)+3)
+# define disc_penalty(a) vlink((a)+2)
+# define pre_break(a) vinfo((a)+3)
+# define post_break(a) vlink((a)+3)
+# define no_break(a) vlink((a)+4)
# define tlink llink
# define vlink_pre_break(a) vlink(pre_break_head(a))
Index: source/texk/web2c/luatexdir/tex/texnodes.w
===================================================================
--- source/texk/web2c/luatexdir/tex/texnodes.w (révision 5187)
+++ source/texk/web2c/luatexdir/tex/texnodes.w (copie de travail)
@@ -3082,6 +3082,8 @@
/* The |post_break| list of a discretionary node is indicated by a prefixed
`\.{\char'174}' instead of the `\..' before the |pre_break| list. */
tprint_esc("discretionary");
+ print_int(disc_penalty(p));
+ print_char('|');
if (vlink(no_break(p)) != null) {
tprint(" replacing ");
node_list_display(vlink(no_break(p)));
@@ -3479,6 +3481,7 @@
{ /* creates an empty |disc_node| */
halfword p; /* the new node */
p = new_node(disc_node, 0);
+ disc_penalty(p) = 0;
return p;
}
mwe.tex
Description: TeX document
