Update copyright to 2005 and add remark about commenting out inclusion
[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
SM
3;; Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 2000, 2001, 2002, 2003,
4;; 2004 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
EN
22;; along with GNU Emacs; see the file COPYING. If not, write to the
23;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24;; Boston, MA 02111-1307, 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
77(defface Buffer-menu-buffer-face
78 '((t (:weight bold)))
79 "Face used to highlight buffer name."
80 :group 'font-lock-highlighting-faces)
81
4f0992b3 82(defcustom Buffer-menu-buffer+size-width 26
bc7bb432
JB
83 "*How wide to jointly make the buffer name and size columns."
84 :type 'number
85 :group 'Buffer-menu)
86
4f0992b3 87(defcustom Buffer-menu-mode-width 16
bc7bb432
JB
88 "*How wide to make the mode name column."
89 :type 'number
90 :group 'Buffer-menu)
91
d5aacb46 92;; This should get updated & resorted when you click on a column heading
bc7bb432
JB
93(defvar Buffer-menu-sort-column nil
94 "*2 for sorting by buffer names. 5 for sorting by file names.
95nil for default sorting by visited order.")
96
97(defconst Buffer-menu-buffer-column 4)
e5ea316b 98
463a7342
JPW
99(defvar Buffer-menu-mode-map nil
100 "Local keymap for `Buffer-menu-mode' buffers.")
2dd96f23 101
7b0a86ab
LT
102(defvar Buffer-menu-files-only nil
103 "Non-nil if the current buffer-menu lists only file buffers.
104This variable determines whether reverting the buffer lists only
105file buffers. It affects both manual reverting and reverting by
106Auto Revert Mode.")
107
108(make-variable-buffer-local 'Buffer-menu-files-only)
109
2dd96f23
JB
110(if Buffer-menu-mode-map
111 ()
112 (setq Buffer-menu-mode-map (make-keymap))
113 (suppress-keymap Buffer-menu-mode-map t)
68e6f094 114 (define-key Buffer-menu-mode-map "q" 'quit-window)
3ed788ec 115 (define-key Buffer-menu-mode-map "v" 'Buffer-menu-select)
2dd96f23
JB
116 (define-key Buffer-menu-mode-map "2" 'Buffer-menu-2-window)
117 (define-key Buffer-menu-mode-map "1" 'Buffer-menu-1-window)
118 (define-key Buffer-menu-mode-map "f" 'Buffer-menu-this-window)
251680cf 119 (define-key Buffer-menu-mode-map "e" 'Buffer-menu-this-window)
8768da77 120 (define-key Buffer-menu-mode-map "\C-m" 'Buffer-menu-this-window)
2dd96f23 121 (define-key Buffer-menu-mode-map "o" 'Buffer-menu-other-window)
35aaf00c 122 (define-key Buffer-menu-mode-map "\C-o" 'Buffer-menu-switch-other-window)
2dd96f23
JB
123 (define-key Buffer-menu-mode-map "s" 'Buffer-menu-save)
124 (define-key Buffer-menu-mode-map "d" 'Buffer-menu-delete)
125 (define-key Buffer-menu-mode-map "k" 'Buffer-menu-delete)
126 (define-key Buffer-menu-mode-map "\C-d" 'Buffer-menu-delete-backwards)
127 (define-key Buffer-menu-mode-map "\C-k" 'Buffer-menu-delete)
128 (define-key Buffer-menu-mode-map "x" 'Buffer-menu-execute)
129 (define-key Buffer-menu-mode-map " " 'next-line)
130 (define-key Buffer-menu-mode-map "n" 'next-line)
131 (define-key Buffer-menu-mode-map "p" 'previous-line)
132 (define-key Buffer-menu-mode-map "\177" 'Buffer-menu-backup-unmark)
133 (define-key Buffer-menu-mode-map "~" 'Buffer-menu-not-modified)
134 (define-key Buffer-menu-mode-map "?" 'describe-mode)
135 (define-key Buffer-menu-mode-map "u" 'Buffer-menu-unmark)
136 (define-key Buffer-menu-mode-map "m" 'Buffer-menu-mark)
d91e2b1a
ER
137 (define-key Buffer-menu-mode-map "t" 'Buffer-menu-visit-tags-table)
138 (define-key Buffer-menu-mode-map "%" 'Buffer-menu-toggle-read-only)
36570c92 139 (define-key Buffer-menu-mode-map "b" 'Buffer-menu-bury)
0f88624e 140 (define-key Buffer-menu-mode-map "g" 'Buffer-menu-revert)
42a19c2a 141 (define-key Buffer-menu-mode-map "V" 'Buffer-menu-view)
7b0a86ab 142 (define-key Buffer-menu-mode-map "T" 'Buffer-menu-toggle-files-only)
2cf5fc7e 143 (define-key Buffer-menu-mode-map [mouse-2] 'Buffer-menu-mouse-select)
d91e2b1a 144)
2dd96f23
JB
145
146;; Buffer Menu mode is suitable only for specially formatted data.
147(put 'Buffer-menu-mode 'mode-class 'special)
148
149(defun Buffer-menu-mode ()
150 "Major mode for editing a list of buffers.
151Each line describes one of the buffers in Emacs.
152Letters do not insert themselves; instead, they are commands.
153\\<Buffer-menu-mode-map>
2cf5fc7e
RS
154\\[Buffer-menu-mouse-select] -- select buffer you click on, in place of the buffer menu.
155\\[Buffer-menu-this-window] -- select current line's buffer in place of the buffer menu.
156\\[Buffer-menu-other-window] -- select that buffer in another window,
157 so the buffer menu buffer remains visible in its window.
42a19c2a
RS
158\\[Buffer-menu-view] -- select current line's buffer, but in view-mode.
159\\[Buffer-menu-view-other-window] -- select that buffer in
160 another window, in view-mode.
2cf5fc7e
RS
161\\[Buffer-menu-switch-other-window] -- make another window display that buffer.
162\\[Buffer-menu-mark] -- mark current line's buffer to be displayed.
163\\[Buffer-menu-select] -- select current line's buffer.
164 Also show buffers marked with m, in other windows.
dc6d9681 165\\[Buffer-menu-1-window] -- select that buffer in full-frame window.
2dd96f23
JB
166\\[Buffer-menu-2-window] -- select that buffer in one window,
167 together with buffer selected before this one in another window.
2dd96f23
JB
168\\[Buffer-menu-visit-tags-table] -- visit-tags-table this buffer.
169\\[Buffer-menu-not-modified] -- clear modified-flag on that buffer.
170\\[Buffer-menu-save] -- mark that buffer to be saved, and move down.
171\\[Buffer-menu-delete] -- mark that buffer to be deleted, and move down.
172\\[Buffer-menu-delete-backwards] -- mark that buffer to be deleted, and move up.
173\\[Buffer-menu-execute] -- delete or save marked buffers.
174\\[Buffer-menu-unmark] -- remove all kinds of marks from current line.
86dbbfc2 175 With prefix argument, also move up one line.
d91e2b1a 176\\[Buffer-menu-backup-unmark] -- back up a line and remove marks.
0f88624e 177\\[Buffer-menu-toggle-read-only] -- toggle read-only status of buffer on this line.
a59faabe 178\\[Buffer-menu-revert] -- update the list of buffers.
7b0a86ab 179\\[Buffer-menu-toggle-files-only] -- toggle whether the menu displays only file buffers.
a59faabe 180\\[Buffer-menu-bury] -- bury the buffer listed on this line."
2dd96f23
JB
181 (kill-all-local-variables)
182 (use-local-map Buffer-menu-mode-map)
2dd96f23
JB
183 (setq major-mode 'Buffer-menu-mode)
184 (setq mode-name "Buffer Menu")
7b0a86ab
LT
185 (set (make-local-variable 'revert-buffer-function)
186 'Buffer-menu-revert-function)
187 (set (make-local-variable 'buffer-stale-function)
012ad4a3 188 #'(lambda (&optional noconfirm) 'fast))
823316aa
KH
189 (setq truncate-lines t)
190 (setq buffer-read-only t)
2dd96f23 191 (run-hooks 'buffer-menu-mode-hook))
710e5da8 192
5f11b513
RS
193;; This function exists so we can make the doc string of Buffer-menu-mode
194;; look nice.
0f88624e
RS
195(defun Buffer-menu-revert ()
196 "Update the list of buffers."
197 (interactive)
198 (revert-buffer))
199
710e5da8 200(defun Buffer-menu-revert-function (ignore1 ignore2)
fda73b45
LT
201 (or (eq buffer-undo-list t)
202 (setq buffer-undo-list nil))
7b0a86ab 203 ;; We can not use save-excursion here. The buffer gets erased.
bfb2dda4
DP
204 (let ((ocol (current-column))
205 (oline (progn (move-to-column 4)
206 (get-text-property (point) 'buffer)))
fda73b45
LT
207 (prop (point-min))
208 ;; do not make undo records for the reversion.
209 (buffer-undo-list t))
7b0a86ab 210 (list-buffers-noselect Buffer-menu-files-only)
bfb2dda4
DP
211 (while (setq prop (next-single-property-change prop 'buffer))
212 (when (eq (get-text-property prop 'buffer) oline)
213 (goto-char prop)
214 (move-to-column ocol)))))
7b0a86ab
LT
215
216(defun Buffer-menu-toggle-files-only (arg)
217 "Toggle whether the current buffer-menu displays only file buffers.
218With a positive ARG display only file buffers. With zero or
219negative ARG, display other buffers as well."
220 (interactive "P")
221 (setq Buffer-menu-files-only
222 (cond ((not arg) (not Buffer-menu-files-only))
223 ((> (prefix-numeric-value arg) 0) t)))
224 (revert-buffer))
225
2dd96f23 226\f
2dd96f23
JB
227(defun Buffer-menu-buffer (error-if-non-existent-p)
228 "Return buffer described by this line of buffer menu."
1b40dbed
RS
229 (let* ((where (save-excursion
230 (beginning-of-line)
231 (+ (point) Buffer-menu-buffer-column)))
601ed8a0
GM
232 (name (and (not (eobp)) (get-text-property where 'buffer-name)))
233 (buf (and (not (eobp)) (get-text-property where 'buffer))))
1b40dbed
RS
234 (if name
235 (or (get-buffer name)
601ed8a0 236 (and buf (buffer-name buf) buf)
1b40dbed
RS
237 (if error-if-non-existent-p
238 (error "No buffer named `%s'" name)
239 nil))
601ed8a0 240 (or (and buf (buffer-name buf) buf)
463a7342
JPW
241 (if error-if-non-existent-p
242 (error "No buffer on this line")
601ed8a0 243 nil)))))
2dd96f23 244\f
06b1a5ef 245(defun buffer-menu (&optional arg)
2dd96f23
JB
246 "Make a menu of buffers so you can save, delete or select them.
247With argument, show only buffers that are visiting files.
248Type ? after invocation to get help on commands available.
6a0d92d3
RS
249Type q to remove the buffer menu from the display.
250
251The first column shows `>' for a buffer you have
252marked to be displayed, `D' for one you have marked for
253deletion, and `.' for the current buffer.
254
bc7bb432
JB
255The C column has a `.' for the buffer from which you came.
256The R column has a `%' if the buffer is read-only.
6a0d92d3
RS
257The M column has a `*' if it is modified,
258or `S' if you have marked it for saving.
6a0d92d3
RS
259After this come the buffer name, its size in characters,
260its major mode, and the visited file name (if any)."
08c82d4d
RS
261 (interactive "P")
262;;; (setq Buffer-menu-window-config (current-window-configuration))
263 (switch-to-buffer (list-buffers-noselect arg))
264 (message
265 "Commands: d, s, x, u; f, o, 1, 2, m, v; ~, %%; q to quit; ? for help."))
266
267(defun buffer-menu-other-window (&optional arg)
268 "Display a list of buffers in another window.
269With the buffer list buffer, you can save, delete or select the buffers.
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.
273For more information, see the function `buffer-menu'."
2dd96f23 274 (interactive "P")
3ed788ec 275;;; (setq Buffer-menu-window-config (current-window-configuration))
08c82d4d 276 (switch-to-buffer-other-window (list-buffers-noselect arg))
2dd96f23 277 (message
3ed788ec
RS
278 "Commands: d, s, x, u; f, o, 1, 2, m, v; ~, %%; q to quit; ? for help."))
279
bc7bb432
JB
280(defun Buffer-menu-no-header ()
281 (beginning-of-line)
282 (if (or Buffer-menu-use-header-line
283 (not (eq (char-after) ?C)))
284 t
285 (ding)
286 (forward-line 1)
287 nil))
288
2dd96f23
JB
289(defun Buffer-menu-mark ()
290 "Mark buffer on this line for being displayed by \\<Buffer-menu-mode-map>\\[Buffer-menu-select] command."
291 (interactive)
bc7bb432 292 (when (Buffer-menu-no-header)
2dd96f23
JB
293 (let ((buffer-read-only nil))
294 (delete-char 1)
295 (insert ?>)
296 (forward-line 1))))
297
86dbbfc2
ER
298(defun Buffer-menu-unmark (&optional backup)
299 "Cancel all requested operations on buffer on this line and move down.
300Optional ARG means move up."
301 (interactive "P")
bc7bb432 302 (when (Buffer-menu-no-header)
2dd96f23
JB
303 (let* ((buf (Buffer-menu-buffer t))
304 (mod (buffer-modified-p buf))
305 (readonly (save-excursion (set-buffer buf) buffer-read-only))
306 (buffer-read-only nil))
307 (delete-char 3)
bc7bb432 308 (insert (if readonly (if mod " %*" " % ") (if mod " *" " ")))))
86dbbfc2 309 (forward-line (if backup -1 1)))
2dd96f23
JB
310
311(defun Buffer-menu-backup-unmark ()
312 "Move up and cancel all requested operations on buffer on line above."
313 (interactive)
314 (forward-line -1)
315 (Buffer-menu-unmark)
316 (forward-line -1))
317
77a43e01
RS
318(defun Buffer-menu-delete (&optional arg)
319 "Mark buffer on this line to be deleted by \\<Buffer-menu-mode-map>\\[Buffer-menu-execute] command.
320Prefix arg is how many buffers to delete.
321Negative arg means delete backwards."
322 (interactive "p")
bc7bb432 323 (when (Buffer-menu-no-header)
2dd96f23 324 (let ((buffer-read-only nil))
77a43e01
RS
325 (if (or (null arg) (= arg 0))
326 (setq arg 1))
327 (while (> arg 0)
328 (delete-char 1)
329 (insert ?D)
330 (forward-line 1)
331 (setq arg (1- arg)))
bc7bb432
JB
332 (while (and (< arg 0)
333 (Buffer-menu-no-header))
77a43e01
RS
334 (delete-char 1)
335 (insert ?D)
336 (forward-line -1)
337 (setq arg (1+ arg))))))
338
339(defun Buffer-menu-delete-backwards (&optional arg)
2dd96f23 340 "Mark buffer on this line to be deleted by \\<Buffer-menu-mode-map>\\[Buffer-menu-execute] command
77a43e01
RS
341and then move up one line. Prefix arg means move that many lines."
342 (interactive "p")
bc7bb432 343 (Buffer-menu-delete (- (or arg 1))))
2dd96f23
JB
344
345(defun Buffer-menu-save ()
346 "Mark buffer on this line to be saved by \\<Buffer-menu-mode-map>\\[Buffer-menu-execute] command."
347 (interactive)
bc7bb432 348 (when (Buffer-menu-no-header)
2dd96f23 349 (let ((buffer-read-only nil))
bc7bb432 350 (forward-char 2)
2dd96f23
JB
351 (delete-char 1)
352 (insert ?S)
353 (forward-line 1))))
354
a8ce00dc 355(defun Buffer-menu-not-modified (&optional arg)
2dd96f23 356 "Mark buffer on this line as unmodified (no changes to save)."
a8ce00dc 357 (interactive "P")
2dd96f23
JB
358 (save-excursion
359 (set-buffer (Buffer-menu-buffer t))
a8ce00dc 360 (set-buffer-modified-p arg))
2dd96f23
JB
361 (save-excursion
362 (beginning-of-line)
bc7bb432
JB
363 (forward-char 2)
364 (if (= (char-after) (if arg ? ?*))
2dd96f23
JB
365 (let ((buffer-read-only nil))
366 (delete-char 1)
a8ce00dc 367 (insert (if arg ?* ? ))))))
2dd96f23 368
bfb2dda4
DP
369(defun Buffer-menu-beginning ()
370 (goto-char (point-min))
371 (unless Buffer-menu-use-header-line
372 (forward-line)))
373
2dd96f23
JB
374(defun Buffer-menu-execute ()
375 "Save and/or delete buffers marked with \\<Buffer-menu-mode-map>\\[Buffer-menu-save] or \\<Buffer-menu-mode-map>\\[Buffer-menu-delete] commands."
376 (interactive)
377 (save-excursion
bfb2dda4 378 (Buffer-menu-beginning)
bc7bb432 379 (while (re-search-forward "^..S" nil t)
2dd96f23
JB
380 (let ((modp nil))
381 (save-excursion
382 (set-buffer (Buffer-menu-buffer t))
383 (save-buffer)
384 (setq modp (buffer-modified-p)))
385 (let ((buffer-read-only nil))
386 (delete-char -1)
387 (insert (if modp ?* ? ))))))
388 (save-excursion
bfb2dda4 389 (Buffer-menu-beginning)
2dd96f23
JB
390 (let ((buff-menu-buffer (current-buffer))
391 (buffer-read-only nil))
4f1ab860 392 (while (re-search-forward "^D" nil t)
2dd96f23
JB
393 (forward-char -1)
394 (let ((buf (Buffer-menu-buffer nil)))
395 (or (eq buf nil)
396 (eq buf buff-menu-buffer)
601ed8a0
GM
397 (save-excursion (kill-buffer buf)))
398 (if (and buf (buffer-name buf))
2dd96f23
JB
399 (progn (delete-char 1)
400 (insert ? ))
401 (delete-region (point) (progn (forward-line 1) (point)))
4f1ab860
DL
402 (unless (bobp)
403 (forward-char -1))))))))
2dd96f23
JB
404
405(defun Buffer-menu-select ()
406 "Select this line's buffer; also display buffers marked with `>'.
08c82d4d
RS
407You can mark buffers with the \\<Buffer-menu-mode-map>\\[Buffer-menu-mark] command.
408This command deletes and replaces all the previously existing windows
409in the selected frame."
2dd96f23
JB
410 (interactive)
411 (let ((buff (Buffer-menu-buffer t))
10e1dad9 412 (menu (current-buffer))
2dd96f23
JB
413 (others ())
414 tem)
bfb2dda4 415 (Buffer-menu-beginning)
a9fb4690 416 (while (re-search-forward "^>" nil t)
2dd96f23
JB
417 (setq tem (Buffer-menu-buffer t))
418 (let ((buffer-read-only nil))
419 (delete-char -1)
420 (insert ?\ ))
421 (or (eq tem buff) (memq tem others) (setq others (cons tem others))))
422 (setq others (nreverse others)
dc6d9681 423 tem (/ (1- (frame-height)) (1+ (length others))))
2dd96f23
JB
424 (delete-other-windows)
425 (switch-to-buffer buff)
426 (or (eq menu buff)
427 (bury-buffer menu))
86dbbfc2
ER
428 (if (equal (length others) 0)
429 (progn
3ed788ec
RS
430;;; ;; Restore previous window configuration before displaying
431;;; ;; selected buffers.
432;;; (if Buffer-menu-window-config
433;;; (progn
434;;; (set-window-configuration Buffer-menu-window-config)
435;;; (setq Buffer-menu-window-config nil)))
86dbbfc2
ER
436 (switch-to-buffer buff))
437 (while others
438 (split-window nil tem)
439 (other-window 1)
440 (switch-to-buffer (car others))
441 (setq others (cdr others)))
442 (other-window 1) ;back to the beginning!
443)))
444
08c82d4d 445
2dd96f23
JB
446\f
447(defun Buffer-menu-visit-tags-table ()
448 "Visit the tags table in the buffer on this line. See `visit-tags-table'."
449 (interactive)
450 (let ((file (buffer-file-name (Buffer-menu-buffer t))))
451 (if file
452 (visit-tags-table file)
453 (error "Specified buffer has no file"))))
454
455(defun Buffer-menu-1-window ()
dc6d9681 456 "Select this line's buffer, alone, in full frame."
2dd96f23
JB
457 (interactive)
458 (switch-to-buffer (Buffer-menu-buffer t))
459 (bury-buffer (other-buffer))
460 (delete-other-windows))
461
2cf5fc7e
RS
462(defun Buffer-menu-mouse-select (event)
463 "Select the buffer whose line you click on."
464 (interactive "e")
465 (let (buffer)
466 (save-excursion
467 (set-buffer (window-buffer (posn-window (event-end event))))
468 (save-excursion
469 (goto-char (posn-point (event-end event)))
470 (setq buffer (Buffer-menu-buffer t))))
471 (select-window (posn-window (event-end event)))
d953b88c
RS
472 (if (and (window-dedicated-p (selected-window))
473 (eq (selected-window) (frame-root-window)))
474 (switch-to-buffer-other-frame buffer)
475 (switch-to-buffer buffer))))
2cf5fc7e 476
2dd96f23
JB
477(defun Buffer-menu-this-window ()
478 "Select this line's buffer in this window."
479 (interactive)
480 (switch-to-buffer (Buffer-menu-buffer t)))
481
482(defun Buffer-menu-other-window ()
483 "Select this line's buffer in other window, leaving buffer menu visible."
484 (interactive)
485 (switch-to-buffer-other-window (Buffer-menu-buffer t)))
486
35aaf00c
RM
487(defun Buffer-menu-switch-other-window ()
488 "Make the other window select this line's buffer.
489The current window remains selected."
490 (interactive)
a0e4e275
JL
491 (let ((pop-up-windows t)
492 same-window-buffer-names
493 same-window-regexps)
494 (display-buffer (Buffer-menu-buffer t))))
35aaf00c 495
2dd96f23
JB
496(defun Buffer-menu-2-window ()
497 "Select this line's buffer, with previous buffer in second window."
498 (interactive)
499 (let ((buff (Buffer-menu-buffer t))
500 (menu (current-buffer))
a0e4e275
JL
501 (pop-up-windows t)
502 same-window-buffer-names
503 same-window-regexps)
86dbbfc2 504 (delete-other-windows)
2dd96f23
JB
505 (switch-to-buffer (other-buffer))
506 (pop-to-buffer buff)
507 (bury-buffer menu)))
c0274f38 508
d91e2b1a 509(defun Buffer-menu-toggle-read-only ()
f450965c 510 "Toggle read-only status of buffer on this line, perhaps via version control."
d91e2b1a
ER
511 (interactive)
512 (let (char)
513 (save-excursion
514 (set-buffer (Buffer-menu-buffer t))
f450965c 515 (vc-toggle-read-only)
d91e2b1a
ER
516 (setq char (if buffer-read-only ?% ? )))
517 (save-excursion
518 (beginning-of-line)
bc7bb432 519 (forward-char 1)
d91e2b1a
ER
520 (if (/= (following-char) char)
521 (let (buffer-read-only)
522 (delete-char 1)
523 (insert char))))))
524
36570c92
RS
525(defun Buffer-menu-bury ()
526 "Bury the buffer listed on this line."
527 (interactive)
bc7bb432 528 (when (Buffer-menu-no-header)
a59faabe
RS
529 (save-excursion
530 (beginning-of-line)
531 (bury-buffer (Buffer-menu-buffer t))
532 (let ((line (buffer-substring (point) (progn (forward-line 1) (point))))
533 (buffer-read-only nil))
534 (delete-region (point) (progn (forward-line -1) (point)))
535 (goto-char (point-max))
536 (insert line))
537 (message "Buried buffer moved to the end"))))
42a19c2a
RS
538
539
540(defun Buffer-menu-view ()
541 "View this line's buffer in View mode."
542 (interactive)
543 (view-buffer (Buffer-menu-buffer t)))
544
545
546(defun Buffer-menu-view-other-window ()
547 "View this line's buffer in View mode in another window."
548 (interactive)
549 (view-buffer-other-window (Buffer-menu-buffer t)))
0b03ce3a
RS
550\f
551
552(define-key ctl-x-map "\C-b" 'list-buffers)
553
554(defun list-buffers (&optional files-only)
555 "Display a list of names of existing buffers.
556The list is displayed in a buffer named `*Buffer List*'.
557Note that buffers with names starting with spaces are omitted.
558Non-null optional arg FILES-ONLY means mention only file buffers.
559
6a0d92d3 560For more information, see the function `buffer-menu'."
0b03ce3a 561 (interactive "P")
08c82d4d
RS
562 (display-buffer (list-buffers-noselect files-only)))
563
bc7bb432
JB
564(defun Buffer-menu-buffer+size (name size &optional name-props size-props)
565 (if (> (+ (length name) (length size) 2) Buffer-menu-buffer+size-width)
566 (setq name
567 (if (string-match "<[0-9]+>$" name)
568 (concat (substring name 0
569 (- Buffer-menu-buffer+size-width
570 (max (length size) 3)
571 (match-end 0)
572 (- (match-beginning 0))
573 2))
574 ":" ; narrow ellipsis
575 (match-string 0 name))
576 (concat (substring name 0
577 (- Buffer-menu-buffer+size-width
578 (max (length size) 3)
579 2))
ee5861c8
AS
580 ":"))) ; narrow ellipsis
581 ;; Don't put properties on (buffer-name).
582 (setq name (copy-sequence name)))
bc7bb432
JB
583 (add-text-properties 0 (length name) name-props name)
584 (add-text-properties 0 (length size) size-props size)
585 (concat name
586 (make-string (- Buffer-menu-buffer+size-width
587 (length name)
588 (length size))
589 ? )
590 size))
591
d5aacb46
SM
592(defun Buffer-menu-sort (column)
593 "Sort the buffer menu by COLUMN."
594 (interactive "P")
595 (when column
596 (setq column (prefix-numeric-value column))
597 (if (< column 2) (setq column 2))
598 (if (> column 5) (setq column 5)))
599 (setq Buffer-menu-sort-column column)
bfb2dda4
DP
600 (let (buffer-read-only l buf m1 m2)
601 (save-excursion
602 (Buffer-menu-beginning)
603 (while (not (eobp))
604 (when (buffer-live-p (setq buf (get-text-property (+ (point) 4) 'buffer)))
605 (setq m1 (char-after)
606 m1 (if (memq m1 '(?> ?D)) m1)
607 m2 (char-after (+ (point) 2))
608 m2 (if (eq m2 ?S) m2))
609 (if (or m1 m2)
610 (push (list buf m1 m2) l)))
611 (forward-line)))
612 (Buffer-menu-revert)
613 (setq buffer-read-only)
614 (save-excursion
615 (Buffer-menu-beginning)
616 (while (not (eobp))
617 (when (setq buf (assq (get-text-property (+ (point) 4) 'buffer) l))
618 (setq m1 (cadr buf)
619 m2 (cadr (cdr buf)))
620 (when m1
621 (delete-char 1)
622 (insert m1)
623 (backward-char 1))
624 (when m2
625 (forward-char 2)
626 (delete-char 1)
627 (insert m2)))
628 (forward-line)))))
d5aacb46
SM
629
630(defun Buffer-menu-make-sort-button (name column)
631 (if (equal column Buffer-menu-sort-column) (setq column nil))
632 (propertize name
633 'help-echo (if column
634 (concat "mouse-2: sort by " (downcase name))
635 "mouse-2: sort by visited order")
636 'mouse-face 'highlight
637 'keymap (let ((map (make-sparse-keymap)))
638 (define-key map [header-line mouse-2]
c8d8f322
DP
639 `(lambda (e)
640 (interactive "e")
589f233e
DP
641 (save-window-excursion
642 (if e (mouse-select-window e))
643 (Buffer-menu-sort ,column))))
d5aacb46
SM
644 map)))
645
61617913 646(defun list-buffers-noselect (&optional files-only buffer-list)
08c82d4d
RS
647 "Create and return a buffer with a list of names of existing buffers.
648The buffer is named `*Buffer List*'.
649Note that buffers with names starting with spaces are omitted.
650Non-null optional arg FILES-ONLY means mention only file buffers.
651
61617913
RS
652If BUFFER-LIST is non-nil, it should be a list of buffers;
653it means list those buffers and no others.
654
6a0d92d3 655For more information, see the function `buffer-menu'."
bc7bb432
JB
656 (let* ((old-buffer (current-buffer))
657 (standard-output standard-output)
658 (mode-end (make-string (- Buffer-menu-mode-width 2) ? ))
5e684428 659 (header (concat "CRM "
d5aacb46
SM
660 (Buffer-menu-buffer+size
661 (Buffer-menu-make-sort-button "Buffer" 2)
662 (Buffer-menu-make-sort-button "Size" 3))
663 " "
664 (Buffer-menu-make-sort-button "Mode" 4) mode-end
665 (Buffer-menu-make-sort-button "File" 5) "\n"))
f4872033 666 list desired-point)
748a336b 667 (when Buffer-menu-use-header-line
d5aacb46 668 (let ((pos 0))
748a336b
SM
669 ;; Turn spaces in the header into stretch specs so they work
670 ;; regardless of the header-line face.
671 (while (string-match "[ \t]+" header pos)
672 (setq pos (match-end 0))
673 (put-text-property (match-beginning 0) pos 'display
5e684428 674 ;; Assume fixed-size chars in the buffer.
6d3bce2b 675 (list 'space :align-to pos)
5e684428
SM
676 header)))
677 ;; Try to better align the one-char headers.
678 (put-text-property 0 3 'face 'fixed-pitch header)
679 ;; Add a "dummy" leading space to align the beginning of the header
680 ;; line with the beginning of the text (rather than with the left
681 ;; scrollbar or the left fringe). –-Stef
682 (setq header (concat (propertize " " 'display '(space :align-to 0))
a6a2fd5e 683 header)))
d5aacb46 684 (with-current-buffer (get-buffer-create "*Buffer List*")
08c82d4d
RS
685 (setq buffer-read-only nil)
686 (erase-buffer)
687 (setq standard-output (current-buffer))
bc7bb432 688 (unless Buffer-menu-use-header-line
5e684428
SM
689 (let ((underline (if (char-displayable-p ?—) ?— ?-)))
690 (insert header
691 (apply 'string
692 (mapcar (lambda (c)
693 (if (memq c '(?\n ?\ )) c underline))
694 header)))))
a6a2fd5e
JL
695 ;; Collect info for every buffer we're interested in.
696 (dolist (buffer (or buffer-list (buffer-list)))
697 (with-current-buffer buffer
698 (let ((name (buffer-name))
699 (file buffer-file-name))
700 (unless (and (not buffer-list)
701 (or
702 ;; Don't mention internal buffers.
703 (and (string= (substring name 0 1) " ") (null file))
704 ;; Maybe don't mention buffers without files.
705 (and files-only (not file))
706 (string= name "*Buffer List*")))
707 ;; Otherwise output info.
708 (let ((mode (concat (format-mode-line mode-name nil nil buffer)
709 (if mode-line-process
710 (format-mode-line mode-line-process
711 nil nil buffer))))
712 (bits (string
713 (if (eq buffer old-buffer) ?. ?\ )
714 ;; Handle readonly status. The output buffer
715 ;; is special cased to appear readonly; it is
716 ;; actually made so at a later date.
717 (if (or (eq buffer standard-output)
718 buffer-read-only)
719 ?% ?\ )
720 ;; Identify modified buffers.
721 (if (buffer-modified-p) ?* ?\ )
722 ;; Space separator.
723 ?\ )))
724 (unless file
725 ;; No visited file. Check local value of
726 ;; list-buffers-directory.
727 (when (and (boundp 'list-buffers-directory)
728 list-buffers-directory)
729 (setq file list-buffers-directory)))
730 (push (list buffer bits name (buffer-size) mode file)
731 list))))))
732 ;; Preserve the original buffer-list ordering, just in case.
733 (setq list (nreverse list))
f4872033 734 ;; Place the buffers's info in the output buffer, sorted if necessary.
bc7bb432
JB
735 (dolist (buffer
736 (if Buffer-menu-sort-column
737 (sort list
738 (if (eq Buffer-menu-sort-column 3)
739 (lambda (a b)
740 (< (nth Buffer-menu-sort-column a)
741 (nth Buffer-menu-sort-column b)))
742 (lambda (a b)
743 (string< (nth Buffer-menu-sort-column a)
744 (nth Buffer-menu-sort-column b)))))
745 list))
746 (if (eq (car buffer) old-buffer)
747 (setq desired-point (point)))
748 (insert (cadr buffer)
749 ;; Put the buffer name into a text property
750 ;; so we don't have to extract it from the text.
751 ;; This way we avoid problems with unusual buffer names.
752 (Buffer-menu-buffer+size (nth 2 buffer)
753 (int-to-string (nth 3 buffer))
754 `(buffer-name ,(nth 2 buffer)
755 buffer ,(car buffer)
756 face Buffer-menu-buffer-face
757 mouse-face highlight
758 help-echo "mouse-2: select this buffer"))
759 " "
760 (if (> (length (nth 4 buffer)) Buffer-menu-mode-width)
761 (substring (nth 4 buffer) 0 Buffer-menu-mode-width)
762 (nth 4 buffer)))
763 (when (nth 5 buffer)
764 (indent-to (+ Buffer-menu-buffer-column Buffer-menu-buffer+size-width
765 Buffer-menu-mode-width 4) 1)
766 (princ (abbreviate-file-name (nth 5 buffer))))
767 (princ "\n"))
0b03ce3a 768 (Buffer-menu-mode)
bc7bb432 769 (when Buffer-menu-use-header-line
748a336b 770 (setq header-line-format header))
08c82d4d
RS
771 ;; DESIRED-POINT doesn't have to be set; it is not when the
772 ;; current buffer is not displayed for some reason.
0b03ce3a 773 (and desired-point
08c82d4d 774 (goto-char desired-point))
7b0a86ab
LT
775 (setq Buffer-menu-files-only files-only)
776 (set-buffer-modified-p nil)
08c82d4d 777 (current-buffer))))
0b03ce3a 778
f4872033 779;; arch-tag: e7dfcfc9-6cb2-46e4-bf55-8ef1936d83c6
c0274f38 780;;; buff-menu.el ends here