Commit df4f8125 authored by Eli Zaretskii's avatar Eli Zaretskii

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 99848b37)
parent 9135bd7a
......@@ -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);
......
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