]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix display of mode-line with bidi formatting controls
authorEli Zaretskii <eliz@gnu.org>
Sun, 18 Jul 2021 14:27:23 +0000 (17:27 +0300)
committerEli Zaretskii <eliz@gnu.org>
Sun, 18 Jul 2021 14:27:23 +0000 (17:27 +0300)
* src/xdisp.c (face_before_or_after_it_pos): Reimplement the bidi
iteration to find the character after the current in visual order.
(Bug#49562)

src/xdisp.c

index 8f4dfa5430cf0ce6f47abf1a712956e28b0d7868..50ab2f8e05125087bc8a2521c3896693e00df41f 100644 (file)
@@ -4557,11 +4557,13 @@ face_before_or_after_it_pos (struct it *it, bool before_p)
       ptrdiff_t bufpos, charpos;
       int base_face_id;
 
-      /* No face change past the end of the string (for the case
-        we are padding with spaces).  No face change before the
-        string start.  */
+      /* No face change past the end of the string (for the case we
+        are padding with spaces).  No face change before the string
+        start.  Ignore face changes before the first visible
+        character on this display line.  */
       if (IT_STRING_CHARPOS (*it) >= SCHARS (it->string)
-         || (IT_STRING_CHARPOS (*it) == 0 && before_p))
+         || (IT_STRING_CHARPOS (*it) == 0 && before_p)
+         || it->current_x <= it->first_visible_x)
        return it->face_id;
 
       if (!it->bidi_p)
@@ -4580,51 +4582,47 @@ face_before_or_after_it_pos (struct it *it, bool before_p)
        }
       else
        {
-         if (before_p)
-           {
-             /* With bidi iteration, the character before the current
-                in the visual order cannot be found by simple
-                iteration, because "reverse" reordering is not
-                supported.  Instead, we need to start from the string
-                beginning and go all the way to the current string
-                position, remembering the previous position.  */
-             /* Ignore face changes before the first visible
-                character on this display line.  */
-             if (it->current_x <= it->first_visible_x)
-               return it->face_id;
-             SAVE_IT (it_copy, *it, it_copy_data);
-             IT_STRING_CHARPOS (it_copy) = 0;
-             bidi_init_it (0, 0, FRAME_WINDOW_P (it_copy.f), &it_copy.bidi_it);
+         /* With bidi iteration, the character before the current in
+            the visual order cannot be found by simple iteration,
+            because "reverse" reordering is not supported.  Instead,
+            we need to start from the string beginning and go all the
+            way to the current string position, remembering the
+            visually-previous position.  We need to start from the
+            string beginning for the character after the current as
+            well, since the iterator state in IT may have been
+            pushed, and the bidi cache is no longer coherent with the
+            string's text.  */
+         SAVE_IT (it_copy, *it, it_copy_data);
+         IT_STRING_CHARPOS (it_copy) = 0;
+         bidi_init_it (0, 0, FRAME_WINDOW_P (it_copy.f), &it_copy.bidi_it);
 
-             do
-               {
-                 charpos = IT_STRING_CHARPOS (it_copy);
-                 if (charpos >= SCHARS (it->string))
-                   break;
-                 bidi_move_to_visually_next (&it_copy.bidi_it);
-               }
-             while (IT_STRING_CHARPOS (it_copy) != IT_STRING_CHARPOS (*it));
-
-             RESTORE_IT (it, it, it_copy_data);
+         do
+           {
+             charpos = it_copy.bidi_it.charpos;
+             if (charpos >= SCHARS (it->string))
+               break;
+             bidi_move_to_visually_next (&it_copy.bidi_it);
            }
-         else
+         while (it_copy.bidi_it.charpos != IT_STRING_CHARPOS (*it));
+
+         if (!before_p)
            {
              /* Set charpos to the string position of the character
                 that comes after IT's current position in the visual
                 order.  */
              int n = (it->what == IT_COMPOSITION ? it->cmp_it.nchars : 1);
-
-             it_copy = *it;
-             /* If this is the first display element,
+             /* If this is the first string character,
                 bidi_move_to_visually_next will deliver character at
                 current position without moving, so we need to enlarge N.  */
-             if (it->bidi_it.first_elt)
+             if (it_copy.bidi_it.first_elt)
                n++;
              while (n--)
                bidi_move_to_visually_next (&it_copy.bidi_it);
 
              charpos = it_copy.bidi_it.charpos;
            }
+
+         RESTORE_IT (it, it, it_copy_data);
        }
       eassert (0 <= charpos && charpos <= SCHARS (it->string));