From 88c569ef11aa1d9e98bca49e7ac570942276eb3d Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 23 Mar 2014 17:57:25 +0200 Subject: [PATCH] Fix bug #17047 with cursor motion when invisible text starts a line. src/xdisp.c (redisplay_window): If all previous attempts to find the cursor row failed, try a few alternatives before falling back to the top-most row of the window. Use row_containing_pos. --- src/ChangeLog | 6 ++++++ src/xdisp.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index e8ae781bf4d..a9a0ebbe4a1 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2014-03-23 Eli Zaretskii + + * xdisp.c (redisplay_window): If all previous attempts to find the + cursor row failed, try a few alternatives before falling back to + the top-most row of the window. (Bug#17047) + 2014-03-22 Daniel Colascione * process.c (conv_sockaddr_to_lisp): When extracting the string diff --git a/src/xdisp.c b/src/xdisp.c index 6f39324d2f0..53bd46328f2 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -16400,12 +16400,50 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) /* 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 happen that we are called with - PT somewhere between BEGV and START. Try to handle that case. */ + PT somewhere between BEGV and START. Try to handle that case, + and similar ones. */ if (w->cursor.vpos < 0) { - struct glyph_row *row = w->current_matrix->rows; - if (row->mode_line_p) - ++row; + /* First, try locating the proper glyph row for PT. */ + struct glyph_row *row = + row_containing_pos (w, PT, w->current_matrix->rows, NULL, 0); + + /* Sometimes point is at the beginning of invisible text that is + before the 1st character displayed in the row. In that case, + row_containing_pos fails to find the row, because no glyphs + with appropriate buffer positions are present in the row. + Therefore, we next try to find the row which shows the 1st + position after the invisible text. */ + if (!row) + { + Lisp_Object val = + get_char_property_and_overlay (make_number (PT), Qinvisible, + Qnil, NULL); + + if (TEXT_PROP_MEANS_INVISIBLE (val)) + { + ptrdiff_t alt_pos; + Lisp_Object invis_end = + Fnext_single_char_property_change (make_number (PT), Qinvisible, + Qnil, Qnil); + + if (NATNUMP (invis_end)) + alt_pos = XFASTINT (invis_end); + else + alt_pos = ZV; + row = row_containing_pos (w, alt_pos, w->current_matrix->rows, + NULL, 0); + } + } + /* Finally, fall back on the first row of the window after the + header line (if any). This is slightly better than not + displaying the cursor at all. */ + if (!row) + { + row = w->current_matrix->rows; + if (row->mode_line_p) + ++row; + } set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0); } -- 2.39.2