aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChong Yidong2008-12-30 13:26:23 +0000
committerChong Yidong2008-12-30 13:26:23 +0000
commit30bf4750fbded1f835e8414bb159c8bb7e585a31 (patch)
tree1625c8d2fd7d6b6dc70c0b8a936310a697ed2e41
parentb4c79e7b015f149d170a39eb4e0b9acd8d0ef030 (diff)
downloademacs-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.el162
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) 1091If 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.
1093Otherwise, 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.
1131Should the point be too close to the roof we redisplay everything 1131Should the point be too close to the roof we redisplay everything
1132from the top. WINDOWS should contain a list of windows to 1132from the top. WINDOWS should contain a list of windows to
1133redisplay, it is assumed that WIN is a member of the list. 1133redisplay, it is assumed that WIN is a member of the list.
1134Should WINDOWS be nil, the windows displaying the 1134Should WINDOWS be nil, the windows displaying the
1135same buffer as WIN, in the current frame, are used. 1135same buffer as WIN, in the current frame, are used.
1136Should WIN be nil, the selected window is used." 1136Should WIN be nil, the selected window is used.
1137If PRESERVE-WIN is non-nil, keep WIN itself unchanged while
1138repositioning 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.