summaryrefslogtreecommitdiff
path: root/lisp/follow.el
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2014-01-15 19:26:45 -0500
committerStefan Monnier <monnier@iro.umontreal.ca>2014-01-15 19:26:45 -0500
commit87b2a7f2da9a94f794f80494d2cf42b8c3e041f1 (patch)
tree069f4c4448bda5f127c777e84064c2a9f9c00b39 /lisp/follow.el
parent93acfb0eff2c089abf14caa95f5599cdbd99fb48 (diff)
downloademacs-87b2a7f2da9a94f794f80494d2cf42b8c3e041f1.tar.gz
* lisp/follow.el (follow-adjust-window): Remove `dest' argument.
Assume we're already in the proper buffer. Inspired by Anders Lindgren <andlind@gmail.com>. (follow-post-command-hook): Call it from the right buffer. (follow-comint-scroll-to-bottom): Adjust call. (follow-all-followers): Use get-buffer-window-list. Fixes: debbugs:16426
Diffstat (limited to 'lisp/follow.el')
-rw-r--r--lisp/follow.el317
1 files changed, 157 insertions, 160 deletions
diff --git a/lisp/follow.el b/lisp/follow.el
index 19ff6f8f0aa..72b4a8aec29 100644
--- a/lisp/follow.el
+++ b/lisp/follow.el
@@ -35,7 +35,7 @@
;; This means that whenever one window is moved, all the
;; others will follow. (Hence the name Follow mode.)
;;
-;; * Should the point (cursor) end up outside a window, another
+;; * Should point (cursor) end up outside a window, another
;; window displaying that point is selected, if possible. This
;; makes it possible to walk between windows using normal cursor
;; movement commands.
@@ -144,7 +144,7 @@
;; this command be added to the global keymap.
;;
;; follow-recenter C-c . C-l
-;; Place the point in the center of the middle window,
+;; Place point in the center of the middle window,
;; or a specified number of lines from either top or bottom.
;;
;; follow-switch-to-buffer C-c . b
@@ -202,6 +202,7 @@
;;; Code:
(require 'easymenu)
+(eval-when-compile (require 'cl-lib))
;;; Variables
@@ -390,7 +391,7 @@ virtual window. This is accomplished by two main techniques:
This means that whenever one window is moved, all the
others will follow. (Hence the name Follow mode.)
-* Should the point (cursor) end up outside a window, another
+* Should point (cursor) end up outside a window, another
window displaying that point is selected, if possible. This
makes it possible to walk between windows using normal cursor
movement commands.
@@ -532,7 +533,7 @@ This is to be called by `comint-postoutput-scroll-to-bottom'."
(select-window win)
(goto-char pos)
(setq follow-windows-start-end-cache nil)
- (follow-adjust-window win pos)
+ (follow-adjust-window win)
(unless is-selected
(select-window selected)
(set-buffer buffer))))))
@@ -744,12 +745,9 @@ contains only windows in the same frame as WIN. If WIN is nil,
it defaults to the selected window."
(unless (window-live-p win)
(setq win (selected-window)))
- (let ((buffer (window-buffer win))
- windows)
- (dolist (w (window-list (window-frame win) 'no-minibuf win))
- (if (eq (window-buffer w) buffer)
- (push w windows)))
- (sort windows 'follow--window-sorter)))
+ (let ((windows (get-buffer-window-list
+ (window-buffer win) 'no-minibuf (window-frame win))))
+ (sort windows #'follow--window-sorter)))
(defun follow-split-followers (windows &optional win)
"Split WINDOWS into two sets: predecessors and successors.
@@ -847,7 +845,7 @@ returned by `follow-windows-start-end'."
(setq win-start-end (cdr win-start-end)))
result))
-;; Check if the point is visible in all windows. (So that
+;; Check if point is visible in all windows. (So that
;; no one will be recentered.)
(defun follow-point-visible-all-windows-p (win-start-end)
@@ -866,7 +864,7 @@ returned by `follow-windows-start-end'."
;; will lead to a redisplay of the screen later on.
;;
;; This is used with the first window in a follow chain. The reason
-;; is that we want to detect that the point is outside the window.
+;; is that we want to detect that point is outside the window.
;; (Without the update, the start of the window will move as the
;; user presses BackSpace, and the other window redisplay routines
;; will move the start of the window in the wrong direction.)
@@ -898,7 +896,7 @@ Return the selected window."
;; Lets select a window showing the end. Make sure we only select it if
;; it wasn't just moved here. (I.e. M-> shall not unconditionally place
-;; the point in the selected window.)
+;; point in the selected window.)
;;
;; (Compatibility kludge: in Emacs `window-end' is equal to `point-max';
;; in XEmacs, it is equal to `point-max + 1'. Should I really bother
@@ -924,10 +922,10 @@ Return the selected window."
win))
-;; Select a window that will display the point if the windows would
+;; Select a window that will display point if the windows would
;; be redisplayed with the first window fixed. This is useful for
;; example when the user has pressed return at the bottom of a window
-;; as the point is not visible in any window.
+;; as point is not visible in any window.
(defun follow-select-if-visible-from-first (dest windows)
"Try to select one of WINDOWS without repositioning the topmost window.
@@ -969,7 +967,7 @@ Otherwise, return nil."
(defun follow-redisplay (&optional windows win preserve-win)
"Reposition the WINDOWS around WIN.
-Should the point be too close to the roof we redisplay everything
+Should point be too close to the roof we redisplay everything
from the top. WINDOWS should contain a list of windows to
redisplay; it is assumed that WIN is a member of the list.
Should WINDOWS be nil, the windows displaying the
@@ -1124,158 +1122,157 @@ non-first windows in Follow mode."
(with-current-buffer (window-buffer win)
(unless (and (symbolp this-command)
(get this-command 'follow-mode-use-cache))
- (setq follow-windows-start-end-cache nil)))
- (follow-adjust-window win (point)))))
-
-(defun follow-adjust-window (win dest)
- ;; Adjust the window WIN and its followers.
- (with-current-buffer (window-buffer win)
- (when (and follow-mode
- (not (window-minibuffer-p win)))
- (let* ((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))
+ (follow-adjust-window win)))))
- ;; Select a window to display point.
- (unless follow-internal-force-redisplay
- (if (eq dest (point-max))
- ;; Be careful at point-max: the display can be aligned
- ;; while DEST can be visible in several windows.
- (cond
- ;; Select the current window, but only when the display
- ;; is correct. (When inserting characters in a tail
- ;; window, the display is not correct, as they are
- ;; shown twice.)
- ;;
- ;; Never stick to the current window after a deletion.
- ;; Otherwise, when typing `DEL' in a window showing
- ;; only the end of the file, a character would be
- ;; removed from the window above, which is very
- ;; unintuitive.
- ((and visible
- aligned
- (not (memq this-command
- '(backward-delete-char
- delete-backward-char
- backward-delete-char-untabify
- kill-region))))
- (follow-debug-message "Max: same"))
- ;; If the end is visible, and the window doesn't
- ;; seems like it just has been moved, select it.
- ((follow-select-if-end-visible win-start-end)
- (follow-debug-message "Max: end visible")
- (setq visible t aligned nil)
- (goto-char dest))
- ;; Just show the end...
- (t
- (follow-debug-message "Max: default")
- (select-window (car (last windows)))
- (goto-char dest)
- (setq visible nil aligned nil)))
-
- ;; We're not at the end, here life is much simpler.
- (cond
- ;; This is the normal case!
- ;; 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")
- (goto-char dest)
- ;; Perform redisplay, in case line is partially visible.
- (setq visible nil))
- ;; Not visible anywhere else, lets pick this one.
- (visible
- (follow-debug-message "visible in selected."))
- ;; If DEST is before the first window start, select the
- ;; first window.
- ((< dest (nth 1 (car win-start-end)))
- (follow-debug-message "before first")
- (select-window (car windows))
- (goto-char dest)
- (setq visible nil aligned nil))
- ;; If we can position the cursor without moving the first
- ;; window, do it. This is the case that catches `RET' at
- ;; the bottom of a window.
- ((follow-select-if-visible-from-first dest windows)
- (follow-debug-message "Below first")
- (setq visible t aligned t))
- ;; None of the above. Stick to the selected window.
- (t
- (follow-debug-message "None")
- (setq visible nil aligned nil))))
-
- ;; If a new window was selected, make sure that the old is
- ;; not scrolled when the point is outside the window.
- (unless (eq win (selected-window))
- (let ((p (window-point win)))
- (set-window-start win (window-start win) nil)
- (set-window-point win p))))
-
- (unless visible
- ;; If point may not be visible in the selected window,
- ;; perform a redisplay; this ensures scrolling.
- (let ((opoint (point)))
- (redisplay)
- ;; If this `redisplay' moved point, we got clobbered by a
- ;; previous call to `set-window-start'. Try again.
- (when (/= (point) opoint)
- (goto-char opoint)
- (redisplay)))
-
- (setq selected-window-up-to-date t)
- (follow-avoid-tail-recenter)
- (setq win-start-end (follow-windows-start-end windows)
- follow-windows-start-end-cache nil
- aligned nil))
-
- ;; Now redraw the windows around the selected window.
- (unless (and (not follow-internal-force-redisplay)
- (or aligned
- (follow-windows-aligned-p win-start-end))
- (follow-point-visible-all-windows-p win-start-end))
- (setq follow-internal-force-redisplay nil)
- (follow-redisplay windows (selected-window)
- selected-window-up-to-date)
- (setq win-start-end (follow-windows-start-end windows)
- follow-windows-start-end-cache nil)
- ;; The point can ends up in another window when DEST is at
- ;; the beginning of the buffer and the selected window is
- ;; not the first. It can also happen when long lines are
- ;; used and there is a big difference between the width of
- ;; the windows. (When scrolling one line in a wide window
- ;; which will cause a move larger that an entire small
- ;; window.)
- (unless (follow-pos-visible dest win win-start-end)
- (follow-select-if-visible dest win-start-end)
- (goto-char dest)))
-
- ;; If the region is visible, make it look good when spanning
- ;; multiple windows.
-
- ;; FIXME: Why not use `use-region-p' here?
- (when (region-active-p)
- (follow-maximize-region
- (selected-window) windows win-start-end)))
-
- ;; Whether or not the buffer was in follow mode, update windows
- ;; displaying the tail so that Emacs won't recenter them.
- (follow-avoid-tail-recenter))))
+(defun follow-adjust-window (win)
+ ;; Adjust the window WIN and its followers.
+ (cl-assert (eq (window-buffer win) (current-buffer)))
+ (when (and follow-mode
+ (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))
+
+ ;; Select a window to display point.
+ (unless follow-internal-force-redisplay
+ (if (eq dest (point-max))
+ ;; Be careful at point-max: the display can be aligned
+ ;; while DEST can be visible in several windows.
+ (cond
+ ;; Select the current window, but only when the display
+ ;; is correct. (When inserting characters in a tail
+ ;; window, the display is not correct, as they are
+ ;; shown twice.)
+ ;;
+ ;; Never stick to the current window after a deletion.
+ ;; Otherwise, when typing `DEL' in a window showing
+ ;; only the end of the file, a character would be
+ ;; removed from the window above, which is very
+ ;; unintuitive.
+ ((and visible
+ aligned
+ (not (memq this-command
+ '(backward-delete-char
+ delete-backward-char
+ backward-delete-char-untabify
+ kill-region))))
+ (follow-debug-message "Max: same"))
+ ;; If the end is visible, and the window doesn't
+ ;; seems like it just has been moved, select it.
+ ((follow-select-if-end-visible win-start-end)
+ (follow-debug-message "Max: end visible")
+ (setq visible t aligned nil)
+ (goto-char dest))
+ ;; Just show the end...
+ (t
+ (follow-debug-message "Max: default")
+ (select-window (car (last windows)))
+ (goto-char dest)
+ (setq visible nil aligned nil)))
+
+ ;; We're not at the end, here life is much simpler.
+ (cond
+ ;; This is the normal case!
+ ;; 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")
+ (goto-char dest)
+ ;; Perform redisplay, in case line is partially visible.
+ (setq visible nil))
+ ;; Not visible anywhere else, lets pick this one.
+ (visible
+ (follow-debug-message "visible in selected."))
+ ;; If DEST is before the first window start, select the
+ ;; first window.
+ ((< dest (nth 1 (car win-start-end)))
+ (follow-debug-message "before first")
+ (select-window (car windows))
+ (goto-char dest)
+ (setq visible nil aligned nil))
+ ;; If we can position the cursor without moving the first
+ ;; window, do it. This is the case that catches `RET' at
+ ;; the bottom of a window.
+ ((follow-select-if-visible-from-first dest windows)
+ (follow-debug-message "Below first")
+ (setq visible t aligned t))
+ ;; None of the above. Stick to the selected window.
+ (t
+ (follow-debug-message "None")
+ (setq visible nil aligned nil))))
+
+ ;; If a new window was selected, make sure that the old is
+ ;; not scrolled when point is outside the window.
+ (unless (eq win (selected-window))
+ (let ((p (window-point win)))
+ (set-window-start win (window-start win) nil)
+ (set-window-point win p))))
+
+ (unless visible
+ ;; If point may not be visible in the selected window,
+ ;; perform a redisplay; this ensures scrolling.
+ (let ((opoint (point)))
+ (redisplay)
+ ;; If this `redisplay' moved point, we got clobbered by a
+ ;; previous call to `set-window-start'. Try again.
+ (when (/= (point) opoint)
+ (goto-char opoint)
+ (redisplay)))
+
+ (setq selected-window-up-to-date t)
+ (follow-avoid-tail-recenter)
+ (setq win-start-end (follow-windows-start-end windows)
+ follow-windows-start-end-cache nil
+ aligned nil))
+
+ ;; Now redraw the windows around the selected window.
+ (unless (and (not follow-internal-force-redisplay)
+ (or aligned
+ (follow-windows-aligned-p win-start-end))
+ (follow-point-visible-all-windows-p win-start-end))
+ (setq follow-internal-force-redisplay nil)
+ (follow-redisplay windows (selected-window)
+ selected-window-up-to-date)
+ (setq win-start-end (follow-windows-start-end windows)
+ follow-windows-start-end-cache nil)
+ ;; Point can end up in another window when DEST is at
+ ;; the beginning of the buffer and the selected window is
+ ;; not the first. It can also happen when long lines are
+ ;; used and there is a big difference between the width of
+ ;; the windows. (When scrolling one line in a wide window
+ ;; which will cause a move larger that an entire small
+ ;; window.)
+ (unless (follow-pos-visible dest win win-start-end)
+ (follow-select-if-visible dest win-start-end)
+ (goto-char dest)))
+
+ ;; If the region is visible, make it look good when spanning
+ ;; multiple windows.
+ (when (region-active-p)
+ (follow-maximize-region
+ (selected-window) windows win-start-end)))
+
+ ;; Whether or not the buffer was in follow mode, update windows
+ ;; displaying the tail so that Emacs won't recenter them.
+ (follow-avoid-tail-recenter)))
;;; The region
;; Tries to make the highlighted area representing the region look
;; good when spanning several windows.
;;
-;; Not perfect, as the point can't be placed at window end, only at
+;; Not perfect, as point can't be placed at window end, only at
;; end-1. This will highlight a little bit in windows above
;; the current.