(multi-occur-by-filename-regexp): Doc fix.
[bpt/emacs.git] / lisp / ibuffer.el
CommitLineData
25d2f683
CW
1;;; ibuffer.el --- operate on buffers like dired
2
30c93a61 3;; Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
25d2f683
CW
4
5;; Author: Colin Walters <walters@verbum.org>
6;; Created: 8 Sep 2000
25d2f683 7;; Keywords: buffer, convenience
25d2f683 8
b5cd37ea 9;; This file is part of GNU Emacs.
25d2f683
CW
10
11;; This program is free software; you can redistribute it and/or
12;; modify it under the terms of the GNU General Public License as
13;; published by the Free Software Foundation; either version 2, or (at
14;; your option) any later version.
15
16;; This program is distributed in the hope that it will be useful, but
17;; WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19;; General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
22;; along with this program ; see the file COPYING. If not, write to
23;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24;; Boston, MA 02111-1307, USA.
25
26;;; Commentary:
27
28;; ibuffer.el is an advanced replacement for the `buffer-menu' which
29;; is normally distributed with Emacs. Its interface is intended to
30;; be analogous to that of Dired.
31
32;;; Code:
33
34(eval-when-compile
35 (require 'cl)
36 (require 'ibuf-macs)
37 (require 'dired))
38
39;;; Compatibility
40(eval-and-compile
41 (if (fboundp 'window-list)
42 (defun ibuffer-window-list ()
43 (window-list nil 'nomini))
44 (defun ibuffer-window-list ()
45 (let ((ibuffer-window-list-result nil))
46 (walk-windows #'(lambda (win) (push win ibuffer-window-list-result)) 'nomini)
47 (nreverse ibuffer-window-list-result))))
48
49 (cond ((boundp 'global-font-lock-mode)
50 (defsubst ibuffer-use-fontification ()
51 (when (boundp 'font-lock-mode)
52 font-lock-mode)))
53 ((boundp 'font-lock-auto-fontify)
54 (defsubst ibuffer-use-fontification ()
55 font-lock-auto-fontify))
56 (t
57 (defsubst ibuffer-use-fontification ()
58 nil))))
59
60(defgroup ibuffer nil
61 "An advanced replacement for `buffer-menu'.
62
63Ibuffer allows you to operate on buffers in a manner much like Dired.
64Operations include sorting, marking by regular expression, and
65the ability to filter the displayed buffers by various criteria."
25d2f683
CW
66 :group 'convenience)
67
68(defcustom ibuffer-formats '((mark modified read-only " " (name 16 16 :left :elide)
69 " " (size 6 -1 :right)
70 " " (mode 16 16 :right :elide) " " filename)
71 (mark " " (name 16 -1) " " filename))
72 "A list of ways to display buffer lines.
73
74With Ibuffer, you are not limited to displaying just certain
75attributes of a buffer such as size, name, and mode in a particular
76fashion. Through this variable, you can completely customize and
77control the appearance of an Ibuffer buffer. See also
78`define-ibuffer-column', which allows you to define your own columns
79for display.
80
81This variable has the form
2e4fae7d 82 ((COLUMN COLUMN ...) (COLUMN COLUMN ...) ...)
25d2f683
CW
83Each element in `ibuffer-formats' should be a list containing COLUMN
84specifiers. A COLUMN can be any of the following:
85
86 SYMBOL - A symbol naming the column. Predefined columns are:
87 mark modified read-only name size mode process filename
88 When you define your own columns using `define-ibuffer-column', just
89 use their name like the predefined columns here. This entry can
90 also be a function of two arguments, which should return a string.
91 The first argument is the buffer object, and the second is the mark
92 on that buffer.
93 or
94 \"STRING\" - A literal string to display.
95 or
96 (SYMBOL MIN-SIZE MAX-SIZE &optional ALIGN ELIDE) - SYMBOL is a
97 symbol naming the column, and MIN-SIZE and MAX-SIZE are integers (or
98 functions of no arguments returning an integer) which constrict the
99 size of a column. If MAX-SIZE is -1, there is no upper bound. The
100 default values are 0 and -1, respectively. If MIN-SIZE is negative,
101 use the end of the string. The optional element ALIGN describes the
102 alignment of the column; it can be :left, :center or :right. The
103 optional element ELIDE describes whether or not to elide the column
104 if it is too long; valid values are :elide and nil. The default is
105 nil (don't elide).
106
107Some example of valid entries in `ibuffer-formats', with
108description (also, feel free to try them out, and experiment with your
109own!):
110
111 (mark \" \" name)
112 This format just displays the current mark (if any) and the name of
113 the buffer, separated by a space.
114 (mark modified read-only \" \" (name 16 16 :left) \" \" (size 6 -1 :right))
115 This format displays the current mark (if any), its modification and
116 read-only status, as well as the name of the buffer and its size. In
117 this format, the name is restricted to 16 characters (longer names
523304ed 118 will be truncated, and shorter names will be padded with spaces), and
25d2f683
CW
119 the name is also aligned to the right. The size of the buffer will
120 be padded with spaces up to a minimum of six characters, but there is
121 no upper limit on its size. The size will also be aligned to the
122 right.
123
124Thus, if you wanted to use these two formats, add
125
126 (setq ibuffer-formats '((mark \" \" name)
127 (mark modified read-only
128 (name 16 16 :left) (size 6 -1 :right))))
129
130to your ~/.emacs file.
131
132Using \\[ibuffer-switch-format], you can rotate the display between
133the specified formats in the list."
134 :type '(repeat sexp)
135 :group 'ibuffer)
136
137(defcustom ibuffer-always-compile-formats (featurep 'bytecomp)
138 "If non-nil, then use the byte-compiler to optimize `ibuffer-formats'.
139This will increase the redisplay speed, at the cost of loading the
140elisp byte-compiler."
141 :type 'boolean
142 :group 'ibuffer)
143
144(defcustom ibuffer-fontification-alist
145 `((10 buffer-read-only font-lock-reference-face)
146 (15 (string-match "^*" (buffer-name)) font-lock-keyword-face)
147 (20 (string-match "^ " (buffer-name)) font-lock-warning-face)
60356fb5 148 (25 (memq major-mode ibuffer-help-buffer-modes) font-lock-comment-face)
25d2f683
CW
149 (30 (eq major-mode 'dired-mode) font-lock-function-name-face))
150 "An alist describing how to fontify buffers.
151Each element should be of the form (PRIORITY FORM FACE), where
152PRIORITY is an integer, FORM is an arbitrary form to evaluate in the
153buffer, and FACE is the face to use for fontification. If the FORM
154evaluates to non-nil, then FACE will be put on the buffer name. The
155element with the highest PRIORITY takes precedence."
156 :type '(repeat
157 (list (integer :tag "Priority")
158 (sexp :tag "Test Form")
159 face))
160 :group 'ibuffer)
161
162(defcustom ibuffer-use-other-window nil
163 "If non-nil, display the Ibuffer in another window by default."
164 :type 'boolean
165 :group 'ibuffer)
166
167(defcustom ibuffer-default-shrink-to-minimum-size nil
168 "If non-nil, minimize the size of the Ibuffer window by default."
169 :type 'boolean
170 :group 'ibuffer)
171(defvar ibuffer-shrink-to-minimum-size nil)
172
3eda3649
CW
173(defcustom ibuffer-truncate-lines t
174 "If non-nil, do not display continuation lines."
175 :type 'boolean
176 :group 'ibuffer)
177
25d2f683
CW
178(defcustom ibuffer-case-fold-search case-fold-search
179 "If non-nil, ignore case when searching."
180 :type 'boolean
181 :group 'ibuffer)
182
183(defcustom ibuffer-default-sorting-mode 'recency
184 "The criteria by which to sort the buffers.
185
186Note that this variable is local to each ibuffer buffer. Thus, you
187can have multiple ibuffer buffers open, each with a different sorted
188view of the buffers."
189 :type '(choice (const :tag "Last view time" :value recency)
190 (const :tag "Lexicographic" :value alphabetic)
191 (const :tag "Buffer size" :value size)
192 (const :tag "Major mode" :value major-mode))
193 :group 'ibuffer)
194(defvar ibuffer-sorting-mode nil)
195
196(defcustom ibuffer-default-sorting-reversep nil
197 "If non-nil, reverse the default sorting order."
198 :type 'boolean
199 :group 'ibuffer)
200(defvar ibuffer-sorting-reversep nil)
201
202(defcustom ibuffer-elide-long-columns nil
203 "If non-nil, then elide column entries which exceed their max length.
204This variable is deprecated; use the :elide argument of
205`ibuffer-formats' to elide just certain columns."
206 :type 'boolean
207 :group 'ibuffer)
208
209(defcustom ibuffer-eliding-string "..."
210 "The string to use for eliding long columns."
211 :type 'string
212 :group 'ibuffer)
213
214(defcustom ibuffer-maybe-show-predicates `(,(lambda (buf)
215 (and (string-match "^ " (buffer-name buf))
216 (null buffer-file-name))))
217 "A list of predicates (a regexp or function) for buffers to display conditionally.
218If a regexp, then it will be matched against the buffer's name.
219If a function, it will be called with the buffer as an argument, and
220should return non-nil if this buffer should be shown.
221
222Viewing of buffers hidden because of these predicates is enabled by
223giving a non-nil prefix argument to `ibuffer-update'. Note that this
224specialized filtering occurs before real filtering."
225 :type '(repeat (choice regexp function))
226 :group 'ibuffer)
227
228(defvar ibuffer-current-format nil)
229
230(defcustom ibuffer-modified-char ?*
231 "The character to display for modified buffers."
232 :type 'character
233 :group 'ibuffer)
234
235(defcustom ibuffer-read-only-char ?%
236 "The character to display for read-only buffers."
237 :type 'character
238 :group 'ibuffer)
239
240(defcustom ibuffer-marked-char ?>
241 "The character to display for marked buffers."
242 :type 'character
243 :group 'ibuffer)
244
245(defcustom ibuffer-deletion-char ?D
246 "The character to display for buffers marked for deletion."
247 :type 'character
248 :group 'ibuffer)
249
250(defcustom ibuffer-expert nil
251 "If non-nil, don't ask for confirmation of \"dangerous\" operations."
252 :type 'boolean
253 :group 'ibuffer)
254
255(defcustom ibuffer-view-ibuffer nil
256 "If non-nil, display the current Ibuffer buffer itself.
257Note that this has a drawback - the data about the current Ibuffer
258buffer will most likely be inaccurate. This includes modification
259state, size, etc."
260 :type 'boolean
261 :group 'ibuffer)
262
263(defcustom ibuffer-always-show-last-buffer nil
264 "If non-nil, always display the previous buffer. This variable
265takes precedence over filtering, and even
266`ibuffer-never-show-predicates'."
267 :type '(choice (const :tag "Always" :value t)
268 (const :tag "Never" :value nil)
269 (const :tag "Always except minibuffer" :value :nomini))
270 :group 'ibuffer)
271
272(defcustom ibuffer-use-header-line (boundp 'header-line-format)
273 "If non-nil, display a header line containing current filters.
274This feature only works on Emacs 21 or later."
275 :type 'boolean
276 :group 'ibuffer)
277
278(defcustom ibuffer-default-directory nil
279 "The default directory to use for a new ibuffer buffer.
2e4fae7d 280If nil, inherit the directory of the buffer in which `ibuffer' was
25d2f683
CW
281called. Otherwise, this variable should be a string naming a
282directory, like `default-directory'."
283 :type '(choice (const :tag "Inherit" :value nil)
284 string)
285 :group 'ibuffer)
286
60356fb5
CW
287(defcustom ibuffer-help-buffer-modes '(help-mode apropos-mode
288 Info-mode Info-edit-mode)
289 "List of \"Help\" major modes."
290 :type '(repeat function)
291 :group 'ibuffer)
292
25d2f683
CW
293(defcustom ibuffer-hooks nil
294 "Hooks run when `ibuffer' is called."
295 :type 'hook
296 :group 'ibuffer)
297
298(defcustom ibuffer-mode-hooks nil
299 "Hooks run upon entry into `ibuffer-mode'."
300 :type 'hook
301 :group 'ibuffer)
302
303(defcustom ibuffer-marked-face 'font-lock-warning-face
304 "Face used for displaying marked buffers."
305 :type 'face
306 :group 'ibuffer)
307
308(defcustom ibuffer-deletion-face 'font-lock-type-face
309 "Face used for displaying buffers marked for deletion."
310 :type 'face
311 :group 'ibuffer)
312
313(defcustom ibuffer-title-face 'font-lock-type-face
314 "Face used for the title string."
315 :type 'face
316 :group 'ibuffer)
317
b5cd37ea
CW
318(defcustom ibuffer-filter-group-name-face 'bold
319 "Face used for displaying filtering group names."
320 :type 'face
321 :group 'ibuffer)
322
25d2f683
CW
323(defcustom ibuffer-directory-abbrev-alist nil
324 "An alist of file name abbreviations like `directory-abbrev-alist'."
325 :type '(repeat (cons :format "%v"
326 :value ("" . "")
327 (regexp :tag "From")
328 (regexp :tag "To")))
329 :group 'ibuffer)
330
331(defvar ibuffer-mode-map nil)
332(defvar ibuffer-mode-operate-map nil)
333(unless ibuffer-mode-map
334 (let ((map (make-sparse-keymap))
335 (operate-map (make-sparse-keymap "Operate")))
336 (define-key map (kbd "0") 'digit-argument)
337 (define-key map (kbd "1") 'digit-argument)
338 (define-key map (kbd "2") 'digit-argument)
339 (define-key map (kbd "3") 'digit-argument)
340 (define-key map (kbd "4") 'digit-argument)
341 (define-key map (kbd "5") 'digit-argument)
342 (define-key map (kbd "6") 'digit-argument)
343 (define-key map (kbd "7") 'digit-argument)
344 (define-key map (kbd "8") 'digit-argument)
345 (define-key map (kbd "9") 'digit-argument)
346
347 (define-key map (kbd "m") 'ibuffer-mark-forward)
348 (define-key map (kbd "t") 'ibuffer-toggle-marks)
349 (define-key map (kbd "u") 'ibuffer-unmark-forward)
350 (define-key map (kbd "=") 'ibuffer-diff-with-file)
351 (define-key map (kbd "j") 'ibuffer-jump-to-buffer)
352 (define-key map (kbd "DEL") 'ibuffer-unmark-backward)
353 (define-key map (kbd "M-DEL") 'ibuffer-unmark-all)
354 (define-key map (kbd "* *") 'ibuffer-unmark-all)
355 (define-key map (kbd "* M") 'ibuffer-mark-by-mode)
356 (define-key map (kbd "* m") 'ibuffer-mark-modified-buffers)
357 (define-key map (kbd "* u") 'ibuffer-mark-unsaved-buffers)
358 (define-key map (kbd "* s") 'ibuffer-mark-special-buffers)
359 (define-key map (kbd "* r") 'ibuffer-mark-read-only-buffers)
360 (define-key map (kbd "* /") 'ibuffer-mark-dired-buffers)
361 (define-key map (kbd "* e") 'ibuffer-mark-dissociated-buffers)
362 (define-key map (kbd "* h") 'ibuffer-mark-help-buffers)
363 (define-key map (kbd ".") 'ibuffer-mark-old-buffers)
364
365 (define-key map (kbd "d") 'ibuffer-mark-for-delete)
366 (define-key map (kbd "C-d") 'ibuffer-mark-for-delete-backwards)
367 (define-key map (kbd "k") 'ibuffer-mark-for-delete)
368 (define-key map (kbd "x") 'ibuffer-do-kill-on-deletion-marks)
369
370 ;; immediate operations
371 (define-key map (kbd "n") 'ibuffer-forward-line)
b5cd37ea 372 (define-key map (kbd "<down>") 'ibuffer-forward-line)
25d2f683
CW
373 (define-key map (kbd "SPC") 'forward-line)
374 (define-key map (kbd "p") 'ibuffer-backward-line)
b5cd37ea 375 (define-key map (kbd "<up>") 'ibuffer-forward-line)
25d2f683
CW
376 (define-key map (kbd "M-}") 'ibuffer-forward-next-marked)
377 (define-key map (kbd "M-{") 'ibuffer-backwards-next-marked)
378 (define-key map (kbd "l") 'ibuffer-redisplay)
379 (define-key map (kbd "g") 'ibuffer-update)
380 (define-key map "`" 'ibuffer-switch-format)
381 (define-key map "-" 'ibuffer-add-to-tmp-hide)
382 (define-key map "+" 'ibuffer-add-to-tmp-show)
383 (define-key map "b" 'ibuffer-bury-buffer)
384 (define-key map (kbd ",") 'ibuffer-toggle-sorting-mode)
385 (define-key map (kbd "s i") 'ibuffer-invert-sorting)
386 (define-key map (kbd "s a") 'ibuffer-do-sort-by-alphabetic)
387 (define-key map (kbd "s v") 'ibuffer-do-sort-by-recency)
388 (define-key map (kbd "s s") 'ibuffer-do-sort-by-size)
389 (define-key map (kbd "s m") 'ibuffer-do-sort-by-major-mode)
390
391 (define-key map (kbd "/ m") 'ibuffer-filter-by-mode)
392 (define-key map (kbd "/ n") 'ibuffer-filter-by-name)
393 (define-key map (kbd "/ c") 'ibuffer-filter-by-content)
394 (define-key map (kbd "/ e") 'ibuffer-filter-by-predicate)
395 (define-key map (kbd "/ f") 'ibuffer-filter-by-filename)
396 (define-key map (kbd "/ >") 'ibuffer-filter-by-size-gt)
397 (define-key map (kbd "/ <") 'ibuffer-filter-by-size-lt)
398 (define-key map (kbd "/ r") 'ibuffer-switch-to-saved-filters)
399 (define-key map (kbd "/ a") 'ibuffer-add-saved-filters)
400 (define-key map (kbd "/ x") 'ibuffer-delete-saved-filters)
401 (define-key map (kbd "/ d") 'ibuffer-decompose-filter)
402 (define-key map (kbd "/ s") 'ibuffer-save-filters)
403 (define-key map (kbd "/ p") 'ibuffer-pop-filter)
404 (define-key map (kbd "/ !") 'ibuffer-negate-filter)
405 (define-key map (kbd "/ t") 'ibuffer-exchange-filters)
406 (define-key map (kbd "/ TAB") 'ibuffer-exchange-filters)
407 (define-key map (kbd "/ o") 'ibuffer-or-filter)
b5cd37ea
CW
408 (define-key map (kbd "/ g") 'ibuffer-filters-to-filter-group)
409 (define-key map (kbd "/ P") 'ibuffer-pop-filter-group)
25d2f683 410 (define-key map (kbd "/ /") 'ibuffer-filter-disable)
b5cd37ea
CW
411
412 (define-key map (kbd "M-n") 'ibuffer-forward-filter-group)
413 (define-key map (kbd "<right>") 'ibuffer-forward-filter-group)
414 (define-key map (kbd "M-p") 'ibuffer-backward-filter-group)
415 (define-key map (kbd "<left>") 'ibuffer-backward-filter-group)
416 (define-key map (kbd "M-j") 'ibuffer-jump-to-filter-group)
25d2f683
CW
417
418 (define-key map (kbd "q") 'ibuffer-quit)
419 (define-key map (kbd "h") 'describe-mode)
420 (define-key map (kbd "?") 'describe-mode)
421
422 (define-key map (kbd "% n") 'ibuffer-mark-by-name-regexp)
423 (define-key map (kbd "% m") 'ibuffer-mark-by-mode-regexp)
424 (define-key map (kbd "% f") 'ibuffer-mark-by-file-name-regexp)
425
426 (define-key map (kbd "C-t") 'ibuffer-visit-tags-table)
427
428 (define-key map (kbd "|") 'ibuffer-do-shell-command-pipe)
429 (define-key map (kbd "!") 'ibuffer-do-shell-command-file)
430 (define-key map (kbd "~") 'ibuffer-do-toggle-modified)
431 ;; marked operations
432 (define-key map (kbd "A") 'ibuffer-do-view)
433 (define-key map (kbd "D") 'ibuffer-do-delete)
434 (define-key map (kbd "E") 'ibuffer-do-eval)
435 (define-key map (kbd "F") 'ibuffer-do-shell-command-file)
436 (define-key map (kbd "I") 'ibuffer-do-query-replace-regexp)
437 (define-key map (kbd "H") 'ibuffer-do-view-other-frame)
438 (define-key map (kbd "N") 'ibuffer-do-shell-command-pipe-replace)
439 (define-key map (kbd "M") 'ibuffer-do-toggle-modified)
440 (define-key map (kbd "O") 'ibuffer-do-occur)
441 (define-key map (kbd "P") 'ibuffer-do-print)
442 (define-key map (kbd "Q") 'ibuffer-do-query-replace)
443 (define-key map (kbd "R") 'ibuffer-do-rename-uniquely)
444 (define-key map (kbd "S") 'ibuffer-do-save)
445 (define-key map (kbd "T") 'ibuffer-do-toggle-read-only)
446 (define-key map (kbd "U") 'ibuffer-do-replace-regexp)
447 (define-key map (kbd "V") 'ibuffer-do-revert)
448 (define-key map (kbd "W") 'ibuffer-do-view-and-eval)
449 (define-key map (kbd "X") 'ibuffer-do-shell-command-pipe)
450
451 (define-key map (kbd "k") 'ibuffer-do-kill-lines)
452 (define-key map (kbd "w") 'ibuffer-copy-filename-as-kill)
453
454 (define-key map (kbd "RET") 'ibuffer-visit-buffer)
455 (define-key map (kbd "e") 'ibuffer-visit-buffer)
456 (define-key map (kbd "f") 'ibuffer-visit-buffer)
457 (define-key map (kbd "C-x C-f") 'ibuffer-find-file)
458 (define-key map (kbd "o") 'ibuffer-visit-buffer-other-window)
459 (define-key map (kbd "C-o") 'ibuffer-visit-buffer-other-window-noselect)
460 (define-key map (kbd "M-o") 'ibuffer-visit-buffer-1-window)
461 (define-key map (kbd "v") 'ibuffer-do-view)
462 (define-key map (kbd "C-x v") 'ibuffer-do-view-horizontally)
463 (define-key map (kbd "C-c C-a") 'ibuffer-auto-mode)
464 (define-key map (kbd "C-x 4 RET") 'ibuffer-visit-buffer-other-window)
465 (define-key map (kbd "C-x 5 RET") 'ibuffer-visit-buffer-other-frame)
466
467 (define-key map [menu-bar view]
468 (cons "View" (make-sparse-keymap "View")))
469
470 (define-key-after map [menu-bar view visit-buffer]
471 '(menu-item "View this buffer" ibuffer-visit-buffer))
472 (define-key-after map [menu-bar view visit-buffer-other-window]
473 '(menu-item "View (other window)" ibuffer-visit-buffer-other-window))
474 (define-key-after map [menu-bar view visit-buffer-other-frame]
475 '(menu-item "View (other frame)" ibuffer-visit-buffer-other-frame))
476 (define-key-after map [menu-bar view ibuffer-update]
477 '(menu-item "Update" ibuffer-update
478 :help "Regenerate the list of buffers"))
479 (define-key-after map [menu-bar view switch-format]
480 '(menu-item "Switch display format" ibuffer-switch-format
481 :help "Toggle between available values of `ibuffer-formats'"))
482
483 (define-key-after map [menu-bar view dashes]
484 '("--"))
485
486 (define-key-after map [menu-bar view sort]
487 (cons "Sort" (make-sparse-keymap "Sort")))
488
489 (define-key-after map [menu-bar view sort do-sort-by-major-mode]
490 '(menu-item "Sort by major mode" ibuffer-do-sort-by-major-mode
491 :help "Sort by the alphabetic order of the buffer's major mode"))
492 (define-key-after map [menu-bar view sort do-sort-by-size]
493 '(menu-item "Sort by buffer size" ibuffer-do-sort-by-size
494 :help "Sort by the size of the buffer"))
495 (define-key-after map [menu-bar view sort do-sort-by-alphabetic]
496 '(menu-item "Sort lexicographically" ibuffer-do-sort-by-alphabetic
497 :help "Sort by the alphabetic order of buffer name"))
498 (define-key-after map [menu-bar view sort do-sort-by-recency]
499 '(menu-item "Sort by view time" ibuffer-do-sort-by-recency
500 :help "Sort by the last time the buffer was displayed"))
501 (define-key-after map [menu-bar view sort invert-sorting]
502 '(menu-item "Reverse sorting order" ibuffer-invert-sorting))
503 (define-key-after map [menu-bar view sort toggle-sorting-mode]
504 '(menu-item "Switch sorting mode" ibuffer-toggle-sorting-mode
505 :help "Switch between the various sorting criteria"))
506
507 (define-key-after map [menu-bar view filter]
508 (cons "Filter" (make-sparse-keymap "Filter")))
509
510 (define-key-after map [menu-bar view filter filter-disable]
511 '(menu-item "Disable all filtering" ibuffer-filter-disable))
512 (define-key-after map [menu-bar view filter filter-by-mode]
513 '(menu-item "Add filter by major mode..." ibuffer-filter-by-mode
514 :help "Show only buffers in a major mode"))
515 (define-key-after map [menu-bar view filter filter-by-name]
516 '(menu-item "Add filter by buffer name..." ibuffer-filter-by-name
517 :help "Show only buffers whose name matches a regexp"))
518 (define-key-after map [menu-bar view filter filter-by-filename]
519 '(menu-item "Add filter by filename..." ibuffer-filter-by-filename
520 :help "Show only buffers whose filename matches a regexp"))
521 (define-key-after map [menu-bar view filter filter-by-size-lt]
522 '(menu-item "Add filter by size less than..." ibuffer-filter-by-size-lt
523 :help "Show only buffers of size less than..."))
524 (define-key-after map [menu-bar view filter filter-by-size-gt]
525 '(menu-item "Add filter by size greater than..." ibuffer-filter-by-size-gt
526 :help "Show only buffers of size greater than..."))
527 (define-key-after map [menu-bar view filter filter-by-content]
528 '(menu-item "Add filter by content (regexp)..." ibuffer-filter-by-content
529 :help "Show only buffers containing a regexp"))
530 (define-key-after map [menu-bar view filter filter-by-predicate]
531 '(menu-item "Add filter by Lisp predicate..." ibuffer-filter-by-predicate
532 :help "Show only buffers for which a predicate is true"))
533 (define-key-after map [menu-bar view filter pop-filter]
534 '(menu-item "Remove top filter" ibuffer-pop-filter))
535 (define-key-after map [menu-bar view filter or-filter]
536 '(menu-item "OR top two filters" ibuffer-or-filter
537 :help "Create a new filter which is the logical OR of the top two filters"))
538 (define-key-after map [menu-bar view filter negate-filter]
539 '(menu-item "Negate top filter" ibuffer-negate-filter))
540 (define-key-after map [menu-bar view filter decompose-filter]
541 '(menu-item "Decompose top filter" ibuffer-decompose-filter
542 :help "Break down a complex filter like OR or NOT"))
543 (define-key-after map [menu-bar view filter exchange-filters]
544 '(menu-item "Swap top two filters" ibuffer-exchange-filters))
545 (define-key-after map [menu-bar view filter save-filters]
546 '(menu-item "Save current filters permanently..." ibuffer-save-filters
547 :help "Use a mnemnonic name to store current filter stack"))
548 (define-key-after map [menu-bar view filter switch-to-saved-filters]
549 '(menu-item "Restore permanently saved filters..." ibuffer-switch-to-saved-filters
550 :help "Replace current filters with a saved stack"))
551 (define-key-after map [menu-bar view filter add-saved-filters]
552 '(menu-item "Add to permanently saved filters..." ibuffer-add-saved-filters
553 :help "Include current filters in an already saved stack"))
554 (define-key-after map [menu-bar view filter delete-saved-filters]
555 '(menu-item "Delete permanently saved filters..." ibuffer-delete-saved-filters
556 :help "Remove stack of filters from saved list"))
b5cd37ea
CW
557 (define-key-after map [menu-bar view filter-groups]
558 (cons "Filter Groups" (make-sparse-keymap "Filter Groups")))
559 (define-key-after map [menu-bar view filter-groups filters-to-filter-group]
560 '(menu-item "Make current filters into filter group"
561 ibuffer-filters-to-filter-group))
562 (define-key-after map [menu-bar view filter-groups pop-filter-group]
563 '(menu-item "Remove top filter group"
564 ibuffer-pop-filter-group))
565 (define-key-after map [menu-bar view filter-groups filters-to-filter-group]
566 '(menu-item "Create filter group from current filters"
567 ibuffer-filters-to-filter-group))
568
25d2f683
CW
569 (define-key-after map [menu-bar view dashes2]
570 '("--"))
571 (define-key-after map [menu-bar view diff-with-file]
572 '(menu-item "Diff with file" ibuffer-diff-with-file
573 :help "View the differences between this buffer and its file"))
574 (define-key-after map [menu-bar view auto-mode]
575 '(menu-item "Toggle Auto Mode" ibuffer-auto-mode
576 :help "Attempt to automatically update the Ibuffer buffer"))
577 (define-key-after map [menu-bar view customize]
578 '(menu-item "Customize Ibuffer" (lambda () (interactive)
579 (customize-group 'ibuffer))
580 :help "Use Custom to customize Ibuffer"))
581
582 (define-key-after map [menu-bar mark]
583 (cons "Mark" (make-sparse-keymap "Mark")))
584
585 (define-key-after map [menu-bar mark toggle-marks]
586 '(menu-item "Toggle marks" ibuffer-toggle-marks
587 :help "Unmark marked buffers, and mark unmarked buffers"))
588 (define-key-after map [menu-bar mark mark-forward]
589 '(menu-item "Mark" ibuffer-mark-forward
590 :help "Mark the buffer at point"))
591 (define-key-after map [menu-bar mark unmark-forward]
592 '(menu-item "Unmark" ibuffer-unmark-forward
593 :help "Unmark the buffer at point"))
594 (define-key-after map [menu-bar mark mark-by-mode]
595 '(menu-item "Mark by mode..." ibuffer-mark-by-mode
596 :help "Mark all buffers in a particular major mode"))
597 (define-key-after map [menu-bar mark mark-modified-buffers]
598 '(menu-item "Mark modified buffers" ibuffer-mark-modified-buffers
599 :help "Mark all buffers which have been modified"))
600 (define-key-after map [menu-bar mark mark-unsaved-buffers]
601 '(menu-item "Mark unsaved buffers" ibuffer-mark-unsaved-buffers
602 :help "Mark all buffers which have a file and are modified"))
603 (define-key-after map [menu-bar mark mark-read-only-buffers]
604 '(menu-item "Mark read-only buffers" ibuffer-mark-read-only-buffers
605 :help "Mark all buffers which are read-only"))
606 (define-key-after map [menu-bar mark mark-special-buffers]
607 '(menu-item "Mark special buffers" ibuffer-mark-special-buffers
608 :help "Mark all buffers whose name begins with a *"))
609 (define-key-after map [menu-bar mark mark-dired-buffers]
610 '(menu-item "Mark dired buffers" ibuffer-mark-dired-buffers
611 :help "Mark buffers in dired-mode"))
612 (define-key-after map [menu-bar mark mark-dissociated-buffers]
613 '(menu-item "Mark dissociated buffers" ibuffer-mark-dissociated-buffers
614 :help "Mark buffers with a non-existent associated file"))
615 (define-key-after map [menu-bar mark mark-help-buffers]
616 '(menu-item "Mark help buffers" ibuffer-mark-help-buffers
617 :help "Mark buffers in help-mode"))
618 (define-key-after map [menu-bar mark mark-old-buffers]
619 '(menu-item "Mark old buffers" ibuffer-mark-old-buffers
620 :help "Mark buffers which have not been viewed recently"))
621 (define-key-after map [menu-bar mark unmark-all]
622 '(menu-item "Unmark All" ibuffer-unmark-all))
623
624 (define-key-after map [menu-bar mark dashes]
625 '("--"))
626
627 (define-key-after map [menu-bar mark mark-by-name-regexp]
628 '(menu-item "Mark by buffer name (regexp)..." ibuffer-mark-by-name-regexp
629 :help "Mark buffers whose name matches a regexp"))
630 (define-key-after map [menu-bar mark mark-by-mode-regexp]
631 '(menu-item "Mark by major mode (regexp)..." ibuffer-mark-by-mode-regexp
632 :help "Mark buffers whose major mode name matches a regexp"))
633 (define-key-after map [menu-bar mark mark-by-file-name-regexp]
634 '(menu-item "Mark by file name (regexp)..." ibuffer-mark-by-file-name-regexp
635 :help "Mark buffers whose file name matches a regexp"))
636
637 ;; Operate map is added later
638
639 (define-key-after operate-map [do-view]
640 '(menu-item "View" ibuffer-do-view))
641 (define-key-after operate-map [do-view-other-frame]
642 '(menu-item "View (separate frame)" ibuffer-do-view-other-frame))
643 (define-key-after operate-map [do-save]
644 '(menu-item "Save" ibuffer-do-save))
645 (define-key-after operate-map [do-replace-regexp]
646 '(menu-item "Replace (regexp)..." ibuffer-do-replace-regexp
647 :help "Replace text inside marked buffers"))
648 (define-key-after operate-map [do-query-replace]
649 '(menu-item "Query Replace..." ibuffer-do-query-replace
650 :help "Replace text in marked buffers, asking each time"))
651 (define-key-after operate-map [do-query-replace-regexp]
652 '(menu-item "Query Replace (regexp)..." ibuffer-do-query-replace-regexp
653 :help "Replace text in marked buffers by regexp, asking each time"))
654 (define-key-after operate-map [do-print]
655 '(menu-item "Print" ibuffer-do-print))
656 (define-key-after operate-map [do-toggle-modified]
657 '(menu-item "Toggle modification flag" ibuffer-do-toggle-modified))
658 (define-key-after operate-map [do-revert]
659 '(menu-item "Revert" ibuffer-do-revert
660 :help "Revert marked buffers to their associated file"))
661 (define-key-after operate-map [do-rename-uniquely]
662 '(menu-item "Rename Uniquely" ibuffer-do-rename-uniquely
663 :help "Rename marked buffers to a new, unique name"))
664 (define-key-after operate-map [do-delete]
665 '(menu-item "Kill" ibuffer-do-delete))
666 (define-key-after operate-map [do-occur]
667 '(menu-item "List lines matching..." ibuffer-do-occur
668 :help "View all lines in marked buffers matching a regexp"))
669 (define-key-after operate-map [do-shell-command-pipe]
670 '(menu-item "Pipe to shell command..." ibuffer-do-shell-command-pipe
671 :help "For each marked buffer, send its contents to a shell command"))
672 (define-key-after operate-map [do-shell-command-pipe-replace]
673 '(menu-item "Pipe to shell command (replace)..." ibuffer-do-shell-command-pipe-replace
674 :help "For each marked buffer, replace its contents with output of shell command"))
675 (define-key-after operate-map [do-shell-command-file]
676 '(menu-item "Shell command on buffer's file..." ibuffer-do-shell-command-file
677 :help "For each marked buffer, run a shell command with its file as argument"))
678 (define-key-after operate-map [do-eval]
679 '(menu-item "Eval..." ibuffer-do-eval
680 :help "Evaluate a Lisp form in each marked buffer"))
681 (define-key-after operate-map [do-view-and-eval]
682 '(menu-item "Eval (viewing buffer)..." ibuffer-do-view-and-eval
683 :help "Evaluate a Lisp form in each marked buffer while viewing it"))
684
685 (setq ibuffer-mode-map map
686 ibuffer-mode-operate-map operate-map)))
687
688(defvar ibuffer-name-map nil)
689(unless ibuffer-name-map
690 (let ((map (make-sparse-keymap)))
691 (set-keymap-parent map ibuffer-mode-map)
692 (define-key map [(mouse-1)] 'ibuffer-mouse-toggle-mark)
693 (define-key map [(mouse-2)] 'ibuffer-mouse-visit-buffer)
694 (define-key map [down-mouse-3] 'ibuffer-mouse-popup-menu)
695 (setq ibuffer-name-map map)))
696
697(defvar ibuffer-mode-name-map nil)
698(unless ibuffer-mode-name-map
699 (let ((map (make-sparse-keymap)))
700 (set-keymap-parent map ibuffer-mode-map)
701 (define-key map [(mouse-2)] 'ibuffer-mouse-filter-by-mode)
702 (define-key map (kbd "RET") 'ibuffer-interactive-filter-by-mode)
703 (setq ibuffer-mode-name-map map)))
704
b5cd37ea
CW
705(defvar ibuffer-mode-filter-group-map nil)
706(unless ibuffer-mode-filter-group-map
707 (let ((map (make-sparse-keymap)))
708 (set-keymap-parent map ibuffer-mode-map)
709 (define-key map [(mouse-1)] 'ibuffer-mouse-toggle-mark)
710 (define-key map [(mouse-2)] 'ibuffer-mouse-toggle-filter-group)
711 (define-key map (kbd "RET") 'ibuffer-toggle-filter-group)
712 (setq ibuffer-mode-filter-group-map map)))
713
25d2f683
CW
714;; quiet the byte-compiler
715(defvar ibuffer-mode-operate-menu nil)
716(defvar ibuffer-mode-mark-menu nil)
717(defvar ibuffer-mode-view-menu nil)
718
719(defvar ibuffer-mode-hooks nil)
720
721(defvar ibuffer-delete-window-on-quit nil
722 "Whether or not to delete the window upon exiting `ibuffer'.")
723
724(defvar ibuffer-did-modification nil)
725
726(defvar ibuffer-sorting-functions-alist nil
727 "An alist of functions which describe how to sort buffers.
728
729Note: You most likely do not want to modify this variable directly;
730use `define-ibuffer-sorter' instead.
731
732The alist elements are constructed like (NAME DESCRIPTION FUNCTION)
733Where NAME is a symbol describing the sorting method, DESCRIPTION is a
734short string which will be displayed in the minibuffer and menu, and
735FUNCTION is a function of two arguments, which will be the buffers to
736compare.")
737
738;;; Utility functions
739(defun ibuffer-columnize-and-insert-list (list &optional pad-width)
740 "Insert LIST into the current buffer in as many columns as possible.
741The maximum number of columns is determined by the current window
742width and the longest string in LIST."
743 (unless pad-width
744 (setq pad-width 3))
745 (let ((width (window-width))
746 (max (+ (apply #'max (mapcar #'length list))
747 pad-width)))
748 (let ((columns (/ width max)))
749 (when (zerop columns)
750 (setq columns 1))
751 (while list
752 (dotimes (i (1- columns))
753 (insert (concat (car list) (make-string (- max (length (car list)))
754 ? )))
755 (setq list (cdr list)))
756 (when (not (null list))
757 (insert (pop list)))
758 (insert "\n")))))
759
25d2f683
CW
760(defsubst ibuffer-current-mark ()
761 (cadr (get-text-property (line-beginning-position)
762 'ibuffer-properties)))
763
764(defun ibuffer-mouse-toggle-mark (event)
765 "Toggle the marked status of the buffer chosen with the mouse."
766 (interactive "e")
767 (unwind-protect
b5cd37ea
CW
768 (let ((pt (save-excursion
769 (mouse-set-point event)
770 (point))))
771 (ibuffer-aif (get-text-property (point) 'ibuffer-filter-group-name)
772 (ibuffer-toggle-marks it)
773 (goto-char pt)
774 (let ((mark (ibuffer-current-mark)))
775 (setq buffer-read-only nil)
776 (if (eq mark ibuffer-marked-char)
777 (ibuffer-set-mark ? )
778 (ibuffer-set-mark ibuffer-marked-char)))))
25d2f683
CW
779 (setq buffer-read-only t)))
780
781(defun ibuffer-find-file (file &optional wildcards)
782 "Like `find-file', but default to the directory of the buffer at point."
783 (interactive
784 (let ((default-directory (let ((buf (ibuffer-current-buffer)))
785 (if (buffer-live-p buf)
786 (with-current-buffer buf
787 default-directory)
788 default-directory))))
789 (list (read-file-name "Find file: " default-directory)
790 current-prefix-arg)))
791 (find-file file wildcards))
792
793(defun ibuffer-mouse-visit-buffer (event)
794 "Visit the buffer chosen with the mouse."
795 (interactive "e")
796 (switch-to-buffer
797 (save-excursion
798 (mouse-set-point event)
b5cd37ea 799 (ibuffer-current-buffer t))))
25d2f683
CW
800
801(defun ibuffer-mouse-popup-menu (event)
802 "Display a menu of operations."
803 (interactive "e")
804 (let ((origline (count-lines (point-min) (point))))
805 (unwind-protect
806 (progn
807 (setq buffer-read-only nil)
808 (ibuffer-save-marks
809 ;; hm. we could probably do this in a better fashion
810 (ibuffer-unmark-all ?\r)
811 (setq buffer-read-only nil)
812 (mouse-set-point event)
813 (ibuffer-set-mark ibuffer-marked-char)
814 (setq buffer-read-only nil)
815 (save-excursion
816 (popup-menu ibuffer-mode-operate-map))))
817 (progn
818 (setq buffer-read-only t)
819 (goto-line (1+ origline))))))
b5cd37ea
CW
820
821(defun ibuffer-skip-properties (props direction)
822 (while (and (not (eobp))
823 (let ((hit nil))
824 (dolist (prop props hit)
825 (when (get-text-property (point) prop)
826 (setq hit t)))))
827 (forward-line direction)
828 (beginning-of-line)))
25d2f683 829
b5cd37ea 830(defun ibuffer-backward-line (&optional arg skip-group-names)
25d2f683
CW
831 "Move backwards ARG lines, wrapping around the list if necessary."
832 (interactive "P")
833 (unless arg
834 (setq arg 1))
835 (beginning-of-line)
836 (while (> arg 0)
837 (forward-line -1)
b5cd37ea
CW
838 (when (or (get-text-property (point) 'ibuffer-title)
839 (and skip-group-names
840 (get-text-property (point) 'ibuffer-filter-group-name)))
25d2f683 841 (goto-char (point-max))
60356fb5 842 (beginning-of-line))
b5cd37ea
CW
843 (ibuffer-skip-properties (append '(ibuffer-summary)
844 (when skip-group-names
845 '(ibuffer-filter-group-name)))
846 -1)
60356fb5
CW
847 ;; Handle the special case of no buffers.
848 (when (get-text-property (point) 'ibuffer-title)
849 (forward-line 1)
850 (setq arg 1))
851 (decf arg)))
25d2f683 852
b5cd37ea 853(defun ibuffer-forward-line (&optional arg skip-group-names)
25d2f683
CW
854 "Move forward ARG lines, wrapping around the list if necessary."
855 (interactive "P")
856 (unless arg
857 (setq arg 1))
858 (beginning-of-line)
214b39be
CW
859 (when (or (eobp)
860 (get-text-property (point) 'ibuffer-summary))
861 (goto-char (point-min)))
b5cd37ea
CW
862 (when (or (get-text-property (point) 'ibuffer-title)
863 (and skip-group-names
864 (get-text-property (point) 'ibuffer-filter-group-name)))
865 (when (> arg 0)
866 (decf arg))
867 (ibuffer-skip-properties (append '(ibuffer-title)
868 (when skip-group-names
869 '(ibuffer-filter-group-name)))
870 1))
25d2f683
CW
871 (if (< arg 0)
872 (ibuffer-backward-line (- arg))
60356fb5
CW
873 (while (> arg 0)
874 (forward-line 1)
875 (when (or (eobp)
876 (get-text-property (point) 'ibuffer-summary))
877 (goto-char (point-min)))
b5cd37ea
CW
878 (decf arg)
879 (ibuffer-skip-properties (append '(ibuffer-title)
880 (when skip-group-names
881 '(ibuffer-filter-group-name)))
882 1))))
25d2f683 883
d246cabf
CW
884(defun ibuffer-visit-buffer (&optional single)
885 "Visit the buffer on this line.
886
887If optional argument SINGLE is non-nil, then also ensure there is only
888one window."
889 (interactive "P")
b5cd37ea 890 (let ((buf (ibuffer-current-buffer t)))
25d2f683 891 (bury-buffer (current-buffer))
d246cabf
CW
892 (switch-to-buffer buf)
893 (when single
894 (delete-other-windows))))
25d2f683
CW
895
896(defun ibuffer-visit-buffer-other-window (&optional noselect)
897 "Visit the buffer on this line in another window."
898 (interactive)
b5cd37ea 899 (let ((buf (ibuffer-current-buffer t)))
25d2f683
CW
900 (bury-buffer (current-buffer))
901 (if noselect
902 (let ((curwin (selected-window)))
903 (pop-to-buffer buf)
904 (select-window curwin))
905 (switch-to-buffer-other-window buf))))
906
907(defun ibuffer-visit-buffer-other-window-noselect ()
908 "Visit the buffer on this line in another window, but don't select it."
909 (interactive)
910 (ibuffer-visit-buffer-other-window t))
911
912(defun ibuffer-visit-buffer-other-frame ()
913 "Visit the buffer on this line in another frame."
914 (interactive)
b5cd37ea 915 (let ((buf (ibuffer-current-buffer t)))
25d2f683
CW
916 (bury-buffer (current-buffer))
917 (switch-to-buffer-other-frame buf)))
918
919(defun ibuffer-visit-buffer-1-window ()
920 "Visit the buffer on this line, and delete other windows."
921 (interactive)
d246cabf 922 (ibuffer-visit-buffer t))
25d2f683
CW
923
924(defun ibuffer-bury-buffer ()
925 "Bury the buffer on this line."
926 (interactive)
b5cd37ea 927 (let ((buf (ibuffer-current-buffer t))
25d2f683 928 (line (+ 1 (count-lines 1 (point)))))
25d2f683
CW
929 (bury-buffer buf)
930 (ibuffer-update nil t)
931 (goto-line line)))
932
933(defun ibuffer-visit-tags-table ()
934 "Visit the tags table in the buffer on this line. See `visit-tags-table'."
935 (interactive)
b5cd37ea 936 (let ((file (buffer-file-name (ibuffer-current-buffer t))))
25d2f683
CW
937 (if file
938 (visit-tags-table file)
939 (error "Specified buffer has no file"))))
940
941(defun ibuffer-do-view (&optional other-frame)
942 "View marked buffers, or the buffer on the current line.
943If optional argument OTHER-FRAME is non-nil, then display each
944marked buffer in a new frame. Otherwise, display each buffer as
945a new window in the current frame, splitting vertically."
946 (interactive)
947 (ibuffer-do-view-1 (if other-frame 'other-frame 'vertically)))
948
949(defun ibuffer-do-view-horizontally (&optional other-frame)
950 "As `ibuffer-do-view', but split windows horizontally."
951 (interactive)
952 (ibuffer-do-view-1 (if other-frame 'other-frame 'horizontally)))
953
954(defun ibuffer-do-view-1 (type)
955 (let ((marked-bufs (ibuffer-get-marked-buffers)))
956 (when (null marked-bufs)
b5cd37ea 957 (setq marked-bufs (list (ibuffer-current-buffer t))))
25d2f683
CW
958 (unless (and (eq type 'other-frame)
959 (not ibuffer-expert)
960 (> (length marked-bufs) 3)
961 (not (y-or-n-p (format "Really create a new frame for %s buffers? "
962 (length marked-bufs)))))
963 (set-buffer-modified-p nil)
964 (delete-other-windows)
965 (switch-to-buffer (pop marked-bufs))
966 (let ((height (/ (1- (if (eq type 'horizontally) (frame-width)
967 (frame-height)))
968 (1+ (length marked-bufs)))))
969 (mapcar (if (eq type 'other-frame)
970 #'(lambda (buf)
971 (let ((curframe (selected-frame)))
972 (select-frame (new-frame))
973 (switch-to-buffer buf)
974 (select-frame curframe)))
975 #'(lambda (buf)
976 (split-window nil height (eq type 'horizontally))
977 (other-window 1)
978 (switch-to-buffer buf)))
979 marked-bufs)))))
980
981(defun ibuffer-do-view-other-frame ()
982 "View each of the marked buffers in a separate frame."
983 (interactive)
984 (ibuffer-do-view t))
985
986(defsubst ibuffer-map-marked-lines (func)
987 (prog1 (ibuffer-map-on-mark ibuffer-marked-char func)
988 (ibuffer-redisplay t)))
989
990(defun ibuffer-shrink-to-fit (&optional owin)
991 (fit-window-to-buffer nil (when owin (/ (frame-height)
992 (length (window-list (selected-frame)))))))
993
994(defun ibuffer-confirm-operation-on (operation names)
995 "Display a buffer asking whether to perform OPERATION on NAMES."
996 (or ibuffer-expert
997 (if (= (length names) 1)
998 (y-or-n-p (format "Really %s buffer %s? " operation (car names)))
999 (let ((buf (get-buffer-create "*Ibuffer confirmation*")))
1000 (with-current-buffer buf
1001 (setq buffer-read-only nil)
1002 (erase-buffer)
1003 (ibuffer-columnize-and-insert-list names)
1004 (goto-char (point-min))
1005 (setq buffer-read-only t))
1006 (let ((lastwin (car (last (ibuffer-window-list)))))
1007 ;; Now attempt to display the buffer...
1008 (save-window-excursion
1009 (select-window lastwin)
1010 ;; The window might be too small to split; in that case,
1011 ;; try a few times to increase its size before giving up.
1012 (let ((attempts 0)
1013 (trying t))
1014 (while trying
1015 (condition-case err
1016 (progn
1017 (split-window)
1018 (setq trying nil))
1019 (error
1020 ;; Handle a failure
1021 (if (or (> (incf attempts) 4)
1022 (and (stringp (cadr err))
1023 ;; This definitely falls in the ghetto hack category...
1024 (not (string-match "too small" (cadr err)))))
1025 (apply #'signal err)
1026 (enlarge-window 3))))))
1027 ;; This part doesn't work correctly sometimes under XEmacs.
1028 (select-window (next-window))
1029 (switch-to-buffer buf)
1030 (unwind-protect
1031 (progn
1032 (fit-window-to-buffer)
1033 (y-or-n-p (format "Really %s %d buffers? "
1034 operation (length names))))
1035 (kill-buffer buf))))))))
1036
1037(defsubst ibuffer-map-lines-nomodify (function)
1038 "As `ibuffer-map-lines', but don't set the modification flag."
1039 (ibuffer-map-lines function t))
1040
1041(defun ibuffer-buffer-names-with-mark (mark)
1042 (let ((ibuffer-buffer-names-with-mark-result nil))
1043 (ibuffer-map-lines-nomodify
57c9cc3e 1044 #'(lambda (buf mk)
25d2f683
CW
1045 (when (char-equal mark mk)
1046 (push (buffer-name buf)
1047 ibuffer-buffer-names-with-mark-result))))
1048 ibuffer-buffer-names-with-mark-result))
1049
1050(defsubst ibuffer-marked-buffer-names ()
1051 (ibuffer-buffer-names-with-mark ibuffer-marked-char))
1052
1053(defsubst ibuffer-deletion-marked-buffer-names ()
1054 (ibuffer-buffer-names-with-mark ibuffer-deletion-char))
1055
1056(defun ibuffer-count-marked-lines (&optional all)
1057 (if all
1058 (ibuffer-map-lines-nomodify
57c9cc3e 1059 #'(lambda (buf mark)
25d2f683
CW
1060 (not (char-equal mark ? ))))
1061 (ibuffer-map-lines-nomodify
57c9cc3e 1062 #'(lambda (buf mark)
25d2f683
CW
1063 (char-equal mark ibuffer-marked-char)))))
1064
1065(defsubst ibuffer-count-deletion-lines ()
1066 (ibuffer-map-lines-nomodify
57c9cc3e 1067 #'(lambda (buf mark)
25d2f683
CW
1068 (char-equal mark ibuffer-deletion-char))))
1069
1070(defsubst ibuffer-map-deletion-lines (func)
1071 (ibuffer-map-on-mark ibuffer-deletion-char func))
1072
1073(define-ibuffer-op save ()
1074 "Save marked buffers as with `save-buffer'."
1075 (:complex t
1076 :opstring "saved"
1077 :modifier-p :maybe)
1078 (when (buffer-modified-p buf)
1079 (if (not (with-current-buffer buf
1080 buffer-file-name))
1081 ;; handle the case where we're prompted
1082 ;; for a file name
1083 (save-window-excursion
1084 (switch-to-buffer buf)
1085 (save-buffer))
1086 (with-current-buffer buf
1087 (save-buffer))))
1088 t)
1089
1090(define-ibuffer-op toggle-modified ()
1091 "Toggle modification flag of marked buffers."
1092 (:opstring "(un)marked as modified"
1093 :modifier-p t)
1094 (set-buffer-modified-p (not (buffer-modified-p))))
1095
1096(define-ibuffer-op toggle-read-only ()
1097 "Toggle read only status in marked buffers."
1098 (:opstring "toggled read only status in"
1099 :modifier-p t)
1100 (toggle-read-only))
1101
1102(define-ibuffer-op delete ()
1103 "Kill marked buffers as with `kill-this-buffer'."
1104 (:opstring "killed"
1105 :active-opstring "kill"
1106 :dangerous t
1107 :complex t
1108 :modifier-p t)
1109 (if (kill-buffer buf)
1110 'kill
1111 nil))
1112
1113(define-ibuffer-op kill-on-deletion-marks ()
1114 "Kill buffers marked for deletion as with `kill-this-buffer'."
1115 (:opstring "killed"
1116 :active-opstring "kill"
1117 :dangerous t
1118 :complex t
1119 :mark :deletion
1120 :modifier-p t)
1121 (if (kill-buffer buf)
1122 'kill
1123 nil))
1124
1125(defun ibuffer-unmark-all (mark)
1126 "Unmark all buffers with mark MARK."
1127 (interactive "cRemove marks (RET means all):")
1128 (if (= (ibuffer-count-marked-lines t) 0)
1129 (message "No buffers marked; use 'm' to mark a buffer")
1130 (cond
1131 ((char-equal mark ibuffer-marked-char)
1132 (ibuffer-map-marked-lines
57c9cc3e 1133 #'(lambda (buf mark)
25d2f683
CW
1134 (ibuffer-set-mark-1 ? )
1135 t)))
1136 ((char-equal mark ibuffer-deletion-char)
1137 (ibuffer-map-deletion-lines
57c9cc3e 1138 #'(lambda (buf mark)
25d2f683
CW
1139 (ibuffer-set-mark-1 ? )
1140 t)))
1141 (t
1142 (ibuffer-map-lines
57c9cc3e 1143 #'(lambda (buf mark)
25d2f683
CW
1144 (when (not (char-equal mark ? ))
1145 (ibuffer-set-mark-1 ? ))
1146 t)))))
1147 (ibuffer-redisplay t))
1148
b5cd37ea 1149(defun ibuffer-toggle-marks (&optional group)
25d2f683
CW
1150 "Toggle which buffers are marked.
1151In other words, unmarked buffers become marked, and marked buffers
1152become unmarked."
1153 (interactive)
1154 (let ((count
1155 (ibuffer-map-lines
57c9cc3e 1156 #'(lambda (buf mark)
25d2f683
CW
1157 (cond ((eq mark ibuffer-marked-char)
1158 (ibuffer-set-mark-1 ? )
1159 nil)
1160 ((eq mark ? )
1161 (ibuffer-set-mark-1 ibuffer-marked-char)
1162 t)
1163 (t
b5cd37ea
CW
1164 nil)))
1165 nil group)))
25d2f683
CW
1166 (message "%s buffers marked" count))
1167 (ibuffer-redisplay t))
1168
1169(defun ibuffer-mark-forward (arg)
1170 "Mark the buffer on this line, and move forward ARG lines."
1171 (interactive "P")
1172 (ibuffer-mark-interactive arg ibuffer-marked-char 1))
1173
1174(defun ibuffer-unmark-forward (arg)
1175 "Unmark the buffer on this line, and move forward ARG lines."
1176 (interactive "P")
1177 (ibuffer-mark-interactive arg ? 1))
1178
1179(defun ibuffer-unmark-backward (arg)
1180 "Unmark the buffer on this line, and move backward ARG lines."
1181 (interactive "P")
1182 (ibuffer-mark-interactive arg ? -1))
1183
1184(defun ibuffer-mark-interactive (arg mark movement)
1185 (assert (eq major-mode 'ibuffer-mode))
1186 (unless arg
1187 (setq arg 1))
b5cd37ea 1188 (ibuffer-forward-line 0 t)
25d2f683
CW
1189 (let ((inhibit-read-only t))
1190 (while (> arg 0)
1191 (ibuffer-set-mark mark)
b5cd37ea 1192 (ibuffer-forward-line movement t)
25d2f683
CW
1193 (setq arg (1- arg)))))
1194
1195(defun ibuffer-set-mark (mark)
1196 (assert (eq major-mode 'ibuffer-mode))
1197 (let ((inhibit-read-only t))
1198 (ibuffer-set-mark-1 mark)
1199 (setq ibuffer-did-modification t)
559ac4c1
CW
1200 (ibuffer-redisplay-current)
1201 (beginning-of-line)))
25d2f683
CW
1202
1203(defun ibuffer-set-mark-1 (mark)
1204 (let ((beg (line-beginning-position))
1205 (end (line-end-position)))
1206 (put-text-property beg end 'ibuffer-properties
1207 (list (ibuffer-current-buffer)
1208 mark))))
1209
1210(defun ibuffer-mark-for-delete (arg)
1211 "Mark the buffers on ARG lines forward for deletion."
1212 (interactive "P")
1213 (ibuffer-mark-interactive arg ibuffer-deletion-char 1))
1214
1215(defun ibuffer-mark-for-delete-backwards (arg)
1216 "Mark the buffers on ARG lines backward for deletion."
1217 (interactive "P")
1218 (ibuffer-mark-interactive arg ibuffer-deletion-char -1))
1219
1220(defun ibuffer-current-buffer (&optional must-be-live)
1221 (let ((buf (car (get-text-property (line-beginning-position)
1222 'ibuffer-properties))))
b5cd37ea
CW
1223 (when must-be-live
1224 (if (bufferp buf)
1225 (unless (buffer-live-p buf)
1226 (error (substitute-command-keys "Buffer %s has been killed; use `\\[ibuffer-update]' to update") buf))
1227 (error "No buffer on this line")))
25d2f683 1228 buf))
523304ed
CW
1229
1230(defun ibuffer-active-formats-name ()
1231 (if (boundp 'ibuffer-filter-format-alist)
1232 (let ((ret nil))
1233 (dolist (filter ibuffer-filtering-qualifiers ret)
1234 (let ((val (assq (car filter) ibuffer-filter-format-alist)))
1235 (when val
1236 (setq ret (car filter)))))
1237 (if ret
1238 ret
1239 :ibuffer-formats))
1240 :ibuffer-formats))
1241
1242(defun ibuffer-current-formats (uncompiledp)
1243 (let* ((name (ibuffer-active-formats-name)))
1244 (ibuffer-check-formats)
1245 (if (eq name :ibuffer-formats)
1246 (if uncompiledp
1247 ibuffer-formats
1248 ibuffer-compiled-formats)
1249 (cadr (assq name
1250 (if uncompiledp
1251 ibuffer-filter-format-alist
1252 ibuffer-compiled-filter-formats))))))
1253
1254(defun ibuffer-current-format (&optional uncompiledp)
25d2f683
CW
1255 (or ibuffer-current-format
1256 (setq ibuffer-current-format 0))
523304ed 1257 (nth ibuffer-current-format (ibuffer-current-formats uncompiledp)))
25d2f683
CW
1258
1259(defun ibuffer-expand-format-entry (form)
1260 (if (or (consp form)
1261 (symbolp form))
1262 (let ((sym (intern (concat "ibuffer-make-column-"
1263 (symbol-name (if (consp form)
1264 (car form)
1265 form))))))
1266 (unless (or (fboundp sym)
1267 (assq sym ibuffer-inline-columns))
1268 (error "Unknown column %s in ibuffer-formats" form))
1269 (let (min max align elide)
1270 (if (consp form)
1271 (setq min (or (nth 1 form) 0)
1272 max (or (nth 2 form) -1)
1273 align (or (nth 3 form) :left)
1274 elide (or (nth 4 form) nil))
1275 (setq min 0
1276 max -1
1277 align :left
1278 elide nil))
1279 (list sym min max align elide)))
1280 form))
1281
1282(defun ibuffer-compile-make-eliding-form (strvar elide from-end-p)
1283 (let ((ellipsis (if (ibuffer-use-fontification)
1284 (propertize ibuffer-eliding-string 'face 'bold)
1285 ibuffer-eliding-string)))
1286 (if (or elide ibuffer-elide-long-columns)
1287 `(if (> strlen 5)
1288 ,(if from-end-p
1289 `(concat ,ellipsis
1290 (substring ,strvar
1291 (length ibuffer-eliding-string)))
1292 `(concat
1293 (substring ,strvar 0 (- strlen ,(length ellipsis)))
1294 ,ellipsis))
1295 ,strvar)
1296 strvar)))
1297
1298(defun ibuffer-compile-make-substring-form (strvar maxvar from-end-p)
1299 (if from-end-p
1300 `(substring str
1301 (- strlen ,maxvar))
1302 `(substring ,strvar 0 ,maxvar)))
1303
1304(defun ibuffer-compile-make-format-form (strvar widthform alignment)
1305 (let* ((left `(make-string tmp2 ? ))
1306 (right `(make-string (- tmp1 tmp2) ? )))
1307 `(progn
1308 (setq tmp1 ,widthform
1309 tmp2 (/ tmp1 2))
1310 ,(case alignment
1311 (:right `(concat ,left ,right ,strvar))
1312 (:center `(concat ,left ,strvar ,right))
1313 (:left `(concat ,strvar ,left ,right))
1314 (t (error "Invalid alignment %s" alignment))))))
1315
1316(defun ibuffer-compile-format (format)
1317 (let ((result nil)
cb059426
CW
1318 ;; We use these variables to keep track of which variables
1319 ;; inside the generated function we need to bind, since
1320 ;; binding variables in Emacs takes time.
1321 str-used tmp1-used tmp2-used global-strlen-used)
25d2f683
CW
1322 (dolist (form format)
1323 (push
cb059426
CW
1324 ;; Generate a form based on a particular format entry, like
1325 ;; " ", mark, or (mode 16 16 :right).
25d2f683 1326 (if (stringp form)
cb059426 1327 ;; It's a string; all we need to do is insert it.
25d2f683
CW
1328 `(insert ,form)
1329 (let* ((form (ibuffer-expand-format-entry form))
1330 (sym (nth 0 form))
1331 (min (nth 1 form))
1332 (max (nth 2 form))
1333 (align (nth 3 form))
1334 (elide (nth 4 form)))
1335 (let* ((from-end-p (when (minusp min)
1336 (setq min (- min))
1337 t))
1338 (letbindings nil)
1339 (outforms nil)
1340 minform
1341 maxform
1342 min-used max-used strlen-used)
1343 (when (or (not (integerp min)) (>= min 0))
cb059426
CW
1344 ;; This is a complex case; they want it limited to a
1345 ;; minimum size.
25d2f683
CW
1346 (setq min-used t)
1347 (setq str-used t strlen-used t global-strlen-used t
1348 tmp1-used t tmp2-used t)
cb059426 1349 ;; Generate code to limit the string to a minimum size.
25d2f683
CW
1350 (setq minform `(progn
1351 (setq str
1352 ,(ibuffer-compile-make-format-form
1353 'str
1354 `(- ,(if (integerp min)
1355 min
1356 'min)
1357 strlen)
1358 align)))))
1359 (when (or (not (integerp max)) (> max 0))
1360 (setq str-used t max-used t)
cb059426 1361 ;; Generate code to limit the string to a maximum size.
25d2f683
CW
1362 (setq maxform `(progn
1363 (setq str
1364 ,(ibuffer-compile-make-substring-form
1365 'str
1366 (if (integerp max)
1367 max
1368 'max)
1369 from-end-p))
1370 (setq strlen (length str))
1371 (setq str
1372 ,(ibuffer-compile-make-eliding-form 'str
1373 elide
1374 from-end-p)))))
cb059426
CW
1375 ;; Now, put these forms together with the rest of the code.
1376 (let ((callform
1377 ;; Is this an "inline" column? This means we have
1378 ;; to get the code from the
1379 ;; `ibuffer-inline-columns' alist and insert it
1380 ;; into our generated code. Otherwise, we just
1381 ;; generate a call to the column function.
1382 (ibuffer-aif (assq sym ibuffer-inline-columns)
1383 (nth 1 it)
1384 `(,sym buffer mark)))
1385 ;; You're not expected to understand this. Hell, I
1386 ;; don't even understand it, and I wrote it five
1387 ;; minutes ago.
1388 (insertgenfn (ibuffer-aif (get sym 'ibuffer-column-summarizer)
1389 ;; I really, really wish Emacs Lisp had closures.
1390 (lambda (arg sym)
1391 `(insert
1392 (let ((ret ,arg))
1393 (put ',sym 'ibuffer-column-summary
1394 (cons ret (get ',sym 'ibuffer-column-summary)))
1395 ret)))
1396 (lambda (arg sym)
1397 `(insert ,arg))))
25d2f683
CW
1398 (mincompform `(< strlen ,(if (integerp min)
1399 min
1400 'min)))
1401 (maxcompform `(> strlen ,(if (integerp max)
1402 max
1403 'max))))
1404 (if (or min-used max-used)
cb059426
CW
1405 ;; The complex case, where we have to limit the
1406 ;; form to a maximum or minimum size.
25d2f683
CW
1407 (progn
1408 (when (and min-used (not (integerp min)))
1409 (push `(min ,min) letbindings))
1410 (when (and max-used (not (integerp max)))
1411 (push `(max ,max) letbindings))
1412 (push
1413 (if (and min-used max-used)
1414 `(if ,mincompform
1415 ,minform
1416 (if ,maxcompform
1417 ,maxform))
1418 (if min-used
1419 `(when ,mincompform
1420 ,minform)
1421 `(when ,maxcompform
1422 ,maxform)))
1423 outforms)
1424 (push (append
1425 `(setq str ,callform)
1426 (when strlen-used
1427 `(strlen (length str))))
1428 outforms)
1429 (setq outforms
cb059426
CW
1430 (append outforms (list (funcall insertgenfn 'str sym)))))
1431 ;; The simple case; just insert the string.
1432 (push (funcall insertgenfn callform sym) outforms))
1433 ;; Finally, return a `let' form which binds the
1434 ;; variables in `letbindings', and contains all the
1435 ;; code in `outforms'.
25d2f683
CW
1436 `(let ,letbindings
1437 ,@outforms)))))
1438 result))
1439 (setq result
cb059426 1440 ;; We don't want to unconditionally load the byte-compiler.
25d2f683
CW
1441 (funcall (if (or ibuffer-always-compile-formats
1442 (featurep 'bytecomp))
1443 #'byte-compile
1444 #'identity)
cb059426
CW
1445 ;; Here, we actually create a lambda form which
1446 ;; inserts all the generated forms for each entry
1447 ;; in the format string.
25d2f683 1448 (nconc (list 'lambda '(buffer mark))
d99b259b 1449 `((let ,(append (when str-used
25d2f683
CW
1450 '(str))
1451 (when global-strlen-used
1452 '(strlen))
1453 (when tmp1-used
1454 '(tmp1))
1455 (when tmp2-used
1456 '(tmp2)))
1457 ,@(nreverse result))))))))
1458
1459(defvar ibuffer-compiled-formats nil)
1460(defvar ibuffer-cached-formats nil)
1461(defvar ibuffer-cached-eliding-string nil)
1462(defvar ibuffer-cached-elide-long-columns 0)
1463
1464(defun ibuffer-recompile-formats ()
1465 "Recompile `ibuffer-formats'."
1466 (interactive)
1467 (setq ibuffer-compiled-formats
523304ed
CW
1468 (mapcar #'ibuffer-compile-format ibuffer-formats))
1469 (when (boundp 'ibuffer-filter-format-alist)
1470 (setq ibuffer-compiled-filter-formats
1471 (mapcar #'(lambda (entry)
1472 (cons (car entry)
1473 (mapcar #'(lambda (formats)
1474 (mapcar #'ibuffer-compile-format formats))
1475 (cdr entry))))
1476 ibuffer-filter-format-alist))))
25d2f683 1477
cb059426
CW
1478(defun ibuffer-clear-summary-columns (format)
1479 (dolist (form format)
1480 (ibuffer-awhen (and (consp form)
1481 (get (car form) 'ibuffer-column-summarizer))
1482 (put (car form) 'ibuffer-column-summary nil))))
1483
25d2f683 1484(defun ibuffer-check-formats ()
523304ed
CW
1485 (when (null ibuffer-formats)
1486 (error "No formats!"))
b5cd37ea
CW
1487 (let ((ext-loaded (featurep 'ibuf-ext)))
1488 (when (or (null ibuffer-compiled-formats)
1489 (null ibuffer-cached-formats)
1490 (not (eq ibuffer-cached-formats ibuffer-formats))
1491 (null ibuffer-cached-eliding-string)
1492 (not (equal ibuffer-cached-eliding-string ibuffer-eliding-string))
1493 (eql 0 ibuffer-cached-elide-long-columns)
1494 (not (eql ibuffer-cached-elide-long-columns
1495 ibuffer-elide-long-columns))
1496 (and ext-loaded
1497 (not (eq ibuffer-cached-filter-formats
1498 ibuffer-filter-format-alist))
1499 (and ibuffer-filter-format-alist
1500 (null ibuffer-compiled-filter-formats))))
1501 (message "Formats have changed, recompiling...")
1502 (ibuffer-recompile-formats)
1503 (setq ibuffer-cached-formats ibuffer-formats
1504 ibuffer-cached-eliding-string ibuffer-eliding-string
1505 ibuffer-cached-elide-long-columns ibuffer-elide-long-columns)
1506 (when ext-loaded
1507 (setq ibuffer-cached-filter-formats ibuffer-filter-format-alist))
1508 (message "Formats have changed, recompiling...done"))))
25d2f683
CW
1509
1510(defvar ibuffer-inline-columns nil)
1511
1512(define-ibuffer-column mark (:name " " :inline t)
1513 (string mark))
1514
1515(define-ibuffer-column read-only (:name "R" :inline t)
1516 (if buffer-read-only
1517 "%"
1518 " "))
1519
1520(define-ibuffer-column modified (:name "M" :inline t)
1521 (if (buffer-modified-p)
1522 (string ibuffer-modified-char)
1523 " "))
1524
1525(define-ibuffer-column name (:inline t
1526 :props
1527 ('mouse-face 'highlight 'keymap ibuffer-name-map
1528 'ibuffer-name-column t
1529 'help-echo "mouse-1: mark this buffer\nmouse-2: select this buffer\nmouse-3: operate on this buffer"))
1530 (buffer-name))
1531
1532(define-ibuffer-column size (:inline t)
1533 (format "%s" (buffer-size)))
1534
1535(define-ibuffer-column mode (:inline t
1536 :props
1537 ('mouse-face 'highlight
1538 'keymap ibuffer-mode-name-map
1539 'help-echo "mouse-2: filter by this mode"))
1540 (format "%s" mode-name))
1541
1542(define-ibuffer-column process ()
1543 (let ((proc (get-buffer-process buffer)))
523304ed
CW
1544 (if proc
1545 (format "(%s %s)" proc (process-status proc))
1546 "none")))
25d2f683
CW
1547
1548(define-ibuffer-column filename ()
1549 (let ((directory-abbrev-alist ibuffer-directory-abbrev-alist))
1550 (abbreviate-file-name
1551 (or buffer-file-name
1552 (and (boundp 'dired-directory)
1553 dired-directory)
1554 ""))))
1555
1556(defun ibuffer-format-column (str width alignment)
1557 (let ((left (make-string (/ width 2) ? ))
1558 (right (make-string (- width (/ width 2)) ? )))
1559 (case alignment
1560 (:right (concat left right str))
1561 (:center (concat left str right))
1562 (t (concat str left right)))))
1563
1564(defun ibuffer-fontify-region-function (beg end &optional verbose)
1565 (when verbose (message "Fontifying..."))
1566 (let ((inhibit-read-only t))
1567 (save-excursion
1568 (goto-char beg)
1569 (beginning-of-line)
1570 (while (< (point) end)
1571 (if (get-text-property (point) 'ibuffer-title-header)
1572 (put-text-property (point) (line-end-position) 'face ibuffer-title-face)
b5cd37ea
CW
1573 (if (get-text-property (point) 'ibuffer-filter-group-name)
1574 (put-text-property (point) (line-end-position) 'face
1575 ibuffer-filter-group-name-face)
1576 (unless (or (get-text-property (point) 'ibuffer-title)
1577 (get-text-property (point) 'ibuffer-summary))
1578 (multiple-value-bind (buf mark)
1579 (get-text-property (point) 'ibuffer-properties)
1580 (let* ((namebeg (next-single-property-change (point) 'ibuffer-name-column
1581 nil (line-end-position)))
1582 (nameend (next-single-property-change namebeg 'ibuffer-name-column
1583 nil (line-end-position))))
1584 (put-text-property namebeg
1585 nameend
1586 'face
1587 (cond ((char-equal mark ibuffer-marked-char)
1588 ibuffer-marked-face)
1589 ((char-equal mark ibuffer-deletion-char)
1590 ibuffer-deletion-face)
1591 (t
1592 (let ((level -1)
1593 result)
1594 (dolist (e ibuffer-fontification-alist result)
1595 (when (and (> (car e) level)
1596 (with-current-buffer buf
1597 (eval (cadr e))))
1598 (setq level (car e)
1599 result
1600 (if (symbolp (caddr e))
1601 (if (facep (caddr e))
1602 (caddr e)
1603 (symbol-value (caddr e))))))))))))))))
25d2f683
CW
1604 (forward-line 1))))
1605 (when verbose (message "Fontifying...done")))
1606
1607(defun ibuffer-unfontify-region-function (beg end)
1608 (let ((inhibit-read-only t))
1609 (remove-text-properties beg end '(face nil))))
1610
1611(defun ibuffer-insert-buffer-line (buffer mark format)
1612 "Insert a line describing BUFFER and MARK using FORMAT."
1613 (assert (eq major-mode 'ibuffer-mode))
1614 (let ((beg (point)))
25d2f683 1615 (funcall format buffer mark)
cb059426
CW
1616 (put-text-property beg (point) 'ibuffer-properties (list buffer mark)))
1617 (insert "\n"))
25d2f683 1618
cb059426 1619;; This function knows a bit too much of the internals. It would be
b5cd37ea 1620;; nice if it was all abstracted away.
25d2f683
CW
1621(defun ibuffer-redisplay-current ()
1622 (assert (eq major-mode 'ibuffer-mode))
1623 (when (eobp)
1624 (forward-line -1))
1625 (beginning-of-line)
cb059426
CW
1626 (let ((curformat (mapcar #'ibuffer-expand-format-entry
1627 (ibuffer-current-format t))))
1628 (ibuffer-clear-summary-columns curformat)
1629 (let ((buf (ibuffer-current-buffer)))
1630 (when buf
1631 (let ((mark (ibuffer-current-mark)))
ed233dd8
CW
1632 (save-excursion
1633 (delete-region (point) (1+ (line-end-position)))
1634 (ibuffer-insert-buffer-line
1635 buf mark
1636 (ibuffer-current-format)))
cb059426
CW
1637 (when ibuffer-shrink-to-minimum-size
1638 (ibuffer-shrink-to-fit)))))))
25d2f683
CW
1639
1640(defun ibuffer-map-on-mark (mark func)
1641 (ibuffer-map-lines
57c9cc3e 1642 #'(lambda (buf mk)
25d2f683 1643 (if (char-equal mark mk)
57c9cc3e 1644 (funcall func buf mark)
25d2f683
CW
1645 nil))))
1646
b5cd37ea
CW
1647(defun ibuffer-map-lines (function &optional nomodify group)
1648 "Call FUNCTION for each buffer.
25d2f683
CW
1649Don't set the ibuffer modification flag iff NOMODIFY is non-nil.
1650
b5cd37ea
CW
1651If optional argument GROUP is non-nil, then only call FUNCTION on
1652buffers in filtering group GROUP.
1653
25d2f683
CW
1654 FUNCTION is called with four arguments: the buffer object itself, the
1655current mark symbol, and the beginning and ending line positions."
1656 (assert (eq major-mode 'ibuffer-mode))
b5cd37ea
CW
1657 (ibuffer-forward-line 0)
1658 (let* ((orig-target-line (1+ (count-lines (save-excursion
1659 (goto-char (point-min))
1660 (ibuffer-forward-line 0)
1661 (point))
1662 (point))))
1663 (target-line-offset orig-target-line)
1664 (ibuffer-map-lines-total 0)
1665 (ibuffer-map-lines-count 0))
25d2f683 1666 (unwind-protect
57c9cc3e
CW
1667 (progn
1668 (setq buffer-read-only nil)
1669 (goto-char (point-min))
b5cd37ea 1670 (ibuffer-forward-line 0 t)
57c9cc3e 1671 (while (and (not (eobp))
b5cd37ea
CW
1672 (not (get-text-property (point) 'ibuffer-summary))
1673 (progn
1674 (ibuffer-forward-line 0 t)
1675 (and (not (eobp))
1676 (not (get-text-property (point) 'ibuffer-summary)))))
57c9cc3e
CW
1677 (let ((result
1678 (if (buffer-live-p (ibuffer-current-buffer))
b5cd37ea
CW
1679 (when (or (null group)
1680 (ibuffer-aif (get-text-property (point) 'ibuffer-filter-group)
1681 (equal group it)))
1682 (save-excursion
1683 (funcall function
1684 (ibuffer-current-buffer)
1685 (ibuffer-current-mark))))
57c9cc3e
CW
1686 ;; Kill the line if the buffer is dead
1687 'kill)))
1688 ;; A given mapping function should return:
1689 ;; `nil' if it chose not to affect the buffer
1690 ;; `kill' means the remove line from the buffer list
1691 ;; `t' otherwise
1692 (incf ibuffer-map-lines-total)
1693 (cond ((null result)
1694 (forward-line 1))
1695 ((eq result 'kill)
1696 (delete-region (line-beginning-position)
1697 (1+ (line-end-position)))
1698 (incf ibuffer-map-lines-count)
1699 (when (< ibuffer-map-lines-total
1700 orig-target-line)
b5cd37ea 1701 (decf target-line-offset)))
57c9cc3e
CW
1702 (t
1703 (incf ibuffer-map-lines-count)
1704 (forward-line 1)))))
1705 ibuffer-map-lines-count)
25d2f683
CW
1706 (progn
1707 (setq buffer-read-only t)
1708 (unless nomodify
1709 (set-buffer-modified-p nil))
57c9cc3e
CW
1710 (goto-char (point-min))
1711 (ibuffer-forward-line 0)
b5cd37ea 1712 (ibuffer-forward-line (1- target-line-offset))))))
25d2f683
CW
1713
1714(defun ibuffer-get-marked-buffers ()
1715 "Return a list of buffer objects currently marked."
1716 (delq nil
1717 (mapcar #'(lambda (e)
1718 (when (eq (cdr e) ibuffer-marked-char)
1719 (car e)))
1720 (ibuffer-current-state-list))))
1721
d246cabf
CW
1722(defun ibuffer-current-state-list (&optional pos)
1723 "Return a list like (BUF . MARK) of all buffers in an ibuffer.
1724If POS is non-nil, return a list like (BUF MARK POINT), where POINT is
1725the value of point at the beginning of the line for that buffer."
25d2f683
CW
1726 (let ((ibuffer-current-state-list-tmp '()))
1727 ;; ah, if only we had closures. I bet this will mysteriously
1728 ;; break later. Don't blame me.
d246cabf
CW
1729 (if pos
1730 (ibuffer-map-lines-nomodify
1731 #'(lambda (buf mark)
1732 (when (buffer-live-p buf)
1733 (push (list buf mark (point)) ibuffer-current-state-list-tmp))))
1734 (ibuffer-map-lines-nomodify
1735 #'(lambda (buf mark)
1736 (when (buffer-live-p buf)
1737 (push (cons buf mark) ibuffer-current-state-list-tmp)))))
25d2f683
CW
1738 (nreverse ibuffer-current-state-list-tmp)))
1739
b5cd37ea
CW
1740(defun ibuffer-current-filter-groups ()
1741 (save-excursion
1742 (goto-char (point-min))
1743 (let ((pos nil)
1744 (result nil))
1745 (while (and (not (eobp))
1746 (setq pos (next-single-property-change
1747 (point) 'ibuffer-filter-group-name)))
1748 (goto-char pos)
1749 (push (cons (get-text-property (point) 'ibuffer-filter-group-name)
1750 pos)
1751 result)
1752 (goto-char (next-single-property-change
1753 pos 'ibuffer-filter-group-name)))
1754 (nreverse result))))
1755
851476d4 1756(defun ibuffer-current-buffers-with-marks (curbufs)
25d2f683
CW
1757 "Return a list like (BUF . MARK) of all open buffers."
1758 (let ((bufs (ibuffer-current-state-list)))
1759 (mapcar #'(lambda (buf) (let ((e (assq buf bufs)))
1760 (if e
1761 e
1762 (cons buf ? ))))
851476d4 1763 curbufs)))
25d2f683
CW
1764
1765(defun ibuffer-buf-matches-predicates (buf predicates)
1766 (let ((hit nil)
1767 (name (buffer-name buf)))
1768 (dolist (pred predicates)
1769 (when (if (stringp pred)
1770 (string-match pred name)
1771 (funcall pred buf))
1772 (setq hit t)))
1773 hit))
1774
1775(defun ibuffer-filter-buffers (ibuffer-buf last bmarklist all)
1776 (let ((ext-loaded (featurep 'ibuf-ext)))
1777 (delq nil
b5cd37ea
CW
1778 (mapcar
1779 ;; element should be like (BUFFER . MARK)
1780 #'(lambda (e)
1781 (let* ((buf (car e)))
1782 (when
1783 ;; This takes precedence over anything else
1784 (or (and ibuffer-always-show-last-buffer
1785 (eq last buf))
1786 (funcall (if ext-loaded
1787 #'ibuffer-ext-visible-p
1788 #'ibuffer-visible-p)
1789 buf all ibuffer-buf))
1790 e)))
1791 bmarklist))))
25d2f683
CW
1792
1793(defun ibuffer-visible-p (buf all &optional ibuffer-buf)
1794 (and (or all
1795 (not
1796 (ibuffer-buf-matches-predicates buf ibuffer-maybe-show-predicates)))
1797 (or ibuffer-view-ibuffer
1798 (and ibuffer-buf
1799 (not (eq ibuffer-buf buf))))))
1800
1801;; This function is a special case; it's not defined by
1802;; `ibuffer-define-sorter'.
1803(defun ibuffer-do-sort-by-recency ()
1804 "Sort the buffers by last view time."
1805 (interactive)
1806 (setq ibuffer-sorting-mode 'recency)
1807 (ibuffer-redisplay t))
1808
1809(defun ibuffer-update-format ()
1810 (when (null ibuffer-current-format)
1811 (setq ibuffer-current-format 0))
1812 (when (null ibuffer-formats)
1813 (error "Ibuffer error: no formats!")))
1814
1815(defun ibuffer-switch-format ()
1816 "Switch the current display format."
1817 (interactive)
1818 (assert (eq major-mode 'ibuffer-mode))
1819 (unless (consp ibuffer-formats)
1820 (error "Ibuffer error: No formats!"))
1821 (setq ibuffer-current-format
80a06d64 1822 (if (>= ibuffer-current-format (1- (length (ibuffer-current-formats nil))))
25d2f683
CW
1823 0
1824 (1+ ibuffer-current-format)))
1825 (ibuffer-update-format)
1826 (ibuffer-redisplay t))
1827
cb059426 1828(defun ibuffer-update-title-and-summary (format)
25d2f683
CW
1829 (assert (eq major-mode 'ibuffer-mode))
1830 ;; Don't do funky font-lock stuff here
1831 (let ((after-change-functions nil))
1832 (if (get-text-property (point-min) 'ibuffer-title)
1833 (delete-region (point-min)
1834 (next-single-property-change
1835 (point-min) 'ibuffer-title)))
1836 (goto-char (point-min))
1837 (put-text-property
1838 (point)
1839 (progn
1840 (let ((opos (point)))
1841 ;; Insert the title names.
cb059426 1842 (dolist (element format)
25d2f683
CW
1843 (insert
1844 (if (stringp element)
1845 element
1846 (let ((sym (car element))
1847 (min (cadr element))
1848 ;; (max (caddr element))
1849 (align (cadddr element)))
1850 ;; Ignore a negative min when we're inserting the title
1851 (when (minusp min)
1852 (setq min (- min)))
1853 (let* ((name (or (get sym 'ibuffer-column-name)
1854 (error "Unknown column %s in ibuffer-formats" sym)))
1855 (len (length name)))
cb059426
CW
1856 (if (< len min)
1857 (ibuffer-format-column name
1858 (- min len)
1859 align)
1860 name))))))
25d2f683
CW
1861 (put-text-property opos (point) 'ibuffer-title-header t)
1862 (insert "\n")
1863 ;; Add the underlines
1864 (let ((str (save-excursion
1865 (forward-line -1)
1866 (beginning-of-line)
1867 (buffer-substring (point) (line-end-position)))))
1868 (apply #'insert (mapcar
1869 #'(lambda (c)
1870 (if (not (or (char-equal c ? )
1871 (char-equal c ?\n)))
1872 ?-
1873 ? ))
1874 str)))
1875 (insert "\n"))
1876 (point))
cb059426
CW
1877 'ibuffer-title t)
1878 ;; Now, insert the summary columns.
1879 (goto-char (point-max))
1880 (if (get-text-property (1- (point-max)) 'ibuffer-summary)
1881 (delete-region (previous-single-property-change
1882 (point-max) 'ibuffer-summary)
1883 (point-max)))
1884 (put-text-property
1885 (point)
1886 (progn
1887 (insert "\n")
1888 (dolist (element format)
1889 (insert
1890 (if (stringp element)
1891 (make-string (length element) ? )
1892 (let ((sym (car element)))
1893 (let ((min (cadr element))
1894 ;; (max (caddr element))
1895 (align (cadddr element)))
1896 ;; Ignore a negative min when we're inserting the title
1897 (when (minusp min)
1898 (setq min (- min)))
1899 (let* ((summary (if (get sym 'ibuffer-column-summarizer)
1900 (funcall (get sym 'ibuffer-column-summarizer)
1901 (get sym 'ibuffer-column-summary))
1902 (make-string (length (get sym 'ibuffer-column-name))
1903 ? )))
1904 (len (length summary)))
1905 (if (< len min)
1906 (ibuffer-format-column summary
1907 (- min len)
1908 align)
1909 summary)))))))
1910 (point))
1911 'ibuffer-summary t)))
25d2f683
CW
1912
1913(defun ibuffer-update-mode-name ()
1914 (setq mode-name (format "Ibuffer by %s" (if ibuffer-sorting-mode
1915 ibuffer-sorting-mode
cb059426 1916 "view time")))
25d2f683
CW
1917 (when ibuffer-sorting-reversep
1918 (setq mode-name (concat mode-name " [rev]")))
1919 (when (and (featurep 'ibuf-ext)
1920 ibuffer-auto-mode)
1921 (setq mode-name (concat mode-name " (Auto)")))
1922 (let ((result ""))
1923 (when (featurep 'ibuf-ext)
1924 (dolist (qualifier ibuffer-filtering-qualifiers)
1925 (setq result
1926 (concat result (ibuffer-format-qualifier qualifier))))
1927 (if ibuffer-use-header-line
1928 (setq header-line-format
1929 (when ibuffer-filtering-qualifiers
1930 (replace-regexp-in-string "%" "%%"
1931 (concat mode-name result))))
1932 (progn
1933 (setq mode-name (concat mode-name result))
1934 (when (boundp 'header-line-format)
1935 (setq header-line-format nil)))))))
1936
1937(defun ibuffer-redisplay (&optional silent)
1938 "Redisplay the current list of buffers.
1939
1940This does not show new buffers; use `ibuffer-update' for that.
1941
1942If SILENT is non-`nil', do not generate progress messages."
1943 (interactive)
57c9cc3e 1944 (ibuffer-forward-line 0)
25d2f683
CW
1945 (unless silent
1946 (message "Redisplaying current buffer list..."))
1947 (let ((blist (ibuffer-current-state-list)))
1948 (when (null blist)
1949 (if (and (featurep 'ibuf-ext)
b5cd37ea 1950 (or ibuffer-filtering-qualifiers ibuffer-hidden-filtering-groups))
25d2f683
CW
1951 (message "No buffers! (note: filtering in effect)")
1952 (error "No buffers!")))
b5cd37ea 1953 (ibuffer-redisplay-engine blist t)
25d2f683
CW
1954 (ibuffer-update-mode-name)
1955 (unless silent
57c9cc3e
CW
1956 (message "Redisplaying current buffer list...done"))
1957 (ibuffer-forward-line 0)))
25d2f683
CW
1958
1959(defun ibuffer-update (arg &optional silent)
1960 "Regenerate the list of all buffers.
1961
1962Display buffers whose name matches one of `ibuffer-maybe-show-predicates'
1963iff arg ARG is non-nil.
1964
1965Do not display messages if SILENT is non-nil."
1966 (interactive "P")
57c9cc3e 1967 (ibuffer-forward-line 0)
25d2f683
CW
1968 (let* ((bufs (buffer-list))
1969 (blist (ibuffer-filter-buffers
1970 (current-buffer)
1971 (if (and
1972 (cadr bufs)
1973 (eq ibuffer-always-show-last-buffer
1974 :nomini)
1975 ;; This is a hack.
1976 (string-match " \\*Minibuf"
1977 (buffer-name (cadr bufs))))
1978 (caddr bufs)
1979 (cadr bufs))
b23af469 1980 (ibuffer-current-buffers-with-marks bufs)
25d2f683
CW
1981 arg)))
1982 (when (null blist)
1983 (if (and (featurep 'ibuf-ext)
1984 ibuffer-filtering-qualifiers)
1985 (message "No buffers! (note: filtering in effect)")
1986 (error "No buffers!")))
1987 (unless silent
1988 (message "Updating buffer list..."))
b5cd37ea 1989 (ibuffer-redisplay-engine blist arg)
25d2f683
CW
1990 (ibuffer-update-mode-name)
1991 (unless silent
1992 (message "Updating buffer list...done")))
1993 (if (eq ibuffer-shrink-to-minimum-size 'onewindow)
1994 (ibuffer-shrink-to-fit t)
1995 (when ibuffer-shrink-to-minimum-size
1996 (ibuffer-shrink-to-fit)))
1997 (ibuffer-forward-line 0))
1998
b5cd37ea
CW
1999(defun ibuffer-sort-bufferlist (bmarklist)
2000 (let* ((sortdat (assq ibuffer-sorting-mode
2001 ibuffer-sorting-functions-alist))
2002 (func (caddr sortdat)))
2003 (let ((result
2004 ;; actually sort the buffers
2005 (if (and sortdat func)
2006 (sort bmarklist func)
2007 bmarklist)))
2008 ;; perhaps reverse the sorted buffer list
2009 (if ibuffer-sorting-reversep
2010 (nreverse result)
2011 result))))
2012
2013(defun ibuffer-insert-filter-group (name display-name format bmarklist)
2014 (add-text-properties
2015 (point)
2016 (progn
2017 (insert "[ " display-name " ]")
2018 (point))
2019 `(ibuffer-filter-group-name ,name keymap ,ibuffer-mode-filter-group-map
2020 mouse-face highlight
2021 help-echo "mouse-1: toggle marks in this group\nmouse-2: hide/show this filtering group "))
2022 (insert "\n")
2023 (when bmarklist
2024 (put-text-property
2025 (point)
2026 (progn
2027 (dolist (entry bmarklist)
2028 (ibuffer-insert-buffer-line (car entry) (cdr entry) format))
2029 (point))
2030 'ibuffer-filter-group
2031 name)))
2032
2033(defun ibuffer-redisplay-engine (bmarklist &optional all)
25d2f683 2034 (assert (eq major-mode 'ibuffer-mode))
b5cd37ea
CW
2035 (let* ((--ibuffer-insert-buffers-and-marks-format
2036 (ibuffer-current-format))
2037 (--ibuffer-expanded-format (mapcar #'ibuffer-expand-format-entry
2038 (ibuffer-current-format t)))
2039 (orig (count-lines (point-min) (point)))
2040 ;; Inhibit font-lock caching tricks, since we're modifying the
2041 ;; entire buffer at once
2042 (after-change-functions nil)
2043 (ext-loaded (featurep 'ibuf-ext))
2044 (bgroups (if ext-loaded
2045 (ibuffer-generate-filter-groups bmarklist)
2046 (list (cons "Default" bmarklist)))))
cb059426 2047 (ibuffer-clear-summary-columns --ibuffer-expanded-format)
25d2f683
CW
2048 (unwind-protect
2049 (progn
2050 (setq buffer-read-only nil)
2051 (erase-buffer)
2052 (ibuffer-update-format)
b5cd37ea
CW
2053 (dolist (group (nreverse bgroups))
2054 (let* ((name (car group))
2055 (disabled (and ext-loaded
2056 (member name ibuffer-hidden-filtering-groups)))
2057 (bmarklist (cdr group)))
2058 (ibuffer-insert-filter-group
2059 name
2060 (if disabled (concat name " ...") name)
2061 --ibuffer-insert-buffers-and-marks-format
2062 (if disabled
2063 nil
2064 (ibuffer-sort-bufferlist bmarklist)))))
cb059426 2065 (ibuffer-update-title-and-summary --ibuffer-expanded-format))
25d2f683
CW
2066 (setq buffer-read-only t)
2067 (set-buffer-modified-p ibuffer-did-modification)
2068 (setq ibuffer-did-modification nil)
2069 (goto-line (1+ orig)))))
2070
2071(defun ibuffer-quit ()
2072 "Quit this `ibuffer' session.
2073Delete the current window iff `ibuffer-delete-window-on-quit' is non-nil."
2074 (interactive)
2075 (if ibuffer-delete-window-on-quit
2076 (progn
2077 (bury-buffer)
2078 (unless (= (count-windows) 1)
2079 (delete-window)))
2080 (bury-buffer)))
2081
2082;;;###autoload
2083(defun ibuffer-list-buffers (&optional files-only)
2084 "Display a list of buffers, in another window.
2085If optional argument FILES-ONLY is non-nil, then add a filter for
2086buffers which are visiting a file."
2087 (interactive "P")
2088 (ibuffer t nil (when files-only
2089 '((filename . ".*"))) t))
2090
2091;;;###autoload
2092(defun ibuffer-other-window (&optional files-only)
2093 "Like `ibuffer', but displayed in another window by default.
2094If optional argument FILES-ONLY is non-nil, then add a filter for
2095buffers which are visiting a file."
2096 (interactive "P")
2097 (ibuffer t nil (when files-only
2098 '((filename . ".*")))))
2099
2100;;;###autoload
b5cd37ea
CW
2101(defun ibuffer (&optional other-window-p name qualifiers noselect
2102 shrink filter-groups)
25d2f683
CW
2103 "Begin using `ibuffer' to edit a list of buffers.
2104Type 'h' after entering ibuffer for more information.
2105
2106Optional argument OTHER-WINDOW-P says to use another window.
2107Optional argument NAME specifies the name of the buffer; it defaults
2108to \"*Ibuffer*\".
2109Optional argument QUALIFIERS is an initial set of filtering qualifiers
2110to use; see `ibuffer-filtering-qualifiers'.
2111Optional argument NOSELECT means don't select the Ibuffer buffer.
2112Optional argument SHRINK means shrink the buffer to minimal size. The
b5cd37ea
CW
2113special value `onewindow' means always use another window.
2114Optional argument FILTER-GROUPS is an initial set of filtering
2115groups to use; see `ibuffer-filtering-groups'."
25d2f683
CW
2116 (interactive "P")
2117 (when ibuffer-use-other-window
34b8f593 2118 (setq other-window-p t))
25d2f683
CW
2119 (let* ((buf (get-buffer-create (or name "*Ibuffer*")))
2120 (already-in (eq (current-buffer) buf))
2121 (need-update nil))
2122 (if other-window-p
2123 (funcall (if noselect #'(lambda (buf) (display-buffer buf t)) #'pop-to-buffer) buf)
2124 (funcall (if noselect #'display-buffer #'switch-to-buffer) buf))
2125 (with-current-buffer buf
b5cd37ea
CW
2126 (save-selected-window
2127 ;; We switch to the buffer's window in order to be able
2128 ;; to modify the value of point
2129 (select-window (get-buffer-window buf))
2130 (unless (eq major-mode 'ibuffer-mode)
2131 (ibuffer-mode)
2132 (setq need-update t))
2133 (when (ibuffer-use-fontification)
2134 (require 'font-lock))
2135 (setq ibuffer-delete-window-on-quit other-window-p)
2136 (when shrink
2137 (setq ibuffer-shrink-to-minimum-size shrink))
2138 (when qualifiers
2139 (require 'ibuf-ext)
2140 (setq ibuffer-filtering-qualifiers qualifiers))
2141 (when filter-groups
2142 (require 'ibuf-ext)
2143 (setq ibuffer-filtering-groups filter-groups))
2144 (ibuffer-update nil)
2145 ;; Skip the group name by default.
2146 (ibuffer-forward-line 0 t)
25d2f683
CW
2147 (unwind-protect
2148 (progn
b5cd37ea
CW
2149 (setq buffer-read-only nil)
2150 (run-hooks 'ibuffer-hooks))
2151 (setq buffer-read-only t))
2152 (unless ibuffer-expert
2153 (message "Commands: m, u, t, RET, g, k, S, D, Q; q to quit; h for help"))))))
25d2f683 2154
b23af469 2155(put 'ibuffer-mode 'mode-class 'special)
25d2f683
CW
2156(defun ibuffer-mode ()
2157 "A major mode for viewing a list of buffers.
2158In ibuffer, you can conveniently perform many operations on the
2159currently open buffers, in addition to filtering your view to a
2160particular subset of them, and sorting by various criteria.
2161
2162Operations on marked buffers:
2163
2164 '\\[ibuffer-do-save]' - Save the marked buffers
2165 '\\[ibuffer-do-view]' - View the marked buffers in this frame.
2166 '\\[ibuffer-do-view-other-frame]' - View the marked buffers in another frame.
2167 '\\[ibuffer-do-revert]' - Revert the marked buffers.
2168 '\\[ibuffer-do-toggle-read-only]' - Toggle read-only state of marked buffers.
2169 '\\[ibuffer-do-delete]' - Kill the marked buffers.
2170 '\\[ibuffer-do-replace-regexp]' - Replace by regexp in each of the marked
2171 buffers.
2172 '\\[ibuffer-do-query-replace]' - Query replace in each of the marked buffers.
2173 '\\[ibuffer-do-query-replace-regexp]' - As above, with a regular expression.
2174 '\\[ibuffer-do-print]' - Print the marked buffers.
2175 '\\[ibuffer-do-occur]' - List lines in all marked buffers which match
2176 a given regexp (like the function `occur').
2177 '\\[ibuffer-do-shell-command-pipe]' - Pipe the contents of the marked
2178 buffers to a shell command.
2179 '\\[ibuffer-do-shell-command-pipe-replace]' - Replace the contents of the marked
2180 buffers with the output of a shell command.
2181 '\\[ibuffer-do-shell-command-file]' - Run a shell command with the
2182 buffer's file as an argument.
2183 '\\[ibuffer-do-eval]' - Evaluate a form in each of the marked buffers. This
2184 is a very flexible command. For example, if you want to make all
2185 of the marked buffers read only, try using (toggle-read-only 1) as
2186 the input form.
2187 '\\[ibuffer-do-view-and-eval]' - As above, but view each buffer while the form
2188 is evaluated.
2189 '\\[ibuffer-do-kill-lines]' - Remove the marked lines from the *Ibuffer* buffer,
2190 but don't kill the associated buffer.
2191 '\\[ibuffer-do-kill-on-deletion-marks]' - Kill all buffers marked for deletion.
2192
2193Marking commands:
2194
2195 '\\[ibuffer-mark-forward]' - Mark the buffer at point.
2196 '\\[ibuffer-toggle-marks]' - Unmark all currently marked buffers, and mark
2197 all unmarked buffers.
2198 '\\[ibuffer-unmark-forward]' - Unmark the buffer at point.
2199 '\\[ibuffer-unmark-backward]' - Unmark the buffer at point, and move to the
2200 previous line.
2201 '\\[ibuffer-unmark-all]' - Unmark all marked buffers.
2202 '\\[ibuffer-mark-by-mode]' - Mark buffers by major mode.
2203 '\\[ibuffer-mark-unsaved-buffers]' - Mark all \"unsaved\" buffers.
2204 This means that the buffer is modified, and has an associated file.
2205 '\\[ibuffer-mark-modified-buffers]' - Mark all modified buffers,
2206 regardless of whether or not they have an associated file.
2207 '\\[ibuffer-mark-special-buffers]' - Mark all buffers whose name begins and
2208 ends with '*'.
2209 '\\[ibuffer-mark-dissociated-buffers]' - Mark all buffers which have
2210 an associated file, but that file doesn't currently exist.
2211 '\\[ibuffer-mark-read-only-buffers]' - Mark all read-only buffers.
2212 '\\[ibuffer-mark-dired-buffers]' - Mark buffers in `dired' mode.
2213 '\\[ibuffer-mark-help-buffers]' - Mark buffers in `help-mode', `apropos-mode', etc.
2214 '\\[ibuffer-mark-old-buffers]' - Mark buffers older than `ibuffer-old-time'.
2215 '\\[ibuffer-mark-for-delete]' - Mark the buffer at point for deletion.
2216 '\\[ibuffer-mark-by-name-regexp]' - Mark buffers by their name, using a regexp.
2217 '\\[ibuffer-mark-by-mode-regexp]' - Mark buffers by their major mode, using a regexp.
2218 '\\[ibuffer-mark-by-file-name-regexp]' - Mark buffers by their filename, using a regexp.
2219
2220Filtering commands:
2221
2222 '\\[ibuffer-filter-by-mode]' - Add a filter by major mode.
2223 '\\[ibuffer-filter-by-name]' - Add a filter by buffer name.
2224 '\\[ibuffer-filter-by-content]' - Add a filter by buffer content.
2225 '\\[ibuffer-filter-by-filename]' - Add a filter by filename.
2226 '\\[ibuffer-filter-by-size-gt]' - Add a filter by buffer size.
2227 '\\[ibuffer-filter-by-size-lt]' - Add a filter by buffer size.
2228 '\\[ibuffer-filter-by-predicate]' - Add a filter by an arbitrary Lisp predicate.
2229 '\\[ibuffer-save-filters]' - Save the current filters with a name.
2230 '\\[ibuffer-switch-to-saved-filters]' - Switch to previously saved filters.
2231 '\\[ibuffer-add-saved-filters]' - Add saved filters to current filters.
2232 '\\[ibuffer-or-filter]' - Replace the top two filters with their logical OR.
2233 '\\[ibuffer-pop-filter]' - Remove the top filter.
2234 '\\[ibuffer-negate-filter]' - Invert the logical sense of the top filter.
2235 '\\[ibuffer-decompose-filter]' - Break down the topmost filter.
2236 '\\[ibuffer-filter-disable]' - Remove all filtering currently in effect.
2237
2238Sorting commands:
2239
2240 '\\[ibuffer-toggle-sorting-mode]' - Rotate between the various sorting modes.
2241 '\\[ibuffer-invert-sorting]' - Reverse the current sorting order.
2242 '\\[ibuffer-do-sort-by-alphabetic]' - Sort the buffers lexicographically.
2243 '\\[ibuffer-do-sort-by-recency]' - Sort the buffers by last viewing time.
2244 '\\[ibuffer-do-sort-by-size]' - Sort the buffers by size.
2245 '\\[ibuffer-do-sort-by-major-mode]' - Sort the buffers by major mode.
2246
2247Other commands:
2248
2249 '\\[ibuffer-switch-format]' - Change the current display format.
2250 '\\[forward-line]' - Move point to the next line.
2251 '\\[previous-line]' - Move point to the previous line.
2252 '\\[ibuffer-update]' - As above, but add new buffers to the list.
2253 '\\[ibuffer-quit]' - Bury the Ibuffer buffer.
2254 '\\[describe-mode]' - This help.
2255 '\\[ibuffer-diff-with-file]' - View the differences between this buffer
2256 and its associated file.
2257 '\\[ibuffer-visit-buffer]' - View the buffer on this line.
2258 '\\[ibuffer-visit-buffer-other-window]' - As above, but in another window.
2259 '\\[ibuffer-visit-buffer-other-window-noselect]' - As both above, but don't select
2260 the new window.
2261 '\\[ibuffer-bury-buffer]' - Bury (not kill!) the buffer on this line.
2262
2263Information on Filtering:
2264
2265 You can filter your ibuffer view via different critera. Each Ibuffer
2266buffer has its own stack of active filters. For example, suppose you
2267are working on an Emacs Lisp project. You can create an Ibuffer
2268buffer displays buffers in just `emacs-lisp' modes via
2269'\\[ibuffer-filter-by-mode] emacs-lisp-mode RET'. In this case, there
2270is just one entry on the filtering stack.
2271
2272You can also combine filters. The various filtering commands push a
2273new filter onto the stack, and the filters combine to show just
2274buffers which satisfy ALL criteria on the stack. For example, suppose
2275you only want to see buffers in `emacs-lisp' mode, whose names begin
2276with \"gnus\". You can accomplish this via:
2277'\\[ibuffer-filter-by-mode] emacs-lisp-mode RET
2278\\[ibuffer-filter-by-name] ^gnus RET'.
2279
2280Additionally, you can OR the top two filters together with
2281'\\[ibuffer-or-filters]'. To see all buffers in either
2282`emacs-lisp-mode' or `lisp-interaction-mode', type:
2283
2284'\\[ibuffer-filter-by-mode] emacs-lisp-mode RET \\[ibuffer-filter-by-mode] lisp-interaction-mode RET \\[ibuffer-or-filters]'.
2285
2286Filters can also be saved and restored using mnemonic names: see the
2287functions `ibuffer-save-filters' and `ibuffer-switch-to-saved-filters'.
2288
2289To remove the top filter on the stack, use '\\[ibuffer-pop-filter]', and
2290to disable all filtering currently in effect, use
2291'\\[ibuffer-filter-disable]'."
2292 (kill-all-local-variables)
2293 (use-local-map ibuffer-mode-map)
2294 (setq major-mode 'ibuffer-mode)
2295 (setq mode-name "Ibuffer")
2296 (setq buffer-read-only t)
2297 (buffer-disable-undo)
3eda3649 2298 (setq truncate-lines ibuffer-truncate-lines)
25d2f683
CW
2299 ;; This makes things less ugly for Emacs 21 users with a non-nil
2300 ;; `show-trailing-whitespace'.
2301 (setq show-trailing-whitespace nil)
2302 ;; Dummy font-lock-defaults to make font-lock turn on. We want this
2303 ;; so we know when to enable ibuffer's internal fontification.
2304 (set (make-local-variable 'font-lock-defaults)
2305 '(nil t nil nil nil
2306 (font-lock-fontify-region-function . ibuffer-fontify-region-function)
2307 (font-lock-unfontify-region-function . ibuffer-unfontify-region-function)))
2308 (set (make-local-variable 'revert-buffer-function)
2309 #'ibuffer-update)
2310 (set (make-local-variable 'ibuffer-sorting-mode)
2311 ibuffer-default-sorting-mode)
2312 (set (make-local-variable 'ibuffer-sorting-reversep)
2313 ibuffer-default-sorting-reversep)
2314 (set (make-local-variable 'ibuffer-shrink-to-minimum-size)
2315 ibuffer-default-shrink-to-minimum-size)
2316 (set (make-local-variable 'ibuffer-filtering-qualifiers) nil)
b5cd37ea
CW
2317 (set (make-local-variable 'ibuffer-filtering-groups) nil)
2318 (set (make-local-variable 'ibuffer-hidden-filtering-groups) nil)
25d2f683
CW
2319 (set (make-local-variable 'ibuffer-compiled-formats) nil)
2320 (set (make-local-variable 'ibuffer-cached-formats) nil)
2321 (set (make-local-variable 'ibuffer-cached-eliding-string) nil)
2322 (set (make-local-variable 'ibuffer-cached-elide-long-columns) nil)
2323 (set (make-local-variable 'ibuffer-current-format) nil)
2324 (set (make-local-variable 'ibuffer-did-modifiction) nil)
2325 (set (make-local-variable 'ibuffer-delete-window-on-quit) nil)
2326 (set (make-local-variable 'ibuffer-did-modification) nil)
b5cd37ea
CW
2327 (set (make-local-variable 'ibuffer-tmp-hide-regexps) nil)
2328 (set (make-local-variable 'ibuffer-tmp-show-regexps) nil)
25d2f683
CW
2329 (define-key ibuffer-mode-map [menu-bar edit] 'undefined)
2330 (define-key ibuffer-mode-map [menu-bar operate] (cons "Operate" ibuffer-mode-operate-map))
2331 (ibuffer-update-format)
2332 (when ibuffer-default-directory
2333 (setq default-directory ibuffer-default-directory))
2334 (run-hooks 'ibuffer-mode-hooks)
2335 ;; called after mode hooks to allow the user to add filters
2336 (ibuffer-update-mode-name))
2337
2338(provide 'ibuffer)
2339
2340;; Local Variables:
2341;; coding: iso-8859-1
2342;; End:
2343
2344;;; ibuffer.el ends here