(UPDATE_SYNTAX_TABLE): Do nothing unless parse_sexp_lookup_properties.
[bpt/emacs.git] / lisp / winner.el
CommitLineData
1ffece3a 1;;; winner.el --- Restore window configuration (or switch buffer)
a14fb2b1 2
4f850b26 3;; Copyright (C) 1997, 1998 Free Software Foundation. Inc.
a14fb2b1
RS
4
5;; Author: Ivar Rummelhoff <ivarr@ifi.uio.no>
6;; Maintainer: Ivar Rummelhoff <ivarr@ifi.uio.no>
7;; Created: 27 Feb 1997
1ffece3a 8;; Keywords: extensions, windows
a14fb2b1 9
21f3d1d3
RS
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
a14fb2b1
RS
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation; either version 2, or (at your option)
15;; any later version.
16
21f3d1d3 17;; GNU Emacs is distributed in the hope that it will be useful,
a14fb2b1
RS
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
26
27;;; Commentary:
1ffece3a
RS
28
29;; Winner mode is a global minor mode that when turned on records
30;; changes in window configuration. This way the changes can be
31;; "undone" using the function `winner-undo'. By default this one is
32;; bound to the key sequence ctrl-x left. If you change your mind
33;; (while undoing), you can press ctrl-x right (calling
34;; `winner-redo'). Unlike the normal undo, you may have to skip
35;; through several identical window configurations in order to find
36;; the one you want. This is a bug due to some techical limitations
37;; in Emacs and can maybe be fixed in the future.
a14fb2b1 38;;
1ffece3a
RS
39;; In addition to this I have added `winner-switch' which is a program
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.
a14fb2b1
RS
45
46;;; Code:
47
4f850b26 48(require 'cl)
1ffece3a 49(require 'ring)
a14fb2b1 50
4f850b26
DL
51(defgroup winner nil
52 "Restoring window configurations."
53 :group 'windows)
54
0471bec2 55;;;###autoload
4f850b26
DL
56(defcustom winner-mode nil
57 "Toggle winner-mode.
58You must modify via \\[customize] for this variable to have an effect."
59 :set (lambda (symbol value)
60 (winner-mode (or value 0)))
61 :initialize 'custom-initialize-default
62 :type 'boolean
63 :group 'winner
64 :require 'winner)
65
66(defcustom winner-dont-bind-my-keys nil
67 "If non-nil: Do not use `winner-mode-map' in Winner mode."
68 :type 'boolean
69 :group 'winner)
a14fb2b1 70
1ffece3a
RS
71(defvar winner-ring-size 100
72 "Maximum number of stored window configurations per frame.")
a14fb2b1 73
4f850b26 74(defcustom winner-skip-buffers
a14fb2b1
RS
75 '("*Messages*",
76 "*Compile-Log*",
77 ".newsrc-dribble",
78 "*Completions*",
79 "*Buffer list*")
4f850b26
DL
80 "Exclude these buffer names from any \(Winner switch\) list of buffers."
81 :type '(repeat string)
82 :group 'winner)
a14fb2b1 83
4f850b26 84(defcustom winner-skip-regexps '("^ ")
79fd9b2f
RS
85 "Winner excludes buffers with names matching any of these regexps.
86They are not included in any Winner mode list of buffers.
a14fb2b1
RS
87
88By default `winner-skip-regexps' is set to \(\"^ \"\),
4f850b26
DL
89which excludes \"invisible buffers\"."
90 :type '(repeat regexp)
91 :group 'winner)
a14fb2b1 92
1ffece3a 93(defvar winner-ring-alist nil)
a14fb2b1 94
1ffece3a
RS
95(defsubst winner-ring (frame)
96 (or (cdr (assq frame winner-ring-alist))
97 (progn
98 (push (cons frame (make-ring winner-ring-size))
99 winner-ring-alist)
100 (cdar winner-ring-alist))))
a14fb2b1 101
1ffece3a 102(defvar winner-modified-list nil)
a14fb2b1 103
1ffece3a 104(defun winner-change-fun ()
d2f27357
KH
105 (or (memq (selected-frame) winner-modified-list)
106 (push (selected-frame) winner-modified-list)))
a14fb2b1 107
1ffece3a
RS
108(defun winner-save-new-configurations ()
109 (while winner-modified-list
110 (ring-insert
111 (winner-ring (car winner-modified-list))
112 (current-window-configuration (pop winner-modified-list)))))
a14fb2b1 113
1ffece3a
RS
114(defun winner-set (conf)
115 (set-window-configuration conf)
116 (if (eq (selected-window) (minibuffer-window))
117 (other-window 1)))
a14fb2b1 118
a14fb2b1 119
1ffece3a 120;;; Winner mode (a minor mode)
a14fb2b1 121
4f850b26
DL
122(defcustom winner-mode-hook nil
123 "Functions to run whenever Winner mode is turned on."
124 :type 'hook
78900bc3 125 :group 'winner)
a14fb2b1 126
78900bc3 127(defcustom winner-mode-leave-hook nil
4f850b26
DL
128 "Functions to run whenever Winner mode is turned off."
129 :type 'hook
78900bc3 130 :group 'winner)
1ffece3a 131
a14fb2b1 132(defvar winner-mode-map nil "Keymap for Winner mode.")
21f3d1d3 133
4f850b26 134;;;###autoload
a14fb2b1
RS
135(defun winner-mode (&optional arg)
136 "Toggle Winner mode.
137With arg, turn Winner mode on if and only if arg is positive."
138 (interactive "P")
139 (let ((on-p (if arg (> (prefix-numeric-value arg) 0)
140 (not winner-mode))))
141 (cond
1ffece3a
RS
142 ;; Turn mode on
143 (on-p
144 (setq winner-mode t)
145 (add-hook 'window-configuration-change-hook 'winner-change-fun)
146 (add-hook 'post-command-hook 'winner-save-new-configurations)
147 (setq winner-modified-list (frame-list))
148 (winner-save-new-configurations)
149 (run-hooks 'winner-mode-hook))
150 ;; Turn mode off
151 (winner-mode
152 (setq winner-mode nil)
153 (run-hooks 'winner-mode-leave-hook)))
a14fb2b1
RS
154 (force-mode-line-update)))
155
1ffece3a 156;; Inspired by undo (simple.el)
ac1f790a
KH
157
158(defvar winner-pending-undo-ring nil)
159
160(defvar winner-undo-counter nil)
161
1ffece3a
RS
162(defun winner-undo (arg)
163 "Switch back to an earlier window configuration saved by Winner mode.
4f850b26
DL
164In other words, \"undo\" changes in window configuration.
165With prefix arg, undo that many levels."
1ffece3a
RS
166 (interactive "p")
167 (cond
168 ((not winner-mode) (error "Winner mode is turned off"))
169 ((eq (selected-window) (minibuffer-window))
170 (error "No winner undo from minibuffer."))
171 (t (setq this-command t)
172 (if (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)))
176 (setq winner-undo-counter 0))
177 (winner-undo-more (or arg 1))
178 (message "Winner undo (%d)!" winner-undo-counter)
179 (setq this-command 'winner-undo))))
180
1ffece3a
RS
181(defun winner-undo-more (count)
182 "Undo N window configuration changes beyond what was already undone.
183Call `winner-undo-start' to get ready to undo recent changes,
184then call `winner-undo-more' one or more times to undo them."
185 (let ((len (ring-length winner-pending-undo-ring)))
186 (incf winner-undo-counter count)
187 (if (>= winner-undo-counter len)
188 (error "No further window configuration undo information")
189 (winner-set
190 (ring-ref winner-pending-undo-ring
191 winner-undo-counter)))))
192
193(defun winner-redo ()
194 "Restore a more recent window configuration saved by Winner mode."
195 (interactive)
196 (cond
197 ((eq last-command 'winner-undo)
198 (ring-remove winner-pending-undo-ring 0)
199 (winner-set
200 (ring-remove winner-pending-undo-ring 0))
201 (or (eq (selected-window) (minibuffer-window))
202 (message "Winner undid undo!")))
203 (t (error "Previous command was not a winner-undo"))))
204
205;;; Winner switch
206
207(defun winner-switch-buffer-list ()
a14fb2b1
RS
208 (loop for buf in (buffer-list)
209 for name = (buffer-name buf)
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))
1ffece3a
RS
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))
a14fb2b1 241
a14fb2b1
RS
242;;;; To be evaluated when the package is loaded:
243
244(unless winner-mode-map
245 (setq winner-mode-map (make-sparse-keymap))
1ffece3a
RS
246 (define-key winner-mode-map [?\C-x left] 'winner-undo)
247 (define-key winner-mode-map [?\C-x right] 'winner-redo))
a14fb2b1
RS
248
249(unless (or (assq 'winner-mode minor-mode-map-alist)
250 winner-dont-bind-my-keys)
251 (push (cons 'winner-mode winner-mode-map)
252 minor-mode-map-alist))
253
254(unless (assq 'winner-mode minor-mode-alist)
255 (push '(winner-mode " Win") minor-mode-alist))
256
257(provide 'winner)
258
21f3d1d3 259;;; winner.el ends here