summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii <eliz@gnu.org>2016-05-21 12:35:08 +0300
committerEli Zaretskii <eliz@gnu.org>2016-05-21 12:35:08 +0300
commit99848b37d2c3e14c0af45fc6da437a806aa58a80 (patch)
tree36e1a4603d96c4bc380b2bcc1fe9203787bc684e /src
parentedb4af7a1d1e8e0ab67b2dedad0ca0380e6866d4 (diff)
downloademacs-99848b37d2c3e14c0af45fc6da437a806aa58a80.tar.gz
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)
Diffstat (limited to 'src')
-rw-r--r--src/xdisp.c64
1 files changed, 52 insertions, 12 deletions
diff --git a/src/xdisp.c b/src/xdisp.c
index 10a0cf24b4a..e78d3d6f5b6 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -8810,6 +8810,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
@@ -8828,16 +8830,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;
@@ -8880,6 +8903,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))
@@ -8907,7 +8931,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. */
@@ -9088,9 +9119,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);