diff options
| author | Chong Yidong | 2008-12-30 13:26:23 +0000 |
|---|---|---|
| committer | Chong Yidong | 2008-12-30 13:26:23 +0000 |
| commit | 30bf4750fbded1f835e8414bb159c8bb7e585a31 (patch) | |
| tree | 1625c8d2fd7d6b6dc70c0b8a936310a697ed2e41 | |
| parent | b4c79e7b015f149d170a39eb4e0b9acd8d0ef030 (diff) | |
| download | emacs-30bf4750fbded1f835e8414bb159c8bb7e585a31.tar.gz emacs-30bf4750fbded1f835e8414bb159c8bb7e585a31.zip | |
(follow-calc-win-end): Use with-selected-window.
(follow-windows-start-end, follow-pos-visible)
(follow-windows-aligned-p): Code cleanup.
(follow-select-if-visible): Try to avoid partially-visible lines.
(follow-select-if-visible-from-first): Call follow-redisplay and
move point to destination.
(follow-redisplay): New arg, to keep selected window unchanged.
(follow-post-command-hook): In final check for destination
visibility, use window-start and window-end instead of the less
accurate follow-pos-visible. If the selected window is redrawn,
tell follow-redisplay to preserve it.
| -rw-r--r-- | lisp/follow.el | 162 |
1 files changed, 84 insertions, 78 deletions
diff --git a/lisp/follow.el b/lisp/follow.el index 3c871a57e5c..59b8a8a38fd 100644 --- a/lisp/follow.el +++ b/lisp/follow.el | |||
| @@ -880,28 +880,23 @@ Returns (end-pos end-of-buffer-p)" | |||
| 880 | ;; This code works on both XEmacs and Emacs, but now | 880 | ;; This code works on both XEmacs and Emacs, but now |
| 881 | ;; that XEmacs has got custom-written code, this could | 881 | ;; that XEmacs has got custom-written code, this could |
| 882 | ;; be optimized for Emacs. | 882 | ;; be optimized for Emacs. |
| 883 | (let ((orig-win (and win (selected-window))) | 883 | (let (height buffer-end-p) |
| 884 | height | 884 | (with-selected-window (or win (selected-window)) |
| 885 | buffer-end-p) | 885 | (save-excursion |
| 886 | (if win (select-window win)) | 886 | (goto-char (window-start)) |
| 887 | (prog1 | 887 | (setq height |
| 888 | (save-excursion | 888 | (- (window-height) |
| 889 | (goto-char (window-start)) | 889 | (if header-line-format 2 1))) |
| 890 | (setq height | 890 | (setq buffer-end-p |
| 891 | (- (window-height) | 891 | (if (bolp) |
| 892 | (if header-line-format 2 1))) | 892 | (not (= height (vertical-motion height))) |
| 893 | (setq buffer-end-p | 893 | (save-restriction |
| 894 | (if (bolp) | 894 | ;; Fix a mis-feature in `vertical-motion': |
| 895 | (not (= height (vertical-motion height))) | 895 | ;; The start of the window is assumed to |
| 896 | (save-restriction | 896 | ;; coinside with the start of a line. |
| 897 | ;; Fix a mis-feature in `vertical-motion': | 897 | (narrow-to-region (point) (point-max)) |
| 898 | ;; The start of the window is assumed to | 898 | (not (= height (vertical-motion height)))))) |
| 899 | ;; coinside with the start of a line. | 899 | (list (point) buffer-end-p)))))) |
| 900 | (narrow-to-region (point) (point-max)) | ||
| 901 | (not (= height (vertical-motion height)))))) | ||
| 902 | (list (point) buffer-end-p)) | ||
| 903 | (if orig-win | ||
| 904 | (select-window orig-win)))))) | ||
| 905 | 900 | ||
| 906 | 901 | ||
| 907 | ;; Can't use `save-window-excursion' since it triggers a redraw. | 902 | ;; Can't use `save-window-excursion' since it triggers a redraw. |
| @@ -955,30 +950,25 @@ Note that this handles the case when the cache has been set to nil." | |||
| 955 | "Builds a list of (WIN START END BUFFER-END-P) for every window in WINDOWS." | 950 | "Builds a list of (WIN START END BUFFER-END-P) for every window in WINDOWS." |
| 956 | (if (follow-cache-valid-p windows) | 951 | (if (follow-cache-valid-p windows) |
| 957 | follow-windows-start-end-cache | 952 | follow-windows-start-end-cache |
| 958 | (let ((win-start-end '()) | 953 | (let ((orig-win (selected-window)) |
| 959 | (orig-win (selected-window))) | 954 | win-start-end) |
| 960 | (while windows | 955 | (dolist (w windows) |
| 961 | (select-window (car windows)) | 956 | (select-window w) |
| 962 | (setq win-start-end | 957 | (push (cons w (cons (window-start) (follow-calc-win-end))) |
| 963 | (cons (cons (car windows) | 958 | win-start-end)) |
| 964 | (cons (window-start) | ||
| 965 | (follow-calc-win-end))) | ||
| 966 | win-start-end)) | ||
| 967 | (setq windows (cdr windows))) | ||
| 968 | (select-window orig-win) | 959 | (select-window orig-win) |
| 969 | (setq follow-windows-start-end-cache (nreverse win-start-end)) | 960 | (setq follow-windows-start-end-cache (nreverse win-start-end))))) |
| 970 | follow-windows-start-end-cache))) | ||
| 971 | 961 | ||
| 972 | 962 | ||
| 973 | (defsubst follow-pos-visible (pos win win-start-end) | 963 | (defsubst follow-pos-visible (pos win win-start-end) |
| 974 | "Non-nil when POS is visible in WIN." | 964 | "Non-nil when POS is visible in WIN." |
| 975 | (let ((wstart-wend-bend (cdr (assq win win-start-end)))) | 965 | (let ((wstart-wend-bend (cdr (assq win win-start-end)))) |
| 976 | (and (>= pos (car wstart-wend-bend)) | 966 | (and (>= pos (car wstart-wend-bend)) |
| 977 | (or (< pos (car (cdr wstart-wend-bend))) | 967 | (or (< pos (cadr wstart-wend-bend)) |
| 978 | (nth 2 wstart-wend-bend))))) | 968 | (nth 2 wstart-wend-bend))))) |
| 979 | 969 | ||
| 980 | 970 | ||
| 981 | ;; By `aligned' we mean that for all adjecent windows, the end of the | 971 | ;; By `aligned' we mean that for all adjacent windows, the end of the |
| 982 | ;; first is equal with the start of the successor. The first window | 972 | ;; first is equal with the start of the successor. The first window |
| 983 | ;; should start at a full screen line. | 973 | ;; should start at a full screen line. |
| 984 | 974 | ||
| @@ -986,11 +976,10 @@ Note that this handles the case when the cache has been set to nil." | |||
| 986 | "Non-nil if the follower windows are aligned." | 976 | "Non-nil if the follower windows are aligned." |
| 987 | (let ((res t)) | 977 | (let ((res t)) |
| 988 | (save-excursion | 978 | (save-excursion |
| 989 | (goto-char (window-start (car (car win-start-end)))) | 979 | (goto-char (window-start (caar win-start-end))) |
| 990 | (if (bolp) | 980 | (unless (bolp) |
| 991 | nil | 981 | (vertical-motion 0 (caar win-start-end)) |
| 992 | (vertical-motion 0 (car (car win-start-end))) | 982 | (setq res (eq (point) (window-start (caar win-start-end)))))) |
| 993 | (setq res (eq (point) (window-start (car (car win-start-end))))))) | ||
| 994 | (while (and res (cdr win-start-end)) | 983 | (while (and res (cdr win-start-end)) |
| 995 | ;; At least two followers left | 984 | ;; At least two followers left |
| 996 | (setq res (eq (car (cdr (cdr (car win-start-end)))) | 985 | (setq res (eq (car (cdr (cdr (car win-start-end)))) |
| @@ -1053,6 +1042,14 @@ Return the selected window." | |||
| 1053 | (setq win (caar win-start-end)) | 1042 | (setq win (caar win-start-end)) |
| 1054 | (select-window win)) | 1043 | (select-window win)) |
| 1055 | (setq win-start-end (cdr win-start-end))) | 1044 | (setq win-start-end (cdr win-start-end))) |
| 1045 | ;; The last line of the window may be partially visible; if so, | ||
| 1046 | ;; and if point is visible in the next window, select the next | ||
| 1047 | ;; window instead. | ||
| 1048 | (and (/= dest (point-max)) | ||
| 1049 | win-start-end | ||
| 1050 | (follow-pos-visible dest (caar win-start-end) win-start-end) | ||
| 1051 | (setq win (caar win-start-end)) | ||
| 1052 | (select-window win)) | ||
| 1056 | win)) | 1053 | win)) |
| 1057 | 1054 | ||
| 1058 | 1055 | ||
| @@ -1090,31 +1087,34 @@ Return the selected window." | |||
| 1090 | ;; as the point is not visible in any window. | 1087 | ;; as the point is not visible in any window. |
| 1091 | 1088 | ||
| 1092 | (defun follow-select-if-visible-from-first (dest windows) | 1089 | (defun follow-select-if-visible-from-first (dest windows) |
| 1093 | "Select and return a window with DEST, if WINDOWS are redrawn from top." | 1090 | "Try to select one of WINDOWS without repositioning the topmost window. |
| 1094 | (let ((win nil) | 1091 | If one of the windows in WINDOWS contains DEST, select it, call |
| 1095 | end-pos-end-p) | 1092 | `follow-redisplay', move point to DEST, and return that window. |
| 1093 | Otherwise, return nil." | ||
| 1094 | (let (win end-pos-end-p) | ||
| 1096 | (save-excursion | 1095 | (save-excursion |
| 1097 | (goto-char (window-start (car windows))) | 1096 | (goto-char (window-start (car windows))) |
| 1098 | ;; Make sure the line start in the beginning of a real screen | 1097 | ;; Make sure the line start in the beginning of a real screen |
| 1099 | ;; line. | 1098 | ;; line. |
| 1100 | (vertical-motion 0 (car windows)) | 1099 | (vertical-motion 0 (car windows)) |
| 1101 | (if (< dest (point)) | 1100 | (when (>= dest (point)) |
| 1102 | ;; Above the start, not visible. | ||
| 1103 | nil | ||
| 1104 | ;; At or below the start. Check the windows. | 1101 | ;; At or below the start. Check the windows. |
| 1105 | (save-window-excursion | 1102 | (save-window-excursion |
| 1106 | (while (and (not win) windows) | 1103 | (let ((windows windows)) |
| 1107 | (set-window-start (car windows) (point) 'noforce) | 1104 | (while (and (not win) windows) |
| 1108 | (setq end-pos-end-p (follow-calc-win-end (car windows))) | 1105 | (set-window-start (car windows) (point) 'noforce) |
| 1109 | (goto-char (car end-pos-end-p)) | 1106 | (setq end-pos-end-p (follow-calc-win-end (car windows))) |
| 1110 | ;; Visible, if dest above end, or if eob is visible inside | 1107 | (goto-char (car end-pos-end-p)) |
| 1111 | ;; the window. | 1108 | ;; Visible, if dest above end, or if eob is visible inside |
| 1112 | (if (or (car (cdr end-pos-end-p)) | 1109 | ;; the window. |
| 1113 | (< dest (point))) | 1110 | (if (or (car (cdr end-pos-end-p)) |
| 1111 | (< dest (point))) | ||
| 1114 | (setq win (car windows)) | 1112 | (setq win (car windows)) |
| 1115 | (setq windows (cdr windows))))))) | 1113 | (setq windows (cdr windows)))))))) |
| 1116 | (if win | 1114 | (when win |
| 1117 | (select-window win)) | 1115 | (select-window win) |
| 1116 | (follow-redisplay windows (car windows)) | ||
| 1117 | (goto-char dest)) | ||
| 1118 | win)) | 1118 | win)) |
| 1119 | 1119 | ||
| 1120 | 1120 | ||
| @@ -1126,14 +1126,16 @@ Return the selected window." | |||
| 1126 | ;; is nil. Start every window directly after the end of the previous | 1126 | ;; is nil. Start every window directly after the end of the previous |
| 1127 | ;; window, to make sure long lines are displayed correctly. | 1127 | ;; window, to make sure long lines are displayed correctly. |
| 1128 | 1128 | ||
| 1129 | (defun follow-redisplay (&optional windows win) | 1129 | (defun follow-redisplay (&optional windows win preserve-win) |
| 1130 | "Reposition the WINDOWS around WIN. | 1130 | "Reposition the WINDOWS around WIN. |
| 1131 | Should the point be too close to the roof we redisplay everything | 1131 | Should the point be too close to the roof we redisplay everything |
| 1132 | from the top. WINDOWS should contain a list of windows to | 1132 | from the top. WINDOWS should contain a list of windows to |
| 1133 | redisplay, it is assumed that WIN is a member of the list. | 1133 | redisplay, it is assumed that WIN is a member of the list. |
| 1134 | Should WINDOWS be nil, the windows displaying the | 1134 | Should WINDOWS be nil, the windows displaying the |
| 1135 | same buffer as WIN, in the current frame, are used. | 1135 | same buffer as WIN, in the current frame, are used. |
| 1136 | Should WIN be nil, the selected window is used." | 1136 | Should WIN be nil, the selected window is used. |
| 1137 | If PRESERVE-WIN is non-nil, keep WIN itself unchanged while | ||
| 1138 | repositioning the other windows." | ||
| 1137 | (or win (setq win (selected-window))) | 1139 | (or win (setq win (selected-window))) |
| 1138 | (or windows (setq windows (follow-all-followers win))) | 1140 | (or windows (setq windows (follow-all-followers win))) |
| 1139 | ;; Calculate the start of the first window. | 1141 | ;; Calculate the start of the first window. |
| @@ -1154,7 +1156,8 @@ Should WIN be nil, the selected window is used." | |||
| 1154 | (follow-calculate-first-window-start-from-below | 1156 | (follow-calculate-first-window-start-from-below |
| 1155 | windows try-first-start win old-win-start))))) | 1157 | windows try-first-start win old-win-start))))) |
| 1156 | (dolist (w windows) | 1158 | (dolist (w windows) |
| 1157 | (set-window-start w start) | 1159 | (unless (and preserve-win (eq w win)) |
| 1160 | (set-window-start w start)) | ||
| 1158 | (setq start (car (follow-calc-win-end w)))))) | 1161 | (setq start (car (follow-calc-win-end w)))))) |
| 1159 | 1162 | ||
| 1160 | 1163 | ||
| @@ -1310,15 +1313,15 @@ non-first windows in Follow mode." | |||
| 1310 | (when (and follow-mode | 1313 | (when (and follow-mode |
| 1311 | (not (window-minibuffer-p win))) | 1314 | (not (window-minibuffer-p win))) |
| 1312 | ;; The buffer shown in the selected window is in follow | 1315 | ;; The buffer shown in the selected window is in follow |
| 1313 | ;; mode. Find the current state of the display and cache | 1316 | ;; mode. Find the current state of the display. |
| 1314 | ;; the result for speed (i.e. `aligned' and `visible'.) | ||
| 1315 | (let* ((windows (follow-all-followers win)) | 1317 | (let* ((windows (follow-all-followers win)) |
| 1316 | (dest (point)) | 1318 | (dest (point)) |
| 1317 | (win-start-end (progn | 1319 | (win-start-end (progn |
| 1318 | (follow-update-window-start (car windows)) | 1320 | (follow-update-window-start (car windows)) |
| 1319 | (follow-windows-start-end windows))) | 1321 | (follow-windows-start-end windows))) |
| 1320 | (aligned (follow-windows-aligned-p win-start-end)) | 1322 | (aligned (follow-windows-aligned-p win-start-end)) |
| 1321 | (visible (follow-pos-visible dest win win-start-end))) | 1323 | (visible (follow-pos-visible dest win win-start-end)) |
| 1324 | selected-window-up-to-date) | ||
| 1322 | (unless (and aligned visible) | 1325 | (unless (and aligned visible) |
| 1323 | (follow-invalidate-cache)) | 1326 | (follow-invalidate-cache)) |
| 1324 | (follow-avoid-tail-recenter) | 1327 | (follow-avoid-tail-recenter) |
| @@ -1392,9 +1395,7 @@ non-first windows in Follow mode." | |||
| 1392 | ;; at the bottom of a window. | 1395 | ;; at the bottom of a window. |
| 1393 | ((follow-select-if-visible-from-first dest windows) | 1396 | ((follow-select-if-visible-from-first dest windows) |
| 1394 | (follow-debug-message "Below first") | 1397 | (follow-debug-message "Below first") |
| 1395 | (setq visible t aligned t) | 1398 | (setq visible t aligned t)) |
| 1396 | (follow-redisplay windows (car windows)) | ||
| 1397 | (goto-char dest)) | ||
| 1398 | ;; None of the above. For simplicity, we stick to the | 1399 | ;; None of the above. For simplicity, we stick to the |
| 1399 | ;; selected window. | 1400 | ;; selected window. |
| 1400 | (t | 1401 | (t |
| @@ -1403,27 +1404,34 @@ non-first windows in Follow mode." | |||
| 1403 | ;; If a new window has been selected, make sure that the | 1404 | ;; If a new window has been selected, make sure that the |
| 1404 | ;; old is not scrolled when the point is outside the | 1405 | ;; old is not scrolled when the point is outside the |
| 1405 | ;; window. | 1406 | ;; window. |
| 1406 | (or (eq win (selected-window)) | 1407 | (unless (eq win (selected-window)) |
| 1407 | (let ((p (window-point win))) | 1408 | (let ((p (window-point win))) |
| 1408 | (set-window-start win (window-start win) nil) | 1409 | (set-window-start win (window-start win) nil) |
| 1409 | (set-window-point win p)))) | 1410 | (set-window-point win p)))) |
| 1410 | ;; Make sure the point is visible in the selected window. | ||
| 1411 | ;; (This could lead to a scroll.) | ||
| 1412 | (unless (or visible | 1411 | (unless (or visible |
| 1413 | (follow-pos-visible dest win win-start-end)) | 1412 | ;; Use the UPDATE argument of window-end |
| 1413 | ;; instead of calling follow-pos-visible | ||
| 1414 | ;; (which may be inaccurate for partially | ||
| 1415 | ;; visible lines). | ||
| 1416 | (and (>= dest (window-start)) | ||
| 1417 | (< dest (window-end nil t)))) | ||
| 1418 | ;; If point is not visible in the selected window, | ||
| 1419 | ;; perform a redisplay; this causes scrolling. | ||
| 1414 | (sit-for 0) | 1420 | (sit-for 0) |
| 1421 | (setq selected-window-up-to-date t) | ||
| 1415 | (follow-avoid-tail-recenter) | 1422 | (follow-avoid-tail-recenter) |
| 1416 | (setq win-start-end (follow-windows-start-end windows)) | 1423 | (setq win-start-end (follow-windows-start-end windows)) |
| 1417 | (follow-invalidate-cache) | 1424 | (follow-invalidate-cache) |
| 1418 | (setq aligned nil)) | 1425 | (setq aligned nil)) |
| 1419 | ;; Redraw the windows whenever needed. | 1426 | ;; Now redraw the windows around the selected window. |
| 1420 | (unless (and (not follow-internal-force-redisplay) | 1427 | (unless (and (not follow-internal-force-redisplay) |
| 1421 | (or aligned | 1428 | (or aligned |
| 1422 | (follow-windows-aligned-p win-start-end)) | 1429 | (follow-windows-aligned-p win-start-end)) |
| 1423 | (follow-point-visible-all-windows-p | 1430 | (follow-point-visible-all-windows-p |
| 1424 | win-start-end)) | 1431 | win-start-end)) |
| 1425 | (setq follow-internal-force-redisplay nil) | 1432 | (setq follow-internal-force-redisplay nil) |
| 1426 | (follow-redisplay windows (selected-window)) | 1433 | (follow-redisplay windows (selected-window) |
| 1434 | selected-window-up-to-date) | ||
| 1427 | (setq win-start-end (follow-windows-start-end windows)) | 1435 | (setq win-start-end (follow-windows-start-end windows)) |
| 1428 | (follow-invalidate-cache) | 1436 | (follow-invalidate-cache) |
| 1429 | ;; When the point ends up in another window. This | 1437 | ;; When the point ends up in another window. This |
| @@ -1833,8 +1841,6 @@ report this using the `report-emacs-bug' function." | |||
| 1833 | ((follow-select-if-visible-from-first | 1841 | ((follow-select-if-visible-from-first |
| 1834 | new-window-point windows) | 1842 | new-window-point windows) |
| 1835 | (follow-debug-message "filter: Seen from first") | 1843 | (follow-debug-message "filter: Seen from first") |
| 1836 | (follow-redisplay windows (car windows)) | ||
| 1837 | (goto-char new-window-point) | ||
| 1838 | (setq win-start-end | 1844 | (setq win-start-end |
| 1839 | (follow-windows-start-end windows))) | 1845 | (follow-windows-start-end windows))) |
| 1840 | ;; None of the above. We stick to the current window. | 1846 | ;; None of the above. We stick to the current window. |