diff options
author | Stefan Monnier <monnier@iro.umontreal.ca> | 2014-01-15 19:26:45 -0500 |
---|---|---|
committer | Stefan Monnier <monnier@iro.umontreal.ca> | 2014-01-15 19:26:45 -0500 |
commit | 87b2a7f2da9a94f794f80494d2cf42b8c3e041f1 (patch) | |
tree | 069f4c4448bda5f127c777e84064c2a9f9c00b39 | |
parent | 93acfb0eff2c089abf14caa95f5599cdbd99fb48 (diff) |
* 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
-rw-r--r-- | lisp/ChangeLog | 9 | ||||
-rw-r--r-- | lisp/follow.el | 317 |
2 files changed, 166 insertions, 160 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index fa2f97d070..56d4a83501 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,12 @@ +2014-01-16 Stefan Monnier <monnier@iro.umontreal.ca> + + * follow.el (follow-adjust-window): Remove `dest' argument (bug#16426). + 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. + 2014-01-15 Daniel Colascione <dancol@dancol.org> * emacs-lisp/bytecomp.el (byte-compile-file): Use whole diff --git a/lisp/follow.el b/lisp/follow.el index 19ff6f8f0a..72b4a8aec2 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. |