From dcc97fec29785051d7d11a66beb5f44fbaae6289 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Thu, 3 Feb 2022 19:36:43 +0200 Subject: [PATCH] Allow ensuring that a window's starting point is never invisible * src/xdisp.c (syms_of_xdisp) : New buffer-local variable. (redisplay_window): If 'make-window-start-visible' is non-nil, don't accept window-start position that is in invisible text or is covered by a "replacing" 'display' property. (Bug#14582) --- src/xdisp.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 381df490703..20b0d97b975 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -19036,8 +19036,9 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) force_start: /* Handle case where place to start displaying has been specified, - unless the specified location is outside the accessible range. */ - if (w->force_start) + unless the specified location is outside the accessible range, or + the buffer wants the window-start point to be always visible. */ + if (w->force_start && !make_window_start_visible) { /* We set this later on if we have to adjust point. */ int new_vpos = -1; @@ -19227,6 +19228,8 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) goto done; } + Lisp_Object iprop, dspec; + struct text_pos ignored; /* Handle case where text has not changed, only point, and it has not moved off the frame, and we are not retrying after hscroll. (current_matrix_up_to_date_p is true when retrying.) */ @@ -19248,10 +19251,28 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) } } /* If current starting point was originally the beginning of a line - but no longer is, find a new starting point. */ + but no longer is, or if the starting point is invisible but the + buffer wants it always visible, find a new starting point. */ else if (w->start_at_line_beg - && !(CHARPOS (startp) <= BEGV - || FETCH_BYTE (BYTEPOS (startp) - 1) == '\n')) + && (!(CHARPOS (startp) <= BEGV + || FETCH_BYTE (BYTEPOS (startp) - 1) == '\n') + || (make_window_start_visible + /* Is window-start in invisible text? */ + && ((CHARPOS (startp) > BEGV + && ((iprop = + Fget_char_property + (make_fixnum (CHARPOS (startp) - 1), Qinvisible, + window)), + TEXT_PROP_MEANS_INVISIBLE (iprop) != 0)) + /* Is window-start covered by a replacing + 'display' property? */ + || (!NILP (dspec = + Fget_char_property + (make_fixnum (CHARPOS (startp)), Qdisplay, + window)) + && handle_display_spec (NULL, dspec, Qnil, Qnil, + &ignored, CHARPOS (startp), + FRAME_WINDOW_P (f)) > 0))))) { #ifdef GLYPH_DEBUG debug_method_add (w, "recenter 1"); @@ -19327,6 +19348,21 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) goto force_start; } + /* Don't use the same window-start if it is covered by a + replacing 'display' property and the buffer requested the + window-start to be always visible. */ + if (make_window_start_visible + && !NILP (dspec = Fget_char_property (make_fixnum (CHARPOS (startp)), + Qdisplay, window)) + && handle_display_spec (NULL, dspec, Qnil, Qnil, &ignored, + CHARPOS (startp), FRAME_WINDOW_P (f)) > 0) + { +#ifdef GLYPH_DEBUG + debug_method_add (w, "recenter 2"); +#endif + goto recenter; + } + #ifdef GLYPH_DEBUG debug_method_add (w, "same window start"); #endif @@ -35973,6 +36009,12 @@ window, nil if it's okay to leave the cursor partially-visible. */); Vmake_cursor_line_fully_visible = Qt; DEFSYM (Qmake_cursor_line_fully_visible, "make-cursor-line-fully-visible"); + DEFVAR_BOOL ("make-window-start-visible", make_window_start_visible, + doc: /* Whether to ensure `window-start' position is never invisible. */); + make_window_start_visible = false; + DEFSYM (Qmake_window_start_visible, "make-window-start-visible"); + Fmake_variable_buffer_local (Qmake_window_start_visible); + DEFSYM (Qclose_tab, "close-tab"); DEFVAR_LISP ("tab-bar-border", Vtab_bar_border, doc: /* Border below tab-bar in pixels. -- 2.39.5