(find-file-noselect): Improve the question wording.
[bpt/emacs.git] / lisp / buff-menu.el
CommitLineData
5e684428 1;;; buff-menu.el --- buffer menu main function and support functions -*- coding:utf-8 -*-
c0274f38 2
f4872033 3;; Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 2000, 2001, 2002, 2003,
aaef169d 4;; 2004, 2005, 2006 Free Software Foundation, Inc.
2dd96f23 5
9750e079 6;; Maintainer: FSF
6d6c3f84 7;; Keywords: convenience
9750e079 8
2dd96f23
JB
9;; This file is part of GNU Emacs.
10
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
35aaf00c 13;; the Free Software Foundation; either version 2, or (at your option)
2dd96f23
JB
14;; any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
b578f267 22;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
23;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24;; Boston, MA 02110-1301, USA.
2dd96f23 25
e41b2db1
ER
26;;; Commentary:
27
28;; Edit, delete, or change attributes of all currently active Emacs
eb8c3be9 29;; buffers from a list summarizing their state. A good way to browse
e41b2db1 30;; any special or scratch buffers you have loaded, since you can't find
6d6c3f84 31;; them by filename. The single entry point is `list-buffers',
86dbbfc2
ER
32;; normally bound to C-x C-b.
33
34;;; Change Log:
35
42a19c2a
RS
36;; Buffer-menu-view: New function
37;; Buffer-menu-view-other-window: New function
38
86dbbfc2
ER
39;; Merged by esr with recent mods to Emacs 19 buff-menu, 23 Mar 1993
40;;
86dbbfc2
ER
41;; Modified by Bob Weiner, Motorola, Inc., 4/14/89
42;;
43;; Added optional backup argument to 'Buffer-menu-unmark' to make it undelete
44;; current entry and then move to previous one.
45;;
46;; Based on FSF code dating back to 1985.
e41b2db1 47
5de9bdab 48;;; Code:
10e1dad9 49
d5aacb46
SM
50;;Trying to preserve the old window configuration works well in
51;;simple scenarios, when you enter the buffer menu, use it, and exit it.
52;;But it does strange things when you switch back to the buffer list buffer
53;;with C-x b, later on, when the window configuration is different.
54;;The choice seems to be, either restore the window configuration
55;;in all cases, or in no cases.
56;;I decided it was better not to restore the window config at all. -- rms.
08c82d4d 57
d5aacb46
SM
58;;But since then, I changed buffer-menu to use the selected window,
59;;so q now once again goes back to the previous window configuration.
08c82d4d 60
d5aacb46
SM
61;;(defvar Buffer-menu-window-config nil
62;; "Window configuration saved from entry to `buffer-menu'.")
2dd96f23 63
d5aacb46
SM
64;; Put buffer *Buffer List* into proper mode right away
65;; so that from now on even list-buffers is enough to get a buffer menu.
2dd96f23 66
bc7bb432
JB
67(defgroup Buffer-menu nil
68 "Show a menu of all buffers in a buffer."
69 :group 'tools
70 :group 'convenience)
71
72(defcustom Buffer-menu-use-header-line t
73 "*Non-nil means to use an immovable header-line."
74 :type 'boolean
75 :group 'Buffer-menu)
76
d247d0fe 77(defface buffer-menu-buffer
bc7bb432 78 '((t (:weight bold)))
d247d0fe 79 "Face used to highlight buffer names in the buffer menu."
2a8f2d4c 80 :group 'Buffer-menu)
d247d0fe 81(put 'Buffer-menu-buffer 'face-alias 'buffer-menu-buffer)
bc7bb432 82
4f0992b3 83(defcustom Buffer-menu-buffer+size-width 26
bc7bb432
JB
84 "*How wide to jointly make the buffer name and size columns."
85 :type 'number
86 :group 'Buffer-menu)
87
4f0992b3 88(defcustom Buffer-menu-mode-width 16
bc7bb432
JB
89 "*How wide to make the mode name column."
90 :type 'number
91 :group 'Buffer-menu)
92
3ce5f932
LT
93(defcustom Buffer-menu-use-frame-buffer-list t
94 "If non-nil, the Buffer Menu uses the selected frame's buffer list.
95Buffers that were never selected in that frame are listed at the end.
96If the value is nil, the Buffer Menu uses the global buffer list.
97This variable matters if the Buffer Menu is sorted by visited order,
98as it is by default."
99 :type 'boolean
100 :group 'Buffer-menu
101 :version "22.1")
102
d5aacb46 103;; This should get updated & resorted when you click on a column heading
bc7bb432 104(defvar Buffer-menu-sort-column nil
e39588f3 105 "2 for sorting by buffer names. 5 for sorting by file names.
bc7bb432
JB
106nil for default sorting by visited order.")
107
108(defconst Buffer-menu-buffer-column 4)
e5ea316b 109
463a7342
JPW
110(defvar Buffer-menu-mode-map nil
111 "Local keymap for `Buffer-menu-mode' buffers.")
2dd96f23 112
7b0a86ab
LT
113(defvar Buffer-menu-files-only nil
114 "Non-nil if the current buffer-menu lists only file buffers.
115This variable determines whether reverting the buffer lists only
116file buffers. It affects both manual reverting and reverting by
117Auto Revert Mode.")
118
fb5614e8
EZ
119(defvar Info-current-file) ;; from info.el
120
7b0a86ab
LT
121(make-variable-buffer-local 'Buffer-menu-files-only)
122
2dd96f23
JB
123(if Buffer-menu-mode-map
124 ()
125 (setq Buffer-menu-mode-map (make-keymap))
126 (suppress-keymap Buffer-menu-mode-map t)
68e6f094 127 (define-key Buffer-menu-mode-map "q" 'quit-window)
3ed788ec 128 (define-key Buffer-menu-mode-map "v" 'Buffer-menu-select)
2dd96f23
JB
129 (define-key Buffer-menu-mode-map "2" 'Buffer-menu-2-window)
130 (define-key Buffer-menu-mode-map "1" 'Buffer-menu-1-window)
131 (define-key Buffer-menu-mode-map "f" 'Buffer-menu-this-window)
251680cf 132 (define-key Buffer-menu-mode-map "e" 'Buffer-menu-this-window)
8768da77 133 (define-key Buffer-menu-mode-map "\C-m" 'Buffer-menu-this-window)
2dd96f23 134 (define-key Buffer-menu-mode-map "o" 'Buffer-menu-other-window)
35aaf00c 135 (define-key Buffer-menu-mode-map "\C-o" 'Buffer-menu-switch-other-window)
2dd96f23
JB
136 (define-key Buffer-menu-mode-map "s" 'Buffer-menu-save)
137 (define-key Buffer-menu-mode-map "d" 'Buffer-menu-delete)
138 (define-key Buffer-menu-mode-map "k" 'Buffer-menu-delete)
139 (define-key Buffer-menu-mode-map "\C-d" 'Buffer-menu-delete-backwards)
140 (define-key Buffer-menu-mode-map "\C-k" 'Buffer-menu-delete)
141 (define-key Buffer-menu-mode-map "x" 'Buffer-menu-execute)
142 (define-key Buffer-menu-mode-map " " 'next-line)
143 (define-key Buffer-menu-mode-map "n" 'next-line)
144 (define-key Buffer-menu-mode-map "p" 'previous-line)
145 (define-key Buffer-menu-mode-map "\177" 'Buffer-menu-backup-unmark)
146 (define-key Buffer-menu-mode-map "~" 'Buffer-menu-not-modified)
147 (define-key Buffer-menu-mode-map "?" 'describe-mode)
148 (define-key Buffer-menu-mode-map "u" 'Buffer-menu-unmark)
149 (define-key Buffer-menu-mode-map "m" 'Buffer-menu-mark)
d91e2b1a
ER
150 (define-key Buffer-menu-mode-map "t" 'Buffer-menu-visit-tags-table)
151 (define-key Buffer-menu-mode-map "%" 'Buffer-menu-toggle-read-only)
36570c92 152 (define-key Buffer-menu-mode-map "b" 'Buffer-menu-bury)
0f88624e 153 (define-key Buffer-menu-mode-map "g" 'Buffer-menu-revert)
42a19c2a 154 (define-key Buffer-menu-mode-map "V" 'Buffer-menu-view)
7b0a86ab 155 (define-key Buffer-menu-mode-map "T" 'Buffer-menu-toggle-files-only)
2cf5fc7e 156 (define-key Buffer-menu-mode-map [mouse-2] 'Buffer-menu-mouse-select)
95f5b5ad 157 (define-key Buffer-menu-mode-map [follow-link] 'mouse-face)
d91e2b1a 158)
2dd96f23
JB
159
160;; Buffer Menu mode is suitable only for specially formatted data.
161(put 'Buffer-menu-mode 'mode-class 'special)
162
163(defun Buffer-menu-mode ()
164 "Major mode for editing a list of buffers.
165Each line describes one of the buffers in Emacs.
166Letters do not insert themselves; instead, they are commands.
167\\<Buffer-menu-mode-map>
2cf5fc7e
RS
168\\[Buffer-menu-mouse-select] -- select buffer you click on, in place of the buffer menu.
169\\[Buffer-menu-this-window] -- select current line's buffer in place of the buffer menu.
170\\[Buffer-menu-other-window] -- select that buffer in another window,
171 so the buffer menu buffer remains visible in its window.
42a19c2a
RS
172\\[Buffer-menu-view] -- select current line's buffer, but in view-mode.
173\\[Buffer-menu-view-other-window] -- select that buffer in
174 another window, in view-mode.
2cf5fc7e
RS
175\\[Buffer-menu-switch-other-window] -- make another window display that buffer.
176\\[Buffer-menu-mark] -- mark current line's buffer to be displayed.
177\\[Buffer-menu-select] -- select current line's buffer.
178 Also show buffers marked with m, in other windows.
dc6d9681 179\\[Buffer-menu-1-window] -- select that buffer in full-frame window.
2dd96f23
JB
180\\[Buffer-menu-2-window] -- select that buffer in one window,
181 together with buffer selected before this one in another window.
2dd96f23
JB
182\\[Buffer-menu-visit-tags-table] -- visit-tags-table this buffer.
183\\[Buffer-menu-not-modified] -- clear modified-flag on that buffer.
184\\[Buffer-menu-save] -- mark that buffer to be saved, and move down.
185\\[Buffer-menu-delete] -- mark that buffer to be deleted, and move down.
186\\[Buffer-menu-delete-backwards] -- mark that buffer to be deleted, and move up.
187\\[Buffer-menu-execute] -- delete or save marked buffers.
188\\[Buffer-menu-unmark] -- remove all kinds of marks from current line.
86dbbfc2 189 With prefix argument, also move up one line.
d91e2b1a 190\\[Buffer-menu-backup-unmark] -- back up a line and remove marks.
0f88624e 191\\[Buffer-menu-toggle-read-only] -- toggle read-only status of buffer on this line.
a59faabe 192\\[Buffer-menu-revert] -- update the list of buffers.
7b0a86ab 193\\[Buffer-menu-toggle-files-only] -- toggle whether the menu displays only file buffers.
a59faabe 194\\[Buffer-menu-bury] -- bury the buffer listed on this line."
2dd96f23
JB
195 (kill-all-local-variables)
196 (use-local-map Buffer-menu-mode-map)
2dd96f23
JB
197 (setq major-mode 'Buffer-menu-mode)
198 (setq mode-name "Buffer Menu")
7b0a86ab
LT
199 (set (make-local-variable 'revert-buffer-function)
200 'Buffer-menu-revert-function)
201 (set (make-local-variable 'buffer-stale-function)
012ad4a3 202 #'(lambda (&optional noconfirm) 'fast))
823316aa
KH
203 (setq truncate-lines t)
204 (setq buffer-read-only t)
5f90d77e 205 (run-mode-hooks 'buffer-menu-mode-hook))
710e5da8 206
5f11b513
RS
207;; This function exists so we can make the doc string of Buffer-menu-mode
208;; look nice.
0f88624e
RS
209(defun Buffer-menu-revert ()
210 "Update the list of buffers."
211 (interactive)
212 (revert-buffer))
213
710e5da8 214(defun Buffer-menu-revert-function (ignore1 ignore2)
fda73b45
LT
215 (or (eq buffer-undo-list t)
216 (setq buffer-undo-list nil))
7b0a86ab 217 ;; We can not use save-excursion here. The buffer gets erased.
3f9c9ff7
LT
218 (let ((opoint (point))
219 (eobp (eobp))
220 (ocol (current-column))
bfb2dda4
DP
221 (oline (progn (move-to-column 4)
222 (get-text-property (point) 'buffer)))
fda73b45
LT
223 (prop (point-min))
224 ;; do not make undo records for the reversion.
225 (buffer-undo-list t))
63de2160
LT
226 ;; We can be called by Auto Revert Mode with the "*Buffer Menu*"
227 ;; temporarily the current buffer. Make sure that the
228 ;; interactively current buffer is correctly identified with a `.'
229 ;; by `list-buffers-noselect'.
230 (with-current-buffer (window-buffer)
231 (list-buffers-noselect Buffer-menu-files-only))
3f9c9ff7
LT
232 (if oline
233 (while (setq prop (next-single-property-change prop 'buffer))
234 (when (eq (get-text-property prop 'buffer) oline)
235 (goto-char prop)
236 (move-to-column ocol)))
237 (goto-char (if eobp (point-max) opoint)))))
7b0a86ab
LT
238
239(defun Buffer-menu-toggle-files-only (arg)
240 "Toggle whether the current buffer-menu displays only file buffers.
241With a positive ARG display only file buffers. With zero or
242negative ARG, display other buffers as well."
243 (interactive "P")
244 (setq Buffer-menu-files-only
245 (cond ((not arg) (not Buffer-menu-files-only))
246 ((> (prefix-numeric-value arg) 0) t)))
247 (revert-buffer))
248
2dd96f23 249\f
2dd96f23
JB
250(defun Buffer-menu-buffer (error-if-non-existent-p)
251 "Return buffer described by this line of buffer menu."
1b40dbed
RS
252 (let* ((where (save-excursion
253 (beginning-of-line)
254 (+ (point) Buffer-menu-buffer-column)))
601ed8a0
GM
255 (name (and (not (eobp)) (get-text-property where 'buffer-name)))
256 (buf (and (not (eobp)) (get-text-property where 'buffer))))
1b40dbed
RS
257 (if name
258 (or (get-buffer name)
601ed8a0 259 (and buf (buffer-name buf) buf)
1b40dbed
RS
260 (if error-if-non-existent-p
261 (error "No buffer named `%s'" name)
262 nil))
601ed8a0 263 (or (and buf (buffer-name buf) buf)
463a7342
JPW
264 (if error-if-non-existent-p
265 (error "No buffer on this line")
601ed8a0 266 nil)))))
2dd96f23 267\f
06b1a5ef 268(defun buffer-menu (&optional arg)
2dd96f23
JB
269 "Make a menu of buffers so you can save, delete or select them.
270With argument, show only buffers that are visiting files.
271Type ? after invocation to get help on commands available.
6a0d92d3
RS
272Type q to remove the buffer menu from the display.
273
274The first column shows `>' for a buffer you have
275marked to be displayed, `D' for one you have marked for
276deletion, and `.' for the current buffer.
277
bc7bb432
JB
278The C column has a `.' for the buffer from which you came.
279The R column has a `%' if the buffer is read-only.
6a0d92d3
RS
280The M column has a `*' if it is modified,
281or `S' if you have marked it for saving.
6a0d92d3
RS
282After this come the buffer name, its size in characters,
283its major mode, and the visited file name (if any)."
08c82d4d
RS
284 (interactive "P")
285;;; (setq Buffer-menu-window-config (current-window-configuration))
286 (switch-to-buffer (list-buffers-noselect arg))
287 (message
288 "Commands: d, s, x, u; f, o, 1, 2, m, v; ~, %%; q to quit; ? for help."))
289
290(defun buffer-menu-other-window (&optional arg)
291 "Display a list of buffers in another window.
292With the buffer list buffer, you can save, delete or select the buffers.
293With argument, show only buffers that are visiting files.
294Type ? after invocation to get help on commands available.
6a0d92d3
RS
295Type q to remove the buffer menu from the display.
296For more information, see the function `buffer-menu'."
2dd96f23 297 (interactive "P")
3ed788ec 298;;; (setq Buffer-menu-window-config (current-window-configuration))
08c82d4d 299 (switch-to-buffer-other-window (list-buffers-noselect arg))
2dd96f23 300 (message
3ed788ec
RS
301 "Commands: d, s, x, u; f, o, 1, 2, m, v; ~, %%; q to quit; ? for help."))
302
bc7bb432
JB
303(defun Buffer-menu-no-header ()
304 (beginning-of-line)
305 (if (or Buffer-menu-use-header-line
306 (not (eq (char-after) ?C)))
307 t
308 (ding)
309 (forward-line 1)
310 nil))
311
2dd96f23
JB
312(defun Buffer-menu-mark ()
313 "Mark buffer on this line for being displayed by \\<Buffer-menu-mode-map>\\[Buffer-menu-select] command."
314 (interactive)
bc7bb432 315 (when (Buffer-menu-no-header)
2dd96f23
JB
316 (let ((buffer-read-only nil))
317 (delete-char 1)
318 (insert ?>)
319 (forward-line 1))))
320
86dbbfc2
ER
321(defun Buffer-menu-unmark (&optional backup)
322 "Cancel all requested operations on buffer on this line and move down.
bfa13d19 323Optional prefix arg means move up."
86dbbfc2 324 (interactive "P")
bc7bb432 325 (when (Buffer-menu-no-header)
2dd96f23
JB
326 (let* ((buf (Buffer-menu-buffer t))
327 (mod (buffer-modified-p buf))
328 (readonly (save-excursion (set-buffer buf) buffer-read-only))
329 (buffer-read-only nil))
330 (delete-char 3)
bc7bb432 331 (insert (if readonly (if mod " %*" " % ") (if mod " *" " ")))))
86dbbfc2 332 (forward-line (if backup -1 1)))
2dd96f23
JB
333
334(defun Buffer-menu-backup-unmark ()
335 "Move up and cancel all requested operations on buffer on line above."
336 (interactive)
337 (forward-line -1)
338 (Buffer-menu-unmark)
339 (forward-line -1))
340
77a43e01
RS
341(defun Buffer-menu-delete (&optional arg)
342 "Mark buffer on this line to be deleted by \\<Buffer-menu-mode-map>\\[Buffer-menu-execute] command.
343Prefix arg is how many buffers to delete.
344Negative arg means delete backwards."
345 (interactive "p")
bc7bb432 346 (when (Buffer-menu-no-header)
2dd96f23 347 (let ((buffer-read-only nil))
77a43e01
RS
348 (if (or (null arg) (= arg 0))
349 (setq arg 1))
350 (while (> arg 0)
351 (delete-char 1)
352 (insert ?D)
353 (forward-line 1)
354 (setq arg (1- arg)))
bc7bb432
JB
355 (while (and (< arg 0)
356 (Buffer-menu-no-header))
77a43e01
RS
357 (delete-char 1)
358 (insert ?D)
359 (forward-line -1)
360 (setq arg (1+ arg))))))
361
362(defun Buffer-menu-delete-backwards (&optional arg)
2dd96f23 363 "Mark buffer on this line to be deleted by \\<Buffer-menu-mode-map>\\[Buffer-menu-execute] command
77a43e01
RS
364and then move up one line. Prefix arg means move that many lines."
365 (interactive "p")
bc7bb432 366 (Buffer-menu-delete (- (or arg 1))))
2dd96f23
JB
367
368(defun Buffer-menu-save ()
369 "Mark buffer on this line to be saved by \\<Buffer-menu-mode-map>\\[Buffer-menu-execute] command."
370 (interactive)
bc7bb432 371 (when (Buffer-menu-no-header)
2dd96f23 372 (let ((buffer-read-only nil))
bc7bb432 373 (forward-char 2)
2dd96f23
JB
374 (delete-char 1)
375 (insert ?S)
376 (forward-line 1))))
377
a8ce00dc 378(defun Buffer-menu-not-modified (&optional arg)
2dd96f23 379 "Mark buffer on this line as unmodified (no changes to save)."
a8ce00dc 380 (interactive "P")
2dd96f23
JB
381 (save-excursion
382 (set-buffer (Buffer-menu-buffer t))
a8ce00dc 383 (set-buffer-modified-p arg))
2dd96f23
JB
384 (save-excursion
385 (beginning-of-line)
bc7bb432 386 (forward-char 2)
bfa13d19 387 (if (= (char-after) (if arg ?\s ?*))
2dd96f23
JB
388 (let ((buffer-read-only nil))
389 (delete-char 1)
bfa13d19 390 (insert (if arg ?* ?\s))))))
2dd96f23 391
bfb2dda4
DP
392(defun Buffer-menu-beginning ()
393 (goto-char (point-min))
394 (unless Buffer-menu-use-header-line
395 (forward-line)))
396
2dd96f23
JB
397(defun Buffer-menu-execute ()
398 "Save and/or delete buffers marked with \\<Buffer-menu-mode-map>\\[Buffer-menu-save] or \\<Buffer-menu-mode-map>\\[Buffer-menu-delete] commands."
399 (interactive)
400 (save-excursion
bfb2dda4 401 (Buffer-menu-beginning)
bc7bb432 402 (while (re-search-forward "^..S" nil t)
2dd96f23
JB
403 (let ((modp nil))
404 (save-excursion
405 (set-buffer (Buffer-menu-buffer t))
406 (save-buffer)
407 (setq modp (buffer-modified-p)))
408 (let ((buffer-read-only nil))
409 (delete-char -1)
bfa13d19 410 (insert (if modp ?* ?\s))))))
2dd96f23 411 (save-excursion
bfb2dda4 412 (Buffer-menu-beginning)
2dd96f23
JB
413 (let ((buff-menu-buffer (current-buffer))
414 (buffer-read-only nil))
4f1ab860 415 (while (re-search-forward "^D" nil t)
2dd96f23
JB
416 (forward-char -1)
417 (let ((buf (Buffer-menu-buffer nil)))
418 (or (eq buf nil)
419 (eq buf buff-menu-buffer)
601ed8a0
GM
420 (save-excursion (kill-buffer buf)))
421 (if (and buf (buffer-name buf))
2dd96f23 422 (progn (delete-char 1)
bfa13d19 423 (insert ?\s))
2dd96f23 424 (delete-region (point) (progn (forward-line 1) (point)))
4f1ab860
DL
425 (unless (bobp)
426 (forward-char -1))))))))
2dd96f23
JB
427
428(defun Buffer-menu-select ()
429 "Select this line's buffer; also display buffers marked with `>'.
08c82d4d
RS
430You can mark buffers with the \\<Buffer-menu-mode-map>\\[Buffer-menu-mark] command.
431This command deletes and replaces all the previously existing windows
432in the selected frame."
2dd96f23
JB
433 (interactive)
434 (let ((buff (Buffer-menu-buffer t))
10e1dad9 435 (menu (current-buffer))
2dd96f23
JB
436 (others ())
437 tem)
bfb2dda4 438 (Buffer-menu-beginning)
a9fb4690 439 (while (re-search-forward "^>" nil t)
2dd96f23
JB
440 (setq tem (Buffer-menu-buffer t))
441 (let ((buffer-read-only nil))
442 (delete-char -1)
bfa13d19 443 (insert ?\s))
2dd96f23
JB
444 (or (eq tem buff) (memq tem others) (setq others (cons tem others))))
445 (setq others (nreverse others)
dc6d9681 446 tem (/ (1- (frame-height)) (1+ (length others))))
2dd96f23
JB
447 (delete-other-windows)
448 (switch-to-buffer buff)
449 (or (eq menu buff)
450 (bury-buffer menu))
86dbbfc2
ER
451 (if (equal (length others) 0)
452 (progn
3ed788ec
RS
453;;; ;; Restore previous window configuration before displaying
454;;; ;; selected buffers.
455;;; (if Buffer-menu-window-config
456;;; (progn
457;;; (set-window-configuration Buffer-menu-window-config)
458;;; (setq Buffer-menu-window-config nil)))
86dbbfc2
ER
459 (switch-to-buffer buff))
460 (while others
461 (split-window nil tem)
462 (other-window 1)
463 (switch-to-buffer (car others))
464 (setq others (cdr others)))
465 (other-window 1) ;back to the beginning!
466)))
467
08c82d4d 468
2dd96f23
JB
469\f
470(defun Buffer-menu-visit-tags-table ()
471 "Visit the tags table in the buffer on this line. See `visit-tags-table'."
472 (interactive)
473 (let ((file (buffer-file-name (Buffer-menu-buffer t))))
474 (if file
475 (visit-tags-table file)
476 (error "Specified buffer has no file"))))
477
478(defun Buffer-menu-1-window ()
dc6d9681 479 "Select this line's buffer, alone, in full frame."
2dd96f23
JB
480 (interactive)
481 (switch-to-buffer (Buffer-menu-buffer t))
482 (bury-buffer (other-buffer))
483 (delete-other-windows))
484
2cf5fc7e
RS
485(defun Buffer-menu-mouse-select (event)
486 "Select the buffer whose line you click on."
487 (interactive "e")
488 (let (buffer)
489 (save-excursion
490 (set-buffer (window-buffer (posn-window (event-end event))))
491 (save-excursion
492 (goto-char (posn-point (event-end event)))
493 (setq buffer (Buffer-menu-buffer t))))
494 (select-window (posn-window (event-end event)))
d953b88c
RS
495 (if (and (window-dedicated-p (selected-window))
496 (eq (selected-window) (frame-root-window)))
497 (switch-to-buffer-other-frame buffer)
498 (switch-to-buffer buffer))))
2cf5fc7e 499
2dd96f23
JB
500(defun Buffer-menu-this-window ()
501 "Select this line's buffer in this window."
502 (interactive)
503 (switch-to-buffer (Buffer-menu-buffer t)))
504
505(defun Buffer-menu-other-window ()
506 "Select this line's buffer in other window, leaving buffer menu visible."
507 (interactive)
508 (switch-to-buffer-other-window (Buffer-menu-buffer t)))
509
35aaf00c
RM
510(defun Buffer-menu-switch-other-window ()
511 "Make the other window select this line's buffer.
512The current window remains selected."
513 (interactive)
a0e4e275
JL
514 (let ((pop-up-windows t)
515 same-window-buffer-names
516 same-window-regexps)
517 (display-buffer (Buffer-menu-buffer t))))
35aaf00c 518
2dd96f23
JB
519(defun Buffer-menu-2-window ()
520 "Select this line's buffer, with previous buffer in second window."
521 (interactive)
522 (let ((buff (Buffer-menu-buffer t))
523 (menu (current-buffer))
a0e4e275
JL
524 (pop-up-windows t)
525 same-window-buffer-names
526 same-window-regexps)
86dbbfc2 527 (delete-other-windows)
2dd96f23
JB
528 (switch-to-buffer (other-buffer))
529 (pop-to-buffer buff)
530 (bury-buffer menu)))
c0274f38 531
d91e2b1a 532(defun Buffer-menu-toggle-read-only ()
f450965c 533 "Toggle read-only status of buffer on this line, perhaps via version control."
d91e2b1a
ER
534 (interactive)
535 (let (char)
536 (save-excursion
537 (set-buffer (Buffer-menu-buffer t))
f450965c 538 (vc-toggle-read-only)
bfa13d19 539 (setq char (if buffer-read-only ?% ?\s)))
d91e2b1a
ER
540 (save-excursion
541 (beginning-of-line)
bc7bb432 542 (forward-char 1)
d91e2b1a
ER
543 (if (/= (following-char) char)
544 (let (buffer-read-only)
545 (delete-char 1)
546 (insert char))))))
547
36570c92
RS
548(defun Buffer-menu-bury ()
549 "Bury the buffer listed on this line."
550 (interactive)
bc7bb432 551 (when (Buffer-menu-no-header)
a59faabe
RS
552 (save-excursion
553 (beginning-of-line)
554 (bury-buffer (Buffer-menu-buffer t))
555 (let ((line (buffer-substring (point) (progn (forward-line 1) (point))))
556 (buffer-read-only nil))
557 (delete-region (point) (progn (forward-line -1) (point)))
558 (goto-char (point-max))
559 (insert line))
560 (message "Buried buffer moved to the end"))))
42a19c2a
RS
561
562
563(defun Buffer-menu-view ()
564 "View this line's buffer in View mode."
565 (interactive)
566 (view-buffer (Buffer-menu-buffer t)))
567
568
569(defun Buffer-menu-view-other-window ()
570 "View this line's buffer in View mode in another window."
571 (interactive)
572 (view-buffer-other-window (Buffer-menu-buffer t)))
0b03ce3a
RS
573\f
574
575(define-key ctl-x-map "\C-b" 'list-buffers)
576
577(defun list-buffers (&optional files-only)
578 "Display a list of names of existing buffers.
579The list is displayed in a buffer named `*Buffer List*'.
580Note that buffers with names starting with spaces are omitted.
581Non-null optional arg FILES-ONLY means mention only file buffers.
582
6a0d92d3 583For more information, see the function `buffer-menu'."
0b03ce3a 584 (interactive "P")
08c82d4d
RS
585 (display-buffer (list-buffers-noselect files-only)))
586
bc7bb432
JB
587(defun Buffer-menu-buffer+size (name size &optional name-props size-props)
588 (if (> (+ (length name) (length size) 2) Buffer-menu-buffer+size-width)
589 (setq name
590 (if (string-match "<[0-9]+>$" name)
591 (concat (substring name 0
592 (- Buffer-menu-buffer+size-width
593 (max (length size) 3)
594 (match-end 0)
595 (- (match-beginning 0))
596 2))
597 ":" ; narrow ellipsis
598 (match-string 0 name))
599 (concat (substring name 0
600 (- Buffer-menu-buffer+size-width
601 (max (length size) 3)
602 2))
ee5861c8
AS
603 ":"))) ; narrow ellipsis
604 ;; Don't put properties on (buffer-name).
605 (setq name (copy-sequence name)))
bc7bb432
JB
606 (add-text-properties 0 (length name) name-props name)
607 (add-text-properties 0 (length size) size-props size)
608 (concat name
609 (make-string (- Buffer-menu-buffer+size-width
610 (length name)
611 (length size))
bfa13d19 612 ?\s)
bc7bb432
JB
613 size))
614
d5aacb46
SM
615(defun Buffer-menu-sort (column)
616 "Sort the buffer menu by COLUMN."
617 (interactive "P")
618 (when column
619 (setq column (prefix-numeric-value column))
620 (if (< column 2) (setq column 2))
621 (if (> column 5) (setq column 5)))
622 (setq Buffer-menu-sort-column column)
bfb2dda4
DP
623 (let (buffer-read-only l buf m1 m2)
624 (save-excursion
625 (Buffer-menu-beginning)
626 (while (not (eobp))
627 (when (buffer-live-p (setq buf (get-text-property (+ (point) 4) 'buffer)))
628 (setq m1 (char-after)
629 m1 (if (memq m1 '(?> ?D)) m1)
630 m2 (char-after (+ (point) 2))
631 m2 (if (eq m2 ?S) m2))
632 (if (or m1 m2)
633 (push (list buf m1 m2) l)))
634 (forward-line)))
635 (Buffer-menu-revert)
636 (setq buffer-read-only)
637 (save-excursion
638 (Buffer-menu-beginning)
639 (while (not (eobp))
640 (when (setq buf (assq (get-text-property (+ (point) 4) 'buffer) l))
641 (setq m1 (cadr buf)
642 m2 (cadr (cdr buf)))
643 (when m1
644 (delete-char 1)
645 (insert m1)
646 (backward-char 1))
647 (when m2
648 (forward-char 2)
649 (delete-char 1)
650 (insert m2)))
651 (forward-line)))))
d5aacb46 652
104fc809
CY
653(defun Buffer-menu-sort-by-column (&optional e)
654 "Sort the buffer menu by the column clicked on."
655 (interactive (list last-input-event))
656 (if e (mouse-select-window e))
657 (let* ((pos (event-start e))
658 (obj (posn-object pos))
659 (col (if obj
660 (get-text-property (cdr obj) 'column (car obj))
661 (get-text-property (posn-point pos) 'column))))
662 (Buffer-menu-sort col)))
663
664(defvar Buffer-menu-sort-button-map
665 (let ((map (make-sparse-keymap)))
666 ;; This keymap handles both nil and non-nil values for
667 ;; Buffer-menu-use-header-line.
668 (define-key map [header-line mouse-1] 'Buffer-menu-sort-by-column)
669 (define-key map [header-line mouse-2] 'Buffer-menu-sort-by-column)
670 (define-key map [mouse-2] 'Buffer-menu-sort-by-column)
671 (define-key map [follow-link] 'mouse-face)
672 (define-key map "\C-m" 'Buffer-menu-sort-by-column)
673 map)
674 "Local keymap for Buffer menu sort buttons.")
675
d5aacb46
SM
676(defun Buffer-menu-make-sort-button (name column)
677 (if (equal column Buffer-menu-sort-column) (setq column nil))
104fc809
CY
678 (propertize name
679 'column column
680 'help-echo (concat
681 (if Buffer-menu-use-header-line
682 "mouse-1, mouse-2: sort by "
683 "mouse-2, RET: sort by ")
684 (if column (downcase name) "visited order"))
685 'mouse-face 'highlight
686 'keymap Buffer-menu-sort-button-map))
d5aacb46 687
61617913 688(defun list-buffers-noselect (&optional files-only buffer-list)
08c82d4d
RS
689 "Create and return a buffer with a list of names of existing buffers.
690The buffer is named `*Buffer List*'.
691Note that buffers with names starting with spaces are omitted.
692Non-null optional arg FILES-ONLY means mention only file buffers.
693
61617913
RS
694If BUFFER-LIST is non-nil, it should be a list of buffers;
695it means list those buffers and no others.
696
6a0d92d3 697For more information, see the function `buffer-menu'."
bc7bb432
JB
698 (let* ((old-buffer (current-buffer))
699 (standard-output standard-output)
bfa13d19 700 (mode-end (make-string (- Buffer-menu-mode-width 2) ?\s))
5e684428 701 (header (concat "CRM "
d5aacb46
SM
702 (Buffer-menu-buffer+size
703 (Buffer-menu-make-sort-button "Buffer" 2)
704 (Buffer-menu-make-sort-button "Size" 3))
705 " "
706 (Buffer-menu-make-sort-button "Mode" 4) mode-end
707 (Buffer-menu-make-sort-button "File" 5) "\n"))
f4872033 708 list desired-point)
748a336b 709 (when Buffer-menu-use-header-line
d5aacb46 710 (let ((pos 0))
fff861a2
JB
711 ;; Turn whitespace chars in the header into stretch specs so
712 ;; they work regardless of the header-line face.
713 (while (string-match "[ \t\n]+" header pos)
748a336b
SM
714 (setq pos (match-end 0))
715 (put-text-property (match-beginning 0) pos 'display
5e684428 716 ;; Assume fixed-size chars in the buffer.
6d3bce2b 717 (list 'space :align-to pos)
5e684428
SM
718 header)))
719 ;; Try to better align the one-char headers.
720 (put-text-property 0 3 'face 'fixed-pitch header)
721 ;; Add a "dummy" leading space to align the beginning of the header
722 ;; line with the beginning of the text (rather than with the left
723 ;; scrollbar or the left fringe). –-Stef
724 (setq header (concat (propertize " " 'display '(space :align-to 0))
a6a2fd5e 725 header)))
d5aacb46 726 (with-current-buffer (get-buffer-create "*Buffer List*")
08c82d4d
RS
727 (setq buffer-read-only nil)
728 (erase-buffer)
729 (setq standard-output (current-buffer))
bc7bb432 730 (unless Buffer-menu-use-header-line
fff861a2 731 ;; Use U+2014 (EM DASH) to underline if possible, else U+002D (HYPHEN-MINUS)
5e684428
SM
732 (let ((underline (if (char-displayable-p ?—) ?— ?-)))
733 (insert header
734 (apply 'string
735 (mapcar (lambda (c)
bfa13d19 736 (if (memq c '(?\n ?\s)) c underline))
5e684428 737 header)))))
a6a2fd5e 738 ;; Collect info for every buffer we're interested in.
3ce5f932
LT
739 (dolist (buffer (or buffer-list
740 (buffer-list
741 (when Buffer-menu-use-frame-buffer-list
742 (selected-frame)))))
a6a2fd5e
JL
743 (with-current-buffer buffer
744 (let ((name (buffer-name))
745 (file buffer-file-name))
746 (unless (and (not buffer-list)
747 (or
748 ;; Don't mention internal buffers.
749 (and (string= (substring name 0 1) " ") (null file))
750 ;; Maybe don't mention buffers without files.
751 (and files-only (not file))
752 (string= name "*Buffer List*")))
753 ;; Otherwise output info.
754 (let ((mode (concat (format-mode-line mode-name nil nil buffer)
755 (if mode-line-process
756 (format-mode-line mode-line-process
757 nil nil buffer))))
758 (bits (string
bfa13d19 759 (if (eq buffer old-buffer) ?. ?\s)
a6a2fd5e
JL
760 ;; Handle readonly status. The output buffer
761 ;; is special cased to appear readonly; it is
762 ;; actually made so at a later date.
763 (if (or (eq buffer standard-output)
764 buffer-read-only)
bfa13d19 765 ?% ?\s)
a6a2fd5e 766 ;; Identify modified buffers.
bfa13d19 767 (if (buffer-modified-p) ?* ?\s)
a6a2fd5e 768 ;; Space separator.
bfa13d19 769 ?\s)))
a6a2fd5e
JL
770 (unless file
771 ;; No visited file. Check local value of
fb5614e8
EZ
772 ;; list-buffers-directory and, for Info buffers,
773 ;; Info-current-file.
774 (cond ((and (boundp 'list-buffers-directory)
775 list-buffers-directory)
776 (setq file list-buffers-directory))
777 ((eq major-mode 'Info-mode)
778 (setq file Info-current-file)
779 (cond
780 ((eq file t)
781 (setq file "*Info Directory*"))
782 ((eq file 'apropos)
783 (setq file "*Info Apropos*"))
784 ((eq file 'history)
785 (setq file "*Info History*"))
786 ((eq file 'toc)
787 (setq file "*Info TOC*"))
788 ((not (stringp file)) ;; avoid errors
789 (setq file nil))))))
a6a2fd5e
JL
790 (push (list buffer bits name (buffer-size) mode file)
791 list))))))
792 ;; Preserve the original buffer-list ordering, just in case.
793 (setq list (nreverse list))
f4872033 794 ;; Place the buffers's info in the output buffer, sorted if necessary.
bc7bb432
JB
795 (dolist (buffer
796 (if Buffer-menu-sort-column
797 (sort list
798 (if (eq Buffer-menu-sort-column 3)
799 (lambda (a b)
800 (< (nth Buffer-menu-sort-column a)
801 (nth Buffer-menu-sort-column b)))
802 (lambda (a b)
803 (string< (nth Buffer-menu-sort-column a)
804 (nth Buffer-menu-sort-column b)))))
805 list))
806 (if (eq (car buffer) old-buffer)
807 (setq desired-point (point)))
808 (insert (cadr buffer)
809 ;; Put the buffer name into a text property
810 ;; so we don't have to extract it from the text.
811 ;; This way we avoid problems with unusual buffer names.
812 (Buffer-menu-buffer+size (nth 2 buffer)
813 (int-to-string (nth 3 buffer))
814 `(buffer-name ,(nth 2 buffer)
815 buffer ,(car buffer)
6bca59a3 816 font-lock-face buffer-menu-buffer
bc7bb432
JB
817 mouse-face highlight
818 help-echo "mouse-2: select this buffer"))
819 " "
820 (if (> (length (nth 4 buffer)) Buffer-menu-mode-width)
821 (substring (nth 4 buffer) 0 Buffer-menu-mode-width)
822 (nth 4 buffer)))
823 (when (nth 5 buffer)
824 (indent-to (+ Buffer-menu-buffer-column Buffer-menu-buffer+size-width
825 Buffer-menu-mode-width 4) 1)
826 (princ (abbreviate-file-name (nth 5 buffer))))
827 (princ "\n"))
0b03ce3a 828 (Buffer-menu-mode)
bc7bb432 829 (when Buffer-menu-use-header-line
748a336b 830 (setq header-line-format header))
08c82d4d
RS
831 ;; DESIRED-POINT doesn't have to be set; it is not when the
832 ;; current buffer is not displayed for some reason.
0b03ce3a 833 (and desired-point
08c82d4d 834 (goto-char desired-point))
7b0a86ab
LT
835 (setq Buffer-menu-files-only files-only)
836 (set-buffer-modified-p nil)
08c82d4d 837 (current-buffer))))
0b03ce3a 838
f4872033 839;; arch-tag: e7dfcfc9-6cb2-46e4-bf55-8ef1936d83c6
c0274f38 840;;; buff-menu.el ends here