Commit 99848b37 authored by Eli Zaretskii's avatar Eli Zaretskii
Browse files

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)
parent edb4af7a
...@@ -8810,6 +8810,8 @@ move_it_in_display_line_to (struct it *it, ...@@ -8810,6 +8810,8 @@ move_it_in_display_line_to (struct it *it,
? WINDOW_LEFT_FRINGE_WIDTH (it->w) ? WINDOW_LEFT_FRINGE_WIDTH (it->w)
: WINDOW_RIGHT_FRINGE_WIDTH (it->w))))) : WINDOW_RIGHT_FRINGE_WIDTH (it->w)))))
{ {
bool moved_forward = false;
if (/* IT->hpos == 0 means the very first glyph if (/* IT->hpos == 0 means the very first glyph
doesn't fit on the line, e.g. a wide image. */ doesn't fit on the line, e.g. a wide image. */
it->hpos == 0 it->hpos == 0
...@@ -8828,16 +8830,37 @@ move_it_in_display_line_to (struct it *it, ...@@ -8828,16 +8830,37 @@ move_it_in_display_line_to (struct it *it,
now that we know it fits in this row. */ now that we know it fits in this row. */
if (BUFFER_POS_REACHED_P ()) 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 if (it->line_wrap != WORD_WRAP
|| wrap_it.sp < 0 || wrap_it.sp < 0
/* If we've just found whitespace to /* If we've just found whitespace
wrap, effectively ignore the where we can wrap, effectively
previous wrap point -- it is no ignore the previous wrap point --
longer relevant, but we won't it is no longer relevant, but we
have an opportunity to update it, won't have an opportunity to
since we've reached the edge of update it, since we've reached
this screen line. */ the edge of this screen line. */
|| (may_wrap || (may_wrap && can_wrap
&& IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))) && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)))
{ {
it->hpos = hpos_before_this_char; it->hpos = hpos_before_this_char;
...@@ -8880,6 +8903,7 @@ move_it_in_display_line_to (struct it *it, ...@@ -8880,6 +8903,7 @@ move_it_in_display_line_to (struct it *it,
result = MOVE_POS_MATCH_OR_ZV; result = MOVE_POS_MATCH_OR_ZV;
break; break;
} }
moved_forward = true;
if (BUFFER_POS_REACHED_P ()) if (BUFFER_POS_REACHED_P ())
{ {
if (ITERATOR_AT_END_OF_LINE_P (it)) if (ITERATOR_AT_END_OF_LINE_P (it))
...@@ -8907,7 +8931,14 @@ move_it_in_display_line_to (struct it *it, ...@@ -8907,7 +8931,14 @@ move_it_in_display_line_to (struct it *it,
longer relevant, but we won't have an opportunity longer relevant, but we won't have an opportunity
to update it, since we are done with this screen to update it, since we are done with this screen
line. */ 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 /* If we've found TO_X, go back there, as we now
know the last word fits on this screen line. */ know the last word fits on this screen line. */
...@@ -9088,9 +9119,18 @@ move_it_in_display_line_to (struct it *it, ...@@ -9088,9 +9119,18 @@ move_it_in_display_line_to (struct it *it,
#undef BUFFER_POS_REACHED_P #undef BUFFER_POS_REACHED_P
/* If we scanned beyond to_pos and didn't find a point to wrap at, /* If we scanned beyond TO_POS, restore the saved iterator either to
restore the saved iterator. */ the wrap point (if found), or to atpos/atx location. We decide which
if (atpos_it.sp >= 0) 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); RESTORE_IT (it, &atpos_it, atpos_data);
else if (atx_it.sp >= 0) else if (atx_it.sp >= 0)
RESTORE_IT (it, &atx_it, atx_data); RESTORE_IT (it, &atx_it, atx_data);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment