Subject: Re: bug#31325: 27.0.50; PROPOSAL: introduce a new function to recenter without redisplaying the frame

From: John Shahid <[email-masked]>
Date: Sat, 30 Jun 2018 20:20:24 +0000

Eli Zaretskii <[email-masked]> writes:

>> From: John Shahid <[email-masked]>
>> Date: Thu, 28 Jun 2018 13:27:34 +0000
>> Cc: [email-masked]
>> 
>> >> 1. introduce a new lisp function for recentering and discourage the use
>> >> of `recenter' from lisp (i.e. declaring it `interactive-only'), or
>> >> 2. add a new `recenter-and-redisplay' and bound it to C-l
>> >> Also, Stefan's suggestion/possible solution:
>> >> 3. adding an argument to `recenter' to control the redisplay behavior
>> >
>> > Either of those is OK.  The benefit of the 3rd is that it would likely
>> > "magically fix" 99% of the existing uses (I'm thinking of adding an
>> > optional argument which we could call `and-redisplay` which when non-nil
>> > tells recenter to do a redisplay, so all existing Elisp calls would be
>> > implicitly modified not to cause a redisplay).
>> 
>> I ended up going with option 3. I also used `redisplay` instead of
>> `and-redisplay`. I felt the `and` is redundant, not sure how strongly
>> you feel about the name.
>
> Thanks, but please also include a NEWS entry announcing the change,
> and a suitable change for the ELisp manual.
>
> And I have a few comments:
>
>> -  (register Lisp_Object arg)
>> +  (register Lisp_Object arg, register Lisp_Object redisplay)
>
> I believe nowadays we remove the 'register' qualifiers whenever we
> change code that uses them.
>
>>  {
>>    struct window *w = XWINDOW (selected_window);
>>    struct buffer *buf = XBUFFER (w->contents);
>> @@ -5933,8 +5934,9 @@ and redisplay normally--don't erase and redraw the frame.  */)
>>  
>>    if (NILP (arg))
>>      {
>> -      if (!NILP (Vrecenter_redisplay)
>> -	  && (!EQ (Vrecenter_redisplay, Qtty)
>> +      if (!NILP (redisplay)
>> +	  && !NILP (Vrecenter_redisplay)
>> +	  && (!EQ (redisplay, Qtty)
>                    ^^^^^^^^^
> This should have been Vrecenter_redisplay, right?

fixed all the issues mentioned above in the attached patch and
documented the change in the NEWS file and the manual.

cheers,

>From 1b7380df866e3ca7c1a940a92c36f43ce8e5043f Mon Sep 17 00:00:00 2001
From: John Shahid <[email-masked]>
Date: Thu, 28 Jun 2018 09:13:45 -0400
Subject: [PATCH] Add a new argument to `recenter' to allow finer control of
 redisplay

* window.c (recenter): add a new REDISPLAY argument to allow the
  caller to control the redisplay behavior. `recenter' will only
  redisplay the frame if this new arg and `recenter-redisplay' are
  both non-nil.
* window.el (recenter-top-bottom): pass an extra non-nil argument to
  `recenter' to force a redisplay
---
 doc/lispref/windows.texi | 12 +++++++-----
 etc/NEWS                 |  5 +++++
 lisp/window.el           | 10 +++++-----
 src/window.c             | 20 +++++++++++---------
 4 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 5497759595..9740bbebf2 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -4138,7 +4138,7 @@ Textual Scrolling
 only if point is already on that position do they signal an error.
 @end defopt
 
-@deffn Command recenter &optional count
+@deffn Command recenter &optional count redisplay
 @cindex centering point
 This function scrolls the text in the selected window so that point is
 displayed at a specified vertical position within the window.  It does
@@ -4152,8 +4152,9 @@ Textual Scrolling
 
 If @var{count} is @code{nil} (or a non-@code{nil} list),
 @code{recenter} puts the line containing point in the middle of the
-window.  If @var{count} is @code{nil}, this function may redraw the
-frame, according to the value of @code{recenter-redisplay}.
+window.  If @var{count} is @code{nil} and @var{redisplay} is
+non-@code{nil}, this function may redraw the frame, according to the
+value of @code{recenter-redisplay}.
 
 When @code{recenter} is called interactively, @var{count} is the raw
 prefix argument.  Thus, typing @kbd{C-u} as the prefix sets the
@@ -4181,8 +4182,9 @@ Textual Scrolling
 
 @defopt recenter-redisplay
 If this variable is non-@code{nil}, calling @code{recenter} with a
-@code{nil} argument redraws the frame.  The default value is
-@code{tty}, which means only redraw the frame if it is a tty frame.
+@code{nil} @var{count} argument and non-@code{nil} @var{redisplay}
+argument redraws the frame.  The default value is @code{tty}, which
+means only redraw the frame if it is a tty frame.
 @end defopt
 
 @deffn Command recenter-top-bottom &optional count
diff --git a/etc/NEWS b/etc/NEWS
index 12757f61d2..8adb962120 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -658,6 +658,11 @@ manual for more details.
 
 * Lisp Changes in Emacs 27.1
 
++++
+** The function 'recenter' accepts an additional optional argument.
+If the optional second argument is nil, recenter will not redisplay
+the frame regardless of the value of 'recenter-redisplay'.
+
 +++
 ** New functions 'major-mode-suspend' and 'major-mode-restore'.
 Use them when switching temporarily to another major mode, e.g. for
diff --git a/lisp/window.el b/lisp/window.el
index fdd510401d..6d9d8bdcd2 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -8778,15 +8778,15 @@ recenter-top-bottom
 	   (min (max 0 scroll-margin)
 		(truncate (/ (window-body-height) 4.0)))))
       (cond ((eq recenter-last-op 'middle)
-	     (recenter))
+	     (recenter nil t))
 	    ((eq recenter-last-op 'top)
-	     (recenter this-scroll-margin))
+	     (recenter this-scroll-margin t))
 	    ((eq recenter-last-op 'bottom)
-	     (recenter (- -1 this-scroll-margin)))
+	     (recenter (- -1 this-scroll-margin) t))
 	    ((integerp recenter-last-op)
-	     (recenter recenter-last-op))
+	     (recenter recenter-last-op t))
 	    ((floatp recenter-last-op)
-	     (recenter (round (* recenter-last-op (window-height))))))))))
+	     (recenter (round (* recenter-last-op (window-height))) t)))))))
 
 (define-key global-map [?\C-l] 'recenter-top-bottom)
 
diff --git a/src/window.c b/src/window.c
index 81fd7f2b47..a966e99ca8 100644
--- a/src/window.c
+++ b/src/window.c
@@ -5898,22 +5898,23 @@ displayed_window_lines (struct window *w)
 }

-DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
+DEFUN ("recenter", Frecenter, Srecenter, 0, 2, "P",
        doc: /* Center point in selected window and maybe redisplay frame.
 With a numeric prefix argument ARG, recenter putting point on screen line ARG
 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 the variable `recenter-redisplay' is 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.
+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 (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.
 
 Just C-u as prefix means put point in the center of the window
 and redisplay normally--don't erase and redraw the frame.  */)
-  (register Lisp_Object arg)
+  (Lisp_Object arg, Lisp_Object redisplay)
 {
   struct window *w = XWINDOW (selected_window);
   struct buffer *buf = XBUFFER (w->contents);
@@ -5933,7 +5934,8 @@ and redisplay normally--don't erase and redraw the frame.  */)
 
   if (NILP (arg))
     {
-      if (!NILP (Vrecenter_redisplay)
+      if (!NILP (redisplay)
+	  && !NILP (Vrecenter_redisplay)
 	  && (!EQ (Vrecenter_redisplay, Qtty)
 	      || !NILP (Ftty_type (selected_frame))))
 	{
-- 
2.18.0