# HG changeset patch # User Karl Heuer # Date 824923071 0 # Node ID a8eeafa7c4affaa115784763e0168f432ee5f708 # Parent 38829b121db772a33426a74a4f451f832f757c52 Update some doc string. Call `add-minor-mode'. (follow-windows-start-end-cache, follow-cache-command-list): New variables. (follow-cache-valid-p, follow-invalidate-cache): New functions. (follow-windows-start-end, follow-post-command-hook, follow-generic-filter): Cache support added. (follow-avoid-tail-recenter): Problem with minibuffer-only frames corrected. (follow-windows-aligned-p): Minor change. diff -r 38829b121db7 -r a8eeafa7c4af lisp/follow.el --- a/lisp/follow.el Wed Feb 21 17:11:13 1996 +0000 +++ b/lisp/follow.el Wed Feb 21 17:17:51 1996 +0000 @@ -5,9 +5,9 @@ ;; Author: Anders Lindgren ;; Maintainer: Anders Lindgren ;; Created: 25 May 1995 -;; Version: 1.5 +;; Version: 1.6 ;; Keywords: display, window, minor-mode -;; Date: 22 Jan 1996 +;; Date: 20 Feb 1996 ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -126,7 +126,8 @@ ;; There exists two system variables which controls the appearence of ;; lines which are wider than the window containing them. The default -;; is to truncate long lines if a window isn't as wide as the frame. +;; is to truncate long lines whenever a window isn't as wide as the +;; frame. ;; ;; To make sure lines are never truncated, please place the following ;; lines in your init file: @@ -135,6 +136,15 @@ ;; (setq truncate-partial-width-windows nil) +;; Since the display of XEmacs is pixel-oriented, a line could be +;; clipped in half at the bottom of the window. +;; +;; To make XEmacs avoid clipping (normal) lines, please place the +;; following line in your init-file: +;; +;; (setq pixel-vertical-clip-threshold 30) + + ;; The correct way to cofigurate Follow mode, or any other mode for ;; that matter, is to create one (or more) function which does ;; whatever you would like to do. The function is then added to @@ -297,7 +307,7 @@ ;; Code in post hook removed. ;; * XEmacs: Post hook is always executed ;; after a mouse button event. -;; 22-Jan-95 andersl * 1.5 released. +;; 22-Jan-96 andersl * 1.5 released. ;; ;;}}} @@ -306,7 +316,7 @@ ;;; LCD Archive Entry: ;; follow|Anders Lindgren|andersl@csd.uu.se| ;; Combines windows into tall virtual window, minor mode. -;; 22-Jan-1996|1.5|~/modes/follow.el.Z| +;; 20-Feb-1996|1.6|~/modes/follow.el.Z| ;;}}} @@ -365,11 +375,11 @@ (defvar follow-mode-off-hook nil "*Hooks to run when follow-mode is turned off.") -(defvar follow-mode-version "follow.el (Release 1.5)" +(defvar follow-mode-version "follow.el (Release 1.6)" "The current version of Follow mode.") (defvar follow-mode-map nil - "Minor mode keymap for Follow mode.") + "*Minor mode keymap for Follow mode.") (defvar follow-mode-line-text " Follow" "*Text shown in the mode line when Follow mode is active. @@ -400,7 +410,7 @@ windows are recentered automatically. However, when using Follow Mode it breaks the display when the end is displayed in a window \"above\" the last window. This is for -example the case when displaying short files. +example the case when displaying a short page in info. Must be set before Follow Mode is loaded. @@ -410,11 +420,24 @@ XEmacs, as of 19.12, does not recenter windows, good!") +(defvar follow-cache-command-list + '(next-line previous-line forward-char backward-char) + "List of commands which don't require recalculation. + +In order to be able to use the cache, a command should not change the +contents of the buffer, nor should it change selected window or current +buffer. + +The commands in this list are checked at load time. + +To mark other commands as suitable for caching, set the symbol +property `follow-mode-use-cache' to non-nil.") + (defvar follow-debug nil "*Non-nil when debugging Follow mode.") -;;; Internal variables +;; Internal variables: (defvar follow-internal-force-redisplay nil "True when Follow mode should redisplay the windows.") @@ -432,6 +455,9 @@ "Non-nil when inside Follow modes `post-command-hook'. Used by `follow-window-size-change'.") +(defvar follow-windows-start-end-cache nil + "Cache used by `follow-window-start-end'.") + ;;}}} ;;{{{ Bug report @@ -655,6 +681,14 @@ (cons (cons 'follow-mode follow-mode-map) minor-mode-map-alist))) ;;}}} +;;{{{ Cache + +(let ((cmds follow-cache-command-list)) + (while cmds + (put (car cmds) 'follow-mode-use-cache t) + (setq cmds (cdr cmds)))) + +;;}}} ;;{{{ The mode @@ -739,9 +773,13 @@ ;; Register follow-mode as a minor mode. -(or (assq 'follow-mode minor-mode-alist) - (setq minor-mode-alist - (cons '(follow-mode follow-mode-line-text) minor-mode-alist))) +(if (fboundp 'add-minor-mode) + ;; XEmacs + (funcall (symbol-function 'add-minor-mode) + 'follow-mode 'follow-mode-line-text) + (or (assq 'follow-mode minor-mode-alist) + (setq minor-mode-alist + (cons '(follow-mode follow-mode-line-text) minor-mode-alist)))) ;;}}} ;;{{{ Find file hook @@ -1123,6 +1161,29 @@ pos)) +;; The result from `follow-windows-start-end' is cached when using +;; a handful simple commands, like cursor movement commands. + +(defsubst follow-cache-valid-p (windows) + "Test if the cached value of `follow-windows-start-end' can be used. +Note that this handles the case when the cache has been set to nil." + (let ((res t) + (cache follow-windows-start-end-cache)) + (while (and res windows cache) + (setq res (and (eq (car windows) + (car (car cache))) + (eq (window-start (car windows)) + (car (cdr (car cache)))))) + (setq windows (cdr windows)) + (setq cache (cdr cache))) + (and res (null windows) (null cache)))) + + +(defsubst follow-invalidate-cache () + "Force `follow-windows-start-end' to recalculate the end of the window." + (setq follow-windows-start-end-cache nil)) + + ;; Build a list of windows and their start and end positions. ;; Useful to avoid calculating start/end position whenever they are needed. ;; The list has the format: @@ -1134,21 +1195,24 @@ (defun follow-windows-start-end (windows) "Builds a list of (WIN START END BUFFER-END-P) for every window in WINDOWS." - (let ((win-start-end '()) - (orig-win (selected-window))) - (while windows - (select-window (car windows)) - (setq win-start-end - (cons (cons (car windows) - (cons (window-start) - (follow-calc-win-end))) - win-start-end)) - (setq windows (cdr windows))) - (select-window orig-win) - (nreverse win-start-end))) + (if (follow-cache-valid-p windows) + follow-windows-start-end-cache + (let ((win-start-end '()) + (orig-win (selected-window))) + (while windows + (select-window (car windows)) + (setq win-start-end + (cons (cons (car windows) + (cons (window-start) + (follow-calc-win-end))) + win-start-end)) + (setq windows (cdr windows))) + (select-window orig-win) + (setq follow-windows-start-end-cache (nreverse win-start-end)) + follow-windows-start-end-cache))) -(defun follow-pos-visible (pos win win-start-end) +(defsubst follow-pos-visible (pos win win-start-end) "Non-nil when POS is visible in WIN." (let ((wstart-wend-bend (cdr (assq win win-start-end)))) (and (>= pos (car wstart-wend-bend)) @@ -1160,7 +1224,7 @@ ;; first is equal with the start of the successor. The first window ;; should start at a full screen line. -(defun follow-windows-aligned-p (win-start-end) +(defsubst follow-windows-aligned-p (win-start-end) "Non-nil if the follower WINDOWS are alinged." (let ((res t)) (save-excursion @@ -1171,8 +1235,8 @@ (setq res (eq (point) (window-start (car (car win-start-end))))))) (while (and res (cdr win-start-end)) ;; At least two followers left - (setq res (eq (nth 2 (car win-start-end)) - (nth 1 (car (cdr win-start-end))))) + (setq res (eq (car (cdr (cdr (car win-start-end)))) + (car (cdr (car (cdr win-start-end)))))) (setq win-start-end (cdr win-start-end))) res)) @@ -1184,10 +1248,9 @@ "Non-nil when the window-point is visible in all windows." (let ((res t)) (while (and res win-start-end) - (setq res (inline - (follow-pos-visible (window-point (car (car win-start-end))) - (car (car win-start-end)) - win-start-end))) + (setq res (follow-pos-visible (window-point (car (car win-start-end))) + (car (car win-start-end)) + win-start-end)) (setq win-start-end (cdr win-start-end))) res)) @@ -1495,26 +1558,30 @@ non-first windows in Follow Mode." (if follow-avoid-tail-recenter-p (let* ((orig-buffer (current-buffer)) - (top (frame-first-window (selected-frame))) - (win top) - (who '()) ; list of (buffer . frame) - start - pair) ; (buffer . frame) - (while ;; look, no body! - (progn - (setq start (window-start win)) - (set-buffer (window-buffer win)) - (setq pair (cons (window-buffer win) (window-frame win))) - (if (member pair who) - (if (and (boundp 'follow-mode) follow-mode - (eq (point-max) start)) - ;; Write the same window start back, but don't - ;; set the NOFORCE flag. - (set-window-start win start)) - (setq who (cons pair who))) - (setq win (next-window win 'not t)) - (not (eq win top)))) ;; Loop while this is true. - (set-buffer orig-buffer)))) + (top (frame-first-window (selected-frame))) + (win top) + (who '()) ; list of (buffer . frame) + start + pair) ; (buffer . frame) + ;; If the only window in the frame is a minibuffer + ;; window, `next-window' will never find it again... + (if (window-minibuffer-p top) + nil + (while ;; look, no body! + (progn + (setq start (window-start win)) + (set-buffer (window-buffer win)) + (setq pair (cons (window-buffer win) (window-frame win))) + (if (member pair who) + (if (and (boundp 'follow-mode) follow-mode + (eq (point-max) start)) + ;; Write the same window start back, but don't + ;; set the NOFORCE flag. + (set-window-start win start)) + (setq who (cons pair who))) + (setq win (next-window win 'not t)) + (not (eq win top)))) ;; Loop while this is true. + (set-buffer orig-buffer))))) ;;}}} @@ -1547,6 +1614,9 @@ (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 @@ -1554,12 +1624,14 @@ ;; cache the result for speed (i.e. `aligned' and `visible'.) (let* ((windows (inline (follow-all-followers win))) (dest (point)) - (win-start-end (progn + (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))) - (follow-avoid-tail-recenter) + (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 @@ -1629,6 +1701,7 @@ (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 @@ -1661,6 +1734,7 @@ (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 @@ -1672,6 +1746,7 @@ (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 ;; happends when dest is in the beginning of the ;; file and the selected window is not the first. @@ -1694,7 +1769,7 @@ (follow-maximize-region (selected-window) windows win-start-end)) - (follow-avoid-tail-recenter) + (inline (follow-avoid-tail-recenter)) ;; DEBUG ;;(if (not (follow-windows-aligned-p ;; (follow-windows-start-end windows))) @@ -2129,18 +2204,20 @@ (if return-to-orig-win (select-window orig-win)) (set-buffer old-buffer)) + + (follow-invalidate-cache) - ;; Normally, if the display has been changed, it is redrawn. All - ;; windows showing only the end of a buffer is unconditionally - ;; recentered, we can't prevent it by calling - ;; `follow-avoid-tail-recenter'. - ;; - ;; By performing a redisplay on our own, Emacs need not perform - ;; the above described redisplay. (However, bu performing it when - ;; there are input available just seems to make things worse.) - (if (and follow-avoid-tail-recenter-p - (not (input-pending-p))) - (sit-for 0))) + ;; Normally, if the display has been changed, it is redrawn. All + ;; windows showing only the end of a buffer is unconditionally + ;; recentered, we can't prevent it by calling + ;; `follow-avoid-tail-recenter'. + ;; + ;; By performing a redisplay on our own, Emacs need not perform + ;; the above described redisplay. (However, bu performing it when + ;; there are input available just seems to make things worse.) + (if (and follow-avoid-tail-recenter-p + (not (input-pending-p))) + (sit-for 0))) ;;}}} @@ -2316,6 +2393,7 @@ follow-calc-win-start follow-pos-visible follow-windows-start-end + follow-cache-valid-p follow-select-if-visible follow-select-if-visible-from-first follow-windows-aligned-p