From df4f8125342bafe1d70130f84acfa67cc0c4a7f4 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 21 May 2016 12:35:08 +0300 Subject: [PATCH] Fix 'vertical-motion' and 'posn-at-point' under 'visual-line-mode' * src/xdisp.c (move_it_in_display_line_to): Don't assume we can wrap on a whitespace character if it's followed by another whitespace character. When returning under WORD_WRAP for a screen line that is continued, restore to wrap point when atpos/atx position would be displayed on the next screen line due to line-wrap. (Bug#23570) This is backported from master (cherry picked from commit 99848b37d2c3e14c0af45fc6da437a806aa58a80) --- src/xdisp.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 24daa0c3b71..adbb6e5088b 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -8805,6 +8805,8 @@ move_it_in_display_line_to (struct it *it, ? WINDOW_LEFT_FRINGE_WIDTH (it->w) : WINDOW_RIGHT_FRINGE_WIDTH (it->w))))) { + bool moved_forward = false; + if (/* IT->hpos == 0 means the very first glyph doesn't fit on the line, e.g. a wide image. */ it->hpos == 0 @@ -8823,16 +8825,37 @@ move_it_in_display_line_to (struct it *it, now that we know it fits in this row. */ if (BUFFER_POS_REACHED_P ()) { + bool can_wrap = true; + + /* If we are at a whitespace character + that barely fits on this screen line, + but the next character is also + whitespace, we cannot wrap here. */ + if (it->line_wrap == WORD_WRAP + && wrap_it.sp >= 0 + && may_wrap + && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) + { + struct it tem_it; + void *tem_data = NULL; + + SAVE_IT (tem_it, *it, tem_data); + set_iterator_to_next (it, true); + if (get_next_display_element (it) + && IT_DISPLAYING_WHITESPACE (it)) + can_wrap = false; + RESTORE_IT (it, &tem_it, tem_data); + } if (it->line_wrap != WORD_WRAP || wrap_it.sp < 0 - /* If we've just found whitespace to - wrap, effectively ignore the - previous wrap point -- it is no - longer relevant, but we won't - have an opportunity to update it, - since we've reached the edge of - this screen line. */ - || (may_wrap + /* If we've just found whitespace + where we can wrap, effectively + ignore the previous wrap point -- + it is no longer relevant, but we + won't have an opportunity to + update it, since we've reached + the edge of this screen line. */ + || (may_wrap && can_wrap && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))) { it->hpos = hpos_before_this_char; @@ -8875,6 +8898,7 @@ move_it_in_display_line_to (struct it *it, result = MOVE_POS_MATCH_OR_ZV; break; } + moved_forward = true; if (BUFFER_POS_REACHED_P ()) { if (ITERATOR_AT_END_OF_LINE_P (it)) @@ -8902,7 +8926,14 @@ move_it_in_display_line_to (struct it *it, longer relevant, but we won't have an opportunity to update it, since we are done with this screen line. */ - if (may_wrap && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) + if (may_wrap && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it) + /* If the character after the one which set the + may_wrap flag is also whitespace, we can't + wrap here, since the screen line cannot be + wrapped in the middle of whitespace. + Therefore, wrap_it _is_ relevant in that + case. */ + && !(moved_forward && IT_DISPLAYING_WHITESPACE (it))) { /* If we've found TO_X, go back there, as we now know the last word fits on this screen line. */ @@ -9083,9 +9114,18 @@ move_it_in_display_line_to (struct it *it, #undef BUFFER_POS_REACHED_P - /* If we scanned beyond to_pos and didn't find a point to wrap at, - restore the saved iterator. */ - if (atpos_it.sp >= 0) + /* If we scanned beyond TO_POS, restore the saved iterator either to + the wrap point (if found), or to atpos/atx location. We decide which + data to use to restore the saved iterator state by their X coordinates, + since buffer positions might increase non-monotonically with screen + coordinates due to bidi reordering. */ + if (result == MOVE_LINE_CONTINUED + && it->line_wrap == WORD_WRAP + && wrap_it.sp >= 0 + && ((atpos_it.sp >= 0 && wrap_it.current_x < atpos_it.current_x) + || (atx_it.sp >= 0 && wrap_it.current_x < atx_it.current_x))) + RESTORE_IT (it, &wrap_it, wrap_data); + else if (atpos_it.sp >= 0) RESTORE_IT (it, &atpos_it, atpos_data); else if (atx_it.sp >= 0) RESTORE_IT (it, &atx_it, atx_data); -- 2.11.4.GIT