Commit 782fbf2a authored by Chong Yidong's avatar Chong Yidong
Browse files

* lisp/follow.el: Rework, eliminating reliance on advice.

(set-process-filter, process-filter, sit-for): Advice deleted.
(follow-mode-off-hook): Obsolete hook removed.
(follow-avoid-tail-recenter-p, follow-process-filter-alist): Vars
deleted.
(follow-auto): Use a :set function.
(follow-mode): Rewritten.  Don't advise process filters.
(follow-switch-to-current-buffer-all, follow-scroll-up)
(follow-scroll-down): Assume follow-mode is bound.
(follow-comint-scroll-to-bottom)
(follow-align-compilation-windows): New functions.
(follow--window-sorter): New function.
(follow-all-followers): Use it to explicitly sort windows by their
positions; don't make assumptions about next-window order.
(follow-windows-start-end, follow-delete-other-windows-and-split)
(follow-calc-win-start): Doc fix.
(follow-windows-aligned-p, follow-select-if-visible): Don't call
vertical-motion unnecessarily.
(follow-adjust-window): New function.
(follow-post-command-hook): Use it.
(follow-call-set-process-filter, follow-call-process-filter)
(follow-intercept-process-output, follow-tidy-process-filter-alist)
(follow-stop-intercept-process-output, follow-generic-filter):
Functions deleted.
(follow-scroll-bar-toolkit-scroll, follow-scroll-bar-drag)
(follow-scroll-bar-scroll-up, follow-scroll-bar-scroll-down): New
functions, replacing advice on scroll-bar-* commands.

