Subject: bug#32839: 27.0.50; recenter doesn't redisplay

From: Juri Linkov <[email-masked]>
Date: Sun, 30 Sep 2018 02:32:57 +0300

>> >>      (recenter 0 t)
>> >>
>> >>    Despite its REDISPLAY argument set to t, the frame is not redisplayed.
>> >
>> > This is how 'recenter' is documented to behave:
>> >
>> >   If ARG is omitted or nil, then recenter with point on the middle line
>> >   of the selected window; if REDISPLAY & ‘recenter-redisplay’ are
>> >   non-nil, also erase the entire frame and redraw it [...]
>> >
>> > IOW, the frame is redrawn only when ARG is nil and REDISPLAY is
>> > non-nil.
>>
>> Then why REDISPLAY is non-nil, if it doesn't redisplay the frame?
>
> There's a long history to this, you may wish to use "git -L" and look
> at the discussions/bug reports related to 'recenter'.
>
> The short answer is that this arrangement (which is new in Emacs 27)
> has its main goal to allow "C-l" to redraw the entire frame when the
> user so desires (by default, only on TTY frames), while avoiding the
> frame redraw in most, if not all, other situations, because redrawing
> a frame causes flickering.  This flickering is caused by Lisp programs
> calling 'recenter', directly or indirectly.

I see that before the recent changes, on a TTY 'C-l' and
all non-interactive calls of 'recenter' cleared the frame,
but now only interactive calls of 'recenter' redraw the frame.

OTOH, what I'm trying to achieve here is to allow C-l with a non-nil
argument to refresh the *Messages* buffer when recenter-redisplay is t.

An additional problem is that when 'recenter-positions' is customized
to not contain the keyword 'middle', then 'recenter-top-bottom' never
uses a nil arg of 'recenter', thus never redraws the frame.

But since redrawing a frame causes flickering, I'm not interested
in setting recenter-redisplay to t.  So I could implement more
fundamental changes for this only if you insist.

However, a minimal change that is needed here is to fix inconsistencies
in the recent changes: the argument name 'redisplay' is confusing -
it implies that it overrides the default value of recenter-redisplay
to force the redisplay.  A proper name would be 'interactive'.
There are dozens of commands already that use this naming convention.

diff --git a/lisp/window.el b/lisp/window.el
index 76de4207e7..584b25224c 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -8759,17 +8759,19 @@ recenter-positions
   :version "23.2"
   :group 'windows)
 
-(defun recenter-top-bottom (&optional arg)
+(defun recenter-top-bottom (&optional arg interactive)
   "Move current buffer line to the specified window line.
 With no prefix argument, successive calls place point according
 to the cycling order defined by `recenter-positions'.
 
 A prefix argument is handled like `recenter':
  With numeric prefix ARG, move current line to window-line ARG.
- With plain `C-u', move current line to window center."
-  (interactive "P")
+ With plain `C-u', move current line to window center.
+
+Interactively, INTERACTIVE is non-nil and handled like in `recenter'."
+  (interactive "P\np")
   (cond
-   (arg (recenter arg t))                 ; Always respect ARG.
+   (arg (recenter arg interactive))     ; Always respect ARG.
    (t
     (setq recenter-last-op
 	  (if (eq this-command last-command)
@@ -8780,15 +8782,15 @@ recenter-top-bottom
 	   (min (max 0 scroll-margin)
 		(truncate (/ (window-body-height) 4.0)))))
       (cond ((eq recenter-last-op 'middle)
-	     (recenter nil t))
+	     (recenter nil interactive))
 	    ((eq recenter-last-op 'top)
-	     (recenter this-scroll-margin t))
+	     (recenter this-scroll-margin interactive))
 	    ((eq recenter-last-op 'bottom)
-	     (recenter (- -1 this-scroll-margin) t))
+	     (recenter (- -1 this-scroll-margin) interactive))
 	    ((integerp recenter-last-op)
-	     (recenter recenter-last-op t))
+	     (recenter recenter-last-op interactive))
 	    ((floatp recenter-last-op)
-	     (recenter (round (* recenter-last-op (window-height))) t)))))))
+	     (recenter (round (* recenter-last-op (window-height))) interactive)))))))
 
 (define-key global-map [?\C-l] 'recenter-top-bottom)
 
diff --git a/src/window.c b/src/window.c
index 6cdc52f90e..dd8c221308 100644
--- a/src/window.c
+++ b/src/window.c
@@ -5944,16 +5944,16 @@ relative to the selected window.  If ARG is negative, it counts up from the
 bottom of the window.  (ARG should be less than the height of the window.)
 
 If ARG is omitted or nil, then recenter with point on the middle line
-of the selected window; if REDISPLAY & `recenter-redisplay' are
+of the selected window; if INTERACTIVE & `recenter-redisplay' are
 non-nil, also erase the entire frame and redraw it (when
 `auto-resize-tool-bars' is set to `grow-only', this resets the
 tool-bar's height to the minimum height needed); if
 `recenter-redisplay' has the special value `tty', then only tty frames
-are redrawn.  Interactively, REDISPLAY is always non-nil.
+are redrawn.  Interactively, INTERACTIVE is always non-nil.
 
 Just C-u as prefix means put point in the center of the window
 and redisplay normally--don't erase and redraw the frame.  */)
-  (Lisp_Object arg, Lisp_Object redisplay)
+  (Lisp_Object arg, Lisp_Object interactive)
 {
   struct window *w = XWINDOW (selected_window);
   struct buffer *buf = XBUFFER (w->contents);
@@ -5973,7 +5973,7 @@ and redisplay normally--don't erase and redraw the frame.  */)
 
   if (NILP (arg))
     {
-      if (!NILP (redisplay)
+      if (!NILP (interactive)
 	  && !NILP (Vrecenter_redisplay)
 	  && (!EQ (Vrecenter_redisplay, Qtty)
 	      || !NILP (Ftty_type (selected_frame))))