]> git.eshelyaron.com Git - emacs.git/commitdiff
Continue work on cursor movement in continued lines.
authorEli Zaretskii <eliz@gnu.org>
Sat, 13 Mar 2010 16:38:01 +0000 (11:38 -0500)
committerEli Zaretskii <eliz@gnu.org>
Sat, 13 Mar 2010 16:38:01 +0000 (11:38 -0500)
 xdisp.c (try_cursor_movement): Give up if rows are
 bidi-reordered and point moved backwards.  Examine all the
 candidate rows that occlude point, to return the best match.
 (row_containing_pos): With bidi-reordered rows, don't return the
 first one that occludes point; rather, examine all candidates and
 return the best match, with he glyph that's closest to point.
 (display_line): When looking for min position, don't consider
 negative values of glyph->charpos.  (Fixes a crash with "C-x 3" at
 ZV.)  Record the position after EOL in it->eol_pos, and use it to
 set end_pos of the last row produced for a continued line.  Fix
 the condition for passing candidate rows to set_cursor_from_row:
 check ends_at_zv_p flag of the best candidate row, not of the
 current row.
 dispextern.h (struct it): New member eol_pos.
 .gdbinit (prowlims): Display the ends_at_zv_p flag.

src/.gdbinit
src/ChangeLog.bidi
src/dispextern.h
src/xdisp.c

index 659bc870710153ece73c42c99367410f3b641923..b959baae8f3f86681273665c149ed00500371041 100644 (file)
@@ -614,7 +614,7 @@ Pretty print all glyphs in it->glyph_row.
 end
 
 define prowlims
-  printf "start=%d,end=%d,reversed=%d,cont=%d\n", $arg0->start.pos.charpos, $arg0->end.pos.charpos, $arg0->reversed_p, $arg0->continued_p
+  printf "start=%d,end=%d,reversed=%d,cont=%d,at_zv=%d\n", $arg0->start.pos.charpos, $arg0->end.pos.charpos, $arg0->reversed_p, $arg0->continued_p, $arg0->ends_at_zv_p
 end
 document prowlims
 Print important attributes of a glyph_row structure.
index 7f7eb0808d23147fea269923b0924fca08afe908..8f96779196d0d5ab5609ca67807ee70a887d09bc 100644 (file)
@@ -1,3 +1,23 @@
+2010-03-13  Eli Zaretskii  <eliz@gnu.org>
+
+       * xdisp.c (try_cursor_movement): Give up if rows are
+       bidi-reordered and point moved backwards.  Examine all the
+       candidate rows that occlude point, to return the best match.
+       (row_containing_pos): With bidi-reordered rows, don't return the
+       first one that occludes point; rather, examine all candidates and
+       return the best match, with he glyph that's closest to point.
+       (display_line): When looking for min position, don't consider
+       negative values of glyph->charpos.  (Fixes a crash with "C-x 3" at
+       ZV.)  Record the position after EOL in it->eol_pos, and use it to
+       set end_pos of the last row produced for a continued line.  Fix
+       the condition for passing candidate rows to set_cursor_from_row:
+       check ends_at_zv_p flag of the best candidate row, not of the
+       current row.
+
+       * dispextern.h (struct it): New member eol_pos.
+
+       * .gdbinit (prowlims): Display the ends_at_zv_p flag.
+
 2010-03-06  Eli Zaretskii  <eliz@gnu.org>
 
        * .gdbinit (prowlims, pmtxrows): New commands.
