1;;; ebuff-menu.el --- electric-buffer-list mode
2
3;; Copyright (C) 1985, 1986, 1994, 2001, 2002, 2003, 2004,
4;;   2005, 2006, 2007 Free Software Foundation, Inc.
5
6;; Author: Richard Mlynarik <mly@ai.mit.edu>
7;; Maintainer: FSF
8;; Keywords: convenience
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
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
17;; GNU Emacs is distributed in the hope that it will be useful,
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., 51 Franklin Street, Fifth Floor,
25;; Boston, MA 02110-1301, USA.
26
27;;; Commentary:
28
29;; Who says one can't have typeout windows in GNU Emacs?   The entry
30;; point, `electric-buffer-list' works like ^r select buffer from the
31;; ITS Emacs lunar or tmacs libraries.
32
33;;; Code:
34
35(require 'electric)
36
37;; this depends on the format of list-buffers (from src/buffer.c) and
38;; on stuff in lisp/buff-menu.el
39
40(defvar electric-buffer-menu-mode-map nil)
41
42(defvar electric-buffer-menu-mode-hook nil
43  "Normal hook run by `electric-buffer-list'.")
44
45;;;###autoload
46(defun electric-buffer-list (arg)
47  "Pop up a buffer describing the set of Emacs buffers.
48Vaguely like ITS lunar select buffer; combining typeoutoid buffer
49listing with menuoid buffer selection.
50
51If the very next character typed is a space then the buffer list
52window disappears.  Otherwise, one may move around in the buffer list
53window, marking buffers to be selected, saved or deleted.
54
55To exit and select a new buffer, type a space when the cursor is on
56the appropriate line of the buffer-list window.  Other commands are
57much like those of `Buffer-menu-mode'.
58
59Run hooks in `electric-buffer-menu-mode-hook' on entry.
60
61\\{electric-buffer-menu-mode-map}"
62  (interactive "P")
63  (let (select buffer)
64    (save-window-excursion
65      (setq buffer (list-buffers-noselect arg))
66      (Electric-pop-up-window buffer)
67      (unwind-protect
68	  (progn
69	    (set-buffer buffer)
70	    (Electric-buffer-menu-mode)
71	    (electric-buffer-update-highlight)
72	    (setq select
73		  (catch 'electric-buffer-menu-select
74		    (message "<<< Press Return to bury the buffer list >>>")
75		    (if (eq (setq unread-command-events (list (read-event)))
76			    ?\s)
77			(progn (setq unread-command-events nil)
78			       (throw 'electric-buffer-menu-select nil)))
79		    (let ((start-point (point))
80			  (first (progn (goto-char (point-min))
81					(unless Buffer-menu-use-header-line
82					  (forward-line 2))
83					(point)))
84			  (last (progn (goto-char (point-max))
85				       (forward-line -1)
86				       (point)))
87			  (goal-column 0))
88		      ;; Use start-point if it is meaningful.
89		      (goto-char (if (or (< start-point first)
90					 (> start-point last))
91				     first
92				   start-point))
93		      (Electric-command-loop 'electric-buffer-menu-select
94					     nil
95					     t
96					     'electric-buffer-menu-looper
97					     (cons first last))))))
98	(set-buffer buffer)
99	(Buffer-menu-mode)
100	(bury-buffer buffer)
101	(message "")))
102    (if select
103	(progn (set-buffer buffer)
104	       (let ((opoint (point-marker)))
105		 (Buffer-menu-execute)
106		 (goto-char (point-min))
107		 (if (prog1 (search-forward "\n>" nil t)
108		       (goto-char opoint) (set-marker opoint nil))
109		     (Buffer-menu-select)
110		     (switch-to-buffer (Buffer-menu-buffer t))))))))
111
112(defun electric-buffer-menu-looper (state condition)
113  (cond ((and condition
114	      (not (memq (car condition) '(buffer-read-only
115					   end-of-buffer
116					   beginning-of-buffer))))
117	 (signal (car condition) (cdr condition)))
118	((< (point) (car state))
119	 (goto-char (point-min))
120	 (unless Buffer-menu-use-header-line
121	   (forward-line 2)))
122	((> (point) (cdr state))
123	 (goto-char (point-max))
124	 (forward-line -1)
125	 (if (pos-visible-in-window-p (point-max))
126	     (recenter -1))))
127  (electric-buffer-update-highlight))
128
129(defvar Helper-return-blurb)
130
131(put 'Electric-buffer-menu-mode 'mode-class 'special)
132(defun Electric-buffer-menu-mode ()
133  "Major mode for editing a list of buffers.
134Each line describes one of the buffers in Emacs.
135Letters do not insert themselves; instead, they are commands.
136\\<electric-buffer-menu-mode-map>
137\\[keyboard-quit] or \\[Electric-buffer-menu-quit] -- exit buffer menu, returning to previous window and buffer
138  configuration.  If the very first character typed is a space, it
139  also has this effect.
140\\[Electric-buffer-menu-select] -- select buffer of line point is on.
141  Also show buffers marked with m in other windows,
142  deletes buffers marked with \"D\", and saves those marked with \"S\".
143\\[Buffer-menu-mark] -- mark buffer to be displayed.
144\\[Buffer-menu-not-modified] -- clear modified-flag on that buffer.
145\\[Buffer-menu-save] -- mark that buffer to be saved.
146\\[Buffer-menu-delete] or \\[Buffer-menu-delete-backwards] -- mark that buffer to be deleted.
147\\[Buffer-menu-unmark] -- remove all kinds of marks from current line.
148\\[Electric-buffer-menu-mode-view-buffer] -- view buffer, returning when done.
149\\[Buffer-menu-backup-unmark] -- back up a line and remove marks.
150
151\\{electric-buffer-menu-mode-map}
152
153Entry to this mode via command `electric-buffer-list' calls the value of
154`electric-buffer-menu-mode-hook'."
155  (let ((saved header-line-format))
156    (kill-all-local-variables)
157    (setq header-line-format saved))
158  (use-local-map electric-buffer-menu-mode-map)
159  (setq mode-name "Electric Buffer Menu")
160  (setq mode-line-buffer-identification "Electric Buffer List")
161  (make-local-variable 'Helper-return-blurb)
162  (setq Helper-return-blurb "return to buffer editing")
163  (setq truncate-lines t)
164  (setq buffer-read-only t)
165  (setq major-mode 'Electric-buffer-menu-mode)
166  (goto-char (point-min))
167  (if (search-forward "\n." nil t) (forward-char -1))
168  (run-mode-hooks 'electric-buffer-menu-mode-hook))
169
170;; generally the same as Buffer-menu-mode-map
171;;  (except we don't indirect to global-map)
172(put 'Electric-buffer-menu-undefined 'suppress-keymap t)
173(if electric-buffer-menu-mode-map
174    nil
175  (let ((map (make-keymap)))
176    (fillarray (car (cdr map)) 'Electric-buffer-menu-undefined)
177    (define-key map "\e" nil)
178    (define-key map "\C-z" 'suspend-emacs)
179    (define-key map "v" 'Electric-buffer-menu-mode-view-buffer)
180    (define-key map (char-to-string help-char) 'Helper-help)
181    (define-key map "?" 'Helper-describe-bindings)
182    (define-key map "\C-c" nil)
183    (define-key map "\C-c\C-c" 'Electric-buffer-menu-quit)
184    (define-key map "\C-]" 'Electric-buffer-menu-quit)
185    (define-key map "q" 'Electric-buffer-menu-quit)
186    (define-key map " " 'Electric-buffer-menu-select)
187    (define-key map "\C-m" 'Electric-buffer-menu-select)
188    (define-key map "\C-l" 'recenter)
189    (define-key map "s" 'Buffer-menu-save)
190    (define-key map "d" 'Buffer-menu-delete)
191    (define-key map "k" 'Buffer-menu-delete)
192    (define-key map "\C-d" 'Buffer-menu-delete-backwards)
193    ;(define-key map "\C-k" 'Buffer-menu-delete)
194    (define-key map "\177" 'Buffer-menu-backup-unmark)
195    (define-key map "~" 'Buffer-menu-not-modified)
196    (define-key map "u" 'Buffer-menu-unmark)
197    (let ((i ?0))
198      (while (<= i ?9)
199	(define-key map (char-to-string i) 'digit-argument)
200	(define-key map (concat "\e" (char-to-string i)) 'digit-argument)
201	(setq i (1+ i))))
202    (define-key map "-" 'negative-argument)
203    (define-key map "\e-" 'negative-argument)
204    (define-key map "m" 'Buffer-menu-mark)
205    (define-key map "\C-u" 'universal-argument)
206    (define-key map "\C-p" 'previous-line)
207    (define-key map "\C-n" 'next-line)
208    (define-key map "p" 'previous-line)
209    (define-key map "n" 'next-line)
210    (define-key map "\C-v" 'scroll-up)
211    (define-key map "\ev" 'scroll-down)
212    (define-key map ">" 'scroll-right)
213    (define-key map "<" 'scroll-left)
214    (define-key map "\e\C-v" 'scroll-other-window)
215    (define-key map "\e>" 'end-of-buffer)
216    (define-key map "\e<" 'beginning-of-buffer)
217    (define-key map "\e\e" nil)
218    (define-key map "\e\e\e" 'Electric-buffer-menu-quit)
219    (define-key map [escape escape escape] 'Electric-buffer-menu-quit)
220    (define-key map [mouse-2] 'Electric-buffer-menu-mouse-select)
221    (setq electric-buffer-menu-mode-map map)))
222
223(defun Electric-buffer-menu-exit ()
224  (interactive)
225  (setq unread-command-events (listify-key-sequence (this-command-keys)))
226  ;; for robustness
227  (condition-case ()
228      (throw 'electric-buffer-menu-select nil)
229    (error (Buffer-menu-mode)
230	   (other-buffer))))
231
232(defun Electric-buffer-menu-select ()
233  "Leave Electric Buffer Menu, selecting buffers and executing changes.
234Save buffers marked \"S\".  Delete buffers marked \"K\".
235Select buffer at point and display buffers marked \">\" in other windows."
236  (interactive)
237  (throw 'electric-buffer-menu-select (point)))
238
239(defun Electric-buffer-menu-mouse-select (event)
240  (interactive "e")
241  (select-window (posn-window (event-end event)))
242  (set-buffer (window-buffer (selected-window)))
243  (goto-char (posn-point (event-end event)))
244  (throw 'electric-buffer-menu-select (point)))
245
246(defun Electric-buffer-menu-quit ()
247  "Leave Electric Buffer Menu, restoring previous window configuration.
248Skip execution of select, save, and delete commands."
249  (interactive)
250  (throw 'electric-buffer-menu-select nil))
251
252(defun Electric-buffer-menu-undefined ()
253  (interactive)
254  (ding)
255  (message "%s"
256	   (if (and (eq (key-binding "\C-c\C-c") 'Electric-buffer-menu-quit)
257		    (eq (key-binding " ") 'Electric-buffer-menu-select)
258		    (eq (key-binding (char-to-string help-char)) 'Helper-help)
259		    (eq (key-binding "?") 'Helper-describe-bindings))
260	       (substitute-command-keys "Type C-c C-c to exit, Space to select, \\[Helper-help] for help, ? for commands")
261	     (substitute-command-keys "\
262Type \\[Electric-buffer-menu-quit] to exit, \
263\\[Electric-buffer-menu-select] to select, \
264\\[Helper-help] for help, \\[Helper-describe-bindings] for commands.")))
265  (sit-for 4))
266
267(defun Electric-buffer-menu-mode-view-buffer ()
268  "View buffer on current line in Electric Buffer Menu.
269Return to Electric Buffer Menu when done."
270  (interactive)
271  (let ((bufnam (Buffer-menu-buffer nil)))
272    (if bufnam
273	(view-buffer bufnam)
274      (ding)
275      (message "Buffer %s does not exist!" bufnam)
276      (sit-for 4))))
277
278(defvar electric-buffer-overlay nil)
279(defun electric-buffer-update-highlight ()
280  (when (eq major-mode 'Electric-buffer-menu-mode)
281    ;; Make sure we have an overlay to use.
282    (or electric-buffer-overlay
283	(progn
284	  (make-local-variable 'electric-buffer-overlay)
285	  (setq electric-buffer-overlay (make-overlay (point) (point)))))
286    (move-overlay electric-buffer-overlay
287		  (save-excursion (beginning-of-line) (point))
288		  (save-excursion (end-of-line) (point)))
289    (overlay-put electric-buffer-overlay 'face 'highlight)))
290
291(provide 'ebuff-menu)
292
293;;; arch-tag: 1d4509b3-eece-4d4f-95ea-77c83eaf0275
294;;; ebuff-menu.el ends here
295