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