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