Fix pos-visible-in-window-p under bidi redisplay when lines are truncated.
authorEli Zaretskii <eliz@gnu.org>
Sat, 23 Jul 2011 10:42:24 +0000 (13:42 +0300)
committerEli Zaretskii <eliz@gnu.org>
Sat, 23 Jul 2011 10:42:24 +0000 (13:42 +0300)
 src/xdisp.c (move_it_in_display_line_to): Record the best matching
 position for TO_CHARPOS while scanning the line, and restore it on
 exit if none of the characters scanned was an exact match.  Fixes
 vertical-motion and pos-visible-in-window-p when exact match is
 impossible due to invisible text, and the lines are truncated.

src/ChangeLog
src/xdisp.c

index c03acbc..dd5a1fb 100644 (file)
@@ -1,3 +1,11 @@
+2011-07-23  Eli Zaretskii  <eliz@gnu.org>
+
+       * xdisp.c (move_it_in_display_line_to): Record the best matching
+       position for TO_CHARPOS while scanning the line, and restore it on
+       exit if none of the characters scanned was an exact match.  Fixes
+       vertical-motion and pos-visible-in-window-p when exact match is
+       impossible due to invisible text, and the lines are truncated.
+
 2011-07-22  Eli Zaretskii  <eliz@gnu.org>
 
        * xdisp.c (compute_stop_pos_backwards): New function.
index 52b1f48..a5eb2aa 100644 (file)
@@ -7620,8 +7620,9 @@ move_it_in_display_line_to (struct it *it,
 {
   enum move_it_result result = MOVE_UNDEFINED;
   struct glyph_row *saved_glyph_row;
-  struct it wrap_it, atpos_it, atx_it;
+  struct it wrap_it, atpos_it, atx_it, ppos_it;
   void *wrap_data = NULL, *atpos_data = NULL, *atx_data = NULL;
+  void *ppos_data = NULL;
   int may_wrap = 0;
   enum it_method prev_method = it->method;
   EMACS_INT prev_pos = IT_CHARPOS (*it);
@@ -7640,6 +7641,19 @@ move_it_in_display_line_to (struct it *it,
   atpos_it.sp = -1;
   atx_it.sp = -1;
 
+  /* Use ppos_it under bidi reordering to save a copy of IT for the
+     position > CHARPOS that is the closest to CHARPOS.  We restore
+     that position in IT when we have scanned the entire display line
+     without finding a match for CHARPOS and all the character
+     positions are greater than CHARPOS.  */
+  if (it->bidi_p)
+    {
+      SAVE_IT (ppos_it, *it, ppos_data);
+      SET_TEXT_POS (ppos_it.current.pos, ZV, ZV_BYTE);
+      if ((op & MOVE_TO_POS) && IT_CHARPOS (*it) >= to_charpos)
+       SAVE_IT (ppos_it, *it, ppos_data);
+    }
+
 #define BUFFER_POS_REACHED_P()                                 \
   ((op & MOVE_TO_POS) != 0                                     \
    && BUFFERP (it->object)                                     \
@@ -7765,6 +7779,11 @@ move_it_in_display_line_to (struct it *it,
          if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos))
            SET_TEXT_POS (this_line_min_pos,
                          IT_CHARPOS (*it), IT_BYTEPOS (*it));
+         if (it->bidi_p
+             && (op & MOVE_TO_POS)
+             && IT_CHARPOS (*it) > to_charpos
+             && IT_CHARPOS (*it) < IT_CHARPOS (ppos_it))
+           SAVE_IT (ppos_it, *it, ppos_data);
          continue;
        }
 
@@ -7975,7 +7994,11 @@ move_it_in_display_line_to (struct it *it,
          if ((op & MOVE_TO_POS) != 0
              && !saw_smaller_pos
              && IT_CHARPOS (*it) > to_charpos)
-           result = MOVE_POS_MATCH_OR_ZV;
+           {
+             result = MOVE_POS_MATCH_OR_ZV;
+             if (it->bidi_p && IT_CHARPOS (ppos_it) < ZV)
+               RESTORE_IT (it, &ppos_it, ppos_data);
+           }
          else
            result = MOVE_NEWLINE_OR_CR;
          break;
@@ -7991,6 +8014,11 @@ move_it_in_display_line_to (struct it *it,
        SET_TEXT_POS (this_line_min_pos, IT_CHARPOS (*it), IT_BYTEPOS (*it));
       if (IT_CHARPOS (*it) < to_charpos)
        saw_smaller_pos = 1;
+      if (it->bidi_p
+         && (op & MOVE_TO_POS)
+         && IT_CHARPOS (*it) >= to_charpos
+         && IT_CHARPOS (*it) < IT_CHARPOS (ppos_it))
+       SAVE_IT (ppos_it, *it, ppos_data);
 
       /* Stop if lines are truncated and IT's current x-position is
         past the right edge of the window now.  */
@@ -8000,10 +8028,21 @@ move_it_in_display_line_to (struct it *it,
          if (!FRAME_WINDOW_P (it->f)
              || IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
            {
-             if (!get_next_display_element (it)
-                 || BUFFER_POS_REACHED_P ())
+             int at_eob_p = 0;
+
+             if ((at_eob_p = !get_next_display_element (it))
+                 || BUFFER_POS_REACHED_P ()
+                 /* If we are past TO_CHARPOS, but never saw any
+                    character positions smaller than TO_CHARPOS,
+                    return MOVE_POS_MATCH_OR_ZV, like the
+                    unidirectional display did.  */
+                 || ((op & MOVE_TO_POS) != 0
+                     && !saw_smaller_pos
+                     && IT_CHARPOS (*it) > to_charpos))
                {
                  result = MOVE_POS_MATCH_OR_ZV;
+                 if (it->bidi_p && !at_eob_p && IT_CHARPOS (ppos_it) < ZV)
+                   RESTORE_IT (it, &ppos_it, ppos_data);
                  break;
                }
              if (ITERATOR_AT_END_OF_LINE_P (it))
@@ -8012,6 +8051,15 @@ move_it_in_display_line_to (struct it *it,
                  break;
                }
            }
+         else if ((op & MOVE_TO_POS) != 0
+                  && !saw_smaller_pos
+                  && IT_CHARPOS (*it) > to_charpos)
+           {
+             result = MOVE_POS_MATCH_OR_ZV;
+             if (it->bidi_p && IT_CHARPOS (ppos_it) < ZV)
+               RESTORE_IT (it, &ppos_it, ppos_data);
+             break;
+           }
          result = MOVE_LINE_TRUNCATED;
          break;
        }
@@ -8035,6 +8083,8 @@ move_it_in_display_line_to (struct it *it,
     xfree (atx_data);
   if (wrap_data)
     xfree (wrap_data);
+  if (ppos_data)
+    xfree (ppos_data);
 
   /* Restore the iterator settings altered at the beginning of this
      function.  */