From: Eli Zaretskii Date: Sat, 6 Aug 2022 13:24:34 +0000 (+0300) Subject: Fix C-n/C-p inside bidirectional text X-Git-Tag: emacs-29.0.90~1447^2~372 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=55c25e73d46685e4b4423b13b0d3287fee170386;p=emacs.git 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. --- diff --git a/src/indent.c b/src/indent.c index fd2e7636656..d2dfaee254e 100644 --- a/src/indent.c +++ b/src/indent.c @@ -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; diff --git a/src/xdisp.c b/src/xdisp.c index 3ca0022a6d3..c756e7f04f6 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -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