- ;; 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.
- (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)))