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