[Dev-luatex] LuaTeX doesn't discard empty paragraphs when textdir is used

Marcel Fabian Krüger tex at 2krueger.de
Mon Aug 2 17:52:33 CEST 2021


On Thu, Jul 29, 2021 at 09:54:20AM +0200, luigi scarso wrote:
> On Mon, Jun 21, 2021 at 5:03 PM Marcel Krüger <tex at 2krueger.de> wrote:
> 
> > Hi,
> >
> > consider the following plain LuaTeX document:
> >
> > \textdir TRT
> > \noindent\par
> > \bye
> >
> > without the `\textdir TRT` line or with `\textdir TLT`, this would lead
> > to "warning  (pdf backend): no pages of output.", but with the non
> > default "\textdir", it creates an empty (except for the page number) page
> > instead.
> >
> > This can be avoided by setting \pardir too:
> >
> > \textdir TRT\pardir TRT
> > \noindent\par
> > \bye
> >
> > again produces no output, but adding a group around it reintroduces the
> > issue:
> >
> > \begingroup
> > \textdir TRT\pardir TRT
> > \noindent\par
> > \endgroup
> > \bye
> >
> > leads to an empty page.
> >
> > Of course similar things happen not only for otherwise empty documents:
> > Instead of empty paragraphs disappearing, they add empty lines.
> >
> > Together, this is not only inconsistent with other engines which always
> > discard empty paragraphs, but also leads to hard to predict behavior
> > (especially for users who are not familiar with the implementation of
> > LuaTeX's directional system), so I think it would be great if LuaTeX
> > could always remove such empty paragraphs.
> >
> >
> (sorry for the delay)
> Do you have  a patch to propose  ?

I attached a patch which adds a \emptyparmode parameter with three
possible states:

  - 0: Never ignore empty paragraphs. Not sure if this is useful, but it
    seemed like an obvious thing to add.
  - 1: The default: A paragraph is empty is it contains at most one
    node. This is the old behavior.
  - 2: A paragraph is empty if it only contains local_par and dir nodes.
    This is what I would consider the expected behavior.

Best regards,
Marcel
-------------- next part --------------
>From 959ea0d0ae5a9a8d96dc5ec0a5c65a5912be3f39 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcel=20Fabian=20Kr=C3=BCger?= <tex at 2krueger.de>
Date: Mon, 2 Aug 2021 17:43:00 +0200
Subject: [PATCH 2/2] Add parameter to control which paragraphs are empty

---
 source/texk/web2c/luatexdir/tex/commands.c    |  1 +
 source/texk/web2c/luatexdir/tex/equivalents.h |  4 ++-
 source/texk/web2c/luatexdir/tex/maincontrol.c | 34 +++++++++++++++++--
 3 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/source/texk/web2c/luatexdir/tex/commands.c b/source/texk/web2c/luatexdir/tex/commands.c
index 576306b35..48c95800f 100644
--- a/source/texk/web2c/luatexdir/tex/commands.c
+++ b/source/texk/web2c/luatexdir/tex/commands.c
@@ -178,6 +178,7 @@ void initialize_commands(void)
     primitive_luatex("glyphdimensionsmode", assign_int_cmd, int_base + glyph_dimensions_code, int_base);
     primitive_luatex("mathdefaultsmode", assign_int_cmd, int_base + math_defaults_mode_code, int_base);
     primitive_luatex("discretionaryligaturemode", assign_int_cmd, int_base + discretionary_ligature_mode_code, int_base);
+    primitive_luatex("emptyparmode", assign_int_cmd, int_base + empty_par_mode_code, int_base);
 
     /*tex
 
diff --git a/source/texk/web2c/luatexdir/tex/equivalents.h b/source/texk/web2c/luatexdir/tex/equivalents.h
index 459c2cb01..8d4718183 100644
--- a/source/texk/web2c/luatexdir/tex/equivalents.h
+++ b/source/texk/web2c/luatexdir/tex/equivalents.h
@@ -311,8 +311,9 @@ the |number_regs| \.{\\dimen} registers.
 #  define glyph_dimensions_code 118
 #  define math_defaults_mode_code 119                                   /* > 0 : latex preferences */
 #  define discretionary_ligature_mode_code 120
+#  define empty_par_mode_code 121
 
-#  define math_option_code 121
+#  define math_option_code 122
 
 #  define mathoption_int_base_code (math_option_code+1)                 /* one reserve */
 #  define mathoption_int_last_code (mathoption_int_base_code+8)
@@ -807,6 +808,7 @@ extern halfword last_cs_name;
 #define compound_hyphen_mode_par           int_par(compound_hyphen_mode_code)
 #define break_after_dir_mode_par           int_par(break_after_dir_mode_code)
 #define exception_penalty_par              int_par(exception_penalty_code)
+#define empty_par_mode_par                 int_par(empty_par_mode_code)
 
 #define cur_lang_par                       int_par(cur_lang_code)
 #define cur_font_par                       equiv(cur_font_loc)
diff --git a/source/texk/web2c/luatexdir/tex/maincontrol.c b/source/texk/web2c/luatexdir/tex/maincontrol.c
index 22f601ba2..bfec24294 100644
--- a/source/texk/web2c/luatexdir/tex/maincontrol.c
+++ b/source/texk/web2c/luatexdir/tex/maincontrol.c
@@ -1876,10 +1876,37 @@ displays.
 void end_graf(int line_break_context)
 {
     if (mode == hmode) {
-        if ((head == tail) || (vlink(head) == tail)) {
-            if (vlink(head) == tail)
-                flush_node(vlink(head));
+        boolean ignore;
+        if (empty_par_mode_par <= 0)
+            ignore = false;
+        else if (empty_par_mode_par == 1)
+            ignore = head == tail || vlink(head) == tail;
+        else {
+            ignore = true;
+            if (head != tail) {
+                halfword cur = head;
+                do {
+                    cur = vlink(cur);
+                    halfword t = type(cur);
+                    if (t != local_par_node && t != dir_node) {
+                        ignore = false;
+                        break;
+                    }
+                } while(cur != tail);
+            }
+        }
+        if (ignore) {
             /*tex |null| paragraphs are ignored, all contain a |local_paragraph| node */
+            if (head != tail) {
+                halfword cur = vlink(head);
+                while (true) {
+                    halfword next = vlink(cur);
+                    flush_node(cur);
+                    if (cur == tail)
+                        break;
+                    cur = next;
+                }
+            }
             pop_nest();
         } else {
             line_break(false, line_break_context);
@@ -4231,6 +4258,7 @@ void initialize(void)
         px_dimen_par = one_bp;
         math_eqno_gap_step_par = 1000 ;
         math_flatten_mode_par = 1; /* ord */
+        empty_par_mode_par = 1;
         cs_text(frozen_protection) = maketexstring("inaccessible");
         format_ident = maketexstring(" (INITEX)");
         cs_text(end_write) = maketexstring("endwrite");
-- 
2.32.0

-------------- next part --------------
>From 959ea0d0ae5a9a8d96dc5ec0a5c65a5912be3f39 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcel=20Fabian=20Kr=C3=BCger?= <tex at 2krueger.de>
Date: Mon, 2 Aug 2021 17:43:00 +0200
Subject: [PATCH 2/2] Add parameter to control which paragraphs are empty

---
 source/texk/web2c/luatexdir/tex/commands.c    |  1 +
 source/texk/web2c/luatexdir/tex/equivalents.h |  4 ++-
 source/texk/web2c/luatexdir/tex/maincontrol.c | 34 +++++++++++++++++--
 3 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/source/texk/web2c/luatexdir/tex/commands.c b/source/texk/web2c/luatexdir/tex/commands.c
index 576306b35..48c95800f 100644
--- a/source/texk/web2c/luatexdir/tex/commands.c
+++ b/source/texk/web2c/luatexdir/tex/commands.c
@@ -178,6 +178,7 @@ void initialize_commands(void)
     primitive_luatex("glyphdimensionsmode", assign_int_cmd, int_base + glyph_dimensions_code, int_base);
     primitive_luatex("mathdefaultsmode", assign_int_cmd, int_base + math_defaults_mode_code, int_base);
     primitive_luatex("discretionaryligaturemode", assign_int_cmd, int_base + discretionary_ligature_mode_code, int_base);
+    primitive_luatex("emptyparmode", assign_int_cmd, int_base + empty_par_mode_code, int_base);
 
     /*tex
 
diff --git a/source/texk/web2c/luatexdir/tex/equivalents.h b/source/texk/web2c/luatexdir/tex/equivalents.h
index 459c2cb01..8d4718183 100644
--- a/source/texk/web2c/luatexdir/tex/equivalents.h
+++ b/source/texk/web2c/luatexdir/tex/equivalents.h
@@ -311,8 +311,9 @@ the |number_regs| \.{\\dimen} registers.
 #  define glyph_dimensions_code 118
 #  define math_defaults_mode_code 119                                   /* > 0 : latex preferences */
 #  define discretionary_ligature_mode_code 120
+#  define empty_par_mode_code 121
 
-#  define math_option_code 121
+#  define math_option_code 122
 
 #  define mathoption_int_base_code (math_option_code+1)                 /* one reserve */
 #  define mathoption_int_last_code (mathoption_int_base_code+8)
@@ -807,6 +808,7 @@ extern halfword last_cs_name;
 #define compound_hyphen_mode_par           int_par(compound_hyphen_mode_code)
 #define break_after_dir_mode_par           int_par(break_after_dir_mode_code)
 #define exception_penalty_par              int_par(exception_penalty_code)
+#define empty_par_mode_par                 int_par(empty_par_mode_code)
 
 #define cur_lang_par                       int_par(cur_lang_code)
 #define cur_font_par                       equiv(cur_font_loc)
diff --git a/source/texk/web2c/luatexdir/tex/maincontrol.c b/source/texk/web2c/luatexdir/tex/maincontrol.c
index 22f601ba2..bfec24294 100644
--- a/source/texk/web2c/luatexdir/tex/maincontrol.c
+++ b/source/texk/web2c/luatexdir/tex/maincontrol.c
@@ -1876,10 +1876,37 @@ displays.
 void end_graf(int line_break_context)
 {
     if (mode == hmode) {
-        if ((head == tail) || (vlink(head) == tail)) {
-            if (vlink(head) == tail)
-                flush_node(vlink(head));
+        boolean ignore;
+        if (empty_par_mode_par <= 0)
+            ignore = false;
+        else if (empty_par_mode_par == 1)
+            ignore = head == tail || vlink(head) == tail;
+        else {
+            ignore = true;
+            if (head != tail) {
+                halfword cur = head;
+                do {
+                    cur = vlink(cur);
+                    halfword t = type(cur);
+                    if (t != local_par_node && t != dir_node) {
+                        ignore = false;
+                        break;
+                    }
+                } while(cur != tail);
+            }
+        }
+        if (ignore) {
             /*tex |null| paragraphs are ignored, all contain a |local_paragraph| node */
+            if (head != tail) {
+                halfword cur = vlink(head);
+                while (true) {
+                    halfword next = vlink(cur);
+                    flush_node(cur);
+                    if (cur == tail)
+                        break;
+                    cur = next;
+                }
+            }
             pop_nest();
         } else {
             line_break(false, line_break_context);
@@ -4231,6 +4258,7 @@ void initialize(void)
         px_dimen_par = one_bp;
         math_eqno_gap_step_par = 1000 ;
         math_flatten_mode_par = 1; /* ord */
+        empty_par_mode_par = 1;
         cs_text(frozen_protection) = maketexstring("inaccessible");
         format_ident = maketexstring(" (INITEX)");
         cs_text(end_write) = maketexstring("endwrite");
-- 
2.32.0



More information about the dev-luatex mailing list