aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/follow.el216
1 files changed, 147 insertions, 69 deletions
diff --git a/lisp/follow.el b/lisp/follow.el
index 91a2e1a1ee2..db1fa77ad9e 100644
--- a/lisp/follow.el
+++ b/lisp/follow.el
@@ -5,9 +5,9 @@
5;; Author: Anders Lindgren <andersl@csd.uu.se> 5;; Author: Anders Lindgren <andersl@csd.uu.se>
6;; Maintainer: Anders Lindgren <andersl@csd.uu.se> 6;; Maintainer: Anders Lindgren <andersl@csd.uu.se>
7;; Created: 25 May 1995 7;; Created: 25 May 1995
8;; Version: 1.5 8;; Version: 1.6
9;; Keywords: display, window, minor-mode 9;; Keywords: display, window, minor-mode
10;; Date: 22 Jan 1996 10;; Date: 20 Feb 1996
11 11
12;; This program is free software; you can redistribute it and/or modify 12;; This program is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by 13;; it under the terms of the GNU General Public License as published by
@@ -126,7 +126,8 @@
126 126
127;; There exists two system variables which controls the appearence of 127;; There exists two system variables which controls the appearence of
128;; lines which are wider than the window containing them. The default 128;; lines which are wider than the window containing them. The default
129;; is to truncate long lines if a window isn't as wide as the frame. 129;; is to truncate long lines whenever a window isn't as wide as the
130;; frame.
130;; 131;;
131;; To make sure lines are never truncated, please place the following 132;; To make sure lines are never truncated, please place the following
132;; lines in your init file: 133;; lines in your init file:
@@ -135,6 +136,15 @@
135;; (setq truncate-partial-width-windows nil) 136;; (setq truncate-partial-width-windows nil)
136 137
137 138
139;; Since the display of XEmacs is pixel-oriented, a line could be
140;; clipped in half at the bottom of the window.
141;;
142;; To make XEmacs avoid clipping (normal) lines, please place the
143;; following line in your init-file:
144;;
145;; (setq pixel-vertical-clip-threshold 30)
146
147
138;; The correct way to cofigurate Follow mode, or any other mode for 148;; The correct way to cofigurate Follow mode, or any other mode for
139;; that matter, is to create one (or more) function which does 149;; that matter, is to create one (or more) function which does
140;; whatever you would like to do. The function is then added to 150;; whatever you would like to do. The function is then added to
@@ -297,7 +307,7 @@
297;; Code in post hook removed. 307;; Code in post hook removed.
298;; * XEmacs: Post hook is always executed 308;; * XEmacs: Post hook is always executed
299;; after a mouse button event. 309;; after a mouse button event.
300;; 22-Jan-95 andersl * 1.5 released. 310;; 22-Jan-96 andersl * 1.5 released.
301;; 311;;
302 312
303;;}}} 313;;}}}
@@ -306,7 +316,7 @@
306;;; LCD Archive Entry: 316;;; LCD Archive Entry:
307;; follow|Anders Lindgren|andersl@csd.uu.se| 317;; follow|Anders Lindgren|andersl@csd.uu.se|
308;; Combines windows into tall virtual window, minor mode. 318;; Combines windows into tall virtual window, minor mode.
309;; 22-Jan-1996|1.5|~/modes/follow.el.Z| 319;; 20-Feb-1996|1.6|~/modes/follow.el.Z|
310 320
311;;}}} 321;;}}}
312 322
@@ -365,11 +375,11 @@
365(defvar follow-mode-off-hook nil 375(defvar follow-mode-off-hook nil
366 "*Hooks to run when follow-mode is turned off.") 376 "*Hooks to run when follow-mode is turned off.")
367 377
368(defvar follow-mode-version "follow.el (Release 1.5)" 378(defvar follow-mode-version "follow.el (Release 1.6)"
369 "The current version of Follow mode.") 379 "The current version of Follow mode.")
370 380
371(defvar follow-mode-map nil 381(defvar follow-mode-map nil
372 "Minor mode keymap for Follow mode.") 382 "*Minor mode keymap for Follow mode.")
373 383
374(defvar follow-mode-line-text " Follow" 384(defvar follow-mode-line-text " Follow"
375 "*Text shown in the mode line when Follow mode is active. 385 "*Text shown in the mode line when Follow mode is active.
@@ -400,7 +410,7 @@ the buffer. Normally it is practical for the user that empty
400windows are recentered automatically. However, when using 410windows are recentered automatically. However, when using
401Follow Mode it breaks the display when the end is displayed 411Follow Mode it breaks the display when the end is displayed
402in a window \"above\" the last window. This is for 412in a window \"above\" the last window. This is for
403example the case when displaying short files. 413example the case when displaying a short page in info.
404 414
405Must be set before Follow Mode is loaded. 415Must be set before Follow Mode is loaded.
406 416
@@ -410,11 +420,24 @@ situation in which Emacs recenters empty windows.
410 420
411XEmacs, as of 19.12, does not recenter windows, good!") 421XEmacs, as of 19.12, does not recenter windows, good!")
412 422
423(defvar follow-cache-command-list
424 '(next-line previous-line forward-char backward-char)
425 "List of commands which don't require recalculation.
426
427In order to be able to use the cache, a command should not change the
428contents of the buffer, nor should it change selected window or current
429buffer.
430
431The commands in this list are checked at load time.
432
433To mark other commands as suitable for caching, set the symbol
434property `follow-mode-use-cache' to non-nil.")
435
413(defvar follow-debug nil 436(defvar follow-debug nil
414 "*Non-nil when debugging Follow mode.") 437 "*Non-nil when debugging Follow mode.")
415 438
416 439
417;;; Internal variables 440;; Internal variables:
418 441
419(defvar follow-internal-force-redisplay nil 442(defvar follow-internal-force-redisplay nil
420 "True when Follow mode should redisplay the windows.") 443 "True when Follow mode should redisplay the windows.")
@@ -432,6 +455,9 @@ XEmacs, as of 19.12, does not recenter windows, good!")
432 "Non-nil when inside Follow modes `post-command-hook'. 455 "Non-nil when inside Follow modes `post-command-hook'.
433Used by `follow-window-size-change'.") 456Used by `follow-window-size-change'.")
434 457
458(defvar follow-windows-start-end-cache nil
459 "Cache used by `follow-window-start-end'.")
460
435;;}}} 461;;}}}
436;;{{{ Bug report 462;;{{{ Bug report
437 463
@@ -655,6 +681,14 @@ Used by `follow-window-size-change'.")
655 (cons (cons 'follow-mode follow-mode-map) minor-mode-map-alist))) 681 (cons (cons 'follow-mode follow-mode-map) minor-mode-map-alist)))
656 682
657;;}}} 683;;}}}
684;;{{{ Cache
685
686(let ((cmds follow-cache-command-list))
687 (while cmds
688 (put (car cmds) 'follow-mode-use-cache t)
689 (setq cmds (cdr cmds))))
690
691;;}}}
658 692
659;;{{{ The mode 693;;{{{ The mode
660 694
@@ -739,9 +773,13 @@ Keys specific to Follow mode:
739 773
740;; Register follow-mode as a minor mode. 774;; Register follow-mode as a minor mode.
741 775
742(or (assq 'follow-mode minor-mode-alist) 776(if (fboundp 'add-minor-mode)
743 (setq minor-mode-alist 777 ;; XEmacs
744 (cons '(follow-mode follow-mode-line-text) minor-mode-alist))) 778 (funcall (symbol-function 'add-minor-mode)
779 'follow-mode 'follow-mode-line-text)
780 (or (assq 'follow-mode minor-mode-alist)
781 (setq minor-mode-alist
782 (cons '(follow-mode follow-mode-line-text) minor-mode-alist))))
745 783
746;;}}} 784;;}}}
747;;{{{ Find file hook 785;;{{{ Find file hook
@@ -1123,6 +1161,29 @@ If WIN is nil the point below all windows is returned."
1123 pos)) 1161 pos))
1124 1162
1125 1163
1164;; The result from `follow-windows-start-end' is cached when using
1165;; a handful simple commands, like cursor movement commands.
1166
1167(defsubst follow-cache-valid-p (windows)
1168 "Test if the cached value of `follow-windows-start-end' can be used.
1169Note that this handles the case when the cache has been set to nil."
1170 (let ((res t)
1171 (cache follow-windows-start-end-cache))
1172 (while (and res windows cache)
1173 (setq res (and (eq (car windows)
1174 (car (car cache)))
1175 (eq (window-start (car windows))
1176 (car (cdr (car cache))))))
1177 (setq windows (cdr windows))
1178 (setq cache (cdr cache)))
1179 (and res (null windows) (null cache))))
1180
1181
1182(defsubst follow-invalidate-cache ()
1183 "Force `follow-windows-start-end' to recalculate the end of the window."
1184 (setq follow-windows-start-end-cache nil))
1185
1186
1126;; Build a list of windows and their start and end positions. 1187;; Build a list of windows and their start and end positions.
1127;; Useful to avoid calculating start/end position whenever they are needed. 1188;; Useful to avoid calculating start/end position whenever they are needed.
1128;; The list has the format: 1189;; The list has the format:
@@ -1134,21 +1195,24 @@ If WIN is nil the point below all windows is returned."
1134 1195
1135(defun follow-windows-start-end (windows) 1196(defun follow-windows-start-end (windows)
1136 "Builds a list of (WIN START END BUFFER-END-P) for every window in WINDOWS." 1197 "Builds a list of (WIN START END BUFFER-END-P) for every window in WINDOWS."
1137 (let ((win-start-end '()) 1198 (if (follow-cache-valid-p windows)
1138 (orig-win (selected-window))) 1199 follow-windows-start-end-cache
1139 (while windows 1200 (let ((win-start-end '())
1140 (select-window (car windows)) 1201 (orig-win (selected-window)))
1141 (setq win-start-end 1202 (while windows
1142 (cons (cons (car windows) 1203 (select-window (car windows))
1143 (cons (window-start) 1204 (setq win-start-end
1144 (follow-calc-win-end))) 1205 (cons (cons (car windows)
1145 win-start-end)) 1206 (cons (window-start)
1146 (setq windows (cdr windows))) 1207 (follow-calc-win-end)))
1147 (select-window orig-win) 1208 win-start-end))
1148 (nreverse win-start-end))) 1209 (setq windows (cdr windows)))
1149 1210 (select-window orig-win)
1150 1211 (setq follow-windows-start-end-cache (nreverse win-start-end))
1151(defun follow-pos-visible (pos win win-start-end) 1212 follow-windows-start-end-cache)))
1213
1214
1215(defsubst follow-pos-visible (pos win win-start-end)
1152 "Non-nil when POS is visible in WIN." 1216 "Non-nil when POS is visible in WIN."
1153 (let ((wstart-wend-bend (cdr (assq win win-start-end)))) 1217 (let ((wstart-wend-bend (cdr (assq win win-start-end))))
1154 (and (>= pos (car wstart-wend-bend)) 1218 (and (>= pos (car wstart-wend-bend))
@@ -1160,7 +1224,7 @@ If WIN is nil the point below all windows is returned."
1160;; first is equal with the start of the successor. The first window 1224;; first is equal with the start of the successor. The first window
1161;; should start at a full screen line. 1225;; should start at a full screen line.
1162 1226
1163(defun follow-windows-aligned-p (win-start-end) 1227(defsubst follow-windows-aligned-p (win-start-end)
1164 "Non-nil if the follower WINDOWS are alinged." 1228 "Non-nil if the follower WINDOWS are alinged."
1165 (let ((res t)) 1229 (let ((res t))
1166 (save-excursion 1230 (save-excursion
@@ -1171,8 +1235,8 @@ If WIN is nil the point below all windows is returned."
1171 (setq res (eq (point) (window-start (car (car win-start-end))))))) 1235 (setq res (eq (point) (window-start (car (car win-start-end)))))))
1172 (while (and res (cdr win-start-end)) 1236 (while (and res (cdr win-start-end))
1173 ;; At least two followers left 1237 ;; At least two followers left
1174 (setq res (eq (nth 2 (car win-start-end)) 1238 (setq res (eq (car (cdr (cdr (car win-start-end))))
1175 (nth 1 (car (cdr win-start-end))))) 1239 (car (cdr (car (cdr win-start-end))))))
1176 (setq win-start-end (cdr win-start-end))) 1240 (setq win-start-end (cdr win-start-end)))
1177 res)) 1241 res))
1178 1242
@@ -1184,10 +1248,9 @@ If WIN is nil the point below all windows is returned."
1184 "Non-nil when the window-point is visible in all windows." 1248 "Non-nil when the window-point is visible in all windows."
1185 (let ((res t)) 1249 (let ((res t))
1186 (while (and res win-start-end) 1250 (while (and res win-start-end)
1187 (setq res (inline 1251 (setq res (follow-pos-visible (window-point (car (car win-start-end)))
1188 (follow-pos-visible (window-point (car (car win-start-end))) 1252 (car (car win-start-end))
1189 (car (car win-start-end)) 1253 win-start-end))
1190 win-start-end)))
1191 (setq win-start-end (cdr win-start-end))) 1254 (setq win-start-end (cdr win-start-end)))
1192 res)) 1255 res))
1193 1256
@@ -1495,26 +1558,30 @@ This is done by reading and rewriting the start positon of
1495non-first windows in Follow Mode." 1558non-first windows in Follow Mode."
1496 (if follow-avoid-tail-recenter-p 1559 (if follow-avoid-tail-recenter-p
1497 (let* ((orig-buffer (current-buffer)) 1560 (let* ((orig-buffer (current-buffer))
1498 (top (frame-first-window (selected-frame))) 1561 (top (frame-first-window (selected-frame)))
1499 (win top) 1562 (win top)
1500 (who '()) ; list of (buffer . frame) 1563 (who '()) ; list of (buffer . frame)
1501 start 1564 start
1502 pair) ; (buffer . frame) 1565 pair) ; (buffer . frame)
1503 (while ;; look, no body! 1566 ;; If the only window in the frame is a minibuffer
1504 (progn 1567 ;; window, `next-window' will never find it again...
1505 (setq start (window-start win)) 1568 (if (window-minibuffer-p top)
1506 (set-buffer (window-buffer win)) 1569 nil
1507 (setq pair (cons (window-buffer win) (window-frame win))) 1570 (while ;; look, no body!
1508 (if (member pair who) 1571 (progn
1509 (if (and (boundp 'follow-mode) follow-mode 1572 (setq start (window-start win))
1510 (eq (point-max) start)) 1573 (set-buffer (window-buffer win))
1511 ;; Write the same window start back, but don't 1574 (setq pair (cons (window-buffer win) (window-frame win)))
1512 ;; set the NOFORCE flag. 1575 (if (member pair who)
1513 (set-window-start win start)) 1576 (if (and (boundp 'follow-mode) follow-mode
1514 (setq who (cons pair who))) 1577 (eq (point-max) start))
1515 (setq win (next-window win 'not t)) 1578 ;; Write the same window start back, but don't
1516 (not (eq win top)))) ;; Loop while this is true. 1579 ;; set the NOFORCE flag.
1517 (set-buffer orig-buffer)))) 1580 (set-window-start win start))
1581 (setq who (cons pair who)))
1582 (setq win (next-window win 'not t))
1583 (not (eq win top)))) ;; Loop while this is true.
1584 (set-buffer orig-buffer)))))
1518 1585
1519;;}}} 1586;;}}}
1520 1587
@@ -1547,6 +1614,9 @@ non-first windows in Follow Mode."
1547 (let ((orig-buffer (current-buffer)) 1614 (let ((orig-buffer (current-buffer))
1548 (win (selected-window))) 1615 (win (selected-window)))
1549 (set-buffer (window-buffer win)) 1616 (set-buffer (window-buffer win))
1617 (or (and (symbolp this-command)
1618 (get this-command 'follow-mode-use-cache))
1619 (follow-invalidate-cache))
1550 (if (and (boundp 'follow-mode) follow-mode 1620 (if (and (boundp 'follow-mode) follow-mode
1551 (not (window-minibuffer-p win))) 1621 (not (window-minibuffer-p win)))
1552 ;; The buffer shown in the selected window is in follow 1622 ;; The buffer shown in the selected window is in follow
@@ -1554,12 +1624,14 @@ non-first windows in Follow Mode."
1554 ;; cache the result for speed (i.e. `aligned' and `visible'.) 1624 ;; cache the result for speed (i.e. `aligned' and `visible'.)
1555 (let* ((windows (inline (follow-all-followers win))) 1625 (let* ((windows (inline (follow-all-followers win)))
1556 (dest (point)) 1626 (dest (point))
1557 (win-start-end (progn 1627 (win-start-end (inline
1558 (follow-update-window-start (car windows)) 1628 (follow-update-window-start (car windows))
1559 (follow-windows-start-end windows))) 1629 (follow-windows-start-end windows)))
1560 (aligned (follow-windows-aligned-p win-start-end)) 1630 (aligned (follow-windows-aligned-p win-start-end))
1561 (visible (follow-pos-visible dest win win-start-end))) 1631 (visible (follow-pos-visible dest win win-start-end)))
1562 (follow-avoid-tail-recenter) 1632 (if (not (and aligned visible))
1633 (follow-invalidate-cache))
1634 (inline (follow-avoid-tail-recenter))
1563 ;; Select a window to display the point. 1635 ;; Select a window to display the point.
1564 (or follow-internal-force-redisplay 1636 (or follow-internal-force-redisplay
1565 (progn 1637 (progn
@@ -1629,6 +1701,7 @@ non-first windows in Follow Mode."
1629 (goto-char dest) 1701 (goto-char dest)
1630 (set-window-start (selected-window) (point-min)) 1702 (set-window-start (selected-window) (point-min))
1631 (setq win-start-end (follow-windows-start-end windows)) 1703 (setq win-start-end (follow-windows-start-end windows))
1704 (follow-invalidate-cache)
1632 (setq visible t) 1705 (setq visible t)
1633 (setq aligned nil)) 1706 (setq aligned nil))
1634 ;; If we can position the cursor without moving the first 1707 ;; If we can position the cursor without moving the first
@@ -1661,6 +1734,7 @@ non-first windows in Follow Mode."
1661 (sit-for 0) 1734 (sit-for 0)
1662 (follow-avoid-tail-recenter) 1735 (follow-avoid-tail-recenter)
1663 (setq win-start-end (follow-windows-start-end windows)) 1736 (setq win-start-end (follow-windows-start-end windows))
1737 (follow-invalidate-cache)
1664 (setq aligned nil)) 1738 (setq aligned nil))
1665 ;; Redraw the windows whenever needed. 1739 ;; Redraw the windows whenever needed.
1666 (if (or follow-internal-force-redisplay 1740 (if (or follow-internal-force-redisplay
@@ -1672,6 +1746,7 @@ non-first windows in Follow Mode."
1672 (setq follow-internal-force-redisplay nil) 1746 (setq follow-internal-force-redisplay nil)
1673 (follow-redisplay windows (selected-window)) 1747 (follow-redisplay windows (selected-window))
1674 (setq win-start-end (follow-windows-start-end windows)) 1748 (setq win-start-end (follow-windows-start-end windows))
1749 (follow-invalidate-cache)
1675 ;; When the point ends up in another window. This 1750 ;; When the point ends up in another window. This
1676 ;; happends when dest is in the beginning of the 1751 ;; happends when dest is in the beginning of the
1677 ;; file and the selected window is not the first. 1752 ;; file and the selected window is not the first.
@@ -1694,7 +1769,7 @@ non-first windows in Follow Mode."
1694 (follow-maximize-region 1769 (follow-maximize-region
1695 (selected-window) windows win-start-end)) 1770 (selected-window) windows win-start-end))
1696 1771
1697 (follow-avoid-tail-recenter) 1772 (inline (follow-avoid-tail-recenter))
1698 ;; DEBUG 1773 ;; DEBUG
1699 ;;(if (not (follow-windows-aligned-p 1774 ;;(if (not (follow-windows-aligned-p
1700 ;; (follow-windows-start-end windows))) 1775 ;; (follow-windows-start-end windows)))
@@ -2129,18 +2204,20 @@ report this using the `follow-submit-feedback' function."
2129 (if return-to-orig-win 2204 (if return-to-orig-win
2130 (select-window orig-win)) 2205 (select-window orig-win))
2131 (set-buffer old-buffer)) 2206 (set-buffer old-buffer))
2132 2207
2133 ;; Normally, if the display has been changed, it is redrawn. All 2208 (follow-invalidate-cache)
2134 ;; windows showing only the end of a buffer is unconditionally 2209
2135 ;; recentered, we can't prevent it by calling 2210 ;; Normally, if the display has been changed, it is redrawn. All
2136 ;; `follow-avoid-tail-recenter'. 2211 ;; windows showing only the end of a buffer is unconditionally
2137 ;; 2212 ;; recentered, we can't prevent it by calling
2138 ;; By performing a redisplay on our own, Emacs need not perform 2213 ;; `follow-avoid-tail-recenter'.
2139 ;; the above described redisplay. (However, bu performing it when 2214 ;;
2140 ;; there are input available just seems to make things worse.) 2215 ;; By performing a redisplay on our own, Emacs need not perform
2141 (if (and follow-avoid-tail-recenter-p 2216 ;; the above described redisplay. (However, bu performing it when
2142 (not (input-pending-p))) 2217 ;; there are input available just seems to make things worse.)
2143 (sit-for 0))) 2218 (if (and follow-avoid-tail-recenter-p
2219 (not (input-pending-p)))
2220 (sit-for 0)))
2144 2221
2145;;}}} 2222;;}}}
2146 2223
@@ -2316,6 +2393,7 @@ messing things up."
2316 follow-calc-win-start 2393 follow-calc-win-start
2317 follow-pos-visible 2394 follow-pos-visible
2318 follow-windows-start-end 2395 follow-windows-start-end
2396 follow-cache-valid-p
2319 follow-select-if-visible 2397 follow-select-if-visible
2320 follow-select-if-visible-from-first 2398 follow-select-if-visible-from-first
2321 follow-windows-aligned-p 2399 follow-windows-aligned-p