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