# HG changeset patch # User Chong Yidong # Date 1230634321 0 # Node ID 503c8d0db2bc6648113a8f36c685680bfe87d58e # Parent 66dd9bb65f2be6b8beb0710cd6aba8b79e9eae27 (follow-calc-win-start): Don't use `inline'. (follow-update-window-start, follow-select-if-visible) (follow-calculate-first-window-start-from-below) (follow-post-command-hook): Code cleanup. (follow-downward, follow-calculate-first-window-start): Function deleted and merged into follow-redisplay. (follow-redisplay): Merge code from follow-downward and follow-calculate-first-window-start. diff -r 66dd9bb65f2b -r 503c8d0db2bc lisp/follow.el --- a/lisp/follow.el Tue Dec 30 10:51:41 2008 +0000 +++ b/lisp/follow.el Tue Dec 30 10:52:01 2008 +0000 @@ -913,7 +913,7 @@ (while (and windows (not (eq (car windows) win))) (setq start (window-start (car windows))) (set-window-start (car windows) pos 'noforce) - (setq pos (car (inline (follow-calc-win-end (car windows))))) + (setq pos (car (follow-calc-win-end (car windows)))) (set-window-start (car windows) start 'noforce) (setq windows (cdr windows))) pos)) @@ -1027,11 +1027,9 @@ "Make sure that the start of WIN starts at a full screen line." (save-excursion (goto-char (window-start win)) - (if (bolp) - nil + (unless (bolp) (vertical-motion 0 win) - (if (eq (point) (window-start win)) - nil + (unless (eq (point) (window-start win)) (vertical-motion 1 win) (set-window-start win (point) 'noforce))))) @@ -1046,15 +1044,14 @@ (defun follow-select-if-visible (dest win-start-end) "Select and return a window, if DEST is visible in it. Return the selected window." - (let ((win nil)) + (let (win) (while (and (not win) win-start-end) ;; Don't select a window that was just moved. This makes it ;; possible to later select the last window after a `end-of-buffer' ;; command. - (if (follow-pos-visible dest (car (car win-start-end)) win-start-end) - (progn - (setq win (car (car win-start-end))) - (select-window win))) + (when (follow-pos-visible dest (caar win-start-end) win-start-end) + (setq win (caar win-start-end)) + (select-window win)) (setq win-start-end (cdr win-start-end))) win)) @@ -1126,7 +1123,8 @@ ;; Redraw all the windows on the screen, starting with the top window. ;; The window used as as marker is WIN, or the selcted window if WIN -;; is nil. +;; is nil. Start every window directly after the end of the previous +;; window, to make sure long lines are displayed correctly. (defun follow-redisplay (&optional windows win) "Reposition the WINDOWS around WIN. @@ -1136,98 +1134,41 @@ Should WINDOWS be nil, the windows displaying the same buffer as WIN, in the current frame, are used. Should WIN be nil, the selected window is used." - (or win - (setq win (selected-window))) - (or windows - (setq windows (follow-all-followers win))) - (follow-downward windows (follow-calculate-first-window-start windows win))) - - -;; Redisplay a chain of windows. Start every window directly after the -;; end of the previous window, to make sure long lines are displayed -;; correctly. - -(defun follow-downward (windows pos) - "Redisplay all WINDOWS starting at POS." - (while windows - (set-window-start (car windows) pos) - (setq pos (car (follow-calc-win-end (car windows)))) - (setq windows (cdr windows)))) - - -;;(defun follow-downward (windows pos) -;; "Redisplay all WINDOWS starting at POS." -;; (let (p) -;; (while windows -;; (setq p (window-point (car windows))) -;; (set-window-start (car windows) pos) -;; (set-window-point (car windows) (max p pos)) -;; (setq pos (car (follow-calc-win-end (car windows)))) -;; (setq windows (cdr windows))))) + (or win (setq win (selected-window))) + (or windows (setq windows (follow-all-followers win))) + ;; Calculate the start of the first window. + (let* ((old-win-start (window-start win)) + (try-first-start (follow-estimate-first-window-start + windows win old-win-start)) + (try-win-start (follow-calc-win-start + windows try-first-start win)) + (start (cond ((= try-win-start old-win-start) + (follow-debug-message "exact") + try-first-start) + ((< try-win-start old-win-start) + (follow-debug-message "above") + (follow-calculate-first-window-start-from-above + windows try-first-start win old-win-start)) + (t + (follow-debug-message "below") + (follow-calculate-first-window-start-from-below + windows try-first-start win old-win-start))))) + (dolist (w windows) + (set-window-start w start) + (setq start (car (follow-calc-win-end w)))))) -;; Return the start of the first window. -;; -;; First, estimate the position. It the value is not perfect (i.e. we -;; have somewhere splited a line between windows) we try to enhance -;; the value. -;; -;; The guess is always perfect if no long lines is split between -;; windows. -;; -;; The worst case peformace of probably very bad, but it is very -;; unlikely that we ever will miss the correct start by more than one -;; or two lines. - -(defun follow-calculate-first-window-start (windows &optional win start) - "Calculate the start of the first window. - -WINDOWS is a chain of windows to work with. WIN is the window -to recenter around. It is assumed that WIN starts at position -START." - (or win - (setq win (selected-window))) - (or start - (setq start (window-start win))) - (let ((guess (follow-estimate-first-window-start windows win start))) - (if (car guess) - (cdr guess) - ;; The guess wasn't exact, try to enhance it. - (let ((win-start (follow-calc-win-start windows (cdr guess) win))) - (cond ((= win-start start) - (follow-debug-message "exact") - (cdr guess)) - ((< win-start start) - (follow-debug-message "above") - (follow-calculate-first-window-start-from-above - windows (cdr guess) win start)) - (t - (follow-debug-message "below") - (follow-calculate-first-window-start-from-below - windows (cdr guess) win start))))))) - - -;; `exact' is disabled due to XEmacs and fonts of variable -;; height. (defun follow-estimate-first-window-start (windows win start) "Estimate the position of the first window. - -Returns (EXACT . POS). If EXACT is non-nil, POS is the starting -position of the first window. Otherwise it is a good guess." - (let ((pred (car (follow-split-followers windows win))) - (exact nil)) +The estimate is computed by assuming that the window WIN, which +should be a member of WINDOWS, starts at position START." + (let ((windows-before (car (follow-split-followers windows win)))) (save-excursion (goto-char start) - ;(setq exact (bolp)) (vertical-motion 0 win) - (while pred - (vertical-motion - (- (if header-line-format 2 1) - (window-height (car pred))) (car pred)) - (if (not (bolp)) - (setq exact nil)) - (setq pred (cdr pred))) - (cons exact (point))))) + (dolist (w windows-before) + (vertical-motion (- 1 (window-text-height w)) w)) + (point)))) ;; Find the starting point, start at GUESS and search downward. @@ -1249,9 +1190,7 @@ (setq res (point-max))) (setq win-start (follow-calc-win-start windows (point) win)) (if (>= win-start start) - (progn - (setq done t) - (setq res (point)))))) + (setq done t res (point))))) res))) @@ -1277,9 +1216,7 @@ (while (not done) (if (not (= (vertical-motion -1 (car windows)) -1)) ;; Hit roof! - (progn - (setq done t) - (setq res (point-min))) + (setq done t res (point-min)) (setq win-start (follow-calc-win-start windows (point) win)) (cond ((= win-start start) ; Perfect match, use this value (setq done t) @@ -1362,190 +1299,154 @@ (defun follow-post-command-hook () "Ensure that the windows in Follow mode are adjacent after each command." - (setq follow-inside-post-command-hook t) - (if (or (not (input-pending-p)) - ;; Sometimes, in XEmacs, mouse events are not handled - ;; properly by `input-pending-p'. A typical example is - ;; when clicking on a node in `info'. - (and (boundp 'current-mouse-event) - (symbol-value 'current-mouse-event) - (fboundp 'button-event-p) - (funcall (symbol-function 'button-event-p) - (symbol-value 'current-mouse-event)))) + (unless (input-pending-p) + (let ((follow-inside-post-command-hook t) + (win (selected-window))) ;; Work in the selected window, not in the current buffer. - (let ((orig-buffer (current-buffer)) - (win (selected-window))) - (set-buffer (window-buffer win)) - (or (and (symbolp this-command) - (get this-command 'follow-mode-use-cache)) - (follow-invalidate-cache)) - (if (and (boundp 'follow-mode) follow-mode - (not (window-minibuffer-p win))) - ;; The buffer shown in the selected window is in follow - ;; mode, lets find the current state of the display and - ;; cache the result for speed (i.e. `aligned' and `visible'.) - (let* ((windows (inline (follow-all-followers win))) - (dest (point)) - (win-start-end (inline - (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))) - (if (not (and aligned visible)) - (follow-invalidate-cache)) - (inline (follow-avoid-tail-recenter)) - ;; Select a window to display the point. - (or follow-internal-force-redisplay - (progn - (if (eq dest (point-max)) - ;; We're at the end, we have to be careful since - ;; 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 - ;; character in a tail window, the display is - ;; not correct, as they are shown twice.) - ;; - ;; Never stick to the current window after a - ;; deletion. The reason is cosmetic, when - ;; typing `DEL' in a window showing only the - ;; end of the file, character are 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) - (setq aligned nil) - (goto-char dest)) - ;; Just show the end... - (t - (follow-debug-message "Max: default") - (select-window (car (reverse windows))) - (goto-char dest) - (setq visible nil) - (setq aligned nil))) + (with-current-buffer (window-buffer win) + (unless (and (symbolp this-command) + (get this-command 'follow-mode-use-cache)) + (follow-invalidate-cache)) + (when (and follow-mode + (not (window-minibuffer-p win))) + ;; The buffer shown in the selected window is in follow + ;; mode. Find the current state of the display and cache + ;; the result for speed (i.e. `aligned' and `visible'.) + (let* ((windows (follow-all-followers win)) + (dest (point)) + (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) + (follow-invalidate-cache)) + (follow-avoid-tail-recenter) + ;; Select a window to display point. + (unless follow-internal-force-redisplay + (if (eq dest (point-max)) + ;; At point-max, we have to be careful since 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. The reason is cosmetic: 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 (reverse 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 will pick the `correct' - ;; window. If the display is wierd do this - ;; anyway, this will be the case after a delete - ;; at the beginning of the window. - ((follow-select-if-visible dest win-start-end) - (follow-debug-message "visible") - (setq visible t) - (goto-char dest)) - ;; Not visible anywhere else, lets pick this one. - ;; (Is this case used?) - (visible - (follow-debug-message "visible in selected.")) - ;; Far out! - ((eq dest (point-min)) - (follow-debug-message "min") - (select-window (car windows)) - (goto-char dest) - (set-window-start (selected-window) (point-min)) - (setq win-start-end (follow-windows-start-end windows)) - (follow-invalidate-cache) - (setq visible t) - (setq 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) - (setq aligned t) - (follow-redisplay windows (car windows)) - (goto-char dest)) - ;; None of the above. For simplicity, we stick to the - ;; selected window. - (t - (follow-debug-message "None") - (setq visible nil) - (setq aligned nil)))) - ;; If a new window has been selected, make sure that the - ;; old is not scrolled when the point is outside the - ;; window. - (or (eq win (selected-window)) - (let ((p (window-point win))) - (set-window-start win (window-start win) nil) - (set-window-point win p))))) - ;; Make sure the point is visible in the selected window. - ;; (This could lead to a scroll.) - (if (or visible - (follow-pos-visible dest win win-start-end)) - nil - (sit-for 0) - (follow-avoid-tail-recenter) - (setq win-start-end (follow-windows-start-end windows)) - (follow-invalidate-cache) - (setq aligned nil)) - ;; Redraw the windows whenever needed. - (if (or follow-internal-force-redisplay - (not (or aligned - (follow-windows-aligned-p win-start-end))) - (not (inline (follow-point-visible-all-windows-p - win-start-end)))) - (progn - (setq follow-internal-force-redisplay nil) - (follow-redisplay windows (selected-window)) - (setq win-start-end (follow-windows-start-end windows)) - (follow-invalidate-cache) - ;; When the point ends up in another window. This - ;; happens when dest is in the beginning of the - ;; file and the selected window is not the first. - ;; It can also, in rare situations 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.) - (if (follow-pos-visible dest win win-start-end) - nil - (follow-select-if-visible dest win-start-end) - (goto-char dest)))) + ;; 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 will pick the `correct' window. If the + ;; display is wierd (e.g., after a delete at the + ;; beginning of the window) do this anyway. + ((follow-select-if-visible dest win-start-end) + (follow-debug-message "visible") + (setq visible t) + (goto-char dest)) + ;; Not visible anywhere else, lets pick this one. + ;; (Is this case used?) + (visible + (follow-debug-message "visible in selected.")) + ;; Far out! + ((eq dest (point-min)) + (follow-debug-message "min") + (select-window (car windows)) + (goto-char dest) + (set-window-start (selected-window) (point-min)) + (setq win-start-end (follow-windows-start-end windows)) + (follow-invalidate-cache) + (setq visible t 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) + (follow-redisplay windows (car windows)) + (goto-char dest)) + ;; None of the above. For simplicity, we stick to the + ;; selected window. + (t + (follow-debug-message "None") + (setq visible nil aligned nil)))) + ;; If a new window has been selected, make sure that the + ;; old is not scrolled when the point is outside the + ;; window. + (or (eq win (selected-window)) + (let ((p (window-point win))) + (set-window-start win (window-start win) nil) + (set-window-point win p)))) + ;; Make sure the point is visible in the selected window. + ;; (This could lead to a scroll.) + (unless (or visible + (follow-pos-visible dest win win-start-end)) + (sit-for 0) + (follow-avoid-tail-recenter) + (setq win-start-end (follow-windows-start-end windows)) + (follow-invalidate-cache) + (setq aligned nil)) + ;; Redraw the windows whenever needed. + (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)) + (setq win-start-end (follow-windows-start-end windows)) + (follow-invalidate-cache) + ;; When the point ends up in another window. This + ;; happens when dest is in the beginning of the file and + ;; the selected window is not the first. It can also, + ;; in rare situations 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. - (if (or (and (boundp 'mark-active) (symbol-value 'mark-active)) - ;; The following isn't used in Emacs, - ;; since `mark-active' is bound. - (and (fboundp 'region-active-p) - (funcall (symbol-function 'region-active-p)))) - (follow-maximize-region - (selected-window) windows win-start-end)) - - (inline (follow-avoid-tail-recenter)) - ;; DEBUG - ;;(if (not (follow-windows-aligned-p - ;; (follow-windows-start-end windows))) - ;; (message "follow-mode: windows still unaligend!")) - ;; END OF DEBUG - ) ; Matches (let* - ;; Buffer not in follow mode: - ;; We still must update the windows displaying the tail so that - ;; Emacs won't recenter them. - (follow-avoid-tail-recenter)) - (set-buffer orig-buffer))) - (setq follow-inside-post-command-hook nil)) + ;; 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, we must + ;; update the windows displaying the tail so that Emacs won't + ;; recenter them. + (follow-avoid-tail-recenter))))) ;;}}} ;;{{{ The region @@ -2143,8 +2044,6 @@ follow-all-followers follow-split-followers follow-redisplay - follow-downward - follow-calculate-first-window-start follow-estimate-first-window-start follow-calculate-first-window-start-from-above follow-calculate-first-window-start-from-below