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