aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard M. Stallman1998-03-09 22:42:13 +0000
committerRichard M. Stallman1998-03-09 22:42:13 +0000
commit2a92dc254096feef5abd038e73074b041c9565f8 (patch)
tree6d8e7a1f6b136aca517f678308d756efd839b965
parent576827ffbeada6e58e0104a99ccb7edef58d81e3 (diff)
downloademacs-2a92dc254096feef5abd038e73074b041c9565f8.tar.gz
emacs-2a92dc254096feef5abd038e73074b041c9565f8.zip
Use list syntax for key definitions.
(winner-mode, winner-save-unconditionally) (winner-hook-installed-p): Save window configuration after every command if window-configuration-change-hook is not present. (winner-save-new-configurations, winner-insert-if-new): Compare a new window configuration with the previous configuration before saving it. (winner-insert-if-new, winner-ring) (winner-configuration, winner-set): Save buffer list together with the window configurations, so that windows that can no longer be correctly restored can instead be deleted. (winner-undo): Compare restored configuration with other configurations that have been reviewed and skip this one if it looks similar. (winner-insert-if-new, winner-save-new-configurations) (winner-save-unconditionally): Just save the final configuration if the same command (changing the window configuration) is applied several times in a row. (winner-switch): Removed the command `winner-switch' (and the variables connected to it), since because of the change above, any "switching package" may now be used without disturbing winner-mode too much. (winner-change-fun): Removed the pushnew command, so that `cl' will not have to be loaded. (winner-set-conf): Introduced "wrapper" around `set-window-configuration', so that `winner-undo' may be called from the minibuffer.
-rw-r--r--lisp/winner.el327
1 files changed, 194 insertions, 133 deletions
diff --git a/lisp/winner.el b/lisp/winner.el
index 59b27e3447a..2b510320056 100644
--- a/lisp/winner.el
+++ b/lisp/winner.el
@@ -1,11 +1,12 @@
1;;; winner.el --- Restore window configuration (or switch buffer) 1;;; winner.el --- Restore old window configurations
2 2
3;; Copyright (C) 1997, 1998 Free Software Foundation. Inc. 3;; Copyright (C) 1997, 1998 Free Software Foundation. Inc.
4 4
5;; Author: Ivar Rummelhoff <ivarr@ifi.uio.no> 5;; Author: Ivar Rummelhoff <ivarr@ifi.uio.no>
6;; Maintainer: Ivar Rummelhoff <ivarr@ifi.uio.no> 6;; Maintainer: Ivar Rummelhoff <ivarr@ifi.uio.no>
7;; Created: 27 Feb 1997 7;; Created: 27 Feb 1997
8;; Keywords: extensions, windows 8;; Time-stamp: <1998-03-05 19:01:37 ivarr>
9;; Keywords: windows
9 10
10;; This file is part of GNU Emacs. 11;; This file is part of GNU Emacs.
11 12
@@ -26,98 +27,172 @@
26 27
27;;; Commentary: 28;;; Commentary:
28 29
29;; Winner mode is a global minor mode that when turned on records 30;; Winner mode is a global minor mode that records the changes in the
30;; changes in window configuration. This way the changes can be 31;; window configuration (i.e. how the frames are partitioned into
31;; "undone" using the function `winner-undo'. By default this one is 32;; windows). This way the changes can be "undone" using the function
32;; bound to the key sequence ctrl-x left. If you change your mind 33;; `winner-undo'. By default this one is bound to the key sequence
33;; (while undoing), you can press ctrl-x right (calling 34;; ctrl-x left. If you change your mind (while undoing), you can
34;; `winner-redo'). Unlike the normal undo, you may have to skip 35;; press ctrl-x right (calling `winner-redo'). Even though it uses
35;; through several identical window configurations in order to find 36;; some features of Emacs20.3, winner.el should also work with
36;; the one you want. This is a bug due to some techical limitations 37;; Emacs19.34 and XEmacs20, provided that the installed version of
37;; in Emacs and can maybe be fixed in the future. 38;; custom is not obsolete.
38;; 39
39;; In addition to this I have added `winner-switch' which is a program 40 ;;; Code:
40;; that switches to other buffers without disturbing Winner mode. If
41;; you bind this command to a key sequence, you may step through all
42;; your buffers (except the ones mentioned in `winner-skip-buffers' or
43;; matched by `winner-skip-regexps'). With a numeric prefix argument
44;; skip several buffers at a time.
45
46;;; Code:
47 41
48(eval-when-compile (require 'cl)) 42(eval-when-compile (require 'cl))
49(require 'ring) 43(require 'ring)
50 44
51(defgroup winner nil 45(when (fboundp 'defgroup)
52 "Restoring window configurations." 46 (defgroup winner nil ; Customization by Dave Love
53 :group 'windows) 47 "Restoring window configurations."
48 :group 'windows))
49
50(unless (fboundp 'defcustom)
51 (defmacro defcustom (symbol &optional initvalue docs &rest rest)
52 (list 'defvar symbol initvalue docs)))
53
54 54
55;;;###autoload 55;;;###autoload
56(defcustom winner-mode nil 56(defcustom winner-mode nil
57 "Toggle winner-mode. 57 "Toggle winner-mode.
58You must modify via \\[customize] for this variable to have an effect." 58You must modify via \\[customize] for this variable to have an effect."
59 :set (lambda (symbol value) 59 :set #'(lambda (symbol value)
60 (winner-mode (or value 0))) 60 (winner-mode (or value 0)))
61 :initialize 'custom-initialize-default 61 :initialize 'custom-initialize-default
62 :type 'boolean 62 :type 'boolean
63 :group 'winner 63 :group 'winner
64 :require 'winner) 64 :require 'winner)
65 65
66(defcustom winner-dont-bind-my-keys nil 66(defcustom winner-dont-bind-my-keys nil
67 "If non-nil: Do not use `winner-mode-map' in Winner mode." 67 "If non-nil: Do not use `winner-mode-map' in Winner mode."
68 :type 'boolean 68 :type 'boolean
69 :group 'winner) 69 :group 'winner)
70 70
71(defvar winner-ring-size 100 71(defcustom winner-ring-size 200
72 "Maximum number of stored window configurations per frame.") 72 "Maximum number of stored window configurations per frame."
73 73 :type 'integer
74(defcustom winner-skip-buffers
75 '("*Messages*",
76 "*Compile-Log*",
77 ".newsrc-dribble",
78 "*Completions*",
79 "*Buffer list*")
80 "Exclude these buffer names from any \(Winner switch\) list of buffers."
81 :type '(repeat string)
82 :group 'winner) 74 :group 'winner)
83 75
84(defcustom winner-skip-regexps '("^ ")
85 "Winner excludes buffers with names matching any of these regexps.
86They are not included in any Winner mode list of buffers.
87 76
88By default `winner-skip-regexps' is set to \(\"^ \"\),
89which excludes \"invisible buffers\"."
90 :type '(repeat regexp)
91 :group 'winner)
92 77
78
79 ;;;; Internal variables and subroutines
80
81
82;; This variable contains the window cofiguration rings.
83;; The key in this alist is the frame.
93(defvar winner-ring-alist nil) 84(defvar winner-ring-alist nil)
94 85
86;; Find the right ring. If it does not exist, create one.
95(defsubst winner-ring (frame) 87(defsubst winner-ring (frame)
96 (or (cdr (assq frame winner-ring-alist)) 88 (or (cdr (assq frame winner-ring-alist))
97 (progn 89 (progn
98 (push (cons frame (make-ring winner-ring-size)) 90 (let ((ring (make-ring winner-ring-size)))
99 winner-ring-alist) 91 (ring-insert ring (winner-configuration frame))
100 (cdar winner-ring-alist)))) 92 (push (cons frame ring) winner-ring-alist)
93 ring))))
94
95(defvar winner-last-saviour nil)
96
97;; Save the current window configuration, if it has changed and return
98;; frame, else return nil. If the last change was due to the same
99;; command, save only the latest configuration.
100(defun winner-insert-if-new (frame)
101 (let ((conf (winner-configuration))
102 (ring (winner-ring frame)))
103 (cond
104 ((winner-equal conf (ring-ref ring 0)) nil)
105 (t (when (and (eq this-command (car winner-last-saviour))
106 (memq frame (cdr winner-last-saviour)))
107 (ring-remove ring 0))
108 (ring-insert ring conf)
109 frame))))
101 110
102(defvar winner-modified-list nil) 111(defvar winner-modified-list nil) ; Which frames have changed?
103 112
113;; This function is called when the window configuration changes.
104(defun winner-change-fun () 114(defun winner-change-fun ()
105 (or (memq (selected-frame) winner-modified-list) 115 (unless (memq (selected-frame) winner-modified-list)
106 (push (selected-frame) winner-modified-list))) 116 (push (selected-frame) winner-modified-list)))
107 117
118;; For Emacs20
108(defun winner-save-new-configurations () 119(defun winner-save-new-configurations ()
109 (while winner-modified-list 120 (setq winner-last-saviour
110 (ring-insert 121 (cons this-command
111 (winner-ring (car winner-modified-list)) 122 (mapcar 'winner-insert-if-new winner-modified-list)))
112 (current-window-configuration (pop winner-modified-list))))) 123 (setq winner-modified-list nil))
113 124
125;; For compatibility with other emacsen.
126(defun winner-save-unconditionally ()
127 (setq winner-last-saviour
128 (cons this-command
129 (list (winner-insert-if-new (selected-frame))))))
130
131;; Arrgh. This is storing the same information twice.
132(defun winner-configuration (&optional frame)
133 (if frame (letf (((selected-frame) frame)) (winner-configuration))
134 (cons (current-window-configuration)
135 (loop for w being the windows
136 collect (window-buffer w)))))
137
138
139;; The same as `set-window-configuration',
140;; but doesn't touch the minibuffer.
141(defun winner-set-conf (winconf)
142 (let ((min-sel (window-minibuffer-p (selected-window)))
143 (minibuf (window-buffer (minibuffer-window)))
144 (minipoint (letf ((selected-window) (minibuffer-window))
145 (point)))
146 win)
147 (set-window-configuration winconf)
148 (setq win (selected-window))
149 (select-window (minibuffer-window))
150 (set-window-buffer (minibuffer-window) minibuf)
151 (goto-char minipoint)
152 (cond
153 (min-sel)
154 ((window-minibuffer-p win)
155 (other-window 1))
156 (t (select-window win)))))
157
158(defun winner-win-data () ; Information about the windows
159 (loop for win being the windows
160 unless (window-minibuffer-p win)
161 collect (list (window-buffer win)
162 (window-width win)
163 (window-height win))))
164
165;; Make sure point doesn't end up in the minibuffer and
166;; delete windows displaying dead buffers. Return nil
167;; if and only if all the windows should have been deleted.
114(defun winner-set (conf) 168(defun winner-set (conf)
115 (set-window-configuration conf) 169 (let ((origpoints
116 (if (eq (selected-window) (minibuffer-window)) 170 (save-excursion
117 (other-window 1))) 171 (loop for buf in (cdr conf)
118 172 collect (if (buffer-name buf)
119 173 (progn (set-buffer buf) (point))
120;;; Winner mode (a minor mode) 174 nil)))))
175 (winner-set-conf (car conf))
176 (let* ((win (selected-window))
177 (xwins (loop for window being the windows
178 for pos in origpoints
179 unless (window-minibuffer-p window)
180 if pos do (progn (select-window window)
181 (goto-char pos))
182 else collect window)))
183 (select-window win)
184 ;; Return t if possible configuration
185 (cond
186 ((null xwins) t)
187 ((progn (mapcar 'delete-window (cdr xwins))
188 (one-window-p t))
189 nil) ; No existing buffers
190 (t (delete-window (car xwins)))))))
191
192
193
194
195 ;;;; Winner mode (a minor mode)
121 196
122(defcustom winner-mode-hook nil 197(defcustom winner-mode-hook nil
123 "Functions to run whenever Winner mode is turned on." 198 "Functions to run whenever Winner mode is turned on."
@@ -131,6 +206,15 @@ which excludes \"invisible buffers\"."
131 206
132(defvar winner-mode-map nil "Keymap for Winner mode.") 207(defvar winner-mode-map nil "Keymap for Winner mode.")
133 208
209;; Is `window-configuration-change-hook' working?
210(defun winner-hook-installed-p ()
211 (save-window-excursion
212 (let ((winner-var nil)
213 (window-configuration-change-hook
214 '((lambda () (setq winner-var t)))))
215 (split-window)
216 winner-var)))
217
134;;;###autoload 218;;;###autoload
135(defun winner-mode (&optional arg) 219(defun winner-mode (&optional arg)
136 "Toggle Winner mode. 220 "Toggle Winner mode.
@@ -142,23 +226,24 @@ With arg, turn Winner mode on if and only if arg is positive."
142 ;; Turn mode on 226 ;; Turn mode on
143 (on-p 227 (on-p
144 (setq winner-mode t) 228 (setq winner-mode t)
145 (add-hook 'window-configuration-change-hook 'winner-change-fun) 229 (cond
146 (add-hook 'post-command-hook 'winner-save-new-configurations) 230 ((winner-hook-installed-p)
231 (add-hook 'window-configuration-change-hook 'winner-change-fun)
232 (add-hook 'post-command-hook 'winner-save-new-configurations))
233 (t (add-hook 'post-command-hook 'winner-save-unconditionally)))
147 (setq winner-modified-list (frame-list)) 234 (setq winner-modified-list (frame-list))
148 (winner-save-new-configurations) 235 (winner-save-new-configurations)
149 (run-hooks 'winner-mode-hook)) 236 (run-hooks 'winner-mode-hook))
150 ;; Turn mode off 237 ;; Turn mode off
151 (winner-mode 238 (winner-mode
152 (setq winner-mode nil) 239 (setq winner-mode nil)
240 (remove-hook 'window-configuration-change-hook 'winner-change-fun)
241 (remove-hook 'post-command-hook 'winner-save-new-configurations)
242 (remove-hook 'post-command-hook 'winner-save-unconditionally)
153 (run-hooks 'winner-mode-leave-hook))) 243 (run-hooks 'winner-mode-leave-hook)))
154 (force-mode-line-update))) 244 (force-mode-line-update)))
155 245
156;; Inspired by undo (simple.el) 246 ;; Inspired by undo (simple.el)
157
158(defvar winner-pending-undo-ring nil)
159
160(defvar winner-undo-counter nil)
161
162(defun winner-undo (arg) 247(defun winner-undo (arg)
163 "Switch back to an earlier window configuration saved by Winner mode. 248 "Switch back to an earlier window configuration saved by Winner mode.
164In other words, \"undo\" changes in window configuration. 249In other words, \"undo\" changes in window configuration.
@@ -166,31 +251,40 @@ With prefix arg, undo that many levels."
166 (interactive "p") 251 (interactive "p")
167 (cond 252 (cond
168 ((not winner-mode) (error "Winner mode is turned off")) 253 ((not winner-mode) (error "Winner mode is turned off"))
169 ((eq (selected-window) (minibuffer-window)) 254 ;; ((eq (selected-window) (minibuffer-window))
170 (error "No winner undo from minibuffer.")) 255 ;; (error "No winner undo from minibuffer."))
171 (t (setq this-command t) 256 (t (setq this-command t)
172 (if (eq last-command 'winner-undo) 257 (unless (eq last-command 'winner-undo)
173 ;; This was no new window configuration after all.
174 (ring-remove winner-pending-undo-ring 0)
175 (setq winner-pending-undo-ring (winner-ring (selected-frame))) 258 (setq winner-pending-undo-ring (winner-ring (selected-frame)))
176 (setq winner-undo-counter 0)) 259 (setq winner-undo-counter 0)
177 (winner-undo-more (or arg 1)) 260 (setq winner-undone-data (list (winner-win-data))))
178 (message "Winner undo (%d)!" winner-undo-counter) 261 (incf winner-undo-counter arg)
262 (winner-undo-this)
263 (unless (window-minibuffer-p (selected-window))
264 (message "Winner undo (%d)" winner-undo-counter))
179 (setq this-command 'winner-undo)))) 265 (setq this-command 'winner-undo))))
180 266
181(defun winner-undo-more (count) 267(defvar winner-pending-undo-ring nil) ; The ring currently used by
182 "Undo N window configuration changes beyond what was already undone. 268 ; undo.
183Call `winner-undo-start' to get ready to undo recent changes, 269(defvar winner-undo-counter nil)
184then call `winner-undo-more' one or more times to undo them." 270(defvar winner-undone-data nil) ; There confs have been passed.
185 (let ((len (ring-length winner-pending-undo-ring))) 271
186 (incf winner-undo-counter count) 272(defun winner-undo-this () ; The heart of winner undo.
187 (if (>= winner-undo-counter len) 273 (if (>= winner-undo-counter (ring-length winner-pending-undo-ring))
188 (error "No further window configuration undo information") 274 (error "No further window configuration undo information")
189 (winner-set 275 (unless (and
190 (ring-ref winner-pending-undo-ring 276 ;; Possible configuration
191 winner-undo-counter))))) 277 (winner-set
192 278 (ring-ref winner-pending-undo-ring
193(defun winner-redo () 279 winner-undo-counter))
280 ;; New configuration
281 (let ((data (winner-win-data)))
282 (if (member data winner-undone-data) nil
283 (push data winner-undone-data))))
284 (ring-remove winner-pending-undo-ring winner-undo-counter)
285 (winner-undo-this))))
286
287(defun winner-redo () ; If you change your mind.
194 "Restore a more recent window configuration saved by Winner mode." 288 "Restore a more recent window configuration saved by Winner mode."
195 (interactive) 289 (interactive)
196 (cond 290 (cond
@@ -199,52 +293,19 @@ then call `winner-undo-more' one or more times to undo them."
199 (winner-set 293 (winner-set
200 (ring-remove winner-pending-undo-ring 0)) 294 (ring-remove winner-pending-undo-ring 0))
201 (or (eq (selected-window) (minibuffer-window)) 295 (or (eq (selected-window) (minibuffer-window))
202 (message "Winner undid undo!"))) 296 (message "Winner undid undo")))
203 (t (error "Previous command was not a winner-undo")))) 297 (t (error "Previous command was not a winner-undo"))))
204 298
205;;; Winner switch 299 ;;;; To be evaluated when the package is loaded:
206 300
207(defun winner-switch-buffer-list () 301(if (fboundp 'compare-window-configurations)
208 (loop for buf in (buffer-list) 302 (defalias 'winner-equal 'compare-window-configurations)
209 for name = (buffer-name buf) 303 (defalias 'winner-equal 'equal))
210 unless (or (eq (current-buffer) buf)
211 (member name winner-skip-buffers)
212 (loop for regexp in winner-skip-regexps
213 if (string-match regexp name) return t
214 finally return nil))
215 collect name))
216
217(defvar winner-switch-list nil)
218
219(defun winner-switch (count)
220 "Step through your buffers without disturbing `winner-mode'.
221`winner-switch' does not consider buffers mentioned in the list
222`winner-skip-buffers' or matched by `winner-skip-regexps'."
223 (interactive "p")
224 (decf count)
225 (setq this-command t)
226 (cond
227 ((eq last-command 'winner-switch)
228 (if winner-mode (ring-remove (winner-ring (selected-frame)) 0))
229 (bury-buffer (current-buffer))
230 (mapcar 'bury-buffer winner-switch-list))
231 (t (setq winner-switch-list (winner-switch-buffer-list))))
232 (setq winner-switch-list (nthcdr count winner-switch-list))
233 (or winner-switch-list
234 (setq winner-switch-list (winner-switch-buffer-list))
235 (error "No more buffers"))
236 (switch-to-buffer (pop winner-switch-list))
237 (message (concat "Winner: [%s] "
238 (mapconcat 'identity winner-switch-list " "))
239 (buffer-name))
240 (setq this-command 'winner-switch))
241
242;;;; To be evaluated when the package is loaded:
243 304
244(unless winner-mode-map 305(unless winner-mode-map
245 (setq winner-mode-map (make-sparse-keymap)) 306 (setq winner-mode-map (make-sparse-keymap))
246 (define-key winner-mode-map [?\C-x left] 'winner-undo) 307 (define-key winner-mode-map [(control x) left] 'winner-undo)
247 (define-key winner-mode-map [?\C-x right] 'winner-redo)) 308 (define-key winner-mode-map [(control x) right] 'winner-redo))
248 309
249(unless (or (assq 'winner-mode minor-mode-map-alist) 310(unless (or (assq 'winner-mode minor-mode-map-alist)
250 winner-dont-bind-my-keys) 311 winner-dont-bind-my-keys)