index 2b581fd0eaad15bb993367552d0a99268ff4aeba..3202385e5412778e97c26d5fc27906bbc44180e9 100644 (file)
@@ -2016,8 +2016,8 @@ struct it
      iterator position in `current'.  */
   EMACS_INT prev_stop;
 
-  /* Last stop position iterated across whose embedding level is equal
-     to the current paragraph's embedding level.  */
+  /* Last stop position iterated across whose bidi embedding level is
+     equal to the current paragraph's base embedding level.  */
   EMACS_INT base_level_stop;
 
   /* Maximum string or buffer position + 1.  ZV when iterating over
@@ -2327,6 +2327,14 @@ struct it
      incremented/reset by display_line, move_it_to etc.  */
   int continuation_lines_width;
 
+  /* Buffer position that ends the buffer text line being iterated.
+     This is normally the position after the newline at EOL.  If this
+     is the last line of the buffer and it doesn't have a newline,
+     value is ZV/ZV_BYTE.  Set and used only if IT->bidi_p, for
+     setting the end position of glyph rows produced for continuation
+     lines, see display_line.  */
+  struct text_pos eol_pos;
+
   /* Current y-position.  Automatically incremented by the height of
      glyph_row in move_it_to and display_line.  */
   int current_y;
index e481809164dccce77ce34389324dfde5acc51d3f..7fcb5243162972859a11c5cf86f4cae5f5b5389f 100644 (file)
@@ -13541,6 +13541,12 @@ try_cursor_movement (window, startp, scroll_step)
       && NILP (Vshow_trailing_whitespace)
       /* Right after splitting windows, last_point may be nil.  */
       && INTEGERP (w->last_point)
+      /* Can't use this optimization if rows were bidi-reordered and
+        point moved backwards, because that would mean we would need
+        to examine previous rows that came from the same continued
+        line.  */
+      && (PT > XFASTINT (w->last_point)
+         || NILP (XBUFFER (w->buffer)->bidi_display_reordering))
       /* This code is not used for mini-buffer for the sake of the case
         of redisplaying to replace an echo area message; since in
         that case the mini-buffer contents per se are usually
@@ -13714,6 +13720,43 @@ try_cursor_movement (window, startp, scroll_step)
            }
          else if (scroll_p)
            rc = CURSOR_MOVEMENT_MUST_SCROLL;
+         else if (!NILP (XBUFFER (w->buffer)->bidi_display_reordering))
+           {
+             /* With bidi-reordered rows, there could be more than
+                one candidate row whose start and end positions
+                occlude point.  We need to find the best
+                candidate.  */
+             int rv = 0;
+
+             do
+               {
+                 rv |= set_cursor_from_row (w, row, w->current_matrix,
+                                            0, 0, 0, 0);
+                 /* As soon as we've found the first suitable row
+                    whose ends_at_zv_p flag is set, we are done.  */
+                 if (rv
+                     && MATRIX_ROW (w->current_matrix, w->cursor.vpos)->ends_at_zv_p)
+                   {
+                     rc = CURSOR_MOVEMENT_SUCCESS;
+                     break;
+                   }
+                 ++row;
+               }
+             while (MATRIX_ROW_BOTTOM_Y (row) < last_y
+                    && MATRIX_ROW_START_CHARPOS (row) <= PT
+                    && PT <= MATRIX_ROW_END_CHARPOS (row)
+                    && cursor_row_p (w, row));
+             /* If we didn't find any candidate rows, or exited the
+                loop before all the candidates were examined, signal
+                to the caller that this method failed.  */
+             if (rc != CURSOR_MOVEMENT_SUCCESS
+                 && (!rv
+                     || (MATRIX_ROW_START_CHARPOS (row) <= PT
+                         && PT <= MATRIX_ROW_END_CHARPOS (row))))
+               rc = CURSOR_MOVEMENT_CANNOT_BE_USED;
+             else
+               rc = CURSOR_MOVEMENT_SUCCESS;
+           }
          else
            {
              do
@@ -15339,6 +15382,8 @@ row_containing_pos (w, charpos, start, end, dy)
      int dy;
 {
   struct glyph_row *row = start;
+  struct glyph_row *best_row = NULL;
+  EMACS_INT mindif = BUF_ZV (XBUFFER (w->buffer)) + 1;
   int last_y;
 
   /* If we happen to start on a header-line, skip that.  */
@@ -15371,7 +15416,30 @@ row_containing_pos (w, charpos, start, end, dy)
                 && !row->ends_at_zv_p
                 && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)))
          && charpos >= MATRIX_ROW_START_CHARPOS (row))
-       return row;
+       {
+         struct glyph *g;
+
+         if (NILP (XBUFFER (w->buffer)->bidi_display_reordering))
+           return row;
+         /* In bidi-reordered rows, there could be several rows
+            occluding point.  We need to find the one which fits
+            CHARPOS the best.  */
+         for (g = row->glyphs[TEXT_AREA];
+              g < row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
+              g++)
+           {
+             if (!STRINGP (g->object))
+               {
+                 if (g->charpos > 0 && eabs (g->charpos - charpos) < mindif)
+                   {
+                     mindif = eabs (g->charpos - charpos);
+                     best_row = row;
+                   }
+               }
+           }
+       }
+      else if (best_row)
+       return best_row;
       ++row;
     }
 }
@@ -17104,6 +17172,7 @@ display_line (it)
   int wrap_row_phys_ascent, wrap_row_phys_height;
   int wrap_row_extra_line_spacing;
   struct display_pos row_end;
+  int cvpos;
 
   /* We always start displaying at hpos zero even if hscrolled.  */
   xassert (it->hpos == 0 && it->current_x == 0);
@@ -17622,7 +17691,7 @@ display_line (it)
        {
          if (BUFFERP (g->object))
            {
-             if (g->charpos && g->charpos < min_pos)
+             if (g->charpos > 0 && g->charpos < min_pos)
                min_pos = g->charpos;
              if (g->charpos > max_pos)
                max_pos = g->charpos;
@@ -17640,7 +17709,7 @@ display_line (it)
            {
              if (INTEGERP (g->object))
                {
-                 if (g->charpos && g->charpos < min_pos)
+                 if (g->charpos > 0 && g->charpos < min_pos)
                    min_pos = g->charpos;
                  if (g->charpos > max_pos)
                    max_pos = g->charpos;
@@ -17671,6 +17740,8 @@ display_line (it)
       else if (row->used[TEXT_AREA] && max_pos)
        {
          SET_TEXT_POS (tpos, max_pos + 1, CHAR_TO_BYTE (max_pos + 1));
+         row_end = it->current;
+         row_end.pos = tpos;
          /* If the character at max_pos+1 is a newline, skip that as
             well.  Note that this may skip some invisible text.  */
          if (FETCH_CHAR (tpos.bytepos) == '\n'
@@ -17680,13 +17751,32 @@ display_line (it)
              it->bidi_p = 0;
              reseat_1 (it, tpos, 0);
              set_iterator_to_next (it, 1);
-             row_end = it->current;
+             /* Record the position after the newline of a continued
+                row.  We will need that to set ROW->end of the last
+                row produced for a continued line.  */
+             if (row->continued_p)
+               {
+                 save_it.eol_pos.charpos = IT_CHARPOS (*it);
+                 save_it.eol_pos.bytepos = IT_BYTEPOS (*it);
+               }
+             else
+               {
+                 row_end = it->current;
+                 save_it.eol_pos.charpos = save_it.eol_pos.bytepos = 0;
+               }
              *it = save_it;
            }
-         else
+         else if (!row->continued_p
+                  && row->continuation_lines_width
+                  && it->eol_pos.charpos > 0)
            {
-             row_end = it->current;
-             row_end.pos = tpos;
+             /* Last row of a continued line.  Use the position
+                recorded in ROW->eol_pos, to the effect that the
+                newline belongs to this row, not to the row which
+                displays the character with the largest buffer
+                position.  */
+             row_end.pos = it->eol_pos;
+             it->eol_pos.charpos = it->eol_pos.bytepos = 0;
            }
          row->end = row_end;
        }
@@ -17709,15 +17799,16 @@ display_line (it)
   it->right_user_fringe_face_id = 0;
 
   /* Maybe set the cursor.  */
-  if ((it->w->cursor.vpos < 0
+  cvpos = it->w->cursor.vpos;
+  if ((cvpos < 0
        /* In bidi-reordered rows, keep checking for proper cursor
          position even if one has been found already, because buffer
          positions in such rows change non-linearly with ROW->VPOS,
          when a line is continued.  One exception: when we are at ZV,
          display cursor on the first suitable glyph row, since all
-         the empty rows after that also have their ends_at_zv_p flag
-         set.  */
-       || (it->bidi_p && !row->ends_at_zv_p))
+         the empty rows after that also have their position set to ZV.  */
+       || (it->bidi_p
+          && !MATRIX_ROW (it->w->desired_matrix, cvpos)->ends_at_zv_p))
       && PT >= MATRIX_ROW_START_CHARPOS (row)
       && PT <= MATRIX_ROW_END_CHARPOS (row)
       && cursor_row_p (it->w, row))