unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Alan Mackenzie <acm@muc.de>
To: Anders Lindgren <andlind@gmail.com>, emacs-devel@gnu.org
Subject: Scrolling and follow-mode
Date: Mon, 21 Apr 2014 16:17:51 +0000	[thread overview]
Message-ID: <20140421161751.GC4266@acm.acm> (raw)

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).
`



             reply	other threads:[~2014-04-21 16:17 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-04-21 16:17 Alan Mackenzie [this message]
2014-04-22 20:20 ` Scrolling and follow-mode Anders Lindgren
2014-04-27 11:52   ` Alan Mackenzie

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20140421161751.GC4266@acm.acm \
    --to=acm@muc.de \
    --cc=andlind@gmail.com \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).