aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2014-04-12 14:21:47 +0300
committerEli Zaretskii2014-04-12 14:21:47 +0300
commit180c8ce0c6a702bc21403e1f5a0b2781bb5f787c (patch)
tree80579c3d79dd86e3580f587055eb9a4587830a7f
parent204db02a2b8826a72d49edd1ca8d32d6d33478c8 (diff)
downloademacs-180c8ce0c6a702bc21403e1f5a0b2781bb5f787c.tar.gz
emacs-180c8ce0c6a702bc21403e1f5a0b2781bb5f787c.zip
Fix bug #17244 with line-move-visual when display string covers a lot of text.
src/xdisp.c (move_it_by_lines): If a large portion of buffer text is covered by a display string that ends in a newline, and that cases going back by DVPOS lines to hit the search limit, lift the limit and go back until DVPOS is reached. src/indent.c (Fvertical_motion): Handle correctly the case when the display string is preceded by an empty line.
-rw-r--r--src/ChangeLog10
-rw-r--r--src/indent.c11
-rw-r--r--src/xdisp.c23
3 files changed, 42 insertions, 2 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 22f25bef6f3..cb17738d139 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,13 @@
12014-04-12 Eli Zaretskii <eliz@gnu.org>
2
3 * xdisp.c (move_it_by_lines): If a large portion of buffer text is
4 covered by a display string that ends in a newline, and that cases
5 going back by DVPOS lines to hit the search limit, lift the limit
6 and go back until DVPOS is reached. (Bug#17244)
7
8 * indent.c (Fvertical_motion): Handle correctly the case when the
9 display string is preceded by an empty line.
10
12014-04-11 Eli Zaretskii <eliz@gnu.org> 112014-04-11 Eli Zaretskii <eliz@gnu.org>
2 12
3 * w32.c (sys_umask) <WRITE_USER>: Remove redundant constant, and 13 * w32.c (sys_umask) <WRITE_USER>: Remove redundant constant, and
diff --git a/src/indent.c b/src/indent.c
index 683d44841b9..dc862518924 100644
--- a/src/indent.c
+++ b/src/indent.c
@@ -2051,8 +2051,15 @@ whether or not it is currently displayed in some window. */)
2051 string, move_it_to will overshoot it, while vertical-motion 2051 string, move_it_to will overshoot it, while vertical-motion
2052 wants to put the cursor _before_ the display string. So in 2052 wants to put the cursor _before_ the display string. So in
2053 that case, we move to buffer position before the display 2053 that case, we move to buffer position before the display
2054 string, and avoid overshooting. */ 2054 string, and avoid overshooting. But if the position before
2055 move_it_to (&it, disp_string_at_start_p ? PT - 1 : PT, 2055 the display string is a newline, we don't do this, because
2056 otherwise we will end up in a screen line that is one too
2057 far back. */
2058 move_it_to (&it,
2059 (!disp_string_at_start_p
2060 || FETCH_BYTE (IT_BYTEPOS (it)) == '\n')
2061 ? PT
2062 : PT - 1,
2056 -1, -1, -1, MOVE_TO_POS); 2063 -1, -1, -1, MOVE_TO_POS);
2057 2064
2058 /* IT may move too far if truncate-lines is on and PT lies 2065 /* IT may move too far if truncate-lines is on and PT lies
diff --git a/src/xdisp.c b/src/xdisp.c
index 53bd46328f2..eb3a6df1fc5 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -9511,6 +9511,7 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
9511 ptrdiff_t start_charpos, i; 9511 ptrdiff_t start_charpos, i;
9512 int nchars_per_row 9512 int nchars_per_row
9513 = (it->last_visible_x - it->first_visible_x) / FRAME_COLUMN_WIDTH (it->f); 9513 = (it->last_visible_x - it->first_visible_x) / FRAME_COLUMN_WIDTH (it->f);
9514 bool hit_pos_limit = false;
9514 ptrdiff_t pos_limit; 9515 ptrdiff_t pos_limit;
9515 9516
9516 /* Start at the beginning of the screen line containing IT's 9517 /* Start at the beginning of the screen line containing IT's
@@ -9527,8 +9528,11 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
9527 pos_limit = BEGV; 9528 pos_limit = BEGV;
9528 else 9529 else
9529 pos_limit = max (start_charpos + dvpos * nchars_per_row, BEGV); 9530 pos_limit = max (start_charpos + dvpos * nchars_per_row, BEGV);
9531
9530 for (i = -dvpos; i > 0 && IT_CHARPOS (*it) > pos_limit; --i) 9532 for (i = -dvpos; i > 0 && IT_CHARPOS (*it) > pos_limit; --i)
9531 back_to_previous_visible_line_start (it); 9533 back_to_previous_visible_line_start (it);
9534 if (i > 0 && IT_CHARPOS (*it) <= pos_limit)
9535 hit_pos_limit = true;
9532 reseat (it, it->current.pos, 1); 9536 reseat (it, it->current.pos, 1);
9533 9537
9534 /* Move further back if we end up in a string or an image. */ 9538 /* Move further back if we end up in a string or an image. */
@@ -9572,6 +9576,25 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
9572 else 9576 else
9573 bidi_unshelve_cache (it2data, 1); 9577 bidi_unshelve_cache (it2data, 1);
9574 } 9578 }
9579 else if (hit_pos_limit && pos_limit > BEGV
9580 && dvpos < 0 && it2.vpos < -dvpos)
9581 {
9582 /* If we hit the limit, but still didn't make it far enough
9583 back, that means there's a display string with a newline
9584 covering a large chunk of text, and that caused
9585 back_to_previous_visible_line_start try to go too far.
9586 Punish those who commit such atrocities by going back
9587 until we've reached DVPOS, after lifting the limit, which
9588 could make it slow for very long lines. "If it hurts,
9589 don't do that!" */
9590 dvpos += it2.vpos;
9591 RESTORE_IT (it, it, it2data);
9592 for (i = -dvpos; i > 0; --i)
9593 {
9594 back_to_previous_visible_line_start (it);
9595 it->vpos--;
9596 }
9597 }
9575 else 9598 else
9576 RESTORE_IT (it, it, it2data); 9599 RESTORE_IT (it, it, it2data);
9577 } 9600 }