* lisp/comint.el (comint-adjust-point): New function.
(comint-postoutput-scroll-to-bottom): Use it.  Call
follow-comint-scroll-to-bottom for Follow mode buffers.
parent eb0ae1d1
......@@ -100,6 +100,13 @@ these commands now).
** erc will look up server/channel names via auth-source and use the
channel keys found, if any.
** Follow mode
*** The obsolete variable `follow-mode-off-hook' has been removed.
*** Follow mode no longer works by using advice.
The option `follow-intercept-processes' has been removed.
** The `server-auth-key' variable can be used to set a permanent
shared key for Emacs Server.
......
2012-05-01 Chong Yidong <cyd@gnu.org>
* follow.el: Eliminate advice.
(set-process-filter, process-filter, sit-for): Advice deleted.
(follow-mode-off-hook): Obsolete hook removed.
(follow-avoid-tail-recenter-p, follow-process-filter-alist): Vars
deleted.
(follow-auto): Use a :set function.
(follow-mode): Rewritten. Don't advise process filters.
(follow-switch-to-current-buffer-all, follow-scroll-up)
(follow-scroll-down): Assume follow-mode is bound.
(follow-comint-scroll-to-bottom)
(follow-align-compilation-windows): New functions.
(follow--window-sorter): New function.
(follow-all-followers): Use it to explicitly sort windows by their
positions; don't make assumptions about next-window order.
(follow-windows-start-end, follow-delete-other-windows-and-split)
(follow-calc-win-start): Doc fix.
(follow-windows-aligned-p, follow-select-if-visible): Don't call
vertical-motion unnecessarily.
(follow-adjust-window): New function.
(follow-post-command-hook): Use it.
(follow-call-set-process-filter, follow-call-process-filter)
(follow-intercept-process-output, follow-tidy-process-filter-alist)
(follow-stop-intercept-process-output, follow-generic-filter):
Functions deleted.
(follow-scroll-bar-toolkit-scroll, follow-scroll-bar-drag)
(follow-scroll-bar-scroll-up, follow-scroll-bar-scroll-down): New
functions, replacing advice on scroll-bar-* commands.
* comint.el (comint-adjust-point): New function.
(comint-postoutput-scroll-to-bottom): Use it. Call
follow-comint-scroll-to-bottom for Follow mode buffers.
2012-05-01 Glenn Morris <rgm@gnu.org>
* term/AT386.el, term/apollo.el, term/bobcat.el, term/cygwin.el:
......
......@@ -2101,43 +2101,51 @@ This function should be a pre-command hook."
(select-window selected))))
nil t))))))
(defvar follow-mode)
(declare-function follow-comint-scroll-to-bottom "follow" ())
(defun comint-postoutput-scroll-to-bottom (_string)
"Go to the end of buffer in some or all windows showing it.
Does not scroll if the current line is the last line in the buffer.
Do not scroll if the current line is the last line in the buffer.
Depends on the value of `comint-move-point-for-output' and
`comint-scroll-show-maximum-output'.
This function should be in the list `comint-output-filter-functions'."
(let* ((selected (selected-window))
(current (current-buffer))
(process (get-buffer-process current))
(scroll comint-move-point-for-output))
(let* ((current (current-buffer))
(process (get-buffer-process current)))
(unwind-protect
(if process
(walk-windows
(lambda (window)
(when (eq (window-buffer window) current)
(select-window window)
(if (and (< (point) (process-mark process))
(or (eq scroll t) (eq scroll 'all)
;; Maybe user wants point to jump to end.
(and (eq scroll 'this) (eq selected window))
(and (eq scroll 'others) (not (eq selected window)))
;; If point was at the end, keep it at end.
(and (marker-position comint-last-output-start)
(>= (point) comint-last-output-start))))
(goto-char (process-mark process)))
;; Optionally scroll so that the text
;; ends at the bottom of the window.
(if (and comint-scroll-show-maximum-output
(= (point) (point-max)))
(save-excursion
(goto-char (point-max))
(recenter (- -1 scroll-margin))))
(select-window selected)))
nil t))
(cond
((null process))
((bound-and-true-p follow-mode)
(follow-comint-scroll-to-bottom))
(t
(let ((selected (selected-window)))
(dolist (w (get-buffer-window-list current nil t))
(select-window w)
(unwind-protect
(progn
(comint-adjust-point selected)
;; Optionally scroll to the bottom of the window.
(and comint-scroll-show-maximum-output
(eobp)
(recenter (- -1 scroll-margin))))
(select-window selected))))))
(set-buffer current))))
(defun comint-adjust-point (selected)
"Move point in the selected window based on Comint settings.
SELECTED is the window that was originally selected."
(let ((process (get-buffer-process (current-buffer))))
(and (< (point) (process-mark process))
(or (memq comint-move-point-for-output '(t all))
;; Maybe user wants point to jump to end.
(eq comint-move-point-for-output
(if (eq (selected-window) selected) 'this 'others))
;; If point was at the end, keep it at end.
(and (marker-position comint-last-output-start)
(>= (point) comint-last-output-start)))
(goto-char (process-mark process)))))
(defun comint-truncate-buffer (&optional _string)
"Truncate the buffer to `comint-buffer-maximum-size'.
This function could be on `comint-output-filter-functions' or bound to a key."
......
;;; follow.el --- synchronize windows showing the same buffer
;; Copyright (C) 1995-1997, 1999, 2001-2012 Free Software Foundation, Inc.
;; Author: Anders Lindgren <andersl@andersl.com>
......@@ -107,24 +106,11 @@
;; (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 configure Follow mode, or any other mode for
;; that matter, is to create one or more functions that do
;; whatever you would like to do. These functions are then added to
;; a hook.
;;
;; When `Follow' mode is activated, functions stored in the hook
;; `follow-mode-hook' are called. When it is deactivated
;; `follow-mode-off-hook' is run.
;;
;; The keymap `follow-key-map' contains key bindings activated by
;; `follow-mode'.
;;
......@@ -196,77 +182,29 @@
;; Example from my ~/.emacs:
;; (global-set-key [f8] 'follow-mode)
;; Implementation:
;;
;; In an ideal world, follow mode would have been implemented in the
;; kernel of the display routines, making sure that the windows (using
;; follow mode) ALWAYS are aligned. On planet Earth, however, we must
;; accept a solution where we ALMOST ALWAYS can make sure that the
;; windows are aligned.
;; The main method by which Follow mode aligns windows is via the
;; function `follow-post-command-hook', which is run after each
;; command. This "fixes up" the alignment of other windows which are
;; showing the same Follow mode buffer, on the same frame as the
;; selected window. It does not try to deal with buffers other than
;; the buffer of the selected frame, or windows on other frames.
;;
;; Follow mode does this in three places:
;; 1) After each user command.
;; 2) After a process output has been performed.
;; 3) When a scrollbar has been moved.
;;
;; This will cover most situations. (Let me know if there are other
;; situations that should be covered.)
;;
;; Note that only the selected window is checked, for the reason of
;; efficiency and code complexity. (I.e. it is possible to make a
;; non-selected window unaligned. It will, however, pop right back
;; when it is selected.)
;; Comint mode specially calls `follow-comint-scroll-to-bottom' on
;; Follow mode buffers. This function scrolls the bottom-most window
;; in a window chain and aligns the other windows accordingly. Follow
;; mode adds a function to `compilation-filter-hook' to align
;; compilation buffers.
;;; Code:
;; Preliminaries
;; Make the compiler shut up!
;; There are two strategies:
;; 1) Shut warnings off completely.
;; 2) Handle each warning separately.
;;
;; Since I would like to see real errors, I've selected the latter
;; method.
;;
;; The problem with undefined variables and functions has been solved
;; by using `set', `symbol-value' and `symbol-function' rather than
;; `setq' and direct references to variables and functions.
;;
;; For example:
;; (if (boundp 'foo) ... (symbol-value 'foo) )
;; (set 'foo ...) <-- XEmacs doesn't fall for this one.
;; (funcall (symbol-function 'set) 'bar ...)
;;
;; Note: When this file is interpreted, `eval-when-compile' is
;; evaluated. Since it doesn't hurt to evaluate it, but it is a bit
;; annoying, we test if the byte-compiler has been loaded. This can,
;; of course, lead to some occasional unintended evaluation...
;;
;; Should someone come up with a better solution, please let me
;; know.
(require 'easymenu)
(eval-when-compile
(if (or (featurep 'bytecomp)
(featurep 'byte-compile))
(cond ((featurep 'xemacs)
;; Make XEmacs shut up! I'm using standard Emacs
;; functions, they are NOT obsolete!
(if (eq (get 'force-mode-line-update 'byte-compile)
'byte-compile-obsolete)
(put 'force-mode-line-update 'byte-compile 'nil))
(if (eq (get 'frame-first-window 'byte-compile)
'byte-compile-obsolete)
(put 'frame-first-window 'byte-compile 'nil))))))
;;; Variables
(defgroup follow nil
"Synchronize windows showing the same buffer."
:prefix "follow-"
:group 'windows
:group 'convenience)
......@@ -275,28 +213,15 @@
:type 'hook
:group 'follow)
(defcustom follow-mode-off-hook nil
"Hooks to run when Follow mode is turned off."
:type 'hook
:group 'follow)
(make-obsolete-variable 'follow-mode-off-hook 'follow-mode-hook "22.2")
;;; Keymap/Menu
;; Define keys for the follow-mode minor mode map and replace some
;; functions in the global map. All `follow' mode special functions
;; can be found on (the somewhat cumbersome) "C-c . <key>"
;; (Control-C dot <key>). (As of Emacs 19.29 the keys
;; C-c <punctuation character> are reserved for minor modes.)
;;
;; To change the prefix, redefine `follow-mode-prefix' before
;; `follow' is loaded, or see the section on `follow-mode-hook'
;; above for an example of how to bind the keys the way you like.
;; functions in the global map. All Follow mode special functions can
;; be found on the `C-c .' prefix key.
;;
;; Please note that the keymap is defined the first time this file is
;; loaded. Also note that the only valid way to manipulate the
;; keymap is to use `define-key'. Don't change it using `setq' or
;; similar!
;; To change the prefix, redefine `follow-mode-prefix' before `follow'
;; is loaded, or see the section on `follow-mode-hook' above for an
;; example of how to bind the keys the way you like.
(defcustom follow-mode-prefix "\C-c."
"Prefix key to use for follow commands in Follow mode.
......@@ -329,6 +254,11 @@ After that, changing the prefix key requires manipulating keymaps."
;; the look and feel of Follow mode.)
(define-key mainmap [remap end-of-buffer] 'follow-end-of-buffer)
(define-key mainmap [remap scroll-bar-toolkit-scroll] 'follow-scroll-bar-toolkit-scroll)
(define-key mainmap [remap scroll-bar-drag] 'follow-scroll-bar-drag)
(define-key mainmap [remap scroll-bar-scroll-up] 'follow-scroll-bar-scroll-up)
(define-key mainmap [remap scroll-bar-scroll-down] 'follow-scroll-bar-scroll-down)
mainmap)
"Minor mode keymap for Follow mode.")
......@@ -340,16 +270,8 @@ After that, changing the prefix key requires manipulating keymaps."
'(["Follow mode" follow-mode
:style toggle :selected follow-mode])))
;; If there is a `tools' menu, we use it. However, we can't add a
;; minor-mode specific item to it (it's broken), so we make the
;; contents ghosted when not in use, and add ourselves to the
;; global map.
(easy-menu-add-item nil '("Tools")
'("Follow"
;; The Emacs code used to just gray out operations when follow-mode was
;; not enabled, whereas the XEmacs code used to remove it altogether.
;; Not sure which is preferable, but clearly the preference should not
;; depend on the flavor.
:filter follow-menu-filter
["Scroll Up" follow-scroll-up follow-mode]
["Scroll Down" follow-scroll-down follow-mode]
......@@ -378,30 +300,12 @@ are \" Fw\", or simply \"\"."
(defcustom follow-auto nil
"Non-nil activates Follow mode whenever a file is loaded."
:type 'boolean
:group 'follow)
(defcustom follow-intercept-processes (fboundp 'start-process)
"When non-nil, Follow mode will monitor process output."
:type 'boolean
:group 'follow)
(defvar follow-avoid-tail-recenter-p (not (featurep 'xemacs))
"When non-nil, patch Emacs so that tail windows won't be recentered.
A \"tail window\" is a window that displays only the end of
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 a short page in info.
Must be set before Follow mode is loaded.
Please note that it is not possible to fully prevent Emacs from
recentering empty windows. Please report if you find a repeatable
situation in which Emacs recenters empty windows.
XEmacs, as of 19.12, does not recenter windows, good!")
:group 'follow
:set (lambda (symbol value)
(if value
(add-hook 'find-file-hook 'follow-find-file-hook t)
(remove-hook 'find-file-hook 'follow-find-file-hook))
(set-default symbol value)))
(defvar follow-cache-command-list
'(next-line previous-line forward-char backward-char)
......@@ -425,9 +329,6 @@ property `follow-mode-use-cache' to non-nil.")
(defvar follow-internal-force-redisplay nil
"True when Follow mode should redisplay the windows.")
(defvar follow-process-filter-alist '()
"The original filters for processes intercepted by Follow mode.")
(defvar follow-active-menu nil
"The menu visible when Follow mode is active.")
......@@ -503,38 +404,31 @@ To split one large window into two side-by-side windows, the commands
Only windows displayed in the same frame follow each other.
If the variable `follow-intercept-processes' is non-nil, Follow mode
will listen to the output of processes and redisplay accordingly.
\(This is the default.)
This command runs the normal hook `follow-mode-hook'.
Keys specific to Follow mode:
\\{follow-mode-map}"
:keymap follow-mode-map
(when (and follow-mode follow-intercept-processes)
(follow-intercept-process-output))
(cond (follow-mode ; On
;; XEmacs: If this is non-nil, the window will scroll before
;; the point will have a chance to get into the next window.
(when (boundp 'scroll-on-clipped-lines)
(setq scroll-on-clipped-lines nil))
(force-mode-line-update)
(add-hook 'post-command-hook 'follow-post-command-hook t))
((not follow-mode) ; Off
(force-mode-line-update))))
;;; Find file hook
;; This will start follow-mode whenever a new file is loaded, if
;; the variable `follow-auto' is non-nil.
(add-hook 'find-file-hook 'follow-find-file-hook t)
(if follow-mode
(progn
(add-hook 'compilation-filter-hook 'follow-align-compilation-windows t t)
(add-hook 'post-command-hook 'follow-post-command-hook t)
(add-hook 'window-size-change-functions 'follow-window-size-change t))
;; Remove globally-installed hook functions only if there is no
;; other Follow mode buffer.
(let ((buffers (buffer-list))
following)
(while (and (not following) buffers)
(setq following (buffer-local-value 'follow-mode (car buffers))
buffers (cdr buffers)))
(unless following
(remove-hook 'post-command-hook 'follow-post-command-hook)
(remove-hook 'window-size-change-functions 'follow-window-size-change)))
(remove-hook 'compilation-filter-hook 'follow-align-compilation-windows t)))
(defun follow-find-file-hook ()
"Find-file hook for Follow mode. See the variable `follow-auto'."
(if follow-auto (follow-mode t)))
(if follow-auto (follow-mode 1)))
;;; User functions
......@@ -566,7 +460,7 @@ Negative ARG means scroll downward.
Works like `scroll-up' when not in Follow mode."
(interactive "P")
(cond ((not (and (boundp 'follow-mode) follow-mode))
(cond ((not follow-mode)
(scroll-up arg))
(arg
(save-excursion (scroll-up arg))
......@@ -595,7 +489,7 @@ Negative ARG means scroll upward.
Works like `scroll-up' when not in Follow mode."
(interactive "P")
(cond ((not (and (boundp 'follow-mode) follow-mode))
(cond ((not follow-mode)
(scroll-up arg))
(arg
(save-excursion (scroll-down arg)))
......@@ -615,6 +509,47 @@ Works like `scroll-up' when not in Follow mode."
(vertical-motion (- next-screen-context-lines 1))
(setq follow-internal-force-redisplay t))))))
(declare-function comint-adjust-point "comint" (window))
(defvar comint-scroll-show-maximum-output)
(defun follow-comint-scroll-to-bottom (&optional window)
"Scroll the bottom-most window in the current Follow chain.
This is to be called by `comint-postoutput-scroll-to-bottom'."
(let* ((buffer (current-buffer))
(selected (selected-window))
(is-selected (eq (window-buffer) buffer))
some-window)
(when (or is-selected
(setq some-window (get-buffer-window)))
(let* ((pos (progn (comint-adjust-point nil) (point)))
(win (if is-selected
selected
(car (last (follow-all-followers some-window))))))
(select-window win)
(goto-char pos)
(setq follow-windows-start-end-cache nil)
(follow-adjust-window win pos)
(unless is-selected
(select-window selected)
(set-buffer buffer))))))
(defun follow-align-compilation-windows ()
"Align the windows of the current Follow mode buffer.
This is to be called from `compilation-filter-hook'."
(let ((buffer (current-buffer))
(win (get-buffer-window))
(selected (selected-window)))
(when (and follow-mode (waiting-for-user-input-p) win)
(let ((windows (follow-all-followers win)))
(unless (eq (window-buffer selected) buffer)
(setq win (car windows))
(select-window win))
(follow-redisplay windows win t)
(setq follow-windows-start-end-cache nil)
(unless (eq selected win)
(select-window selected)
(set-buffer buffer))))))
;;; Buffer
;;;###autoload
......@@ -630,11 +565,7 @@ two windows always will display two successive pages.
If ARG is positive, the leftmost window is selected. If negative,
the rightmost is selected. If ARG is nil, the leftmost window is
selected if the original window is the first one in the frame.
To bind this command to a hotkey, place the following line
in your `~/.emacs' file, replacing [f7] by your favorite key:
(global-set-key [f7] 'follow-delete-other-windows-and-split)"
selected if the original window is the first one in the frame."
(interactive "P")
(let ((other (or (and (null arg)
(not (eq (selected-window)
......@@ -670,24 +601,19 @@ Defaults to current buffer."
(current-buffer))))
(or buffer (setq buffer (current-buffer)))
(let ((orig-window (selected-window)))
(walk-windows
(function
(lambda (win)
(select-window win)
(switch-to-buffer buffer))))
(walk-windows (lambda (win)
(select-window win)
(switch-to-buffer buffer))
'no-minibuf)
(select-window orig-window)
(follow-redisplay)))
(defun follow-switch-to-current-buffer-all ()
"Show current buffer in all windows on this frame, and enter Follow mode.
To bind this command to a hotkey place the following line
in your `~/.emacs' file:
(global-set-key [f7] 'follow-switch-to-current-buffer-all)"
"Show current buffer in all windows on this frame, and enter Follow mode."
(interactive)
(or (and (boundp 'follow-mode) follow-mode)
(follow-mode 1))
(unless follow-mode
(follow-mode 1))
(follow-switch-to-buffer-all))
;;; Movement
......@@ -756,9 +682,7 @@ from the bottom."
(win (nth (/ (- (length windows) 1) 2) windows)))
(select-window win)
(goto-char dest)
(recenter)
;;(setq follow-internal-force-redisplay t)
)))
(recenter))))
(defun follow-redraw ()
......@@ -796,28 +720,35 @@ of the way from the true end."
;;; Display
(defun follow-all-followers (&optional testwin)
"Return all windows displaying the same buffer as the TESTWIN.
The list contains only windows displayed in the same frame as TESTWIN.
If TESTWIN is nil the selected window is used."
(or (window-live-p testwin)
(setq testwin (selected-window)))
(let* ((top (frame-first-window (window-frame testwin)))
(win top)
(done nil)
(windows '())
(buffer (window-buffer testwin)))
(while (and (not done) win)
(if (eq (window-buffer win) buffer)
(setq windows (cons win windows)))
(setq win (next-window win 'not))
(if (eq win top)
(setq done t)))
(nreverse windows)))
(defun follow--window-sorter (w1 w2)
"Sorting function for W1 and W2 based on their positions.
Return non-nil if W1 is above W2; if their top-lines
are at the same position, return non-nil if W1 is to the
left of W2."
(let* ((edge-1 (window-pixel-edges w1))
(edge-2 (window-pixel-edges w2))
(y1 (nth 1 edge-1))
(y2 (nth 1 edge-2)))
(if (= y1 y2)
(< (car edge-1) (car edge-2))
(< y1 y2))))
(defun follow-all-followers (&optional win)
"Return all windows displaying the same buffer as the WIN.
The list is sorted with topmost and leftmost windows first, and
contains only windows in the same frame as WIN. If WIN is nil,
it defaults to the selected window."
(unless (window-live-p win)
(setq win (selected-window)))
(let ((buffer (window-buffer win))
windows)
(dolist (w (window-list (window-frame win) 'no-minibuf win))
(if (eq (window-buffer w) buffer)
(push w windows)))
(sort windows 'follow--window-sorter)))
(defun follow-split-followers (windows &optional win)
"Split the WINDOWS into the sets: predecessors and successors.
"Split WINDOWS into two sets: predecessors and successors.
Return `(PRED . SUCC)' where `PRED' and `SUCC' are ordered starting
from the selected window."
(or win
......@@ -828,7 +759,6 @@ from the selected window."
(setq windows (cdr windows)))
(cons pred (cdr windows))))
(defun follow-calc-win-end (&optional win)
"Calculate the end position for window WIN.
Return (END-POS END-OF-BUFFER).
......@@ -845,20 +775,19 @@ window is used."
(list end (= end (point-max))))
(list last-line-pos nil))))
;; Can't use `save-window-excursion' since it triggers a redraw.
(defun follow-calc-win-start (windows pos win)
"Calculate where WIN will start if the first in WINDOWS start at POS.
If WIN is nil the point below all windows is returned."
(let (start)
(while (and windows (not (eq (car windows) win)))
(setq start (window-start (car windows)))
"Determine the start of window WIN in a Follow mode window chain.
WINDOWS is a list of chained windows, and POS is the starting
position for the first window in the list. If WIN is nil, return
the point below all windows."
(while (and windows (not (eq (car windows) win)))
(let ((old-start (window-start (car windows))))
;; Can't use `save-window-excursion' since it triggers a redraw.
(set-window-start (car windows) pos 'noforce)
(setq pos (car (follow-calc-win-end (car windows))))
(set-window-start (car windows) start 'noforce)
(setq windows (cdr windows)))
pos))
(set-window-start (car windows) old-start 'noforce)
(setq windows (cdr windows))))
pos)
;; The result from `follow-windows-start-end' is cached when using
;; a handful simple commands, like cursor movement commands.
......@@ -877,23 +806,8 @@ Note that this handles the case when the cache has been set to nil."
(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:
;; ((Win Start End End-of-buffer-visible-p) ...)
;; Used to have a `save-window-excursion', but it obviously triggered
;; redraws of the display. Check if I used it for anything.