[LyX/master] Fix RTL numeral-run wrapper nesting around font/language switches

Udi Fogiel <[email protected]> Tue, 14 Jul 2026 18:49:58 +0000
Newsgroups gmane.editors.lyx.cvs
Message-ID <[email protected]>
commit 2e04158e29c63dc07c1aa97192b621f3688cd4d7
Author: Udi Fogiel <[email protected]>
Date:   Tue Jul 14 21:49:16 2026 +0300

    Fix RTL numeral-run wrapper nesting around font/language switches
    
    The {\beginL ... \endL} wrapper was opened/closed in the wrong spot
    relative to font/language switching, so its closing brace could land
    inside a still-open group instead of closing its own. Move the close
    to fire right after the old font/language closes and before the new
    one opens.
---
 src/Paragraph.cpp | 61 +++++++++++++++++++++++++++++++------------------------
 1 file changed, 35 insertions(+), 26 deletions(-)

diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp
index 0a39810eb3..63f6cbeecd 100644
--- a/src/Paragraph.cpp
+++ b/src/Paragraph.cpp
@@ -3012,6 +3012,25 @@ void Paragraph::latex(BufferParams const & bparams,
 			open_font &= !langClosed;
 		}
 
+		// Do we need to close the RTL numeral-run wrapper? This must
+		// happen after the previous font is closed above (so e.g. a
+		// still-open \textbf{ closes first) but before the next font/
+		// language is opened below (so \endL} closes this run before
+		// a language switch's own \L{/\R{} opens).
+		// Insets (c == META_INSET) are never part of a numeral run.
+		bool const numeral_here = c != META_INSET
+			&& i >= start_pos && (end_pos == -1 || i < end_pos)
+			&& !runparams.pass_thru
+			&& !bparams.useBidiPackage(runparams)
+			&& isRTLNumberRun(i)
+			&& (current_font.language()->lang() == "hebrew"
+			    || current_font.language()->lang() == "farsi"
+			    || current_font.language()->lang() == "arabic_arabi");
+		if (in_numeral_run && !numeral_here) {
+			closeNumeralRun();
+			in_numeral_run = false;
+		}
+
 		// if necessary, close language environment before opening CJK
 		string const running_lang = running_font.language()->babel();
 		string const lang_end_command = lyxrc.language_command_end;
@@ -3121,26 +3140,12 @@ void Paragraph::latex(BufferParams const & bparams,
 			}
 		}
 
-		// Do we need to open or close the RTL numeral-run wrapper? This
-		// must happen after the general font/language open-close above
-		// but before anything writes the character itself,
-		// including simpleTeXBlanks() below for spaces, so that the
-		// wrap correctly brackets just the run's own text.
-		// Insets (c == META_INSET) are never part of a numeral run.
-		bool const numeral_here = c != META_INSET
-			&& i >= start_pos && (end_pos == -1 || i < end_pos)
-			&& !runparams.pass_thru
-			&& !bparams.useBidiPackage(runparams)
-			&& isRTLNumberRun(i)
-			&& (current_font.language()->lang() == "hebrew"
-			    || current_font.language()->lang() == "farsi"
-			    || current_font.language()->lang() == "arabic_arabi");
-		if (numeral_here != in_numeral_run) {
-			if (numeral_here)
-				openNumeralRun();
-			else
-				closeNumeralRun();
-			in_numeral_run = numeral_here;
+		// Open the RTL numeral-run wrapper now, after any font/language
+		// switch above has already written its own output, but still
+		// before the character itself is written below.
+		if (numeral_here && !in_numeral_run) {
+			openNumeralRun();
+			in_numeral_run = true;
 		}
 
 		// FIXME: think about end_pos implementation...
@@ -3297,12 +3302,6 @@ void Paragraph::latex(BufferParams const & bparams,
 		runparams.post_macro = rp.post_macro;
 	}
 
-	// Close a numeral-run wrapper left open at the end of the paragraph
-	if (in_numeral_run) {
-		closeNumeralRun();
-		in_numeral_run = false;
-	}
-
 	// Close wrapper for alien script
 	if (!alien_script.empty()) {
 		os << "}";
@@ -3363,6 +3362,15 @@ void Paragraph::latex(BufferParams const & bparams,
 				basefont, basefont, needPar);
 #endif
 	}
+
+	// Close a numeral-run wrapper left open at the end of the
+	// paragraph, after the font above (so a still-open \textbf{
+	// closes first).
+	if (in_numeral_run) {
+		closeNumeralRun();
+		in_numeral_run = false;
+	}
+
 	if (needPar) {
 		// The \par could not be inserted at the same nesting
 		// level of the font size change, so do it now.
@@ -4489,6 +4497,7 @@ bool isNumberRunOperator(char_type c)
 } // namespace
 
 
+// FIXME: this doesn't stop a run at a font/language switch.
 bool Paragraph::isRTLNumberRun(pos_type pos) const
 {
 	pos_type const psize = size();
-- 
lyx-cvs mailing list
[email protected]
https://lists.lyx.org/mailman/listinfo/lyx-cvs