X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/e79016aa9acf416538fd18cc50a582553030eca2..66db4b5b2a1a2ff5a68de1b3ca93cbeb11132566:/lisp/follow.el diff --git a/lisp/follow.el b/lisp/follow.el index 91a2e1a1ee..cae16af116 100644 --- a/lisp/follow.el +++ b/lisp/follow.el @@ -5,23 +5,26 @@ ;; 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 +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. -;; This program is distributed in the hope that it will be useful, +;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with this program; see the file COPYING. If not, write to -;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. ;;; Commentary: @@ -126,7 +129,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 +139,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 +310,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 +319,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 +378,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 +413,7 @@ the buffer. Normally it is practical for the user that empty 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 +423,24 @@ situation in which Emacs recenters empty windows. 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 +458,9 @@ XEmacs, as of 19.12, does not recenter windows, good!") "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 @@ -654,6 +683,14 @@ Used by `follow-window-size-change'.") (setq minor-mode-map-alist (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 +776,13 @@ Keys specific to Follow mode: ;; 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 +1164,29 @@ If WIN is nil the point below all windows is returned." 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 +1198,24 @@ If WIN is nil the point below all windows is returned." (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))) - - -(defun follow-pos-visible (pos win 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))) + + +(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 +1227,7 @@ If WIN is nil the point below all windows is returned." ;; 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 +1238,8 @@ If WIN is nil the point below all windows is returned." (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 +1251,9 @@ If WIN is nil the point below all windows is returned." "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 +1561,30 @@ This is done by reading and rewriting the start positon of 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 +1617,9 @@ non-first windows in Follow Mode." (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 +1627,14 @@ non-first windows in Follow Mode." ;; 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 +1704,7 @@ non-first windows in Follow Mode." (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 +1737,7 @@ non-first windows in Follow Mode." (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 +1749,7 @@ non-first windows in Follow Mode." (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 +1772,7 @@ non-first windows in Follow Mode." (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 +2207,20 @@ report this using the `follow-submit-feedback' function." (if return-to-orig-win (select-window orig-win)) (set-buffer old-buffer)) - - ;; 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))) + + (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))) ;;}}} @@ -2316,6 +2396,7 @@ messing things up." 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