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