]> code.delx.au - gnu-emacs/blobdiff - lisp/follow.el
; Fix breakage from previous commit
[gnu-emacs] / lisp / follow.el
index f2427374f245fce58a90752fcc67d27d4db81d59..c510e5a848beeed12a9004cc135ebea7c4bd2d26 100644 (file)
@@ -1,10 +1,10 @@
 ;;; follow.el --- synchronize windows showing the same buffer
 
-;; Copyright (C) 1995-1997, 1999, 2001-2015 Free Software Foundation,
+;; Copyright (C) 1995-1997, 1999, 2001-2016 Free Software Foundation,
 ;; Inc.
 
-;; Author: Anders Lindgren <andersl@andersl.com>
-;; Maintainer: emacs-devel@gnu.org (Anders' email bounces, Sep 2005)
+;; Author: Anders Lindgren
+;; Maintainer: emacs-devel@gnu.org
 ;; Created: 1995-05-25
 ;; Keywords: display, window, minor-mode, convenience
 
@@ -399,11 +399,11 @@ virtual window.  This is accomplished by two main techniques:
   makes it possible to walk between windows using normal cursor
   movement commands.
 
-Follow mode comes to its prime when used on a large screen and two
-side-by-side windows are used.  The user can, with the help of Follow
-mode, use two full-height windows as though they would have been
-one.  Imagine yourself editing a large function, or section of text,
-and being able to use 144 lines instead of the normal 72... (your
+Follow mode comes to its prime when used on a large screen and two or
+more side-by-side windows are used.  The user can, with the help of
+Follow mode, use these full-height windows as though they were one.
+Imagine yourself editing a large function, or section of text, and
+being able to use 144 or 216 lines instead of the normal 72... (your
 mileage may vary).
 
 To split one large window into two side-by-side windows, the commands
@@ -423,16 +423,18 @@ Keys specific to Follow mode:
        (add-hook 'post-command-hook 'follow-post-command-hook t)
        (add-hook 'window-size-change-functions 'follow-window-size-change t)
         (add-hook 'after-change-functions 'follow-after-change nil t)
-
-        (setq window-start-group-function 'follow-window-start)
-        (setq window-end-group-function 'follow-window-end)
-        (setq set-window-start-group-function 'follow-set-window-start)
-        (setq recenter-group-function 'follow-recenter)
-        (setq pos-visible-in-window-p-group-function
+        (add-hook 'isearch-update-post-hook 'follow-post-command-hook nil t)
+        (add-hook 'replace-update-post-hook 'follow-post-command-hook nil t)
+        (add-hook 'ispell-update-post-hook 'follow-post-command-hook nil t)
+
+        (setq window-group-start-function 'follow-window-start)
+        (setq window-group-end-function 'follow-window-end)
+        (setq set-window-group-start-function 'follow-set-window-start)
+        (setq recenter-window-group-function 'follow-recenter)
+        (setq pos-visible-in-window-group-p-function
               'follow-pos-visible-in-window-p)
         (setq selected-window-group-function 'follow-all-followers)
-        (setq move-to-window-line-group-function 'follow-move-to-window-line)
-        (setq sit*-for-function 'follow-sit-for))
+        (setq move-to-window-group-line-function 'follow-move-to-window-line))
 
     ;; Remove globally-installed hook functions only if there is no
     ;; other Follow mode buffer.
@@ -445,15 +447,17 @@ Keys specific to Follow mode:
        (remove-hook 'post-command-hook 'follow-post-command-hook)
        (remove-hook 'window-size-change-functions 'follow-window-size-change)))
 
-    (kill-local-variable 'sit*-for-function)
-    (kill-local-variable 'move-to-window-line-group-function)
+    (kill-local-variable 'move-to-window-group-line-function)
     (kill-local-variable 'selected-window-group-function)
-    (kill-local-variable 'pos-visible-in-window-p-group-function)
-    (kill-local-variable 'recenter-group-function)
-    (kill-local-variable 'set-window-start-group-function)
-    (kill-local-variable 'window-end-group-function)
-    (kill-local-variable 'window-start-group-function)
-
+    (kill-local-variable 'pos-visible-in-window-group-p-function)
+    (kill-local-variable 'recenter-window-group-function)
+    (kill-local-variable 'set-window-group-start-function)
+    (kill-local-variable 'window-group-end-function)
+    (kill-local-variable 'window-group-start-function)
+
+    (remove-hook 'ispell-update-post-hook 'follow-post-command-hook t)
+    (remove-hook 'replace-update-post-hook 'follow-post-command-hook t)
+    (remove-hook 'isearch-update-post-hook 'follow-post-command-hook t)
     (remove-hook 'after-change-functions 'follow-after-change t)
     (remove-hook 'compilation-filter-hook 'follow-align-compilation-windows t)))
 
@@ -528,6 +532,80 @@ Return the new position."
 ;; position...  (This would also be corrected if we would have had a
 ;; good redisplay abstraction.)
 
+(defun follow-scroll-up-arg (arg)
+  "Scroll the text in a follow mode window chain up by ARG lines.
+If ARG is nil, scroll the size of the current window.
+
+This is an internal function for `follow-scroll-up' and
+`follow-scroll-up-window'."
+  (let ((opoint (point))  (owin (selected-window)))
+    (while
+        ;; If we are too near EOB, try scrolling the previous window.
+        (condition-case nil (progn (scroll-up arg) nil)
+          (end-of-buffer
+           (condition-case nil (progn (follow-previous-window) t)
+             (error
+              (select-window owin)
+              (goto-char opoint)
+              (signal 'end-of-buffer nil))))))
+    (unless (and scroll-preserve-screen-position
+                 (get this-command 'scroll-command))
+      (goto-char opoint))
+    (setq follow-fixed-window t)))
+
+(defun follow-scroll-down-arg (arg)
+  "Scroll the text in a follow mode window chain down by ARG lines.
+If ARG is nil, scroll the size of the current window.
+
+This is an internal function for `follow-scroll-down' and
+`follow-scroll-down-window'."
+  (let ((opoint (point)))
+    (scroll-down arg)
+    (unless (and scroll-preserve-screen-position
+                 (get this-command 'scroll-command))
+      (goto-char opoint))
+    (setq follow-fixed-window t)))
+
+;;;###autoload
+(defun follow-scroll-up-window (&optional arg)
+  "Scroll text in a Follow mode window up by that window's size.
+The other windows in the window chain will scroll synchronously.
+
+If called with no ARG, the `next-screen-context-lines' last lines of
+the window will be visible after the scroll.
+
+If called with an argument, scroll ARG lines up.
+Negative ARG means scroll downward.
+
+Works like `scroll-up' when not in Follow mode."
+  (interactive "P")
+  (cond ((not follow-mode)
+        (scroll-up arg))
+       ((eq arg '-)
+        (follow-scroll-down-window))
+       (t (follow-scroll-up-arg arg))))
+(put 'follow-scroll-up-window 'scroll-command t)
+
+;;;###autoload
+(defun follow-scroll-down-window (&optional arg)
+  "Scroll text in a Follow mode window down by that window's size.
+The other windows in the window chain will scroll synchronously.
+
+If called with no ARG, the `next-screen-context-lines' top lines of
+the window in the chain will be visible after the scroll.
+
+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-window))
+       (t (follow-scroll-down-arg arg))))
+(put 'follow-scroll-down-window 'scroll-command t)
+
 ;;;###autoload
 (defun follow-scroll-up (&optional arg)
   "Scroll text in a Follow mode window chain up.
@@ -542,23 +620,18 @@ Works like `scroll-up' when not in Follow mode."
   (interactive "P")
   (cond ((not follow-mode)
         (scroll-up arg))
-       ((eq arg '-)
-        (follow-scroll-down))
-       (t
-        (let ((opoint (point))  (owin (selected-window)))
-          (while
-              ;; If we are too near EOB, try scrolling the previous window.
-              (condition-case nil (progn (scroll-up arg) nil)
-                (end-of-buffer
-                 (condition-case nil (progn (follow-previous-window) t)
-                   (error
-                    (select-window owin)
-                    (goto-char opoint)
-                    (signal 'end-of-buffer nil))))))
-          (unless (and scroll-preserve-screen-position
-                       (get this-command 'scroll-command))
-            (goto-char opoint))
-          (setq follow-fixed-window t)))))
+       (arg (follow-scroll-up-arg arg))
+        (t
+        (let* ((windows (follow-all-followers))
+               (end (window-end (car (reverse windows)))))
+          (if (eq end (point-max))
+              (signal 'end-of-buffer nil)
+            (select-window (car windows))
+            ;; `window-end' might return nil.
+            (if end
+                (goto-char end))
+            (vertical-motion (- next-screen-context-lines))
+            (set-window-start (car windows) (point)))))))
 (put 'follow-scroll-up 'scroll-command t)
 
 ;;;###autoload
@@ -575,15 +648,22 @@ Works like `scroll-down' when not in Follow mode."
   (interactive "P")
   (cond ((not follow-mode)
         (scroll-down arg))
-       ((eq arg '-)
-        (follow-scroll-up))
-       (t
-        (let ((opoint (point)))
-          (scroll-down arg)
-          (unless (and scroll-preserve-screen-position
-                       (get this-command 'scroll-command))
-            (goto-char opoint))
-          (setq follow-fixed-window t)))))
+       (arg (follow-scroll-down-arg arg))
+        (t
+        (let* ((windows (follow-all-followers))
+               (win (car (reverse windows)))
+               (start (window-start (car windows))))
+          (if (eq start (point-min))
+              (signal 'beginning-of-buffer nil)
+            (select-window win)
+            (goto-char start)
+            (vertical-motion (- (- (window-height win)
+                                   (if header-line-format 2 1)
+                                   next-screen-context-lines)))
+            (set-window-start win (point))
+            (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))
@@ -888,10 +968,10 @@ Note that this handles the case when the cache has been set to nil."
     (let ((orig-win (selected-window))
          win-start-end)
       (dolist (w windows)
-       (select-window w)
+       (select-window w 'norecord)
        (push (cons w (cons (window-start) (follow-calc-win-end)))
              win-start-end))
-      (select-window orig-win)
+      (select-window orig-win 'norecord)
       (setq follow-windows-start-end-cache (nreverse win-start-end)))))
 
 (defsubst follow-pos-visible (pos win win-start-end)
@@ -1444,33 +1524,30 @@ non-first windows in Follow mode."
   "Redraw all windows in FRAME, when in Follow mode."
   ;; Below, we call `post-command-hook'.  Avoid an infloop.
   (unless follow-inside-post-command-hook
-    (let ((buffers '())
-         (orig-window (selected-window))
-         (orig-buffer (current-buffer))
-         (orig-frame (selected-frame))
-         windows
-         buf)
-      (select-frame frame)
-      (unwind-protect
-         (walk-windows
-          (lambda (win)
-            (setq buf (window-buffer win))
-            (unless (memq buf buffers)
-              (set-buffer buf)
-              (when follow-mode
-                (setq windows (follow-all-followers win))
-                (if (not (memq orig-window windows))
-                    (follow-redisplay windows win)
-                  ;; Make sure we're redrawing around the selected
-                  ;; window.
-                  (select-window orig-window)
-                  (follow-post-command-hook)
-                  (setq orig-window (selected-window)))
-                (setq buffers (cons buf buffers)))))
-          'no-minibuf)
-       (select-frame orig-frame)
-       (set-buffer orig-buffer)
-       (select-window orig-window)))))
+    (save-current-buffer
+      (let ((orig-frame (selected-frame)))
+        (select-frame frame)
+        (let ((picked-window (selected-window))   ; Note: May change below.
+              (seen-buffers '()))
+          (unwind-protect
+              (walk-windows
+               (lambda (win)
+                 (let ((buf (window-buffer win)))
+                   (unless (memq buf seen-buffers)
+                     (set-buffer buf)
+                     (when follow-mode
+                       (let ((windows (follow-all-followers win)))
+                         (if (not (memq picked-window windows))
+                             (follow-redisplay windows win)
+                           ;; Make sure we're redrawing around the selected
+                           ;; window.
+                           (select-window picked-window 'norecord)
+                           (follow-post-command-hook)
+                           (setq picked-window (selected-window))))
+                       (push buf seen-buffers)))))
+               'no-minibuf)
+            (select-window picked-window 'norecord)))
+        (select-frame orig-frame)))))
 
 (add-hook 'window-scroll-functions 'follow-avoid-tail-recenter t)
 
@@ -1478,9 +1555,9 @@ non-first windows in Follow mode."
 
 ;; These routines are the Follow Mode versions of the low level
 ;; functions described on page "Window Start and End" of the elisp
-;; manual, e.g. `window*-start'.  The aim is to be able to handle
-;; Follow Mode windows by replacing `window-start' by `window*-start',
-;; etc.
+;; manual, e.g. `window-group-start'.  The aim is to be able to handle
+;; Follow Mode windows by replacing `window-start' by
+;; `window-group-start', etc.
 
 (defun follow-after-change (_beg _end _old-len)
   "After change function: set `follow-start-end-invalid'."
@@ -1614,27 +1691,6 @@ zero means top of the first window in the group, negative means
                  lines (+ lines count)))))))
     (+ lines (move-to-window-line arg))))
 
-(defun follow-sit-for (seconds &optional nodisp)
-  "Redisplay, then wait for SECONDS seconds.  Stop when input is available.
-Before redisplaying, synchronise all Follow windows.
-
-SECONDS may be a floating-point value.
-\(On operating systems that do not support waiting for fractions of a
-second, floating-point values are rounded down to the nearest integer.)
-
-Redisplay does not happen if input is available before it starts.
-If optional arg NODISP is t, don't synchronise or redisplay, just
-wait for input.
-
-Value is t if waited the full time with no input arriving, and nil
-otherwise.
-
-The functionality is intended to be the same as `sit-for''s."
-  (when (and (not (input-pending-p t))
-             (not nodisp))
-    (follow-adjust-window (selected-window)))
-  (sit-for seconds nodisp))
-
 ;;; Profile support
 
 ;; The following (non-evaluated) section can be used to