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