From: Eli Zaretskii <eliz@gnu.org>
Date: Thu, 3 Feb 2022 17:36:43 +0000 (+0200)
Subject: Allow ensuring that a window's starting point is never invisible
X-Git-Tag: emacs-29.0.90~2553
X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=dcc97fec29785051d7d11a66beb5f44fbaae6289;p=emacs.git

Allow ensuring that a window's starting point is never invisible

* src/xdisp.c (syms_of_xdisp) <make-window-start-visible>: 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)
---

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.