[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#28936: move_it_in_display_line_to returns MOVE_POS_MATCH_OR_ZV befor
From: |
Keith David Bershatsky |
Subject: |
bug#28936: move_it_in_display_line_to returns MOVE_POS_MATCH_OR_ZV before ZV |
Date: |
Sun, 22 Oct 2017 11:05:45 -0700 |
Thank you, Eli, for looking into #28936.
With respect to `move_it_in_display_line`, I was not able to reliably land on
`it.first_visible_x + lnum_pixel_width` when horizontal scrolling to the right
AND text truncated on the left. IT overshoots the target by one text
character. After trial an error, I assumed that this one text character
overshoot was due to a built-in limitation of that function. Hence, I have
written `move_it_in_display_line_to_x` so that I can reach any X.
I was able to reproduce the MOVE_POS_MATCH_OR_ZV bug when word-wrap is non-nil.
I have disabled the workaround of `&& IT_CHARPOS (*IT) == ZV` so that we can
see the bug in action.
I have not yet created a minimal working example to demonstrate the
MOVE_LINE_TRUNCATED bug when trying to reach an X that is approximately 1000 or
greater while horizontal scrolling a current line. There is a comment about
that issue below: "When `auto-hscroll-mode' is set to ..."
Here is a recipe demonstrating the MOVE_POS_MATCH_OR_ZV bug:
STEP #1: Add the two functions below at an appropriate location in xdisp.c.
STEP #2: Launch the Emacs containing the new functions.
STEP #3: In a scratch buffer, type: Hello world!
[ZV must immediately follow "!" for this example to work.]
STEP #4: Place the cursor somewhere on the word "world", and evaluate:
(bug-28936 (selected-window))
STEP #5: Observe that the result is "1" when it should be "2".
int
move_it_in_display_line_to_x (struct window *w, struct it *it, int target_x)
{
struct it saved_it;
void *saved_data = bidi_shelve_cache ();
enum move_it_result rc = MOVE_X_REACHED;
int new_x, prev_x;
/* Advance straight to `it->first_visible_x` if IT is prior thereto. */
if (it->current_x < it->first_visible_x)
move_it_in_display_line_to (it, ZV, it->first_visible_x, MOVE_TO_POS |
MOVE_TO_X);
/* When `auto-hscroll-mode' is set to `current-line` and we are horizontal
scrolling
a long line that approaches or exceeds an `it.current.x` of approximately
1000, `rc`
will erroneously return early with a MOVE_LINE_TRUNCATED indicator without
pushing
forwards until IT reaches the target_x. As a workaround, ignore
MOVE_LINE_TRUNCATED. */
while (it->current_x + it->pixel_width <= target_x
&& (rc == MOVE_X_REACHED
|| rc == MOVE_LINE_TRUNCATED
|| (it->line_wrap == WORD_WRAP
&& rc == MOVE_POS_MATCH_OR_ZV)))
{
SAVE_IT (saved_it, *it, saved_data);
new_x = it->current_x + it->pixel_width;
if (new_x == it->current_x)
new_x++;
rc = move_it_in_display_line_to (it, ZV, new_x, MOVE_TO_POS | MOVE_TO_X);
if (ITERATOR_AT_END_OF_LINE_P (it)
|| FETCH_BYTE (IT_BYTEPOS (*it)) == '\n'
/* There is a bug in `move_it_in_display_line_to' such that it returns
MOVE_POS_MATCH_OR_ZV before reaching ZV when the latter is at the end
of the line: abcdefg[EOB]. The workaround is to add an extra check
using IT_CHARPOS and comparing it to ZV. */
|| (rc == MOVE_POS_MATCH_OR_ZV
/* && IT_CHARPOS (*it) == ZV */
))
break;
}
/* When word-wrap is on, TO_X may lie past the end of a wrapped line.
Then it->current is the character on the next line, so backtrack to the
space before the wrap point. */
if (it->line_wrap == WORD_WRAP
&& rc == MOVE_LINE_CONTINUED)
{
prev_x = max (it->current_x - 1, 0);
RESTORE_IT (it, &saved_it, saved_data);
move_it_in_display_line_to (it, -1, prev_x, MOVE_TO_X);
}
bidi_unshelve_cache (saved_data, true);
return rc;
}
DEFUN ("bug-28936", Fbug_28936, Sbug_28936, 1, 1, 0,
doc: /* Demonstrate the Emacs bug # 28936. */)
(Lisp_Object window)
{
struct window *w = decode_live_window (window);
struct it it;
void *itdata = bidi_shelve_cache ();
struct text_pos start_text_position;
int target_x;
enum move_it_result rc;
struct buffer *b = XBUFFER (w->contents);
b->word_wrap_ = Qt;
SET_TEXT_POS_FROM_MARKER (start_text_position, w->start);
start_display (&it, w, start_text_position);
move_it_to (&it, PT, it.last_visible_x, it.last_visible_y - 1, -1,
MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
target_x = it.current_x;
move_it_by_lines (&it, 0);
rc = move_it_in_display_line_to_x (w, &it, target_x);
bidi_unshelve_cache (itdata, false);
return make_number (rc);
}
- bug#28936: move_it_in_display_line_to returns MOVE_POS_MATCH_OR_ZV before ZV, Keith David Bershatsky, 2017/10/21
- bug#28936: move_it_in_display_line_to returns MOVE_POS_MATCH_OR_ZV before ZV, Keith David Bershatsky, 2017/10/22
- bug#28936: move_it_in_display_line_to returns MOVE_POS_MATCH_OR_ZV before ZV, Eli Zaretskii, 2017/10/22
- bug#28936: move_it_in_display_line_to returns MOVE_POS_MATCH_OR_ZV before ZV,
Keith David Bershatsky <=
- bug#28936: nRe: bug#28936: move_it_in_display_line_to returns MOVE_POS_MATCH_OR_ZV before ZV, Keith David Bershatsky, 2017/10/22
- bug#28936: move_it_in_display_line_to returns MOVE_POS_MATCH_OR_ZV before ZV, Keith David Bershatsky, 2017/10/23
- bug#28936: enhancement request: remove vertical scroll bar automatically when not needed, Keith David Bershatsky, 2017/10/24
- bug#28936: enhancement request: remove vertical scroll bar automatically when not needed, Keith David Bershatsky, 2017/10/25