;;; follow.el --- synchronize windows showing the same buffer
-;; Copyright (C) 1995, 1996, 1997, 1999, 2001, 2002, 2003, 2004,
-;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;; Copyright (C) 1995-1997, 1999, 2001-2011 Free Software Foundation, Inc.
;; Author: Anders Lindgren <andersl@andersl.com>
;; Maintainer: FSF (Anders' email bounces, Sep 2005)
;; XEmacs can calculate the end of the window by using
;; the 'guarantee options. GOOD!
(let ((end (window-end win t)))
- (if (= end (funcall (symbol-function 'point-max)
- (window-buffer win)))
+ (if (= end (point-max (window-buffer win)))
(list end t)
(list (+ end 1) nil)))
;; Emacs: We have to calculate the end by ourselves.
(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)
+ (let (win win-end)
(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.
(when (follow-pos-visible dest (caar win-start-end) win-start-end)
- (setq win (caar win-start-end))
+ (setq win (caar win-start-end)
+ win-end (car (cddr (car win-start-end))))
(select-window win))
(setq win-start-end (cdr win-start-end)))
;; The last line of the window may be partially visible; if so,
;; and if point is visible in the next window, select the next
;; window instead.
- (and (/= dest (point-max))
+ (and win
+ (/= dest (point-max))
win-start-end
(follow-pos-visible dest (caar win-start-end) win-start-end)
+ (save-excursion
+ (goto-char dest)
+ (vertical-motion 1 win)
+ (>= (point) win-end))
(setq win (caar win-start-end))
(select-window win))
win))
;; it wasn't just moved here. (i.e. M-> shall not unconditionally place
;; the point in the selected window.)
;;
-;; (Compability cludge: in Emacs `window-end' is equal to `point-max';
+;; (Compatibility cludge: in Emacs `window-end' is equal to `point-max';
;; in XEmacs, it is equal to `point-max + 1'. Should I really bother
;; checking `window-end' now when I check `end-of-buffer' explicitly?)
(setq win (or win (selected-window)))
(setq start (or start (window-start win)))
(save-excursion
- (let ((done nil)
- win-start
- res)
+ (let (done win-start res opoint)
;; Always calculate what happens when no line is displayed in the first
;; window. (The `previous' res is needed below!)
(goto-char guess)
(vertical-motion 0 (car windows))
(setq res (point))
(while (not done)
+ (setq opoint (point))
(if (not (= (vertical-motion -1 (car windows)) -1))
;; Hit roof!
(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)
- (setq res (point)))
+ (cond ((>= (point) opoint)
+ ;; In some pathological cases, vertical-motion may
+ ;; return -1 even though point has not decreased. In
+ ;; that case, avoid looping forever.
+ (setq done t res (point)))
+ ((= win-start start) ; Perfect match, use this value
+ (setq done t res (point)))
((< win-start start) ; Walked to far, use preious result
(setq done t))
(t ; Store result for next iteration
;; especially if it is placed in the debug filter section. I must
;; investigate this further...
-(defun follow-avoid-tail-recenter (&rest rest)
+(defun follow-avoid-tail-recenter (&rest _rest)
"Make sure windows displaying the end of a buffer aren't recentered.
This is done by reading and rewriting the start position of
((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.
+ ;; ok, this will pick the `correct' window.
((follow-select-if-visible dest win-start-end)
(follow-debug-message "visible")
- (setq visible t)
- (goto-char dest))
+ (goto-char dest)
+ ;; We have to perform redisplay, since scrolling is
+ ;; needed in case the line is partially visible.
+ (setq visible nil))
;; Not visible anywhere else, lets pick this one.
;; (Is this case used?)
(visible
(let ((p (window-point win)))
(set-window-start win (window-start win) nil)
(set-window-point win p))))
- (unless (or visible
- ;; Use the UPDATE argument of window-end
- ;; instead of calling follow-pos-visible
- ;; (which may be inaccurate for partially
- ;; visible lines).
- (and (>= dest (window-start))
- (< dest (window-end nil t))))
- ;; If point is not visible in the selected window,
- ;; perform a redisplay; this causes scrolling.
- (sit-for 0)
+ (unless visible
+ ;; If point may not be visible in the selected window,
+ ;; perform a redisplay; this ensures scrolling.
+ (redisplay)
(setq selected-window-up-to-date t)
(follow-avoid-tail-recenter)
(setq win-start-end (follow-windows-start-end windows))
;; | save it". -- Douglas Adams, "Last Chance to See" |
;; \------------------------------------------------------------------------/
-;; arch-tag: 7b16bb1a-808c-4991-a8cc-66d3822936d0
;;; follow.el ends here