From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Anders Lindgren Newsgroups: gmane.emacs.devel Subject: Re: Scrolling and follow-mode Date: Tue, 22 Apr 2014 22:20:46 +0200 Message-ID: References: <20140421161751.GC4266@acm.acm> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/alternative; boundary=f46d04428c98eb43b004f7a759f9 X-Trace: ger.gmane.org 1398204918 1756 80.91.229.3 (22 Apr 2014 22:15:18 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Tue, 22 Apr 2014 22:15:18 +0000 (UTC) Cc: emacs-devel@gnu.org To: Alan Mackenzie Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Apr 23 00:15:11 2014 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1Wciy4-0002RJ-HW for ged-emacs-devel@m.gmane.org; Wed, 23 Apr 2014 00:15:08 +0200 Original-Received: from localhost ([::1]:57566 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Wciy4-0001gF-1I for ged-emacs-devel@m.gmane.org; Tue, 22 Apr 2014 18:15:08 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:40972) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WchBU-00036K-B0 for emacs-devel@gnu.org; Tue, 22 Apr 2014 16:20:54 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WchBS-0004Nw-05 for emacs-devel@gnu.org; Tue, 22 Apr 2014 16:20:52 -0400 Original-Received: from mail-we0-x22d.google.com ([2a00:1450:400c:c03::22d]:35092) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WchBR-0004Np-4K for emacs-devel@gnu.org; Tue, 22 Apr 2014 16:20:49 -0400 Original-Received: by mail-we0-f173.google.com with SMTP id w61so5412472wes.4 for ; Tue, 22 Apr 2014 13:20:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=/eI5E9jPjOUo3N5BYT4ftId3b6v41ZXDLvww0ZYqqQ0=; b=iSiKjQtbPWvD4ij7rGToERcrKnDRqEX2Oo5+/bjTyqBZbd80/UbiYBz6v5qcPHiRgu IGfvjpRJrNmsYuiGydIiT5oB8UASidcAHr5u41V9c/SuGqR+gdl+fOOBCg3Yp/8IVU9X ZU3cpjrq/yRDE9EQ1I2Zmi0wKNZ445zlMDdrhDHXjn84z2opBPak8XHsjK8NfWw/Da2G pv0K6QjEo1ZOq5SoDKHrvK8eIuy3rI2acz6at3mpre+f39QHJEbj5oLqJB1yFNPMjhVS gMpfULNQxSykUzH5avz987LiDxoYE43+gw4U2tHNUzJJHbVTptQygSHEGKVCEknrJSd9 PaEg== X-Received: by 10.180.82.133 with SMTP id i5mr10883wiy.50.1398198047030; Tue, 22 Apr 2014 13:20:47 -0700 (PDT) Original-Received: by 10.217.87.196 with HTTP; Tue, 22 Apr 2014 13:20:46 -0700 (PDT) In-Reply-To: <20140421161751.GC4266@acm.acm> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:400c:c03::22d X-Mailman-Approved-At: Tue, 22 Apr 2014 18:15:04 -0400 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:171599 Archived-At: --f46d04428c98eb43b004f7a759f9 Content-Type: text/plain; charset=UTF-8 Hi Alan and Emacs! Scrolling a few lines at a time was obviously something that I do very seldom -- it appears that I missed that case when I wrote follow-mode, and I have never seen this problem for the (almost) twenty years I've been using it. Thanks for finding and fixing the problem! When it comes to the patch, it looks well written. I have only two comments: * The documentation says that `follow-fixed-window` is the window that must not be scrolled. However, in the code, it's only read once, as the condition to a `when`, so the actual value doesn't matter as long as it's non-nil. Wouldn't it better do document is a boolean? * The code at (your) lines --- 1201,1222 ---- could be cleaner. It contains a `let*` that sets two variables, `dest` and `windows` and set a bunch others to a default nil value. The others are later set using a `setq`. I would suggest placing your code before the first assignment of `dest` and simply move the point, that way `dest` will get the value of the new point. Then use a new `let*` to set the others. Like the following (untested) code: (let ((windows (follow-all-followers win))) (when follow-fixed-window (follow-debug-message "fixed") (follow-redisplay windows win) (goto-char (follow-get-scrolled-point (point) windows)) (setq follow-fixed-window nil)) (let* ((dest (point)) (win-start-end (progn (follow-update-window-start (car windows)) (follow-windows-start-end windows))) (aligned (follow-windows-aligned-p win-start-end)) (visible (follow-pos-visible dest win win-start-end)) selected-window-up-to-date) (unless (and aligned visible) (setq follow-windows-start-end-cache nil)) Again, thanks! Sincerely, Anders Lindgren On Mon, Apr 21, 2014 at 6:17 PM, Alan Mackenzie wrote: > Hi, Anders, hi, Emacs. > > With follow-mode enabled, the functions follow-scroll-up and > follow-scroll-down don't work very well when given a numerical argument. > > In follow-scroll-up, the flag follow-internal-force-redisplay gets set, > which causes the post-command-hook function (a) to bypass the code which > selects the window to put point in; (b) to force redisplay to rescroll > the current window. Both of these are undesirable when point is near a > boundary of one window, and should pass into the adjacent window on the > scrolling. > > I have fixed this by causing the two scrolling functions to set a flag > which causes follow-adjust-window to align its windows as its first > action, then allowing it to select the appropriate window for point with > the existing code. There are one or two minor changes too. > > Comments on this fix are welcome. Here is the patch (based on the > recent trunk revision 116992. > > > > > *** emacs/emacs.bzr/trunk/lisp/follow.el 2014-02-15 > 19:53:57.000000000 +0000 > --- follow.el 2014-04-21 16:15:28.000000000 +0000 > *************** > *** 347,352 **** > --- 347,355 ---- > (defvar follow-windows-start-end-cache nil > "Cache used by `follow-window-start-end'.") > > + (defvar follow-fixed-window nil > + "When non-nil, the window which must not be scrolled. > + This is typically set by explicit scrolling commands.") > ;;; Debug messages > > ;; This inline function must be as small as possible! > *************** > *** 439,444 **** > --- 442,496 ---- > > ;;; Scroll > > + (defun follow-get-scrolled-point (dest windows) > + "Calculate the correct value for point after a scrolling operation. > + > + DEST is our default position, typically where point was before the > scroll. > + If `scroll-preserve-screen-position' is non-nil and active, DEST will be > + in the same screen position as before the scroll. WINDOWS is the list of > + windows in the follow chain. > + > + This function attempts to duplicate the point placing from > + `window_scroll_line_based' in the Emacs core source window.c. > + > + Return the new position." > + (if (and scroll-preserve-screen-position > + (get this-command 'scroll-command)) > + dest > + (let ((dest-column > + (save-excursion > + (goto-char dest) > + (- (current-column) > + (progn (vertical-motion 0) (current-column))))) > + (limit0 > + (with-selected-window (car windows) > + (save-excursion > + (goto-char (window-start)) > + (vertical-motion 0) > + (point)))) > + (limitn > + (with-selected-window (car (reverse windows)) > + (save-excursion > + (goto-char (window-end nil t)) > + (if (pos-visible-in-window-p) > + (point) ; i.e. (point-max) > + (1- (point))))))) > + (follow-debug-message "dest: %s; dest-column: %s; limitn: %s" dest > dest-column limitn) > + (cond > + ((< dest limit0) > + (with-selected-window (car windows) > + (save-excursion > + (goto-char limit0) > + (vertical-motion (cons dest-column 0)) > + (point)))) > + ((> dest limitn) > + (with-selected-window (car (reverse windows)) > + (save-excursion > + (goto-char limitn) > + (vertical-motion (cons dest-column 0)) > + (point)))) > + (t dest))))) > + > ;; `scroll-up' and `-down', but for windows in Follow mode. > ;; > ;; Almost like the real thing, except when the cursor ends up outside > *************** > *** 454,459 **** > --- 506,512 ---- > ;; position... (This would also be corrected if we would have had a > ;; good redisplay abstraction.) > > + ;;;###autoload > (defun follow-scroll-up (&optional arg) > "Scroll text in a Follow mode window chain up. > > *************** > *** 467,475 **** > (interactive "P") > (cond ((not follow-mode) > (scroll-up arg)) > (arg > ! (save-excursion (scroll-up arg)) > ! (setq follow-internal-force-redisplay t)) > (t > (let* ((windows (follow-all-followers)) > (end (window-end (car (reverse windows))))) > --- 520,534 ---- > (interactive "P") > (cond ((not follow-mode) > (scroll-up arg)) > + ((eq arg '-) > + (follow-scroll-down)) > (arg > ! (let ((opoint (point))) > ! (scroll-up arg) > ! (unless (and scroll-preserve-screen-position > ! (get this-command 'scroll-command)) > ! (goto-char opoint)) > ! (setq follow-fixed-window (selected-window)))) > (t > (let* ((windows (follow-all-followers)) > (end (window-end (car (reverse windows))))) > *************** > *** 481,488 **** > (goto-char end)) > (vertical-motion (- next-screen-context-lines)) > (set-window-start (car windows) (point))))))) > > ! > (defun follow-scroll-down (&optional arg) > "Scroll text in a Follow mode window chain down. > > --- 540,548 ---- > (goto-char end)) > (vertical-motion (- next-screen-context-lines)) > (set-window-start (car windows) (point))))))) > + (put 'follow-scroll-up 'scroll-command t) > > ! ;;;###autoload > (defun follow-scroll-down (&optional arg) > "Scroll text in a Follow mode window chain down. > > *************** > *** 492,503 **** > If called with an argument, scroll ARG lines down. > Negative ARG means scroll upward. > > ! Works like `scroll-up' when not in Follow mode." > (interactive "P") > (cond ((not follow-mode) > ! (scroll-up arg)) > (arg > ! (save-excursion (scroll-down arg))) > (t > (let* ((windows (follow-all-followers)) > (win (car (reverse windows))) > --- 552,571 ---- > If called with an argument, scroll ARG lines down. > Negative ARG means scroll upward. > > ! Works like `scroll-down' when not in Follow mode." > (interactive "P") > (cond ((not follow-mode) > ! (scroll-down arg)) > ! ((eq arg '-) > ! (follow-scroll-up)) > (arg > ! (let ((opoint (point))) > ! (scroll-down arg) > ! (unless (and scroll-preserve-screen-position > ! (get this-command 'scroll-command)) > ! (goto-char opoint)) > ! (setq follow-fixed-window (selected-window))) > ! ) > (t > (let* ((windows (follow-all-followers)) > (win (car (reverse windows))) > *************** > *** 513,518 **** > --- 581,587 ---- > (goto-char start) > (vertical-motion (- next-screen-context-lines 1)) > (setq follow-internal-force-redisplay t)))))) > + (put 'follow-scroll-down 'scroll-command t) > > (declare-function comint-adjust-point "comint" (window)) > (defvar comint-scroll-show-maximum-output) > *************** > *** 1132,1143 **** > (not (window-minibuffer-p win))) > (let* ((dest (point)) > (windows (follow-all-followers win)) > ! (win-start-end (progn > ! (follow-update-window-start (car windows)) > ! (follow-windows-start-end windows))) > ! (aligned (follow-windows-aligned-p win-start-end)) > ! (visible (follow-pos-visible dest win win-start-end)) > selected-window-up-to-date) > (unless (and aligned visible) > (setq follow-windows-start-end-cache nil)) > > --- 1201,1222 ---- > (not (window-minibuffer-p win))) > (let* ((dest (point)) > (windows (follow-all-followers win)) > ! win-start-end aligned visible > selected-window-up-to-date) > + > + ;; If we've explicitly scrolled, align the windows first. > + (when follow-fixed-window > + (follow-debug-message "fixed") > + (follow-redisplay windows win) > + (setq dest (follow-get-scrolled-point dest windows)) > + (goto-char dest) > + (setq follow-fixed-window nil)) > + (setq > + win-start-end (progn > + (follow-update-window-start (car windows)) > + (follow-windows-start-end windows)) > + aligned (follow-windows-aligned-p win-start-end) > + visible (follow-pos-visible dest win win-start-end)) > (unless (and aligned visible) > (setq follow-windows-start-end-cache nil)) > > *************** > *** 1184,1190 **** > ;; It should be optimized for speed. > ((and visible aligned) > (follow-debug-message "same")) > ! ;; Pick a position in any window. If the display is ok, > ;; this picks the `correct' window. > ((follow-select-if-visible dest win-start-end) > (follow-debug-message "visible") > --- 1263,1269 ---- > ;; It should be optimized for speed. > ((and visible aligned) > (follow-debug-message "same")) > ! ;; Pick a position in any window. If the display is ok, > ;; this picks the `correct' window. > ((follow-select-if-visible dest win-start-end) > (follow-debug-message "visible") > > > > -- > Alan Mackenzie (Nuremberg, Germany). > ` > --f46d04428c98eb43b004f7a759f9 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable
Hi Alan and Emacs!

Scrolling a few line= s at a time was obviously something that I do very seldom -- it appears tha= t I missed that case when I wrote follow-mode, and I have never seen this p= roblem for the (almost) twenty years I've been using it. Thanks for fin= ding and fixing the problem!

When it comes to the patch, it looks well written. I ha= ve only two comments:

* The documentation says tha= t `follow-fixed-window` is the window that must not be scrolled. However, i= n the code, it's only read once, as the condition to a `when`, so the a= ctual value doesn't matter as long as it's non-nil. Wouldn't it= better do document is a boolean?

* The code at (your) lines=C2=A0--- 1201,1222 ---- could be cleaner. I= t contains a `let*` that sets two variables, `dest` and `windows` and set a= bunch others to a default nil value. The others are later set using a `set= q`. I would suggest=C2=A0placing your code before the first assignment of `dest` an= d simply move the point, that way `dest` will get the value of the new poin= t. Then use a new `let*` to set the others. Like the following (untested) c= ode:

(let ((windows (follow-all-followers win)))
=C2=A0 (when follow= -fixed-window
=C2=A0 =C2=A0 (follow-debug-message "fixed")
=C2= =A0 =C2=A0 (follow-redisplay windows win)
=C2=A0 =C2=A0 (goto-cha= r (follow-get-scrolled-point (point) windows))
=C2=A0 =C2=A0 (set= q follow-fixed-window nil))
=C2=A0 (let* ((dest (point))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(w= in-start-end (progn
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (follow-update-window-start (= car windows))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (follow-windows-start-end windows= )))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(aligned (follow-windows-aligned-p w= in-start-end))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(visible (follow= -pos-visible dest win win-start-end))
=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0selected-window-up-to-date)
=C2=A0 =C2=A0 (unless (and ali= gned visible)
=C2=A0 =C2=A0 =C2=A0 (setq follow-windows-start-end-cache nil))
<= div>

Again, thanks!

Sincerely,
=C2=A0 =C2=A0 Anders Lindgren



On Mon, Apr 21, 2014 at 6:17 PM, Alan Mackenzie <= ;acm@muc.de> = wrote:
Hi, Anders, hi, Emacs.

With follow-mode enabled, the functions follow-scroll-up and
follow-scroll-down don't work very well when given a numerical argument= .

In follow-scroll-up, the flag follow-internal-force-redisplay gets set,
which causes the post-command-hook function (a) to bypass the code which selects the window to put point in; (b) to force redisplay to rescroll
the current window. =C2=A0Both of these are undesirable when point is near = a
boundary of one window, and should pass into the adjacent window on the
scrolling.

I have fixed this by causing the two scrolling functions to set a flag
which causes follow-adjust-window to align its windows as its first
action, then allowing it to select the appropriate window for point with the existing code. =C2=A0There are one or two minor changes too.

Comments on this fix are welcome. =C2=A0Here is the patch (based on the
recent trunk revision 116992.




*** emacs/emacs.bzr/trunk/lisp/follow.el =C2=A0 =C2=A0 =C2=A0 =C2=A02014-02= -15 19:53:57.000000000 +0000
--- follow.el =C2=A0 2014-04-21 16:15:28.000000000 +0000
***************
*** 347,352 ****
--- 347,355 ----
=C2=A0 (defvar follow-windows-start-end-cache nil
=C2=A0 =C2=A0 "Cache used by `follow-window-start-end'.")

+ (defvar follow-fixed-window nil
+ =C2=A0 "When non-nil, the window which must not be scrolled.
+ This is typically set by explicit scrolling commands.")
=C2=A0 ;;; Debug messages

=C2=A0 ;; This inline function must be as small as possible!
***************
*** 439,444 ****
--- 442,496 ----

=C2=A0 ;;; Scroll

+ (defun follow-get-scrolled-point (dest windows)
+ =C2=A0 "Calculate the correct value for point after a scrolling oper= ation.
+
+ DEST is our default position, typically where point was before the scroll= .
+ If `scroll-preserve-screen-position' is non-nil and active, DEST will= be
+ in the same screen position as before the scroll. =C2=A0WINDOWS is the li= st of
+ windows in the follow chain.
+
+ This function attempts to duplicate the point placing from
+ `window_scroll_line_based' in the Emacs core source window.c.
+
+ Return the new position."
+ =C2=A0 (if (and scroll-preserve-screen-position
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(get this-command 'scroll-command))=
+ =C2=A0 =C2=A0 =C2=A0 dest
+ =C2=A0 =C2=A0 (let ((dest-column
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(save-excursion
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(goto-char dest)
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(- (current-column)
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (progn (vertical-motion = 0) (current-column)))))
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 (limit0
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(with-selected-window (car windows)
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(save-excursion
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(goto-char (window-start)= )
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(vertical-motion 0)
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(point))))
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 (limitn
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(with-selected-window (car (reverse win= dows))
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(save-excursion
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(goto-char (window-end ni= l t))
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(if (pos-visible-in-windo= w-p)
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(point) =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0; i.e. (point-max)
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(1- (point)))))))<= br> + =C2=A0 =C2=A0 =C2=A0 (follow-debug-message "dest: %s; dest-column: %= s; limitn: %s" dest dest-column limitn)
+ =C2=A0 =C2=A0 =C2=A0 (cond
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0((< dest limit0)
+ =C2=A0 =C2=A0 =C2=A0 (with-selected-window (car windows)
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 (save-excursion
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (goto-char limit0)
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (vertical-motion (cons dest-column 0))=
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (point))))
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0((> dest limitn)
+ =C2=A0 =C2=A0 =C2=A0 (with-selected-window (car (reverse windows))
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 (save-excursion
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (goto-char limitn)
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (vertical-motion (cons dest-column 0))=
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (point))))
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0(t dest)))))
+
=C2=A0 ;; `scroll-up' and `-down', but for windows in Follow mode.<= br> =C2=A0 ;;
=C2=A0 ;; Almost like the real thing, except when the cursor ends up outsid= e
***************
*** 454,459 ****
--- 506,512 ----
=C2=A0 ;; position... =C2=A0(This would also be corrected if we would have = had a
=C2=A0 ;; good redisplay abstraction.)

+ ;;;###autoload
=C2=A0 (defun follow-scroll-up (&optional arg)
=C2=A0 =C2=A0 "Scroll text in a Follow mode window chain up.

***************
*** 467,475 ****
=C2=A0 =C2=A0 (interactive "P")
=C2=A0 =C2=A0 (cond ((not follow-mode)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(scroll-up arg))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (arg
! =C2=A0 =C2=A0 =C2=A0 =C2=A0(save-excursion (scroll-up arg))
! =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq follow-internal-force-redisplay t))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (t
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(let* ((windows (follow-all-followers)) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (end (window-end (c= ar (reverse windows)))))
--- 520,534 ----
=C2=A0 =C2=A0 (interactive "P")
=C2=A0 =C2=A0 (cond ((not follow-mode)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(scroll-up arg))
+ =C2=A0 =C2=A0 =C2=A0 ((eq arg '-)
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0(follow-scroll-down))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (arg
! =C2=A0 =C2=A0 =C2=A0 =C2=A0(let ((opoint (point)))
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(scroll-up arg)
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(unless (and scroll-preserve-screen-pos= ition
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 (get this-command 'scroll-command))
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(goto-char opoint))
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq follow-fixed-window (selected-win= dow))))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (t
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(let* ((windows (follow-all-followers)) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (end (window-end (c= ar (reverse windows)))))
***************
*** 481,488 ****
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(goto-char en= d))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(vertical-motion (- next-sc= reen-context-lines))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(set-window-start (car wind= ows) (point)))))))

!
=C2=A0 (defun follow-scroll-down (&optional arg)
=C2=A0 =C2=A0 "Scroll text in a Follow mode window chain down.

--- 540,548 ----
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(goto-char en= d))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(vertical-motion (- next-sc= reen-context-lines))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(set-window-start (car wind= ows) (point)))))))
+ (put 'follow-scroll-up 'scroll-command t)

! ;;;###autoload
=C2=A0 (defun follow-scroll-down (&optional arg)
=C2=A0 =C2=A0 "Scroll text in a Follow mode window chain down.

***************
*** 492,503 ****
=C2=A0 If called with an argument, scroll ARG lines down.
=C2=A0 Negative ARG means scroll upward.

! Works like `scroll-up' when not in Follow mode."
=C2=A0 =C2=A0 (interactive "P")
=C2=A0 =C2=A0 (cond ((not follow-mode)
! =C2=A0 =C2=A0 =C2=A0 =C2=A0(scroll-up arg))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (arg
! =C2=A0 =C2=A0 =C2=A0 =C2=A0(save-excursion (scroll-down arg)))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (t
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(let* ((windows (follow-all-followers)) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (win (car (reverse = windows)))
--- 552,571 ----
=C2=A0 If called with an argument, scroll ARG lines down.
=C2=A0 Negative ARG means scroll upward.

! Works like `scroll-down' when not in Follow mode."
=C2=A0 =C2=A0 (interactive "P")
=C2=A0 =C2=A0 (cond ((not follow-mode)
! =C2=A0 =C2=A0 =C2=A0 =C2=A0(scroll-down arg))
! =C2=A0 =C2=A0 =C2=A0 ((eq arg '-)
! =C2=A0 =C2=A0 =C2=A0 =C2=A0(follow-scroll-up))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (arg
! =C2=A0 =C2=A0 =C2=A0 =C2=A0(let ((opoint (point)))
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(scroll-down arg)
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(unless (and scroll-preserve-screen-pos= ition
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 (get this-command 'scroll-command))
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(goto-char opoint))
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq follow-fixed-window (selected-win= dow)))
! =C2=A0 =C2=A0 =C2=A0 =C2=A0)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (t
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(let* ((windows (follow-all-followers)) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (win (car (reverse = windows)))
***************
*** 513,518 ****
--- 581,587 ----
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(goto-char start)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(vertical-motion (- next-sc= reen-context-lines 1))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(setq follow-internal-force= -redisplay t))))))
+ (put 'follow-scroll-down 'scroll-command t)

=C2=A0 (declare-function comint-adjust-point "comint" (window)) =C2=A0 (defvar comint-scroll-show-maximum-output)
***************
*** 1132,1143 ****
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(not (window-minibuf= fer-p win)))
=C2=A0 =C2=A0 =C2=A0 (let* ((dest (point))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(windows (follow-all-follow= ers win))
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(win-start-end (progn
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (follow-update-window-start (car windows))
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 (follow-windows-start-end windows)))
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(aligned (follow-windows-aligned= -p win-start-end))
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(visible (follow-pos-visible des= t win win-start-end))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0selected-window-up-to-date)=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (unless (and aligned visible)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq follow-windows-start-end-cache nil= ))

--- 1201,1222 ----
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(not (window-minibuf= fer-p win)))
=C2=A0 =C2=A0 =C2=A0 (let* ((dest (point))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(windows (follow-all-follow= ers win))
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0win-start-end aligned visible =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0selected-window-up-to-date)=
+
+ =C2=A0 =C2=A0 =C2=A0 ;; If we've explicitly scrolled, align the windo= ws first.
+ =C2=A0 =C2=A0 =C2=A0 (when follow-fixed-window
+ =C2=A0 =C2=A0 =C2=A0 (follow-debug-message "fixed")
+ =C2=A0 =C2=A0 =C2=A0 (follow-redisplay windows win)
+ =C2=A0 =C2=A0 =C2=A0 (setq dest (follow-get-scrolled-point dest windows))=
+ =C2=A0 =C2=A0 =C2=A0 (goto-char dest)
+ =C2=A0 =C2=A0 =C2=A0 (setq follow-fixed-window nil))
+ =C2=A0 =C2=A0 =C2=A0 (setq
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0win-start-end (progn
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0(follow-update-window-start (car windows))
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0(follow-windows-start-end windows))
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0aligned (follow-windows-aligned-p win-start-en= d)
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0visible (follow-pos-visible dest win win-start= -end))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 (unless (and aligned visible)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq follow-windows-start-end-cache nil= ))

***************
*** 1184,1190 ****
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; It should be optimized f= or speed.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0((and visible aligned)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (follow-debug-message &quo= t;same"))
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; Pick a position in any window= . =C2=A0If the display is ok,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; this picks the `correct&= #39; window.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0((follow-select-if-visible = dest win-start-end)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (follow-debug-message &quo= t;visible")
--- 1263,1269 ----
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; It should be optimized f= or speed.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0((and visible aligned)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (follow-debug-message &quo= t;same"))
! =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; Pick a position in any window. =C2= =A0If the display is ok,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; this picks the `correct&= #39; window.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0((follow-select-if-visible = dest win-start-end)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (follow-debug-message &quo= t;visible")



--
Alan Mackenzie (Nuremberg, Germany).
`

--f46d04428c98eb43b004f7a759f9--