ebuff-menu.el 10.8 KB
Newer Older
Eric S. Raymond's avatar
Eric S. Raymond committed
1 2
;;; ebuff-menu.el --- electric-buffer-list mode

3
;; Copyright (C) 1985-1986, 1994, 2001-2011  Free Software Foundation, Inc.
Jim Blandy's avatar
Jim Blandy committed
4

Eric S. Raymond's avatar
Eric S. Raymond committed
5
;; Author: Richard Mlynarik <mly@ai.mit.edu>
Richard M. Stallman's avatar
Richard M. Stallman committed
6
;; Maintainer: FSF
Dave Love's avatar
Dave Love committed
7
;; Keywords: convenience
Eric S. Raymond's avatar
Eric S. Raymond committed
8

Jim Blandy's avatar
Jim Blandy committed
9 10
;; This file is part of GNU Emacs.

11
;; GNU Emacs is free software: you can redistribute it and/or modify
Jim Blandy's avatar
Jim Blandy committed
12
;; it under the terms of the GNU General Public License as published by
13 14
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
Jim Blandy's avatar
Jim Blandy committed
15 16 17 18 19 20 21

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
22
;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
Jim Blandy's avatar
Jim Blandy committed
23

Eric S. Raymond's avatar
Eric S. Raymond committed
24 25
;;; Commentary:

26 27 28
;; Who says one can't have typeout windows in GNU Emacs?   The entry
;; point, `electric-buffer-list' works like ^r select buffer from the
;; ITS Emacs lunar or tmacs libraries.
Eric S. Raymond's avatar
Eric S. Raymond committed
29 30

;;; Code:
Jim Blandy's avatar
Jim Blandy committed
31 32 33 34 35 36

(require 'electric)

;; this depends on the format of list-buffers (from src/buffer.c) and
;; on stuff in lisp/buff-menu.el

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
(defvar electric-buffer-menu-mode-map
  (let ((map (make-keymap)))
    (fillarray (car (cdr map)) 'Electric-buffer-menu-undefined)
    (define-key map "\e" nil)
    (define-key map "\C-z" 'suspend-frame)
    (define-key map "v" 'Electric-buffer-menu-mode-view-buffer)
    (define-key map (char-to-string help-char) 'Helper-help)
    (define-key map "?" 'Helper-describe-bindings)
    (define-key map "\C-c" nil)
    (define-key map "\C-c\C-c" 'Electric-buffer-menu-quit)
    (define-key map "\C-]" 'Electric-buffer-menu-quit)
    (define-key map "q" 'Electric-buffer-menu-quit)
    (define-key map " " 'Electric-buffer-menu-select)
    (define-key map "\C-m" 'Electric-buffer-menu-select)
    (define-key map "\C-l" 'recenter)
    (define-key map "s" 'Buffer-menu-save)
    (define-key map "d" 'Buffer-menu-delete)
    (define-key map "k" 'Buffer-menu-delete)
    (define-key map "\C-d" 'Buffer-menu-delete-backwards)
    ;; (define-key map "\C-k" 'Buffer-menu-delete)
    (define-key map "\177" 'Buffer-menu-backup-unmark)
    (define-key map "~" 'Buffer-menu-not-modified)
    (define-key map "u" 'Buffer-menu-unmark)
    (let ((i ?0))
      (while (<= i ?9)
	(define-key map (char-to-string i) 'digit-argument)
	(define-key map (concat "\e" (char-to-string i)) 'digit-argument)
	(setq i (1+ i))))
    (define-key map "-" 'negative-argument)
    (define-key map "\e-" 'negative-argument)
    (define-key map "m" 'Buffer-menu-mark)
    (define-key map "\C-u" 'universal-argument)
    (define-key map "\C-p" 'previous-line)
    (define-key map "\C-n" 'next-line)
    (define-key map "p" 'previous-line)
    (define-key map "n" 'next-line)
    (define-key map "\C-v" 'scroll-up)
    (define-key map "\ev" 'scroll-down)
    (define-key map ">" 'scroll-right)
    (define-key map "<" 'scroll-left)
    (define-key map "\e\C-v" 'scroll-other-window)
    (define-key map "\e>" 'end-of-buffer)
    (define-key map "\e<" 'beginning-of-buffer)
    (define-key map "\e\e" nil)
    (define-key map "\e\e\e" 'Electric-buffer-menu-quit)
    ;; This binding prevents the "escape => ESC" function-key-map mapping from
    ;; kicking in!
    ;; (define-key map [escape escape escape] 'Electric-buffer-menu-quit)
    (define-key map [mouse-2] 'Electric-buffer-menu-mouse-select)
    map))
Jim Blandy's avatar
Jim Blandy committed
87

Thien-Thi Nguyen's avatar
Thien-Thi Nguyen committed
88 89 90
(defvar electric-buffer-menu-mode-hook nil
  "Normal hook run by `electric-buffer-list'.")

