Commit 87b2a7f2 authored by Stefan Monnier's avatar Stefan Monnier
Browse files

* 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
parent 93acfb0e
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> 2014-01-15 Daniel Colascione <dancol@dancol.org>
* emacs-lisp/bytecomp.el (byte-compile-file): Use whole * emacs-lisp/bytecomp.el (byte-compile-file): Use whole
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
;; This means that whenever one window is moved, all the ;; This means that whenever one window is moved, all the
;; others will follow. (Hence the name Follow mode.) ;; 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 ;; window displaying that point is selected, if possible. This
;; makes it possible to walk between windows using normal cursor ;; makes it possible to walk between windows using normal cursor
;; movement commands. ;; movement commands.
...@@ -144,7 +144,7 @@ ...@@ -144,7 +144,7 @@
;; this command be added to the global keymap. ;; this command be added to the global keymap.
;; ;;
;; follow-recenter C-c . C-l ;; 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. ;; or a specified number of lines from either top or bottom.
;; ;;
;; follow-switch-to-buffer C-c . b ;; follow-switch-to-buffer C-c . b
...@@ -202,6 +202,7 @@ ...@@ -202,6 +202,7 @@
;;; Code: ;;; Code:
(require 'easymenu) (require 'easymenu)
(eval-when-compile (require 'cl-lib))
;;; Variables ;;; Variables
...@@ -390,7 +391,7 @@ virtual window. This is accomplished by two main techniques: ...@@ -390,7 +391,7 @@ virtual window. This is accomplished by two main techniques:
This means that whenever one window is moved, all the This means that whenever one window is moved, all the
others will follow. (Hence the name Follow mode.) 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 window displaying that point is selected, if possible. This
makes it possible to walk between windows using normal cursor makes it possible to walk between windows using normal cursor
movement commands. movement commands.
...@@ -532,7 +533,7 @@ This is to be called by `comint-postoutput-scroll-to-bottom'." ...@@ -532,7 +533,7 @@ This is to be called by `comint-postoutput-scroll-to-bottom'."
(select-window win) (select-window win)
(goto-char pos) (goto-char pos)
(setq follow-windows-start-end-cache nil) (setq follow-windows-start-end-cache nil)
(follow-adjust-window win pos) (follow-adjust-window win)
(unless is-selected (unless is-selected
(select-window selected) (select-window selected)
(set-buffer buffer)))))) (set-buffer buffer))))))
...@@ -744,12 +745,9 @@ contains only windows in the same frame as WIN. If WIN is nil, ...@@ -744,12 +745,9 @@ contains only windows in the same frame as WIN. If WIN is nil,
it defaults to the selected window." it defaults to the selected window."
(unless (window-live-p win) (unless (window-live-p win)
(setq win (selected-window))) (setq win (selected-window)))
(let ((buffer (window-buffer win)) (let ((windows (get-buffer-window-list
windows) (window-buffer win) 'no-minibuf (window-frame win))))
(dolist (w (window-list (window-frame win) 'no-minibuf win)) (sort windows #'follow--window-sorter)))
(if (eq (window-buffer w) buffer)
(push w windows)))
(sort windows 'follow--window-sorter)))
(defun follow-split-followers (windows &optional win) (defun follow-split-followers (windows &optional win)
"Split WINDOWS into two sets: predecessors and successors. "Split WINDOWS into two sets: predecessors and successors.
...@@ -847,7 +845,7 @@ returned by `follow-windows-start-end'." ...@@ -847,7 +845,7 @@ returned by `follow-windows-start-end'."
(setq win-start-end (cdr win-start-end))) (setq win-start-end (cdr win-start-end)))
result)) 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.) ;; no one will be recentered.)
(defun follow-point-visible-all-windows-p (win-start-end) (defun follow-point-visible-all-windows-p (win-start-end)
...@@ -866,7 +864,7 @@ returned by `follow-windows-start-end'." ...@@ -866,7 +864,7 @@ returned by `follow-windows-start-end'."
;; will lead to a redisplay of the screen later on. ;; will lead to a redisplay of the screen later on.
;; ;;
;; This is used with the first window in a follow chain. The reason ;; 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 ;; (Without the update, the start of the window will move as the
;; user presses BackSpace, and the other window redisplay routines ;; user presses BackSpace, and the other window redisplay routines
;; will move the start of the window in the wrong direction.) ;; will move the start of the window in the wrong direction.)
...@@ -898,7 +896,7 @@ Return the selected window." ...@@ -898,7 +896,7 @@ Return the selected window."
;; Lets select a window showing the end. Make sure we only select it if ;; 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 ;; 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'; ;; (Compatibility kludge: in Emacs `window-end' is equal to `point-max';
;; in XEmacs, it is equal to `point-max + 1'. Should I really bother ;; in XEmacs, it is equal to `point-max + 1'. Should I really bother
...@@ -924,10 +922,10 @@ Return the selected window." ...@@ -924,10 +922,10 @@ Return the selected window."
win)) 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 ;; be redisplayed with the first window fixed. This is useful for
;; example when the user has pressed return at the bottom of a window ;; 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) (defun follow-select-if-visible-from-first (dest windows)
"Try to select one of WINDOWS without repositioning the topmost window. "Try to select one of WINDOWS without repositioning the topmost window.
...@@ -969,7 +967,7 @@ Otherwise, return nil." ...@@ -969,7 +967,7 @@ Otherwise, return nil."
(defun follow-redisplay (&optional windows win preserve-win) (defun follow-redisplay (&optional windows win preserve-win)
"Reposition the WINDOWS around 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 from the top. WINDOWS should contain a list of windows to
redisplay; it is assumed that WIN is a member of the list. redisplay; it is assumed that WIN is a member of the list.
Should WINDOWS be nil, the windows displaying the Should WINDOWS be nil, the windows displaying the
...@@ -1124,158 +1122,157 @@ non-first windows in Follow mode." ...@@ -1124,158 +1122,157 @@ non-first windows in Follow mode."
(with-current-buffer (window-buffer win) (with-current-buffer (window-buffer win)
(unless (and (symbolp this-command) (unless (and (symbolp this-command)
(get this-command 'follow-mode-use-cache)) (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)) (setq follow-windows-start-end-cache nil))
(follow-adjust-window win)))))
;; Select a window to display point. (defun follow-adjust-window (win)
(unless follow-internal-force-redisplay ;; Adjust the window WIN and its followers.
(if (eq dest (point-max)) (cl-assert (eq (window-buffer win) (current-buffer)))
;; Be careful at point-max: the display can be aligned (when (and follow-mode
;; while DEST can be visible in several windows. (not (window-minibuffer-p win)))
(cond (let* ((dest (point))
;; Select the current window, but only when the display (windows (follow-all-followers win))
;; is correct. (When inserting characters in a tail (win-start-end (progn
;; window, the display is not correct, as they are (follow-update-window-start (car windows))
;; shown twice.) (follow-windows-start-end windows)))
;; (aligned (follow-windows-aligned-p win-start-end))
;; Never stick to the current window after a deletion. (visible (follow-pos-visible dest win win-start-end))
;; Otherwise, when typing `DEL' in a window showing selected-window-up-to-date)
;; only the end of the file, a character would be (unless (and aligned visible)
;; removed from the window above, which is very (setq follow-windows-start-end-cache nil))
;; unintuitive.
((and visible ;; Select a window to display point.
aligned (unless follow-internal-force-redisplay
(not (memq this-command (if (eq dest (point-max))
'(backward-delete-char ;; Be careful at point-max: the display can be aligned
delete-backward-char ;; while DEST can be visible in several windows.
backward-delete-char-untabify (cond
kill-region)))) ;; Select the current window, but only when the display
(follow-debug-message "Max: same")) ;; is correct. (When inserting characters in a tail
;; If the end is visible, and the window doesn't ;; window, the display is not correct, as they are
;; seems like it just has been moved, select it. ;; shown twice.)
((follow-select-if-end-visible win-start-end) ;;
(follow-debug-message "Max: end visible") ;; Never stick to the current window after a deletion.
(setq visible t aligned nil) ;; Otherwise, when typing `DEL' in a window showing
(goto-char dest)) ;; only the end of the file, a character would be
;; Just show the end... ;; removed from the window above, which is very
(t ;; unintuitive.
(follow-debug-message "Max: default") ((and visible
(select-window (car (last windows))) aligned
(goto-char dest) (not (memq this-command
(setq visible nil aligned nil))) '(backward-delete-char
delete-backward-char
;; We're not at the end, here life is much simpler. backward-delete-char-untabify
(cond kill-region))))
;; This is the normal case! (follow-debug-message "Max: same"))
;; It should be optimized for speed. ;; If the end is visible, and the window doesn't
((and visible aligned) ;; seems like it just has been moved, select it.
(follow-debug-message "same")) ((follow-select-if-end-visible win-start-end)
;; Pick a position in any window. If the display is ok, (follow-debug-message "Max: end visible")
;; this picks the `correct' window. (setq visible t aligned nil)
((follow-select-if-visible dest win-start-end) (goto-char dest))
(follow-debug-message "visible") ;; Just show the end...
(goto-char dest) (t
;; Perform redisplay, in case line is partially visible. (follow-debug-message "Max: default")
(setq visible nil)) (select-window (car (last windows)))
;; Not visible anywhere else, lets pick this one. (goto-char dest)
(visible (setq visible nil aligned nil)))
(follow-debug-message "visible in selected."))
;; If DEST is before the first window start, select the ;; We're not at the end, here life is much simpler.
;; first window. (cond
((< dest (nth 1 (car win-start-end))) ;; This is the normal case!
(follow-debug-message "before first") ;; It should be optimized for speed.
(select-window (car windows)) ((and visible aligned)
(goto-char dest) (follow-debug-message "same"))
(setq visible nil aligned nil)) ;; Pick a position in any window. If the display is ok,
;; If we can position the cursor without moving the first ;; this picks the `correct' window.
;; window, do it. This is the case that catches `RET' at ((follow-select-if-visible dest win-start-end)
;; the bottom of a window. (follow-debug-message "visible")
((follow-select-if-visible-from-first dest windows) (goto-char dest)
(follow-debug-message "Below first") ;; Perform redisplay, in case line is partially visible.
(setq visible t aligned t)) (setq visible nil))
;; None of the above. Stick to the selected window. ;; Not visible anywhere else, lets pick this one.
(t (visible
(follow-debug-message "None") (follow-debug-message "visible in selected."))
(setq visible nil aligned nil)))) ;; If DEST is before the first window start, select the
;; first window.
;; If a new window was selected, make sure that the old is ((< dest (nth 1 (car win-start-end)))
;; not scrolled when the point is outside the window. (follow-debug-message "before first")
(unless (eq win (selected-window)) (select-window (car windows))
(let ((p (window-point win))) (goto-char dest)
(set-window-start win (window-start win) nil) (setq visible nil aligned nil))
(set-window-point win p)))) ;; If we can position the cursor without moving the first
;; window, do it. This is the case that catches `RET' at
(unless visible ;; the bottom of a window.
;; If point may not be visible in the selected window, ((follow-select-if-visible-from-first dest windows)
;; perform a redisplay; this ensures scrolling. (follow-debug-message "Below first")
(let ((opoint (point))) (setq visible t aligned t))
(redisplay) ;; None of the above. Stick to the selected window.
;; If this `redisplay' moved point, we got clobbered by a (t
;; previous call to `set-window-start'. Try again. (follow-debug-message "None")
(when (/= (point) opoint) (setq visible nil aligned nil))))
(goto-char opoint)
(redisplay))) ;; If a new window was selected, make sure that the old is
;; not scrolled when point is outside the window.
(setq selected-window-up-to-date t) (unless (eq win (selected-window))
(follow-avoid-tail-recenter) (let ((p (window-point win)))
(setq win-start-end (follow-windows-start-end windows) (set-window-start win (window-start win) nil)
follow-windows-start-end-cache nil (set-window-point win p))))
aligned nil))
(unless visible
;; Now redraw the windows around the selected window. ;; If point may not be visible in the selected window,
(unless (and (not follow-internal-force-redisplay) ;; perform a redisplay; this ensures scrolling.
(or aligned (let ((opoint (point)))
(follow-windows-aligned-p win-start-end)) (redisplay)
(follow-point-visible-all-windows-p win-start-end)) ;; If this `redisplay' moved point, we got clobbered by a
(setq follow-internal-force-redisplay nil) ;; previous call to `set-window-start'. Try again.
(follow-redisplay windows (selected-window) (when (/= (point) opoint)
selected-window-up-to-date) (goto-char opoint)
(setq win-start-end (follow-windows-start-end windows) (redisplay)))
follow-windows-start-end-cache nil)
;; The point can ends up in another window when DEST is at (setq selected-window-up-to-date t)
;; the beginning of the buffer and the selected window is (follow-avoid-tail-recenter)
;; not the first. It can also happen when long lines are (setq win-start-end (follow-windows-start-end windows)
;; used and there is a big difference between the width of follow-windows-start-end-cache nil
;; the windows. (When scrolling one line in a wide window aligned nil))
;; which will cause a move larger that an entire small
;; window.) ;; Now redraw the windows around the selected window.
(unless (follow-pos-visible dest win win-start-end) (unless (and (not follow-internal-force-redisplay)
(follow-select-if-visible dest win-start-end) (or aligned
(goto-char dest))) (follow-windows-aligned-p win-start-end))
(follow-point-visible-all-windows-p win-start-end))
;; If the region is visible, make it look good when spanning (setq follow-internal-force-redisplay nil)
;; multiple windows. (follow-redisplay windows (selected-window)
selected-window-up-to-date)
;; FIXME: Why not use `use-region-p' here? (setq win-start-end (follow-windows-start-end windows)
(when (region-active-p) follow-windows-start-end-cache nil)
(follow-maximize-region ;; Point can end up in another window when DEST is at
(selected-window) windows win-start-end))) ;; the beginning of the buffer and the selected window is
;; not the first. It can also happen when long lines are
;; Whether or not the buffer was in follow mode, update windows ;; used and there is a big difference between the width of
;; displaying the tail so that Emacs won't recenter them. ;; the windows. (When scrolling one line in a wide window
(follow-avoid-tail-recenter)))) ;; 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 ;;; The region
;; Tries to make the highlighted area representing the region look ;; Tries to make the highlighted area representing the region look
;; good when spanning several windows. ;; 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 ;; end-1. This will highlight a little bit in windows above
;; the current. ;; the current.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment