compare symbol names with `equal'
[bpt/emacs.git] / lisp / buff-menu.el
CommitLineData
e5f9458f 1;;; buff-menu.el --- Interface for viewing and manipulating buffers
c0274f38 2
ba318903 3;; Copyright (C) 1985-1987, 1993-1995, 2000-2014 Free Software
ab422c4d 4;; Foundation, Inc.
2dd96f23 5
34dc21db 6;; Maintainer: emacs-devel@gnu.org
6d6c3f84 7;; Keywords: convenience
bd78fa1d 8;; Package: emacs
9750e079 9
2dd96f23
JB
10;; This file is part of GNU Emacs.
11
eb3fa2cf 12;; GNU Emacs is free software: you can redistribute it and/or modify
2dd96f23 13;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
2dd96f23
JB
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
eb3fa2cf 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
2dd96f23 24
e41b2db1
ER
25;;; Commentary:
26
e5f9458f
CY
27;; The Buffer Menu is used to view, edit, delete, or change attributes
28;; of buffers. The entry points are C-x C-b (`list-buffers') and
29;; M-x buffer-menu.
e41b2db1 30
5de9bdab 31;;; Code:
10e1dad9 32
e5f9458f 33(require 'tabulated-list)
2dd96f23 34
bc7bb432
JB
35(defgroup Buffer-menu nil
36 "Show a menu of all buffers in a buffer."
37 :group 'tools
38 :group 'convenience)
39
40(defcustom Buffer-menu-use-header-line t
e5f9458f 41 "If non-nil, use the header line to display Buffer Menu column titles."
bc7bb432
JB
42 :type 'boolean
43 :group 'Buffer-menu)
44
d247d0fe 45(defface buffer-menu-buffer
bc7bb432 46 '((t (:weight bold)))
e5f9458f 47 "Face for buffer names in the Buffer Menu."
2a8f2d4c 48 :group 'Buffer-menu)
d247d0fe 49(put 'Buffer-menu-buffer 'face-alias 'buffer-menu-buffer)
bc7bb432 50
e5f9458f
CY
51(defcustom Buffer-menu-buffer+size-width nil
52 "Combined width of buffer name and size columns in Buffer Menu.
ac59c2f6
CY
53If nil, use `Buffer-menu-name-width' and `Buffer-menu-size-width'.
54
55If non-nil, the value of `Buffer-menu-name-width' is overridden;
56the name column is assigned width `Buffer-menu-buffer+size-width'
57minus `Buffer-menu-size-width'. This use is deprecated."
58b1ae1e 58 :type '(choice (const nil) number)
e5f9458f 59 :group 'Buffer-menu
2a1e2476 60 :version "24.3")
e5f9458f
CY
61
62(make-obsolete-variable 'Buffer-menu-buffer+size-width
58b1ae1e 63 "use `Buffer-menu-name-width' and `Buffer-menu-size-width' instead."
2a1e2476 64 "24.3")
e5f9458f
CY
65
66(defcustom Buffer-menu-name-width 19
b06eeda8 67 "Width of buffer name column in the Buffer Menu."
e5f9458f
CY
68 :type 'number
69 :group 'Buffer-menu
2a1e2476 70 :version "24.3")
e5f9458f
CY
71
72(defcustom Buffer-menu-size-width 7
b06eeda8 73 "Width of buffer size column in the Buffer Menu."
e5f9458f
CY
74 :type 'number
75 :group 'Buffer-menu
2a1e2476 76 :version "24.3")
bc7bb432 77
4f0992b3 78(defcustom Buffer-menu-mode-width 16
e5f9458f 79 "Width of mode name column in the Buffer Menu."
bc7bb432
JB
80 :type 'number
81 :group 'Buffer-menu)
82
3ce5f932
LT
83(defcustom Buffer-menu-use-frame-buffer-list t
84 "If non-nil, the Buffer Menu uses the selected frame's buffer list.
85Buffers that were never selected in that frame are listed at the end.
86If the value is nil, the Buffer Menu uses the global buffer list.
87This variable matters if the Buffer Menu is sorted by visited order,
88as it is by default."
89 :type 'boolean
90 :group 'Buffer-menu
91 :version "22.1")
92
7b0a86ab 93(defvar Buffer-menu-files-only nil
e5f9458f
CY
94 "Non-nil if the current Buffer Menu lists only file buffers.
95This is set by the prefix argument to `buffer-menu' and related
96commands.")
392225ee
JB
97(make-variable-buffer-local 'Buffer-menu-files-only)
98
e5f9458f
CY
99(defvar Info-current-file) ; from info.el
100(defvar Info-current-node) ; from info.el
fb5614e8 101
392225ee 102(defvar Buffer-menu-mode-map
e5f9458f 103 (let ((map (make-sparse-keymap))
6a6baf11 104 (menu-map (make-sparse-keymap)))
e5f9458f 105 (set-keymap-parent map tabulated-list-mode-map)
392225ee
JB
106 (define-key map "v" 'Buffer-menu-select)
107 (define-key map "2" 'Buffer-menu-2-window)
108 (define-key map "1" 'Buffer-menu-1-window)
109 (define-key map "f" 'Buffer-menu-this-window)
110 (define-key map "e" 'Buffer-menu-this-window)
111 (define-key map "\C-m" 'Buffer-menu-this-window)
112 (define-key map "o" 'Buffer-menu-other-window)
113 (define-key map "\C-o" 'Buffer-menu-switch-other-window)
114 (define-key map "s" 'Buffer-menu-save)
115 (define-key map "d" 'Buffer-menu-delete)
116 (define-key map "k" 'Buffer-menu-delete)
392225ee 117 (define-key map "\C-k" 'Buffer-menu-delete)
e5f9458f 118 (define-key map "\C-d" 'Buffer-menu-delete-backwards)
392225ee
JB
119 (define-key map "x" 'Buffer-menu-execute)
120 (define-key map " " 'next-line)
392225ee
JB
121 (define-key map "\177" 'Buffer-menu-backup-unmark)
122 (define-key map "~" 'Buffer-menu-not-modified)
392225ee
JB
123 (define-key map "u" 'Buffer-menu-unmark)
124 (define-key map "m" 'Buffer-menu-mark)
125 (define-key map "t" 'Buffer-menu-visit-tags-table)
126 (define-key map "%" 'Buffer-menu-toggle-read-only)
127 (define-key map "b" 'Buffer-menu-bury)
392225ee
JB
128 (define-key map "V" 'Buffer-menu-view)
129 (define-key map "T" 'Buffer-menu-toggle-files-only)
9cda680d
JL
130 (define-key map (kbd "M-s a C-s") 'Buffer-menu-isearch-buffers)
131 (define-key map (kbd "M-s a M-C-s") 'Buffer-menu-isearch-buffers-regexp)
924494f4 132 (define-key map (kbd "M-s a C-o") 'Buffer-menu-multi-occur)
e5f9458f 133
0d909786
CY
134 (define-key map [mouse-2] 'Buffer-menu-mouse-select)
135 (define-key map [follow-link] 'mouse-face)
136
c9753fb4 137 (define-key map [menu-bar Buffer-menu-mode] (cons (purecopy "Buffer-Menu") menu-map))
1ec4b7b2
SM
138 (bindings--define-key menu-map [quit]
139 '(menu-item "Quit" quit-window
140 :help "Remove the buffer menu from the display"))
141 (bindings--define-key menu-map [rev]
142 '(menu-item "Refresh" revert-buffer
143 :help "Refresh the *Buffer List* buffer contents"))
144 (bindings--define-key menu-map [s0] menu-bar-separator)
145 (bindings--define-key menu-map [tf]
146 '(menu-item "Show Only File Buffers" Buffer-menu-toggle-files-only
6a6baf11 147 :button (:toggle . Buffer-menu-files-only)
1ec4b7b2
SM
148 :help "Toggle whether the current buffer-menu displays only file buffers"))
149 (bindings--define-key menu-map [s1] menu-bar-separator)
6a6baf11 150 ;; FIXME: The "Select" entries could use better names...
1ec4b7b2
SM
151 (bindings--define-key menu-map [sel]
152 '(menu-item "Select Marked" Buffer-menu-select
153 :help "Select this line's buffer; also display buffers marked with `>'"))
154 (bindings--define-key menu-map [bm2]
155 '(menu-item "Select Two" Buffer-menu-2-window
156 :help "Select this line's buffer, with previous buffer in second window"))
157 (bindings--define-key menu-map [bm1]
158 '(menu-item "Select Current" Buffer-menu-1-window
159 :help "Select this line's buffer, alone, in full frame"))
160 (bindings--define-key menu-map [ow]
161 '(menu-item "Select in Other Window" Buffer-menu-other-window
162 :help "Select this line's buffer in other window, leaving buffer menu visible"))
163 (bindings--define-key menu-map [tw]
164 '(menu-item "Select in Current Window" Buffer-menu-this-window
165 :help "Select this line's buffer in this window"))
166 (bindings--define-key menu-map [s2] menu-bar-separator)
167 (bindings--define-key menu-map [is]
168 '(menu-item "Regexp Isearch Marked Buffers..." Buffer-menu-isearch-buffers-regexp
169 :help "Search for a regexp through all marked buffers using Isearch"))
170 (bindings--define-key menu-map [ir]
171 '(menu-item "Isearch Marked Buffers..." Buffer-menu-isearch-buffers
172 :help "Search for a string through all marked buffers using Isearch"))
924494f4
MM
173 (bindings--define-key menu-map [mo]
174 '(menu-item "Multi Occur Marked Buffers..." Buffer-menu-multi-occur
175 :help "Show lines matching a regexp in marked buffers using Occur"))
1ec4b7b2
SM
176 (bindings--define-key menu-map [s3] menu-bar-separator)
177 (bindings--define-key menu-map [by]
178 '(menu-item "Bury" Buffer-menu-bury
179 :help "Bury the buffer listed on this line"))
180 (bindings--define-key menu-map [vt]
181 '(menu-item "Set Unmodified" Buffer-menu-not-modified
182 :help "Mark buffer on this line as unmodified (no changes to save)"))
183 (bindings--define-key menu-map [ex]
184 '(menu-item "Execute" Buffer-menu-execute
185 :help "Save and/or delete buffers marked with s or k commands"))
186 (bindings--define-key menu-map [s4] menu-bar-separator)
187 (bindings--define-key menu-map [delb]
188 '(menu-item "Mark for Delete and Move Backwards" Buffer-menu-delete-backwards
189 :help "Mark buffer on this line to be deleted by x command and move up one line"))
190 (bindings--define-key menu-map [del]
191 '(menu-item "Mark for Delete" Buffer-menu-delete
192 :help "Mark buffer on this line to be deleted by x command"))
193
194 (bindings--define-key menu-map [sv]
195 '(menu-item "Mark for Save" Buffer-menu-save
196 :help "Mark buffer on this line to be saved by x command"))
197 (bindings--define-key menu-map [umk]
198 '(menu-item "Unmark" Buffer-menu-unmark
199 :help "Cancel all requested operations on buffer on this line and move down"))
200 (bindings--define-key menu-map [mk]
201 '(menu-item "Mark" Buffer-menu-mark
202 :help "Mark buffer on this line for being displayed by v command"))
392225ee
JB
203 map)
204 "Local keymap for `Buffer-menu-mode' buffers.")
2dd96f23 205
e5bd0a28
SM
206(define-obsolete-variable-alias 'buffer-menu-mode-hook
207 'Buffer-menu-mode-hook "23.1")
208
e5f9458f
CY
209(define-derived-mode Buffer-menu-mode tabulated-list-mode "Buffer Menu"
210 "Major mode for Buffer Menu buffers.
a5bf43ba
CY
211The Buffer Menu is invoked by the commands \\[list-buffers],
212\\[buffer-menu], and \\[buffer-menu-other-window].
213See `buffer-menu' for a description of its contents.
e5f9458f 214
a5bf43ba 215In Buffer Menu mode, the following commands are defined:
e5f9458f
CY
216\\<Buffer-menu-mode-map>
217\\[quit-window] Remove the Buffer Menu from the display.
218\\[Buffer-menu-this-window] Select current line's buffer in place of the buffer menu.
219\\[Buffer-menu-other-window] Select that buffer in another window,
220 so the Buffer Menu remains visible in its window.
221\\[Buffer-menu-view] Select current line's buffer, in View mode.
222\\[Buffer-menu-view-other-window] Select that buffer in
223 another window, in view-mode.
224\\[Buffer-menu-switch-other-window] Make another window display that buffer.
225\\[Buffer-menu-mark] Mark current line's buffer to be displayed.
226\\[Buffer-menu-select] Select current line's buffer.
227 Also show buffers marked with m, in other windows.
228\\[Buffer-menu-1-window] Select that buffer in full-frame window.
229\\[Buffer-menu-2-window] Select that buffer in one window, together with the
230 buffer selected before this one in another window.
a5bf43ba 231\\[Buffer-menu-isearch-buffers] Incremental search in the marked buffers.
e5f9458f 232\\[Buffer-menu-isearch-buffers-regexp] Isearch for regexp in the marked buffers.
924494f4 233\\[Buffer-menu-multi-occur] Show lines matching regexp in the marked buffers.
e5f9458f
CY
234\\[Buffer-menu-visit-tags-table] visit-tags-table this buffer.
235\\[Buffer-menu-not-modified] Clear modified-flag on that buffer.
236\\[Buffer-menu-save] Mark that buffer to be saved, and move down.
237\\[Buffer-menu-delete] Mark that buffer to be deleted, and move down.
238\\[Buffer-menu-delete-backwards] Mark that buffer to be deleted, and move up.
239\\[Buffer-menu-execute] Delete or save marked buffers.
240\\[Buffer-menu-unmark] Remove all marks from current line.
241 With prefix argument, also move up one line.
242\\[Buffer-menu-backup-unmark] Back up a line and remove marks.
243\\[Buffer-menu-toggle-read-only] Toggle read-only status of buffer on this line.
244\\[revert-buffer] Update the list of buffers.
245\\[Buffer-menu-toggle-files-only] Toggle whether the menu displays only file buffers.
246\\[Buffer-menu-bury] Bury the buffer listed on this line."
a5bf43ba
CY
247 (set (make-local-variable 'buffer-stale-function)
248 (lambda (&optional _noconfirm) 'fast))
249 (add-hook 'tabulated-list-revert-hook 'list-buffers--refresh nil t))
250
251(defun buffer-menu (&optional arg)
252 "Switch to the Buffer Menu.
253By default, the Buffer Menu lists all buffers except those whose
254names start with a space (which are for internal use). With
255prefix argument ARG, show only buffers that are visiting files.
256
257In the Buffer Menu, the first column (denoted \"C\") shows \".\"
258for the buffer from which you came, \">\" for buffers you mark to
259be displayed, and \"D\" for those you mark for deletion.
260
261The \"R\" column has a \"%\" if the buffer is read-only.
262The \"M\" column has a \"*\" if it is modified, or \"S\" if you
263have marked it for saving.
264
265The remaining columns show the buffer name, the buffer size in
266characters, its major mode, and the visited file name (if any).
267
268See `Buffer-menu-mode' for the keybindings available the Buffer
269Menu."
08c82d4d 270 (interactive "P")
08c82d4d
RS
271 (switch-to-buffer (list-buffers-noselect arg))
272 (message
273 "Commands: d, s, x, u; f, o, 1, 2, m, v; ~, %%; q to quit; ? for help."))
274
275(defun buffer-menu-other-window (&optional arg)
e5f9458f
CY
276 "Display the Buffer Menu in another window.
277See `buffer-menu' for a description of the Buffer Menu.
278
279By default, all buffers are listed except those whose names start
280with a space (which are for internal use). With prefix argument
281ARG, show only buffers that are visiting files."
2dd96f23 282 (interactive "P")
08c82d4d 283 (switch-to-buffer-other-window (list-buffers-noselect arg))
2dd96f23 284 (message
3ed788ec
RS
285 "Commands: d, s, x, u; f, o, 1, 2, m, v; ~, %%; q to quit; ? for help."))
286
f0809a9d 287;;;###autoload
e5f9458f
CY
288(defun list-buffers (&optional arg)
289 "Display a list of existing buffers.
290The list is displayed in a buffer named \"*Buffer List*\".
a5bf43ba 291See `buffer-menu' for a description of the Buffer Menu.
e5f9458f
CY
292
293By default, all buffers are listed except those whose names start
294with a space (which are for internal use). With prefix argument
295ARG, show only buffers that are visiting files."
296 (interactive "P")
297 (display-buffer (list-buffers-noselect arg)))
298
299(defun Buffer-menu-toggle-files-only (arg)
300 "Toggle whether the current buffer-menu displays only file buffers.
301With a positive ARG, display only file buffers. With zero or
302negative ARG, display other buffers as well."
303 (interactive "P")
304 (setq Buffer-menu-files-only
305 (cond ((not arg) (not Buffer-menu-files-only))
306 ((> (prefix-numeric-value arg) 0) t)))
307 (message (if Buffer-menu-files-only
308 "Showing only file-visiting buffers."
309 "Showing all non-internal buffers."))
310 (revert-buffer))
311
312(defalias 'Buffer-menu-sort 'tabulated-list-sort)
313\f
314
315(defun Buffer-menu-buffer (&optional error-if-non-existent-p)
316 "Return the buffer described by the current Buffer Menu line.
317If there is no buffer here, return nil if ERROR-IF-NON-EXISTENT-P
318is nil or omitted, and signal an error otherwise."
319 (let ((buffer (tabulated-list-get-id)))
320 (cond ((null buffer)
321 (if error-if-non-existent-p
322 (error "No buffer on this line")))
323 ((not (buffer-live-p buffer))
324 (if error-if-non-existent-p
325 (error "This buffer has been killed")))
326 (t buffer))))
327
bc7bb432
JB
328(defun Buffer-menu-no-header ()
329 (beginning-of-line)
330 (if (or Buffer-menu-use-header-line
331 (not (eq (char-after) ?C)))
332 t
333 (ding)
334 (forward-line 1)
335 nil))
336
e5f9458f
CY
337(defun Buffer-menu-beginning ()
338 (goto-char (point-min))
339 (unless Buffer-menu-use-header-line
340 (forward-line)))
341
342\f
343;;; Commands for modifying Buffer Menu entries.
344
2dd96f23 345(defun Buffer-menu-mark ()
e5f9458f
CY
346 "Mark the Buffer menu entry at point for later display.
347It will be displayed by the \\<Buffer-menu-mode-map>\\[Buffer-menu-select] command."
2dd96f23 348 (interactive)
e5f9458f
CY
349 (tabulated-list-set-col 0 ">" t)
350 (forward-line))
2dd96f23 351
86dbbfc2
ER
352(defun Buffer-menu-unmark (&optional backup)
353 "Cancel all requested operations on buffer on this line and move down.
bfa13d19 354Optional prefix arg means move up."
86dbbfc2 355 (interactive "P")
cf59e41c 356 (Buffer-menu--unmark)
86dbbfc2 357 (forward-line (if backup -1 1)))
2dd96f23
JB
358
359(defun Buffer-menu-backup-unmark ()
360 "Move up and cancel all requested operations on buffer on line above."
361 (interactive)
362 (forward-line -1)
cf59e41c
AA
363 (Buffer-menu--unmark))
364
365(defun Buffer-menu--unmark ()
366 (tabulated-list-set-col 0 " " t)
367 (let ((buf (Buffer-menu-buffer)))
368 (when buf
369 (if (buffer-modified-p buf)
370 (tabulated-list-set-col 2 "*" t)
371 (tabulated-list-set-col 2 " " t)))))
2dd96f23 372
77a43e01 373(defun Buffer-menu-delete (&optional arg)
e5f9458f
CY
374 "Mark the buffer on this Buffer Menu buffer line for deletion.
375A subsequent \\<Buffer-menu-mode-map>`\\[Buffer-menu-execute]' command
376will delete it.
377
378If prefix argument ARG is non-nil, it specifies the number of
379buffers to delete; a negative ARG means to delete backwards."
77a43e01 380 (interactive "p")
e5f9458f
CY
381 (if (or (null arg) (= arg 0))
382 (setq arg 1))
383 (while (> arg 0)
384 (when (Buffer-menu-buffer)
385 (tabulated-list-set-col 0 "D" t))
386 (forward-line 1)
387 (setq arg (1- arg)))
388 (while (< arg 0)
389 (when (Buffer-menu-buffer)
390 (tabulated-list-set-col 0 "D" t))
391 (forward-line -1)
392 (setq arg (1+ arg))))
77a43e01
RS
393
394(defun Buffer-menu-delete-backwards (&optional arg)
e5f9458f 395 "Mark the buffer on this Buffer Menu line for deletion, and move up.
a5bf43ba
CY
396A subsequent \\<Buffer-menu-mode-map>`\\[Buffer-menu-execute]'
397command will delete the marked buffer. Prefix ARG means move
398that many lines."
77a43e01 399 (interactive "p")
bc7bb432 400 (Buffer-menu-delete (- (or arg 1))))
2dd96f23
JB
401
402(defun Buffer-menu-save ()
e5f9458f
CY
403 "Mark the buffer on this Buffer Menu line for saving.
404A subsequent \\<Buffer-menu-mode-map>`\\[Buffer-menu-execute]' command
405will save it."
2dd96f23 406 (interactive)
e5f9458f
CY
407 (when (Buffer-menu-buffer)
408 (tabulated-list-set-col 2 "S" t)
409 (forward-line 1)))
2dd96f23 410
a8ce00dc 411(defun Buffer-menu-not-modified (&optional arg)
e5f9458f
CY
412 "Mark the buffer on this line as unmodified (no changes to save).
413If ARG is non-nil (interactively, with a prefix argument), mark
414it as modified."
a8ce00dc 415 (interactive "P")
70ef8857 416 (with-current-buffer (Buffer-menu-buffer t)
a8ce00dc 417 (set-buffer-modified-p arg))
e5f9458f 418 (tabulated-list-set-col 2 (if arg "*" " ") t))
bfb2dda4 419
2dd96f23 420(defun Buffer-menu-execute ()
e5f9458f
CY
421 "Save and/or delete marked buffers in the Buffer Menu.
422Buffers marked with \\<Buffer-menu-mode-map>`\\[Buffer-menu-save]' are saved.
423Buffers marked with \\<Buffer-menu-mode-map>`\\[Buffer-menu-delete]' are deleted."
2dd96f23
JB
424 (interactive)
425 (save-excursion
bfb2dda4 426 (Buffer-menu-beginning)
e5f9458f
CY
427 (while (not (eobp))
428 (let ((buffer (tabulated-list-get-id))
429 (entry (tabulated-list-get-entry)))
430 (cond ((null entry)
431 (forward-line 1))
432 ((not (buffer-live-p buffer))
433 (tabulated-list-delete-entry))
434 (t
435 (let ((delete (eq (char-after) ?D)))
436 (when (equal (aref entry 2) "S")
437 (condition-case nil
438 (progn
439 (with-current-buffer buffer
440 (save-buffer))
441 (tabulated-list-set-col 2 " " t))
442 (error (warn "Error saving %s" buffer))))
443 (if delete
444 (unless (eq buffer (current-buffer))
445 (kill-buffer buffer)
446 (tabulated-list-delete-entry))
447 (forward-line 1)))))))))
2dd96f23
JB
448
449(defun Buffer-menu-select ()
e5f9458f
CY
450 "Select this line's buffer; also, display buffers marked with `>'.
451You can mark buffers with the \\<Buffer-menu-mode-map>`\\[Buffer-menu-mark]' command.
08c82d4d
RS
452This command deletes and replaces all the previously existing windows
453in the selected frame."
2dd96f23 454 (interactive)
e5f9458f
CY
455 (let* ((this-buffer (Buffer-menu-buffer t))
456 (menu-buffer (current-buffer))
457 (others (delq this-buffer (Buffer-menu-marked-buffers t)))
458 (height (/ (1- (frame-height)) (1+ (length others)))))
2dd96f23 459 (delete-other-windows)
e5f9458f
CY
460 (switch-to-buffer this-buffer)
461 (unless (eq menu-buffer this-buffer)
462 (bury-buffer menu-buffer))
463 (dolist (buffer others)
464 (split-window nil height)
465 (other-window 1)
466 (switch-to-buffer buffer))
467 ;; Back to the beginning!
468 (other-window 1)))
469
470(defun Buffer-menu-marked-buffers (&optional unmark)
471 "Return the list of buffers marked with `Buffer-menu-mark'.
472If UNMARK is non-nil, unmark them."
9cda680d
JL
473 (let (buffers)
474 (Buffer-menu-beginning)
475 (while (re-search-forward "^>" nil t)
e5f9458f
CY
476 (let ((buffer (Buffer-menu-buffer)))
477 (if (and buffer unmark)
478 (tabulated-list-set-col 0 " " t))
479 (if (buffer-live-p buffer)
480 (push buffer buffers))))
9cda680d
JL
481 (nreverse buffers)))
482
483(defun Buffer-menu-isearch-buffers ()
484 "Search for a string through all marked buffers using Isearch."
485 (interactive)
486 (multi-isearch-buffers (Buffer-menu-marked-buffers)))
487
488(defun Buffer-menu-isearch-buffers-regexp ()
489 "Search for a regexp through all marked buffers using Isearch."
490 (interactive)
491 (multi-isearch-buffers-regexp (Buffer-menu-marked-buffers)))
08c82d4d 492
96673afe 493(defun Buffer-menu-multi-occur (regexp &optional nlines)
924494f4 494 "Show all lines in marked buffers containing a match for a regexp."
96673afe
JL
495 (interactive (occur-read-primary-args))
496 (multi-occur (Buffer-menu-marked-buffers) regexp nlines))
924494f4 497
2dd96f23
JB
498\f
499(defun Buffer-menu-visit-tags-table ()
500 "Visit the tags table in the buffer on this line. See `visit-tags-table'."
501 (interactive)
502 (let ((file (buffer-file-name (Buffer-menu-buffer t))))
503 (if file
504 (visit-tags-table file)
505 (error "Specified buffer has no file"))))
506
507(defun Buffer-menu-1-window ()
dc6d9681 508 "Select this line's buffer, alone, in full frame."
2dd96f23
JB
509 (interactive)
510 (switch-to-buffer (Buffer-menu-buffer t))
511 (bury-buffer (other-buffer))
512 (delete-other-windows))
513
514(defun Buffer-menu-this-window ()
515 "Select this line's buffer in this window."
516 (interactive)
517 (switch-to-buffer (Buffer-menu-buffer t)))
518
519(defun Buffer-menu-other-window ()
520 "Select this line's buffer in other window, leaving buffer menu visible."
521 (interactive)
522 (switch-to-buffer-other-window (Buffer-menu-buffer t)))
523
35aaf00c
RM
524(defun Buffer-menu-switch-other-window ()
525 "Make the other window select this line's buffer.
526The current window remains selected."
527 (interactive)
3199b96f 528 (display-buffer (Buffer-menu-buffer t) t))
35aaf00c 529
2dd96f23
JB
530(defun Buffer-menu-2-window ()
531 "Select this line's buffer, with previous buffer in second window."
532 (interactive)
533 (let ((buff (Buffer-menu-buffer t))
3199b96f 534 (menu (current-buffer)))
86dbbfc2 535 (delete-other-windows)
2dd96f23 536 (switch-to-buffer (other-buffer))
3199b96f 537 (switch-to-buffer-other-window buff)
2dd96f23 538 (bury-buffer menu)))
c0274f38 539
d91e2b1a 540(defun Buffer-menu-toggle-read-only ()
b68b3337
CY
541 "Toggle read-only status of buffer on this line.
542This behaves like invoking \\[toggle-read-only] in that buffer."
d91e2b1a 543 (interactive)
ba10c48c
SM
544 (let ((read-only
545 (with-current-buffer (Buffer-menu-buffer t)
9a930676 546 (read-only-mode 'toggle)
ba10c48c 547 buffer-read-only)))
e5f9458f 548 (tabulated-list-set-col 1 (if read-only "%" " ") t)))
d91e2b1a 549
36570c92
RS
550(defun Buffer-menu-bury ()
551 "Bury the buffer listed on this line."
552 (interactive)
e5f9458f
CY
553 (let ((buffer (tabulated-list-get-id)))
554 (cond ((null buffer))
555 ((buffer-live-p buffer)
556 (bury-buffer buffer)
557 (save-excursion
558 (let ((elt (tabulated-list-delete-entry)))
559 (goto-char (point-max))
560 (apply 'tabulated-list-print-entry elt)))
561 (message "Buffer buried."))
562 (t
563 (tabulated-list-delete-entry)
564 (message "Buffer is dead; removing from list.")))))
42a19c2a
RS
565
566(defun Buffer-menu-view ()
567 "View this line's buffer in View mode."
568 (interactive)
569 (view-buffer (Buffer-menu-buffer t)))
570
42a19c2a
RS
571(defun Buffer-menu-view-other-window ()
572 "View this line's buffer in View mode in another window."
573 (interactive)
574 (view-buffer-other-window (Buffer-menu-buffer t)))
0b03ce3a 575\f
e5f9458f 576;;; Functions for populating the Buffer Menu.
d5aacb46 577
f0809a9d 578;;;###autoload
61617913 579(defun list-buffers-noselect (&optional files-only buffer-list)
e5f9458f
CY
580 "Create and return a Buffer Menu buffer.
581This is called by `buffer-menu' and others as a subroutine.
582
583If FILES-ONLY is non-nil, show only file-visiting buffers.
584If BUFFER-LIST is non-nil, it should be a list of buffers; it
585means list those buffers and no others."
586 (let ((old-buffer (current-buffer))
587 (buffer (get-buffer-create "*Buffer List*")))
588 (with-current-buffer buffer
0b03ce3a 589 (Buffer-menu-mode)
f1a71c6e
AS
590 (setq Buffer-menu-files-only
591 (and files-only (>= (prefix-numeric-value files-only) 0)))
e5f9458f
CY
592 (list-buffers--refresh buffer-list old-buffer)
593 (tabulated-list-print))
594 buffer))
595
0d909786
CY
596(defun Buffer-menu-mouse-select (event)
597 "Select the buffer whose line you click on."
598 (interactive "e")
599 (select-window (posn-window (event-end event)))
600 (let ((buffer (tabulated-list-get-id (posn-point (event-end event)))))
601 (when (buffer-live-p buffer)
290d5b58 602 (if (and (window-dedicated-p)
0d909786
CY
603 (eq (selected-window) (frame-root-window)))
604 (switch-to-buffer-other-frame buffer)
605 (switch-to-buffer buffer)))))
606
e5f9458f
CY
607(defun list-buffers--refresh (&optional buffer-list old-buffer)
608 ;; Set up `tabulated-list-format'.
609 (let ((name-width Buffer-menu-name-width)
610 (size-width Buffer-menu-size-width))
611 ;; Handle obsolete variable:
612 (if Buffer-menu-buffer+size-width
613 (setq name-width (- Buffer-menu-buffer+size-width size-width)))
614 (setq tabulated-list-format
615 (vector '("C" 1 t :pad-right 0)
616 '("R" 1 t :pad-right 0)
617 '("M" 1 t)
618 `("Buffer" ,name-width t)
f0809a9d
SM
619 `("Size" ,size-width tabulated-list-entry-size->
620 :right-align t)
e5f9458f
CY
621 `("Mode" ,Buffer-menu-mode-width t)
622 '("File" 1 t))))
1241b724 623 (setq tabulated-list-use-header-line Buffer-menu-use-header-line)
e5f9458f
CY
624 ;; Collect info for each buffer we're interested in.
625 (let ((buffer-menu-buffer (current-buffer))
626 (show-non-file (not Buffer-menu-files-only))
627 entries)
628 (dolist (buffer (or buffer-list
629 (buffer-list (if Buffer-menu-use-frame-buffer-list
630 (selected-frame)))))
631 (with-current-buffer buffer
632 (let* ((name (buffer-name))
633 (file buffer-file-name))
634 (when (and (buffer-live-p buffer)
635 (or buffer-list
636 (and (not (string= (substring name 0 1) " "))
637 (not (eq buffer buffer-menu-buffer))
638 (or file show-non-file))))
639 (push (list buffer
640 (vector (if (eq buffer old-buffer) "." " ")
641 (if buffer-read-only "%" " ")
642 (if (buffer-modified-p) "*" " ")
643 (Buffer-menu--pretty-name name)
644 (number-to-string (buffer-size))
645 (concat (format-mode-line mode-name nil nil buffer)
646 (if mode-line-process
647 (format-mode-line mode-line-process
648 nil nil buffer)))
649 (Buffer-menu--pretty-file-name file)))
650 entries)))))
651 (setq tabulated-list-entries (nreverse entries)))
652 (tabulated-list-init-header))
653
654(defun tabulated-list-entry-size-> (entry1 entry2)
655 (> (string-to-number (aref (cadr entry1) 4))
656 (string-to-number (aref (cadr entry2) 4))))
657
658(defun Buffer-menu--pretty-name (name)
0d909786
CY
659 (propertize name
660 'font-lock-face 'buffer-menu-buffer
661 'mouse-face 'highlight))
e5f9458f
CY
662
663(defun Buffer-menu--pretty-file-name (file)
664 (cond (file
665 (abbreviate-file-name file))
666 ((and (boundp 'list-buffers-directory)
667 list-buffers-directory)
668 list-buffers-directory)
669 ((eq major-mode 'Info-mode)
670 (Buffer-menu-info-node-description Info-current-file))
671 (t "")))
672
673(defun Buffer-menu-info-node-description (file)
674 (cond
675 ((equal file "dir") "*Info Directory*")
676 ((eq file 'apropos) "*Info Apropos*")
677 ((eq file 'history) "*Info History*")
678 ((eq file 'toc) "*Info TOC*")
679 ((not (stringp file)) "") ; Avoid errors
680 (t
681 (concat "(" (file-name-nondirectory file) ") " Info-current-node))))
0b03ce3a 682
c0274f38 683;;; buff-menu.el ends here