# HG changeset patch # User Eli Zaretskii # Date 1268498281 18000 # Node ID d65c199e8bddcefcf7eab4398f41b6b3592a968e # Parent a744b1df50bd4063e9d928cba08f398908bbd97f Continue work on cursor movement in continued lines. xdisp.c (try_cursor_movement): Give up if rows are bidi-reordered and point moved backwards. Examine all the candidate rows that occlude point, to return the best match. (row_containing_pos): With bidi-reordered rows, don't return the first one that occludes point; rather, examine all candidates and return the best match, with he glyph that's closest to point. (display_line): When looking for min position, don't consider negative values of glyph->charpos. (Fixes a crash with "C-x 3" at ZV.) Record the position after EOL in it->eol_pos, and use it to set end_pos of the last row produced for a continued line. Fix the condition for passing candidate rows to set_cursor_from_row: check ends_at_zv_p flag of the best candidate row, not of the current row. dispextern.h (struct it): New member eol_pos. .gdbinit (prowlims): Display the ends_at_zv_p flag. diff -r a744b1df50bd -r d65c199e8bdd src/.gdbinit --- a/src/.gdbinit Sat Mar 13 04:02:01 2010 -0500 +++ b/src/.gdbinit Sat Mar 13 11:38:01 2010 -0500 @@ -614,7 +614,7 @@ end define prowlims - printf "start=%d,end=%d,reversed=%d,cont=%d\n", $arg0->start.pos.charpos, $arg0->end.pos.charpos, $arg0->reversed_p, $arg0->continued_p + printf "start=%d,end=%d,reversed=%d,cont=%d,at_zv=%d\n", $arg0->start.pos.charpos, $arg0->end.pos.charpos, $arg0->reversed_p, $arg0->continued_p, $arg0->ends_at_zv_p end document prowlims Print important attributes of a glyph_row structure. diff -r a744b1df50bd -r d65c199e8bdd src/ChangeLog.bidi --- a/src/ChangeLog.bidi Sat Mar 13 04:02:01 2010 -0500 +++ b/src/ChangeLog.bidi Sat Mar 13 11:38:01 2010 -0500 @@ -1,3 +1,23 @@ +2010-03-13 Eli Zaretskii + + * xdisp.c (try_cursor_movement): Give up if rows are + bidi-reordered and point moved backwards. Examine all the + candidate rows that occlude point, to return the best match. + (row_containing_pos): With bidi-reordered rows, don't return the + first one that occludes point; rather, examine all candidates and + return the best match, with he glyph that's closest to point. + (display_line): When looking for min position, don't consider + negative values of glyph->charpos. (Fixes a crash with "C-x 3" at + ZV.) Record the position after EOL in it->eol_pos, and use it to + set end_pos of the last row produced for a continued line. Fix + the condition for passing candidate rows to set_cursor_from_row: + check ends_at_zv_p flag of the best candidate row, not of the + current row. + + * dispextern.h (struct it): New member eol_pos. + + * .gdbinit (prowlims): Display the ends_at_zv_p flag. + 2010-03-06 Eli Zaretskii * .gdbinit (prowlims, pmtxrows): New commands. diff -r a744b1df50bd -r d65c199e8bdd src/dispextern.h --- a/src/dispextern.h Sat Mar 13 04:02:01 2010 -0500 +++ b/src/dispextern.h Sat Mar 13 11:38:01 2010 -0500 @@ -2016,8 +2016,8 @@ iterator position in `current'. */ EMACS_INT prev_stop; - /* Last stop position iterated across whose embedding level is equal - to the current paragraph's embedding level. */ + /* Last stop position iterated across whose bidi embedding level is + equal to the current paragraph's base embedding level. */ EMACS_INT base_level_stop; /* Maximum string or buffer position + 1. ZV when iterating over @@ -2327,6 +2327,14 @@ incremented/reset by display_line, move_it_to etc. */ int continuation_lines_width; + /* Buffer position that ends the buffer text line being iterated. + This is normally the position after the newline at EOL. If this + is the last line of the buffer and it doesn't have a newline, + value is ZV/ZV_BYTE. Set and used only if IT->bidi_p, for + setting the end position of glyph rows produced for continuation + lines, see display_line. */ + struct text_pos eol_pos; + /* Current y-position. Automatically incremented by the height of glyph_row in move_it_to and display_line. */ int current_y; diff -r a744b1df50bd -r d65c199e8bdd src/xdisp.c --- a/src/xdisp.c Sat Mar 13 04:02:01 2010 -0500 +++ b/src/xdisp.c Sat Mar 13 11:38:01 2010 -0500 @@ -13541,6 +13541,12 @@ && NILP (Vshow_trailing_whitespace) /* Right after splitting windows, last_point may be nil. */ && INTEGERP (w->last_point) + /* Can't use this optimization if rows were bidi-reordered and + point moved backwards, because that would mean we would need + to examine previous rows that came from the same continued + line. */ + && (PT > XFASTINT (w->last_point) + || NILP (XBUFFER (w->buffer)->bidi_display_reordering)) /* This code is not used for mini-buffer for the sake of the case of redisplaying to replace an echo area message; since in that case the mini-buffer contents per se are usually @@ -13714,6 +13720,43 @@ } else if (scroll_p) rc = CURSOR_MOVEMENT_MUST_SCROLL; + else if (!NILP (XBUFFER (w->buffer)->bidi_display_reordering)) + { + /* With bidi-reordered rows, there could be more than + one candidate row whose start and end positions + occlude point. We need to find the best + candidate. */ + int rv = 0; + + do + { + rv |= set_cursor_from_row (w, row, w->current_matrix, + 0, 0, 0, 0); + /* As soon as we've found the first suitable row + whose ends_at_zv_p flag is set, we are done. */ + if (rv + && MATRIX_ROW (w->current_matrix, w->cursor.vpos)->ends_at_zv_p) + { + rc = CURSOR_MOVEMENT_SUCCESS; + break; + } + ++row; + } + while (MATRIX_ROW_BOTTOM_Y (row) < last_y + && MATRIX_ROW_START_CHARPOS (row) <= PT + && PT <= MATRIX_ROW_END_CHARPOS (row) + && cursor_row_p (w, row)); + /* If we didn't find any candidate rows, or exited the + loop before all the candidates were examined, signal + to the caller that this method failed. */ + if (rc != CURSOR_MOVEMENT_SUCCESS + && (!rv + || (MATRIX_ROW_START_CHARPOS (row) <= PT + && PT <= MATRIX_ROW_END_CHARPOS (row)))) + rc = CURSOR_MOVEMENT_CANNOT_BE_USED; + else + rc = CURSOR_MOVEMENT_SUCCESS; + } else { do @@ -15339,6 +15382,8 @@ int dy; { struct glyph_row *row = start; + struct glyph_row *best_row = NULL; + EMACS_INT mindif = BUF_ZV (XBUFFER (w->buffer)) + 1; int last_y; /* If we happen to start on a header-line, skip that. */ @@ -15371,7 +15416,30 @@ && !row->ends_at_zv_p && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))) && charpos >= MATRIX_ROW_START_CHARPOS (row)) - return row; + { + struct glyph *g; + + if (NILP (XBUFFER (w->buffer)->bidi_display_reordering)) + return row; + /* In bidi-reordered rows, there could be several rows + occluding point. We need to find the one which fits + CHARPOS the best. */ + for (g = row->glyphs[TEXT_AREA]; + g < row->glyphs[TEXT_AREA] + row->used[TEXT_AREA]; + g++) + { + if (!STRINGP (g->object)) + { + if (g->charpos > 0 && eabs (g->charpos - charpos) < mindif) + { + mindif = eabs (g->charpos - charpos); + best_row = row; + } + } + } + } + else if (best_row) + return best_row; ++row; } } @@ -17104,6 +17172,7 @@ int wrap_row_phys_ascent, wrap_row_phys_height; int wrap_row_extra_line_spacing; struct display_pos row_end; + int cvpos; /* We always start displaying at hpos zero even if hscrolled. */ xassert (it->hpos == 0 && it->current_x == 0); @@ -17622,7 +17691,7 @@ { if (BUFFERP (g->object)) { - if (g->charpos && g->charpos < min_pos) + if (g->charpos > 0 && g->charpos < min_pos) min_pos = g->charpos; if (g->charpos > max_pos) max_pos = g->charpos; @@ -17640,7 +17709,7 @@ { if (INTEGERP (g->object)) { - if (g->charpos && g->charpos < min_pos) + if (g->charpos > 0 && g->charpos < min_pos) min_pos = g->charpos; if (g->charpos > max_pos) max_pos = g->charpos; @@ -17671,6 +17740,8 @@ else if (row->used[TEXT_AREA] && max_pos) { SET_TEXT_POS (tpos, max_pos + 1, CHAR_TO_BYTE (max_pos + 1)); + row_end = it->current; + row_end.pos = tpos; /* If the character at max_pos+1 is a newline, skip that as well. Note that this may skip some invisible text. */ if (FETCH_CHAR (tpos.bytepos) == '\n' @@ -17680,13 +17751,32 @@ it->bidi_p = 0; reseat_1 (it, tpos, 0); set_iterator_to_next (it, 1); - row_end = it->current; + /* Record the position after the newline of a continued + row. We will need that to set ROW->end of the last + row produced for a continued line. */ + if (row->continued_p) + { + save_it.eol_pos.charpos = IT_CHARPOS (*it); + save_it.eol_pos.bytepos = IT_BYTEPOS (*it); + } + else + { + row_end = it->current; + save_it.eol_pos.charpos = save_it.eol_pos.bytepos = 0; + } *it = save_it; } - else - { - row_end = it->current; - row_end.pos = tpos; + else if (!row->continued_p + && row->continuation_lines_width + && it->eol_pos.charpos > 0) + { + /* Last row of a continued line. Use the position + recorded in ROW->eol_pos, to the effect that the + newline belongs to this row, not to the row which + displays the character with the largest buffer + position. */ + row_end.pos = it->eol_pos; + it->eol_pos.charpos = it->eol_pos.bytepos = 0; } row->end = row_end; } @@ -17709,15 +17799,16 @@ it->right_user_fringe_face_id = 0; /* Maybe set the cursor. */ - if ((it->w->cursor.vpos < 0 + cvpos = it->w->cursor.vpos; + if ((cvpos < 0 /* In bidi-reordered rows, keep checking for proper cursor position even if one has been found already, because buffer positions in such rows change non-linearly with ROW->VPOS, when a line is continued. One exception: when we are at ZV, display cursor on the first suitable glyph row, since all - the empty rows after that also have their ends_at_zv_p flag - set. */ - || (it->bidi_p && !row->ends_at_zv_p)) + the empty rows after that also have their position set to ZV. */ + || (it->bidi_p + && !MATRIX_ROW (it->w->desired_matrix, cvpos)->ends_at_zv_p)) && PT >= MATRIX_ROW_START_CHARPOS (row) && PT <= MATRIX_ROW_END_CHARPOS (row) && cursor_row_p (it->w, row))