]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix bug #9549 with longlines-show-hard-newlines.
authorEli Zaretskii <eliz@gnu.org>
Tue, 20 Sep 2011 17:13:45 +0000 (20:13 +0300)
committerEli Zaretskii <eliz@gnu.org>
Tue, 20 Sep 2011 17:13:45 +0000 (20:13 +0300)
 src/xdisp.c (set_cursor_from_row): If the row ends in a newline from
 a display string, extend search for cursor position to end of row.
 (find_row_edges): If the row ends in a newline from a display
 string, increment its MATRIX_ROW_END_CHARPOS by one.
 Handle the case of a display string with multiple newlines.

src/ChangeLog
src/xdisp.c

index 12a45918e8710135f4a8365e191fa92caf393979..f0b1ecc3caa86a6fae471c55a2bc027192e423ea 100644 (file)
@@ -1,3 +1,11 @@
+2011-09-20  Eli Zaretskii  <eliz@gnu.org>
+
+       * xdisp.c (set_cursor_from_row): If the row ends in a newline from
+       a display string, extend search for cursor position to end of row.
+       (find_row_edges): If the row ends in a newline from a display
+       string, increment its MATRIX_ROW_END_CHARPOS by one.  (Bug#9549)
+       Handle the case of a display string with multiple newlines.
+
 2011-09-19  Lars Magne Ingebrigtsen  <larsi@gnus.org>
 
        * lread.c (Fread_from_string): Document what FINAL-STRING-INDEX is
index d58eea538f5ebe544903072a4fae22f38546dd41..81cba29206a717161249eb1dbaf9410d901a9863 100644 (file)
@@ -13666,6 +13666,17 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
 
          x = -1;
 
+         /* If the row ends in a newline from a display string,
+            reordering could have moved the glyphs belonging to the
+            string out of the [GLYPH_BEFORE..GLYPH_AFTER] range.  So
+            in this case we extend the search to the last glyph in
+            the row that was not inserted by redisplay.  */
+         if (row->ends_in_newline_from_string_p)
+           {
+             glyph_after = end;
+             pos_after = MATRIX_ROW_END_CHARPOS (row) + delta;
+           }
+
          /* GLYPH_BEFORE and GLYPH_AFTER are the glyphs that
             correspond to POS_BEFORE and POS_AFTER, respectively.  We
             need START and STOP in the order that corresponds to the
@@ -18341,7 +18352,8 @@ find_row_edges (struct it *it, struct glyph_row *row,
      Line ends in a newline from buffer       eol_pos + 1
      Line is continued from buffer            max_pos + 1
      Line is truncated on right               it->current.pos
-     Line ends in a newline from string       max_pos
+     Line ends in a newline from string       max_pos + 1(*)
+      (*) + 1 only when line ends in a forward scan
      Line is continued from string            max_pos
      Line is continued from display vector    max_pos
      Line is entirely from a string           min_pos == max_pos
@@ -18354,8 +18366,76 @@ find_row_edges (struct it *it, struct glyph_row *row,
     row->maxpos = it->current.pos;
   else if (row->used[TEXT_AREA])
     {
-      if (row->ends_in_newline_from_string_p)
-       SET_TEXT_POS (row->maxpos, max_pos, max_bpos);
+      int seen_this_string = 0;
+      struct glyph_row *r1 = row - 1;
+
+      /* Did we see the same display string on the previous row?  */
+      if (STRINGP (it->object)
+         /* this is not the first row */
+         && row > it->w->desired_matrix->rows
+         /* previous row is not the header line */
+         && !r1->mode_line_p
+         /* previous row also ends in a newline from a string */
+         && r1->ends_in_newline_from_string_p)
+       {
+         struct glyph *start, *end;
+
+         /* Search for the last glyph of the previous row that came
+            from buffer or string.  Depending on whether the row is
+            L2R or R2L, we need to process it front to back or the
+            other way round.  */
+         if (!r1->reversed_p)
+           {
+             start = r1->glyphs[TEXT_AREA];
+             end = start + r1->used[TEXT_AREA];
+             /* Glyphs inserted by redisplay have an integer (zero)
+                as their object.  */
+             while (end > start
+                    && INTEGERP ((end - 1)->object)
+                    && (end - 1)->charpos <= 0)
+               --end;
+             if (end > start)
+               {
+                 if (EQ ((end - 1)->object, it->object))
+                   seen_this_string = 1;
+               }
+             else
+               abort ();
+           }
+         else
+           {
+             end = r1->glyphs[TEXT_AREA] - 1;
+             start = end + r1->used[TEXT_AREA];
+             while (end < start
+                    && INTEGERP ((end + 1)->object)
+                    && (end + 1)->charpos <= 0)
+               ++end;
+             if (end < start)
+               {
+                 if (EQ ((end + 1)->object, it->object))
+                   seen_this_string = 1;
+               }
+             else
+               abort ();
+           }
+       }
+      /* Take note of each display string that covers a newline only
+        once, the first time we see it.  This is for when a display
+        string includes more than one newline in it.  */
+      if (row->ends_in_newline_from_string_p && !seen_this_string)
+       {
+         /* If we were scanning the buffer forward when we displayed
+            the string, we want to account for at least one buffer
+            position that belongs to this row (position covered by
+            the display string), so that cursor positioning will
+            consider this row as a candidate when point is at the end
+            of the visual line represented by this row.  This is not
+            required when scanning back, because max_pos will already
+            have a much larger value.  */
+         if (CHARPOS (row->end.pos) > max_pos)
+           INC_BOTH (max_pos, max_bpos);
+         SET_TEXT_POS (row->maxpos, max_pos, max_bpos);
+       }
       else if (CHARPOS (it->eol_pos) > 0)
        SET_TEXT_POS (row->maxpos,
                      CHARPOS (it->eol_pos) + 1, BYTEPOS (it->eol_pos) + 1);