Fix C-n/C-p inside bidirectional text

* src/xdisp.c (move_it_by_lines, try_cursor_movement): Handle
glyph rows whose direction of increasing buffer positions is
reverse of the normal: going down in the window makes buffer
positions higher.
* src/indent.c (Fvertical_motion): When looking for the last glyph
row occupied by point, take into account the bidi iteration
direction.
This commit is contained in:
Eli Zaretskii 2022-08-06 16:24:34 +03:00
parent d8abff398b
commit 55c25e73d4
2 changed files with 46 additions and 5 deletions

View file

@ -2345,7 +2345,15 @@ whether or not it is currently displayed in some window. */)
last line that it occupies. */
if (it_start < ZV)
{
while (IT_CHARPOS (it) <= it_start)
if ((it.bidi_it.scan_dir > 0)
? IT_CHARPOS (it) < it_start
: IT_CHARPOS (it) > it_start)
{
it.vpos = 0;
it.current_y = 0;
move_it_by_lines (&it, 1);
}
while (IT_CHARPOS (it) == it_start)
{
it.vpos = 0;
it.current_y = 0;

View file

@ -10956,15 +10956,21 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
int nchars_per_row
= (it->last_visible_x - it->first_visible_x) / FRAME_COLUMN_WIDTH (it->f);
bool hit_pos_limit = false;
bool reverse_rows = false;
ptrdiff_t pos_limit;
/* Start at the beginning of the screen line containing IT's
position. This may actually move vertically backwards,
in case of overlays, so adjust dvpos accordingly. */
dvpos += it->vpos;
start_charpos = IT_CHARPOS (*it);
move_it_vertically_backward (it, 0);
dvpos -= it->vpos;
/* Do we have glyph rows whose positions _increase_ as we go up? */
if (IT_CHARPOS (*it) > start_charpos)
reverse_rows = true;
/* Go back -DVPOS buffer lines, but no farther than -DVPOS full
screen lines, and reseat the iterator there. */
start_charpos = IT_CHARPOS (*it);
@ -11015,7 +11021,8 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
SAVE_IT (it2, *it, it2data);
move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS);
/* Move back again if we got too far ahead. */
if (IT_CHARPOS (*it) >= start_charpos)
if ((IT_CHARPOS (*it) >= start_charpos && !reverse_rows)
|| (IT_CHARPOS (*it) <= start_charpos && reverse_rows))
RESTORE_IT (it, &it2, it2data);
else
bidi_unshelve_cache (it2data, true);
@ -18837,6 +18844,8 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp,
{
/* Cursor has to be moved backward. Note that PT >=
CHARPOS (startp) because of the outer if-statement. */
struct glyph_row *row0 = row;
while (!row->mode_line_p
&& (MATRIX_ROW_START_CHARPOS (row) > PT
|| (MATRIX_ROW_START_CHARPOS (row) == PT
@ -18851,6 +18860,23 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp,
--row;
}
/* With bidi-reordered rows we can have buffer positions
_decrease_ when going down by rows. If we haven't
found our row in the loop above, give it another try
now going in the other direction from the original row. */
if (!(MATRIX_ROW_START_CHARPOS (row) <= PT
&& PT <= MATRIX_ROW_END_CHARPOS (row))
&& row0->continued_p)
{
row = row0;
while (MATRIX_ROW_START_CHARPOS (row) > PT
&& MATRIX_ROW_BOTTOM_Y (row) < last_y)
{
eassert (row->enabled_p);
++row;
}
}
/* Consider the following case: Window starts at BEGV,
there is invisible, intangible text at BEGV, so that
display starts at some point START > BEGV. It can
@ -18874,9 +18900,16 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp,
&& !cursor_row_p (row))
++row;
/* If within the scroll margin, scroll. */
if (row->y < top_scroll_margin
&& CHARPOS (startp) != BEGV)
/* If within the scroll margin, either the top one or
the bottom one, scroll. */
if ((row->y < top_scroll_margin
&& CHARPOS (startp) != BEGV)
|| MATRIX_ROW_BOTTOM_Y (row) > last_y
|| PT > MATRIX_ROW_END_CHARPOS (row)
|| (MATRIX_ROW_BOTTOM_Y (row) == last_y
&& PT == MATRIX_ROW_END_CHARPOS (row)
&& !row->ends_at_zv_p
&& !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)))
scroll_p = true;
}
else