Jim Blandy's avatar
Jim Blandy committed
91 92
;;;###autoload
(defun electric-buffer-list (arg)
Thien-Thi Nguyen's avatar
Thien-Thi Nguyen committed
93
  "Pop up a buffer describing the set of Emacs buffers.
Jim Blandy's avatar
Jim Blandy committed
94 95 96 97 98 99 100 101 102
Vaguely like ITS lunar select buffer; combining typeoutoid buffer
listing with menuoid buffer selection.

If the very next character typed is a space then the buffer list
window disappears.  Otherwise, one may move around in the buffer list
window, marking buffers to be selected, saved or deleted.

To exit and select a new buffer, type a space when the cursor is on
the appropriate line of the buffer-list window.  Other commands are
Thien-Thi Nguyen's avatar
Thien-Thi Nguyen committed
103
much like those of `Buffer-menu-mode'.
Jim Blandy's avatar
Jim Blandy committed
104

Thien-Thi Nguyen's avatar
Thien-Thi Nguyen committed
105
Run hooks in `electric-buffer-menu-mode-hook' on entry.
Jim Blandy's avatar
Jim Blandy committed
106

107
\\{electric-buffer-menu-mode-map}"
Jim Blandy's avatar
Jim Blandy committed
108 109 110
  (interactive "P")
  (let (select buffer)
    (save-window-excursion
111 112
      (setq buffer (list-buffers-noselect arg))
      (Electric-pop-up-window buffer)
Jim Blandy's avatar
Jim Blandy committed
113 114 115 116
      (unwind-protect
	  (progn
	    (set-buffer buffer)
	    (Electric-buffer-menu-mode)
117
	    (electric-buffer-update-highlight)
Jim Blandy's avatar
Jim Blandy committed
118 119
	    (setq select
		  (catch 'electric-buffer-menu-select
120
		    (message "<<< Press Return to bury the buffer list >>>")
121
		    (if (eq (setq unread-command-events (list (read-event)))
122
			    ?\s)
Jim Blandy's avatar
Jim Blandy committed
123
			(progn (setq unread-command-events nil)
Jim Blandy's avatar
Jim Blandy committed
124
			       (throw 'electric-buffer-menu-select nil)))
125 126
		    (let ((start-point (point))
			  (first (progn (goto-char (point-min))
127 128
					(unless Buffer-menu-use-header-line
					  (forward-line 2))
Jim Blandy's avatar
Jim Blandy committed
129 130 131 132 133
					(point)))
			  (last (progn (goto-char (point-max))
				       (forward-line -1)
				       (point)))
			  (goal-column 0))
134 135 136 137 138
		      ;; Use start-point if it is meaningful.
		      (goto-char (if (or (< start-point first)
					 (> start-point last))
				     first
				   start-point))
Jim Blandy's avatar
Jim Blandy committed
139 140 141 142 143 144 145
		      (Electric-command-loop 'electric-buffer-menu-select
					     nil
					     t
					     'electric-buffer-menu-looper
					     (cons first last))))))
	(set-buffer buffer)
	(Buffer-menu-mode)
Stefan Monnier's avatar
Stefan Monnier committed
146
	(bury-buffer)                ;Get rid of window, if dedicated.
Jim Blandy's avatar
Jim Blandy committed
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
	(message "")))
    (if select
	(progn (set-buffer buffer)
	       (let ((opoint (point-marker)))
		 (Buffer-menu-execute)
		 (goto-char (point-min))
		 (if (prog1 (search-forward "\n>" nil t)
		       (goto-char opoint) (set-marker opoint nil))
		     (Buffer-menu-select)
		     (switch-to-buffer (Buffer-menu-buffer t))))))))

(defun electric-buffer-menu-looper (state condition)
  (cond ((and condition
	      (not (memq (car condition) '(buffer-read-only
					   end-of-buffer
					   beginning-of-buffer))))
	 (signal (car condition) (cdr condition)))
	((< (point) (car state))
	 (goto-char (point-min))
166 167
	 (unless Buffer-menu-use-header-line
	   (forward-line 2)))
Jim Blandy's avatar
Jim Blandy committed
168 169 170 171
	((> (point) (cdr state))
	 (goto-char (point-max))
	 (forward-line -1)
	 (if (pos-visible-in-window-p (point-max))
172 173
	     (recenter -1))))
  (electric-buffer-update-highlight))
Jim Blandy's avatar
Jim Blandy committed
174

175 176
(defvar Helper-return-blurb)

Jim Blandy's avatar
Jim Blandy committed
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
(put 'Electric-buffer-menu-mode 'mode-class 'special)
(defun Electric-buffer-menu-mode ()
  "Major mode for editing a list of buffers.
Each line describes one of the buffers in Emacs.
Letters do not insert themselves; instead, they are commands.
\\<electric-buffer-menu-mode-map>
\\[keyboard-quit] or \\[Electric-buffer-menu-quit] -- exit buffer menu, returning to previous window and buffer
  configuration.  If the very first character typed is a space, it
  also has this effect.
\\[Electric-buffer-menu-select] -- select buffer of line point is on.
  Also show buffers marked with m in other windows,
  deletes buffers marked with \"D\", and saves those marked with \"S\".
\\[Buffer-menu-mark] -- mark buffer to be displayed.
\\[Buffer-menu-not-modified] -- clear modified-flag on that buffer.
\\[Buffer-menu-save] -- mark that buffer to be saved.
\\[Buffer-menu-delete] or \\[Buffer-menu-delete-backwards] -- mark that buffer to be deleted.
\\[Buffer-menu-unmark] -- remove all kinds of marks from current line.
\\[Electric-buffer-menu-mode-view-buffer] -- view buffer, returning when done.
\\[Buffer-menu-backup-unmark] -- back up a line and remove marks.

\\{electric-buffer-menu-mode-map}

Thien-Thi Nguyen's avatar
Thien-Thi Nguyen committed
199 200
Entry to this mode via command `electric-buffer-list' calls the value of
`electric-buffer-menu-mode-hook'."
201 202 203
  (let ((saved header-line-format))
    (kill-all-local-variables)
    (setq header-line-format saved))
Jim Blandy's avatar
Jim Blandy committed
204 205 206 207 208 209 210 211 212 213
  (use-local-map electric-buffer-menu-mode-map)
  (setq mode-name "Electric Buffer Menu")
  (setq mode-line-buffer-identification "Electric Buffer List")
  (make-local-variable 'Helper-return-blurb)
  (setq Helper-return-blurb "return to buffer editing")
  (setq truncate-lines t)
  (setq buffer-read-only t)
  (setq major-mode 'Electric-buffer-menu-mode)
  (goto-char (point-min))
  (if (search-forward "\n." nil t) (forward-char -1))
214
  (run-mode-hooks 'electric-buffer-menu-mode-hook))
Jim Blandy's avatar
Jim Blandy committed
215 216 217 218

;; generally the same as Buffer-menu-mode-map
;;  (except we don't indirect to global-map)
(put 'Electric-buffer-menu-undefined 'suppress-keymap t)
219

220

Jim Blandy's avatar
Jim Blandy committed
221 222
(defun Electric-buffer-menu-exit ()
  (interactive)
223
  (setq unread-command-events (listify-key-sequence (this-command-keys)))
Jim Blandy's avatar
Jim Blandy committed
224 225 226 227 228 229 230 231
  ;; for robustness
  (condition-case ()
      (throw 'electric-buffer-menu-select nil)
    (error (Buffer-menu-mode)
	   (other-buffer))))

(defun Electric-buffer-menu-select ()
  "Leave Electric Buffer Menu, selecting buffers and executing changes.
Thien-Thi Nguyen's avatar
Thien-Thi Nguyen committed
232 233
Save buffers marked \"S\".  Delete buffers marked \"K\".
Select buffer at point and display buffers marked \">\" in other windows."
Jim Blandy's avatar
Jim Blandy committed
234 235 236
  (interactive)
  (throw 'electric-buffer-menu-select (point)))

237 238 239 240 241 242 243
(defun Electric-buffer-menu-mouse-select (event)
  (interactive "e")
  (select-window (posn-window (event-end event)))
  (set-buffer (window-buffer (selected-window)))
  (goto-char (posn-point (event-end event)))
  (throw 'electric-buffer-menu-select (point)))

Jim Blandy's avatar
Jim Blandy committed
244 245
(defun Electric-buffer-menu-quit ()
  "Leave Electric Buffer Menu, restoring previous window configuration.
Thien-Thi Nguyen's avatar
Thien-Thi Nguyen committed
246
Skip execution of select, save, and delete commands."
Jim Blandy's avatar
Jim Blandy committed
247 248 249 250 251 252
  (interactive)
  (throw 'electric-buffer-menu-select nil))

(defun Electric-buffer-menu-undefined ()
  (interactive)
  (ding)
253 254
  (message "%s"
	   (if (and (eq (key-binding "\C-c\C-c") 'Electric-buffer-menu-quit)
Jim Blandy's avatar
Jim Blandy committed
255
		    (eq (key-binding " ") 'Electric-buffer-menu-select)
Eric S. Raymond's avatar
Eric S. Raymond committed
256
		    (eq (key-binding (char-to-string help-char)) 'Helper-help)
Jim Blandy's avatar
Jim Blandy committed
257
		    (eq (key-binding "?") 'Helper-describe-bindings))
Eric S. Raymond's avatar
Eric S. Raymond committed
258
	       (substitute-command-keys "Type C-c C-c to exit, Space to select, \\[Helper-help] for help, ? for commands")
Jim Blandy's avatar
Jim Blandy committed
259 260 261 262 263 264 265 266
	     (substitute-command-keys "\
Type \\[Electric-buffer-menu-quit] to exit, \
\\[Electric-buffer-menu-select] to select, \
\\[Helper-help] for help, \\[Helper-describe-bindings] for commands.")))
  (sit-for 4))

(defun Electric-buffer-menu-mode-view-buffer ()
  "View buffer on current line in Electric Buffer Menu.
Thien-Thi Nguyen's avatar
Thien-Thi Nguyen committed
267
Return to Electric Buffer Menu when done."
Jim Blandy's avatar
Jim Blandy committed
268 269 270 271 272 273 274 275
  (interactive)
  (let ((bufnam (Buffer-menu-buffer nil)))
    (if bufnam
	(view-buffer bufnam)
      (ding)
      (message "Buffer %s does not exist!" bufnam)
      (sit-for 4))))

276 277
(defvar electric-buffer-overlay nil)
(defun electric-buffer-update-highlight ()
278 279 280 281 282 283 284
  (when (eq major-mode 'Electric-buffer-menu-mode)
    ;; Make sure we have an overlay to use.
    (or electric-buffer-overlay
	(progn
	  (make-local-variable 'electric-buffer-overlay)
	  (setq electric-buffer-overlay (make-overlay (point) (point)))))
    (move-overlay electric-buffer-overlay
285 286
		  (line-beginning-position)
		  (line-end-position))
287
    (overlay-put electric-buffer-overlay 'face 'highlight)))
288

Richard M. Stallman's avatar
Richard M. Stallman committed
289 290
(provide 'ebuff-menu)

Eric S. Raymond's avatar
Eric S. Raymond committed
291
;;; ebuff-menu.el ends here