ibuffer.el 110 KB
Newer Older
Colin Walters's avatar
Colin Walters committed
1 2
;;; ibuffer.el --- operate on buffers like dired

3
;; Copyright (C) 2000-2013 Free Software Foundation, Inc.
Colin Walters's avatar
Colin Walters committed
4 5

;; Author: Colin Walters <walters@verbum.org>
6
;; Maintainer: John Paul Wallington <jpw@gnu.org>
Colin Walters's avatar
Colin Walters committed
7 8 9
;; Created: 8 Sep 2000
;; Keywords: buffer, convenience

10
;; This file is part of GNU Emacs.
Colin Walters's avatar
Colin Walters committed
11

12 13 14 15
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
Colin Walters's avatar
Colin Walters committed
16

17 18 19 20
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
Colin Walters's avatar
Colin Walters committed
21 22

;; You should have received a copy of the GNU General Public License
23
;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
Colin Walters's avatar
Colin Walters committed
24 25 26 27 28 29 30 31 32 33

;;; Commentary:

;; ibuffer.el is an advanced replacement for the `buffer-menu' which
;; is normally distributed with Emacs.  Its interface is intended to
;; be analogous to that of Dired.

;;; Code:

(eval-when-compile
34
  (require 'cl-lib)
Colin Walters's avatar
Colin Walters committed
35 36 37
  (require 'ibuf-macs)
  (require 'dired))

38
(require 'font-core)
39

40 41 42 43 44 45 46 47 48
;; These come from ibuf-ext.el, which can not be require'd at compile time
;; because it has a recursive dependency on ibuffer.el
(defvar ibuffer-auto-mode)
(defvar ibuffer-cached-filter-formats)
(defvar ibuffer-compiled-filter-formats)
(defvar ibuffer-filter-format-alist)
(defvar ibuffer-filter-group-kill-ring)
(defvar ibuffer-filter-groups)
(defvar ibuffer-filtering-qualifiers)
49
(defvar ibuffer-header-line-format)
50 51 52 53 54
(defvar ibuffer-hidden-filter-groups)
(defvar ibuffer-inline-columns)
(defvar ibuffer-show-empty-filter-groups)
(defvar ibuffer-tmp-hide-regexps)
(defvar ibuffer-tmp-show-regexps)
55

56 57
(declare-function ibuffer-ext-visible-p "ibuf-ext"
		  (buf all &optional ibuffer-buf))
58
(declare-function ibuffer-mark-on-buffer "ibuf-ext"
59
		  (func &optional ibuffer-mark-on-buffer-mark group))
60
(declare-function ibuffer-generate-filter-groups "ibuf-ext"
61 62 63
		  (bmarklist &optional noempty nodefault))
(declare-function ibuffer-format-filter-group-data "ibuf-ext" (filter))

Colin Walters's avatar
Colin Walters committed
64
(defgroup ibuffer nil
65 66 67 68
  "Advanced replacement for `buffer-menu'.
Ibuffer lets you operate on buffers in a Dired-like way,
with the ability to sort, mark by regular expression,
and filter displayed buffers by various criteria."
69
  :version "22.1"
Colin Walters's avatar
Colin Walters committed
70 71
  :group 'convenience)

72 73
(defcustom ibuffer-formats '((mark modified read-only " " (name 18 18 :left :elide)
				   " " (size 9 -1 :right)
74
				   " " (mode 16 16 :left :elide) " " filename-and-process)
Colin Walters's avatar
Colin Walters committed
75 76 77 78 79
			     (mark " " (name 16 -1) " " filename))
  "A list of ways to display buffer lines.

With Ibuffer, you are not limited to displaying just certain
attributes of a buffer such as size, name, and mode in a particular
Colin Walters's avatar
Colin Walters committed
80
order.  Through this variable, you can completely customize and
Colin Walters's avatar
Colin Walters committed
81 82 83 84 85
control the appearance of an Ibuffer buffer.  See also
`define-ibuffer-column', which allows you to define your own columns
for display.

This variable has the form
86
 ((COLUMN COLUMN ...) (COLUMN COLUMN ...) ...)
Colin Walters's avatar
Colin Walters committed
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
Each element in `ibuffer-formats' should be a list containing COLUMN
specifiers.  A COLUMN can be any of the following:

  SYMBOL - A symbol naming the column.  Predefined columns are:
       mark modified read-only name size mode process filename
   When you define your own columns using `define-ibuffer-column', just
   use their name like the predefined columns here.  This entry can
   also be a function of two arguments, which should return a string.
   The first argument is the buffer object, and the second is the mark
   on that buffer.
 or
  \"STRING\" - A literal string to display.
 or
  (SYMBOL MIN-SIZE MAX-SIZE &optional ALIGN ELIDE) - SYMBOL is a
   symbol naming the column, and MIN-SIZE and MAX-SIZE are integers (or
   functions of no arguments returning an integer) which constrict the
   size of a column.  If MAX-SIZE is -1, there is no upper bound.  The
   default values are 0 and -1, respectively.  If MIN-SIZE is negative,
   use the end of the string.  The optional element ALIGN describes the
   alignment of the column; it can be :left, :center or :right.  The
   optional element ELIDE describes whether or not to elide the column
   if it is too long; valid values are :elide and nil.  The default is
   nil (don't elide).

Some example of valid entries in `ibuffer-formats', with
description (also, feel free to try them out, and experiment with your
own!):

 (mark \" \" name)
  This format just displays the current mark (if any) and the name of
  the buffer, separated by a space.
 (mark modified read-only \" \" (name 16 16 :left) \" \" (size 6 -1 :right))
  This format displays the current mark (if any), its modification and
  read-only status, as well as the name of the buffer and its size.  In
  this format, the name is restricted to 16 characters (longer names
122
  will be truncated, and shorter names will be padded with spaces), and
Colin Walters's avatar
Colin Walters committed
123
  the name is also aligned to the left.  The size of the buffer will
Colin Walters's avatar
Colin Walters committed
124 125 126 127
  be padded with spaces up to a minimum of six characters, but there is
  no upper limit on its size.  The size will also be aligned to the
  right.

128 129
Thus, if you wanted to use these two formats, the appropriate
value for this variable would be
Colin Walters's avatar
Colin Walters committed
130

131 132 133 134
  '((mark \" \" name)
    (mark modified read-only
          (name 16 16 :left)
          (size 6 -1 :right)))
Colin Walters's avatar
Colin Walters committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148

Using \\[ibuffer-switch-format], you can rotate the display between
the specified formats in the list."
  :type '(repeat sexp)
  :group 'ibuffer)

(defcustom ibuffer-always-compile-formats (featurep 'bytecomp)
  "If non-nil, then use the byte-compiler to optimize `ibuffer-formats'.
This will increase the redisplay speed, at the cost of loading the
elisp byte-compiler."
  :type 'boolean
  :group 'ibuffer)

(defcustom ibuffer-fontification-alist
149
  `((10 buffer-read-only font-lock-constant-face)
150 151 152 153 154 155
    (15 (and buffer-file-name
	     (string-match ibuffer-compressed-file-name-regexp
			   buffer-file-name))
	font-lock-doc-face)
    (20 (string-match "^*" (buffer-name)) font-lock-keyword-face)
    (25 (and (string-match "^ " (buffer-name))
156 157
	     (null buffer-file-name))
	italic)
158 159
    (30 (memq major-mode ibuffer-help-buffer-modes) font-lock-comment-face)
    (35 (eq major-mode 'dired-mode) font-lock-function-name-face))
Colin Walters's avatar
Colin Walters committed
160 161 162 163 164
  "An alist describing how to fontify buffers.
Each element should be of the form (PRIORITY FORM FACE), where
PRIORITY is an integer, FORM is an arbitrary form to evaluate in the
buffer, and FACE is the face to use for fontification.  If the FORM
evaluates to non-nil, then FACE will be put on the buffer name.  The
165 166
element with the highest PRIORITY takes precedence.

167
If you change this variable, you must kill the Ibuffer buffer and
168
recreate it for the change to take effect."
Colin Walters's avatar
Colin Walters committed
169 170 171 172 173 174 175
  :type '(repeat
	  (list (integer :tag "Priority")
		(sexp :tag "Test Form")
		face))
  :group 'ibuffer)

(defcustom ibuffer-use-other-window nil
176
  "If non-nil, display Ibuffer in another window by default."
Colin Walters's avatar
Colin Walters committed
177 178 179 180 181 182 183 184 185
  :type 'boolean
  :group 'ibuffer)

(defcustom ibuffer-default-shrink-to-minimum-size nil
  "If non-nil, minimize the size of the Ibuffer window by default."
  :type 'boolean
  :group 'ibuffer)
(defvar ibuffer-shrink-to-minimum-size nil)

186 187 188 189 190
(defcustom ibuffer-display-summary t
  "If non-nil, summarize Ibuffer columns."
  :type 'boolean
  :group 'ibuffer)

191 192 193 194 195
(defcustom ibuffer-truncate-lines t
  "If non-nil, do not display continuation lines."
  :type 'boolean
  :group 'ibuffer)

Colin Walters's avatar
Colin Walters committed
196 197 198 199 200 201 202 203
(defcustom ibuffer-case-fold-search case-fold-search
  "If non-nil, ignore case when searching."
  :type 'boolean
  :group 'ibuffer)

(defcustom ibuffer-default-sorting-mode 'recency
  "The criteria by which to sort the buffers.

204 205
Note that this variable is local to each Ibuffer buffer.  Thus, you
can have multiple Ibuffer buffers open, each with a different sorted
Colin Walters's avatar
Colin Walters committed
206 207 208 209
view of the buffers."
  :type '(choice (const :tag "Last view time" :value recency)
		 (const :tag "Lexicographic" :value alphabetic)
		 (const :tag "Buffer size" :value size)
210
		 (const :tag "File name" :value filename/process)
Colin Walters's avatar
Colin Walters committed
211 212 213
		 (const :tag "Major mode" :value major-mode))
  :group 'ibuffer)
(defvar ibuffer-sorting-mode nil)
214
(defvar ibuffer-last-sorting-mode nil)
Colin Walters's avatar
Colin Walters committed
215 216 217 218 219 220 221 222

(defcustom ibuffer-default-sorting-reversep nil
  "If non-nil, reverse the default sorting order."
  :type 'boolean
  :group 'ibuffer)
(defvar ibuffer-sorting-reversep nil)

(defcustom ibuffer-elide-long-columns nil
223
  "If non-nil, then elide column entries which exceed their max length."
Colin Walters's avatar
Colin Walters committed
224 225
  :type 'boolean
  :group 'ibuffer)
226 227 228
(make-obsolete-variable 'ibuffer-elide-long-columns
                        "use the :elide argument of `ibuffer-formats'."
                        "22.1")
Colin Walters's avatar
Colin Walters committed
229 230 231 232 233 234 235 236 237

(defcustom ibuffer-eliding-string "..."
  "The string to use for eliding long columns."
  :type 'string
  :group 'ibuffer)

(defcustom ibuffer-maybe-show-predicates `(,(lambda (buf)
					      (and (string-match "^ " (buffer-name buf))
						   (null buffer-file-name))))
238 239 240
  "A list of predicates for buffers to display conditionally.

A predicate can be a regexp or a function.
Colin Walters's avatar
Colin Walters committed
241 242 243 244
If a regexp, then it will be matched against the buffer's name.
If a function, it will be called with the buffer as an argument, and
should return non-nil if this buffer should be shown.

245
Viewing of buffers hidden because of these predicates may be customized
246
via `ibuffer-default-display-maybe-show-predicates' and is toggled by
247 248
giving a non-nil prefix argument to `ibuffer-update'.
Note that this specialized filtering occurs before real filtering."
Colin Walters's avatar
Colin Walters committed
249 250 251
  :type '(repeat (choice regexp function))
  :group 'ibuffer)

252 253 254 255 256 257 258
(defcustom ibuffer-default-display-maybe-show-predicates nil
  "Non-nil means show buffers that match `ibuffer-maybe-show-predicates'."
  :type 'boolean
  :group 'ibuffer)

(defvar ibuffer-display-maybe-show-predicates nil)

Colin Walters's avatar
Colin Walters committed
259 260
(defvar ibuffer-current-format nil)

261 262 263 264 265
(defcustom ibuffer-movement-cycle t
  "If non-nil, then forward and backwards movement commands cycle."
  :type 'boolean
  :group 'ibuffer)

Colin Walters's avatar
Colin Walters committed
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
(defcustom ibuffer-modified-char ?*
  "The character to display for modified buffers."
  :type 'character
  :group 'ibuffer)

(defcustom ibuffer-read-only-char ?%
  "The character to display for read-only buffers."
  :type 'character
  :group 'ibuffer)

(defcustom ibuffer-marked-char ?>
  "The character to display for marked buffers."
  :type 'character
  :group 'ibuffer)

(defcustom ibuffer-deletion-char ?D
  "The character to display for buffers marked for deletion."
  :type 'character
  :group 'ibuffer)

(defcustom ibuffer-expert nil
  "If non-nil, don't ask for confirmation of \"dangerous\" operations."
  :type 'boolean
  :group 'ibuffer)

(defcustom ibuffer-view-ibuffer nil
  "If non-nil, display the current Ibuffer buffer itself.
Note that this has a drawback - the data about the current Ibuffer
buffer will most likely be inaccurate.  This includes modification
state, size, etc."
  :type 'boolean
  :group 'ibuffer)

(defcustom ibuffer-always-show-last-buffer nil
300 301
  "If non-nil, always display the previous buffer.
This variable takes precedence over filtering, and even
Colin Walters's avatar
Colin Walters committed
302 303 304 305 306 307
`ibuffer-never-show-predicates'."
  :type '(choice (const :tag "Always" :value t)
		 (const :tag "Never" :value nil)
		 (const :tag "Always except minibuffer" :value :nomini))
  :group 'ibuffer)

308 309 310 311 312 313
(defcustom ibuffer-jump-offer-only-visible-buffers nil
  "If non-nil, only offer buffers visible in the Ibuffer buffer
in completion lists of the `ibuffer-jump-to-buffer' command."
  :type 'boolean
  :group 'ibuffer)

Colin Walters's avatar
Colin Walters committed
314
(defcustom ibuffer-use-header-line (boundp 'header-line-format)
315
  "If non-nil, display a header line containing current filters."
Colin Walters's avatar
Colin Walters committed
316 317 318 319
  :type 'boolean
  :group 'ibuffer)

(defcustom ibuffer-default-directory nil
320
  "The default directory to use for a new Ibuffer buffer.
321
If nil, inherit the directory of the buffer in which `ibuffer' was
Colin Walters's avatar
Colin Walters committed
322 323 324 325 326 327
called.  Otherwise, this variable should be a string naming a
directory, like `default-directory'."
  :type '(choice (const :tag "Inherit" :value nil)
		 string)
  :group 'ibuffer)

328 329
(defcustom ibuffer-help-buffer-modes
  '(help-mode apropos-mode Info-mode Info-edit-mode)
330 331 332 333
  "List of \"Help\" major modes."
  :type '(repeat function)
  :group 'ibuffer)

334
(defcustom ibuffer-compressed-file-name-regexp
335
  "\\.\\(arj\\|bgz\\|bz2\\|gz\\|lzh\\|taz\\|tgz\\|xz\\|zip\\|z\\)$"
336
  "Regexp to match compressed file names."
337
  :version "24.1"                       ; added xz
338
  :type 'regexp
339
  :group 'ibuffer)
340

341 342
(define-obsolete-variable-alias 'ibuffer-hooks 'ibuffer-hook "22.1")

343
(defcustom ibuffer-hook nil
344
  "Hook run when `ibuffer' is called."
Colin Walters's avatar
Colin Walters committed
345 346
  :type 'hook
  :group 'ibuffer)
347 348

(define-obsolete-variable-alias 'ibuffer-mode-hooks 'ibuffer-mode-hook "22.1")
Colin Walters's avatar
Colin Walters committed
349

350
(defcustom ibuffer-mode-hook nil
351
  "Hook run upon entry into `ibuffer-mode'."
Colin Walters's avatar
Colin Walters committed
352 353 354
  :type 'hook
  :group 'ibuffer)

355 356 357 358 359
(defcustom ibuffer-load-hook nil
  "Hook run when Ibuffer is loaded."
  :type 'hook
  :group 'ibuffer)

360
(defcustom ibuffer-marked-face 'warning
Colin Walters's avatar
Colin Walters committed
361 362 363 364
  "Face used for displaying marked buffers."
  :type 'face
  :group 'ibuffer)

365
(defcustom ibuffer-deletion-face 'error
Colin Walters's avatar
Colin Walters committed
366 367 368 369 370 371 372 373 374
  "Face used for displaying buffers marked for deletion."
  :type 'face
  :group 'ibuffer)

(defcustom ibuffer-title-face 'font-lock-type-face
  "Face used for the title string."
  :type 'face
  :group 'ibuffer)

375 376 377 378 379
(defcustom ibuffer-filter-group-name-face 'bold
  "Face used for displaying filtering group names."
  :type 'face
  :group 'ibuffer)

Colin Walters's avatar
Colin Walters committed
380 381 382 383 384 385 386 387
(defcustom ibuffer-directory-abbrev-alist nil
  "An alist of file name abbreviations like `directory-abbrev-alist'."
  :type '(repeat (cons :format "%v"
		       :value ("" . "")
		       (regexp :tag "From")
		       (regexp :tag "To")))
  :group 'ibuffer)

388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
(defvar ibuffer-mode-groups-popup
  (let ((groups-map (make-sparse-keymap "Filter Groups")))
    ;; Filter groups

    (define-key-after groups-map [filters-to-filter-group]
      '(menu-item "Create filter group from current filters..."
        ibuffer-filters-to-filter-group
        :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers)))
    (define-key-after groups-map [forward-filter-group]
      '(menu-item "Move point to the next filter group"
        ibuffer-forward-filter-group))
    (define-key-after groups-map [backward-filter-group]
      '(menu-item "Move point to the previous filter group"
        ibuffer-backward-filter-group))
    (define-key-after groups-map [jump-to-filter-group]
      '(menu-item "Move point to a specific filter group..."
        ibuffer-jump-to-filter-group))
    (define-key-after groups-map [kill-filter-group]
      '(menu-item "Kill filter group named..."
        ibuffer-kill-filter-group
        :enable (and (featurep 'ibuf-ext) ibuffer-filter-groups)))
    (define-key-after groups-map [yank-filter-group]
      '(menu-item "Yank last killed filter group before..."
        ibuffer-yank-filter-group
        :enable (and (featurep 'ibuf-ext) ibuffer-filter-group-kill-ring)))
    (define-key-after groups-map [pop-filter-group]
      '(menu-item "Remove top filter group"
        ibuffer-pop-filter-group
        :enable (and (featurep 'ibuf-ext) ibuffer-filter-groups)))
    (define-key-after groups-map [clear-filter-groups]
      '(menu-item "Remove all filter groups"
        ibuffer-clear-filter-groups
        :enable (and (featurep 'ibuf-ext) ibuffer-filter-groups)))
    (define-key-after groups-map [pop-filter-group]
      '(menu-item "Decompose filter group..."
        ibuffer-pop-filter-group
        :help "\"Unmake\" a filter group"
        :enable (and (featurep 'ibuf-ext) ibuffer-filter-groups)))
    (define-key-after groups-map [save-filter-groups]
      '(menu-item "Save current filter groups permanently..."
        ibuffer-save-filter-groups
        :enable (and (featurep 'ibuf-ext) ibuffer-filter-groups)
Paul Eggert's avatar
Paul Eggert committed
430
        :help "Use a mnemonic name to store current filter groups"))
431 432 433 434 435 436 437 438 439 440 441 442 443 444
    (define-key-after groups-map [switch-to-saved-filter-groups]
      '(menu-item "Restore permanently saved filters..."
        ibuffer-switch-to-saved-filter-groups
        :enable (and (featurep 'ibuf-ext) ibuffer-saved-filter-groups)
        :help "Replace current filters with a saved stack"))
    (define-key-after groups-map [delete-saved-filter-groups]
      '(menu-item "Delete permanently saved filter groups..."
        ibuffer-delete-saved-filter-groups
        :enable (and (featurep 'ibuf-ext) ibuffer-saved-filter-groups)))
    (define-key-after groups-map [set-filter-groups-by-mode]
      '(menu-item "Set current filter groups to filter by mode"
        ibuffer-set-filter-groups-by-mode))

    groups-map))
445

446 447
(defvar ibuffer-mode-map
  (let ((map (make-keymap)))
Colin Walters's avatar
Colin Walters committed
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
    (define-key map (kbd "0") 'digit-argument)
    (define-key map (kbd "1") 'digit-argument)
    (define-key map (kbd "2") 'digit-argument)
    (define-key map (kbd "3") 'digit-argument)
    (define-key map (kbd "4") 'digit-argument)
    (define-key map (kbd "5") 'digit-argument)
    (define-key map (kbd "6") 'digit-argument)
    (define-key map (kbd "7") 'digit-argument)
    (define-key map (kbd "8") 'digit-argument)
    (define-key map (kbd "9") 'digit-argument)

    (define-key map (kbd "m") 'ibuffer-mark-forward)
    (define-key map (kbd "t") 'ibuffer-toggle-marks)
    (define-key map (kbd "u") 'ibuffer-unmark-forward)
    (define-key map (kbd "=") 'ibuffer-diff-with-file)
    (define-key map (kbd "j") 'ibuffer-jump-to-buffer)
464
    (define-key map (kbd "M-g") 'ibuffer-jump-to-buffer)
465 466
    (define-key map (kbd "M-s a C-s") 'ibuffer-do-isearch)
    (define-key map (kbd "M-s a M-C-s") 'ibuffer-do-isearch-regexp)
467
    (define-key map (kbd "M-s a C-o") 'ibuffer-do-occur)
Colin Walters's avatar
Colin Walters committed
468 469 470 471 472 473 474 475 476 477 478
    (define-key map (kbd "DEL") 'ibuffer-unmark-backward)
    (define-key map (kbd "M-DEL") 'ibuffer-unmark-all)
    (define-key map (kbd "* *") 'ibuffer-unmark-all)
    (define-key map (kbd "* M") 'ibuffer-mark-by-mode)
    (define-key map (kbd "* m") 'ibuffer-mark-modified-buffers)
    (define-key map (kbd "* u") 'ibuffer-mark-unsaved-buffers)
    (define-key map (kbd "* s") 'ibuffer-mark-special-buffers)
    (define-key map (kbd "* r") 'ibuffer-mark-read-only-buffers)
    (define-key map (kbd "* /") 'ibuffer-mark-dired-buffers)
    (define-key map (kbd "* e") 'ibuffer-mark-dissociated-buffers)
    (define-key map (kbd "* h") 'ibuffer-mark-help-buffers)
479
    (define-key map (kbd "* z") 'ibuffer-mark-compressed-file-buffers)
Colin Walters's avatar
Colin Walters committed
480
    (define-key map (kbd ".") 'ibuffer-mark-old-buffers)
481

Colin Walters's avatar
Colin Walters committed
482 483 484 485
    (define-key map (kbd "d") 'ibuffer-mark-for-delete)
    (define-key map (kbd "C-d") 'ibuffer-mark-for-delete-backwards)
    (define-key map (kbd "k") 'ibuffer-mark-for-delete)
    (define-key map (kbd "x") 'ibuffer-do-kill-on-deletion-marks)
486

Colin Walters's avatar
Colin Walters committed
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
    ;; immediate operations
    (define-key map (kbd "n") 'ibuffer-forward-line)
    (define-key map (kbd "SPC") 'forward-line)
    (define-key map (kbd "p") 'ibuffer-backward-line)
    (define-key map (kbd "M-}") 'ibuffer-forward-next-marked)
    (define-key map (kbd "M-{") 'ibuffer-backwards-next-marked)
    (define-key map (kbd "l") 'ibuffer-redisplay)
    (define-key map (kbd "g") 'ibuffer-update)
    (define-key map "`" 'ibuffer-switch-format)
    (define-key map "-" 'ibuffer-add-to-tmp-hide)
    (define-key map "+" 'ibuffer-add-to-tmp-show)
    (define-key map "b" 'ibuffer-bury-buffer)
    (define-key map (kbd ",") 'ibuffer-toggle-sorting-mode)
    (define-key map (kbd "s i") 'ibuffer-invert-sorting)
    (define-key map (kbd "s a") 'ibuffer-do-sort-by-alphabetic)
    (define-key map (kbd "s v") 'ibuffer-do-sort-by-recency)
    (define-key map (kbd "s s") 'ibuffer-do-sort-by-size)
504
    (define-key map (kbd "s f") 'ibuffer-do-sort-by-filename/process)
Colin Walters's avatar
Colin Walters committed
505 506
    (define-key map (kbd "s m") 'ibuffer-do-sort-by-major-mode)

507 508
    (define-key map (kbd "/ m") 'ibuffer-filter-by-used-mode)
    (define-key map (kbd "/ M") 'ibuffer-filter-by-derived-mode)
Colin Walters's avatar
Colin Walters committed
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
    (define-key map (kbd "/ n") 'ibuffer-filter-by-name)
    (define-key map (kbd "/ c") 'ibuffer-filter-by-content)
    (define-key map (kbd "/ e") 'ibuffer-filter-by-predicate)
    (define-key map (kbd "/ f") 'ibuffer-filter-by-filename)
    (define-key map (kbd "/ >") 'ibuffer-filter-by-size-gt)
    (define-key map (kbd "/ <") 'ibuffer-filter-by-size-lt)
    (define-key map (kbd "/ r") 'ibuffer-switch-to-saved-filters)
    (define-key map (kbd "/ a") 'ibuffer-add-saved-filters)
    (define-key map (kbd "/ x") 'ibuffer-delete-saved-filters)
    (define-key map (kbd "/ d") 'ibuffer-decompose-filter)
    (define-key map (kbd "/ s") 'ibuffer-save-filters)
    (define-key map (kbd "/ p") 'ibuffer-pop-filter)
    (define-key map (kbd "/ !") 'ibuffer-negate-filter)
    (define-key map (kbd "/ t") 'ibuffer-exchange-filters)
    (define-key map (kbd "/ TAB") 'ibuffer-exchange-filters)
    (define-key map (kbd "/ o") 'ibuffer-or-filter)
525 526
    (define-key map (kbd "/ g") 'ibuffer-filters-to-filter-group)
    (define-key map (kbd "/ P") 'ibuffer-pop-filter-group)
527
    (define-key map (kbd "/ D") 'ibuffer-decompose-filter-group)
Colin Walters's avatar
Colin Walters committed
528
    (define-key map (kbd "/ /") 'ibuffer-filter-disable)
529 530

    (define-key map (kbd "M-n") 'ibuffer-forward-filter-group)
531
    (define-key map "\t" 'ibuffer-forward-filter-group)
532
    (define-key map (kbd "M-p") 'ibuffer-backward-filter-group)
533
    (define-key map [backtab] 'ibuffer-backward-filter-group)
534
    (define-key map (kbd "M-j") 'ibuffer-jump-to-filter-group)
Colin Walters's avatar
Colin Walters committed
535 536 537 538 539 540
    (define-key map (kbd "C-k") 'ibuffer-kill-line)
    (define-key map (kbd "C-y") 'ibuffer-yank)
    (define-key map (kbd "/ S") 'ibuffer-save-filter-groups)
    (define-key map (kbd "/ R") 'ibuffer-switch-to-saved-filter-groups)
    (define-key map (kbd "/ X") 'ibuffer-delete-saved-filter-groups)
    (define-key map (kbd "/ \\") 'ibuffer-clear-filter-groups)
541

Colin Walters's avatar
Colin Walters committed
542 543 544 545 546 547 548
    (define-key map (kbd "q") 'ibuffer-quit)
    (define-key map (kbd "h") 'describe-mode)
    (define-key map (kbd "?") 'describe-mode)

    (define-key map (kbd "% n") 'ibuffer-mark-by-name-regexp)
    (define-key map (kbd "% m") 'ibuffer-mark-by-mode-regexp)
    (define-key map (kbd "% f") 'ibuffer-mark-by-file-name-regexp)
549

Colin Walters's avatar
Colin Walters committed
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
    (define-key map (kbd "C-t") 'ibuffer-visit-tags-table)

    (define-key map (kbd "|") 'ibuffer-do-shell-command-pipe)
    (define-key map (kbd "!") 'ibuffer-do-shell-command-file)
    (define-key map (kbd "~") 'ibuffer-do-toggle-modified)
    ;; marked operations
    (define-key map (kbd "A") 'ibuffer-do-view)
    (define-key map (kbd "D") 'ibuffer-do-delete)
    (define-key map (kbd "E") 'ibuffer-do-eval)
    (define-key map (kbd "F") 'ibuffer-do-shell-command-file)
    (define-key map (kbd "I") 'ibuffer-do-query-replace-regexp)
    (define-key map (kbd "H") 'ibuffer-do-view-other-frame)
    (define-key map (kbd "N") 'ibuffer-do-shell-command-pipe-replace)
    (define-key map (kbd "M") 'ibuffer-do-toggle-modified)
    (define-key map (kbd "O") 'ibuffer-do-occur)
    (define-key map (kbd "P") 'ibuffer-do-print)
    (define-key map (kbd "Q") 'ibuffer-do-query-replace)
    (define-key map (kbd "R") 'ibuffer-do-rename-uniquely)
    (define-key map (kbd "S") 'ibuffer-do-save)
    (define-key map (kbd "T") 'ibuffer-do-toggle-read-only)
    (define-key map (kbd "U") 'ibuffer-do-replace-regexp)
    (define-key map (kbd "V") 'ibuffer-do-revert)
    (define-key map (kbd "W") 'ibuffer-do-view-and-eval)
    (define-key map (kbd "X") 'ibuffer-do-shell-command-pipe)
574

Colin Walters's avatar
Colin Walters committed
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
    (define-key map (kbd "k") 'ibuffer-do-kill-lines)
    (define-key map (kbd "w") 'ibuffer-copy-filename-as-kill)

    (define-key map (kbd "RET") 'ibuffer-visit-buffer)
    (define-key map (kbd "e") 'ibuffer-visit-buffer)
    (define-key map (kbd "f") 'ibuffer-visit-buffer)
    (define-key map (kbd "C-x C-f") 'ibuffer-find-file)
    (define-key map (kbd "o") 'ibuffer-visit-buffer-other-window)
    (define-key map (kbd "C-o") 'ibuffer-visit-buffer-other-window-noselect)
    (define-key map (kbd "M-o") 'ibuffer-visit-buffer-1-window)
    (define-key map (kbd "v") 'ibuffer-do-view)
    (define-key map (kbd "C-x v") 'ibuffer-do-view-horizontally)
    (define-key map (kbd "C-c C-a") 'ibuffer-auto-mode)
    (define-key map (kbd "C-x 4 RET") 'ibuffer-visit-buffer-other-window)
    (define-key map (kbd "C-x 5 RET") 'ibuffer-visit-buffer-other-frame)

    (define-key map [menu-bar view]
      (cons "View" (make-sparse-keymap "View")))

    (define-key-after map [menu-bar view visit-buffer]
      '(menu-item "View this buffer" ibuffer-visit-buffer))
    (define-key-after map [menu-bar view visit-buffer-other-window]
      '(menu-item "View (other window)" ibuffer-visit-buffer-other-window))
    (define-key-after map [menu-bar view visit-buffer-other-frame]
      '(menu-item "View (other frame)" ibuffer-visit-buffer-other-frame))
    (define-key-after map [menu-bar view ibuffer-update]
      '(menu-item "Update" ibuffer-update
602
        :help "Regenerate the list of buffers"))
Colin Walters's avatar
Colin Walters committed
603 604
    (define-key-after map [menu-bar view switch-format]
      '(menu-item "Switch display format" ibuffer-switch-format
605
        :help "Toggle between available values of `ibuffer-formats'"))
Colin Walters's avatar
Colin Walters committed
606 607 608 609 610 611 612 613

    (define-key-after map [menu-bar view dashes]
      '("--"))

    (define-key-after map [menu-bar view sort]
      (cons "Sort" (make-sparse-keymap "Sort")))

    (define-key-after map [menu-bar view sort do-sort-by-major-mode]
Colin Walters's avatar
Colin Walters committed
614
      '(menu-item "Sort by major mode" ibuffer-do-sort-by-major-mode))
Colin Walters's avatar
Colin Walters committed
615
    (define-key-after map [menu-bar view sort do-sort-by-size]
Colin Walters's avatar
Colin Walters committed
616
      '(menu-item "Sort by buffer size" ibuffer-do-sort-by-size))
Colin Walters's avatar
Colin Walters committed
617 618
    (define-key-after map [menu-bar view sort do-sort-by-alphabetic]
      '(menu-item "Sort lexicographically" ibuffer-do-sort-by-alphabetic
619
        :help "Sort by the alphabetic order of buffer name"))
Colin Walters's avatar
Colin Walters committed
620 621
    (define-key-after map [menu-bar view sort do-sort-by-recency]
      '(menu-item "Sort by view time" ibuffer-do-sort-by-recency
622
        :help "Sort by the last time the buffer was displayed"))
623 624
    (define-key-after map [menu-bar view sort dashes]
      '("--"))
Colin Walters's avatar
Colin Walters committed
625 626 627 628
    (define-key-after map [menu-bar view sort invert-sorting]
      '(menu-item "Reverse sorting order" ibuffer-invert-sorting))
    (define-key-after map [menu-bar view sort toggle-sorting-mode]
      '(menu-item "Switch sorting mode" ibuffer-toggle-sorting-mode
629
        :help "Switch between the various sorting criteria"))
Colin Walters's avatar
Colin Walters committed
630 631 632 633 634

    (define-key-after map [menu-bar view filter]
      (cons "Filter" (make-sparse-keymap "Filter")))

    (define-key-after map [menu-bar view filter filter-disable]
635
      '(menu-item "Disable all filtering" ibuffer-filter-disable
636
        :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers)))
Colin Walters's avatar
Colin Walters committed
637
    (define-key-after map [menu-bar view filter filter-by-mode]
Glenn Morris's avatar
Glenn Morris committed
638 639 640
      '(menu-item "Add filter by any major mode..." ibuffer-filter-by-mode))
    (define-key-after map [menu-bar view filter filter-by-used-mode]
      '(menu-item "Add filter by a major mode in use..."
641
        ibuffer-filter-by-used-mode))
642 643 644
    (define-key-after map [menu-bar view filter filter-by-derived-mode]
      '(menu-item "Add filter by derived mode..."
                  ibuffer-filter-by-derived-mode))
Colin Walters's avatar
Colin Walters committed
645
    (define-key-after map [menu-bar view filter filter-by-name]
Colin Walters's avatar
Colin Walters committed
646
      '(menu-item "Add filter by buffer name..." ibuffer-filter-by-name))
Colin Walters's avatar
Colin Walters committed
647
    (define-key-after map [menu-bar view filter filter-by-filename]
Colin Walters's avatar
Colin Walters committed
648
      '(menu-item "Add filter by filename..." ibuffer-filter-by-filename))
Colin Walters's avatar
Colin Walters committed
649
    (define-key-after map [menu-bar view filter filter-by-size-lt]
Colin Walters's avatar
Colin Walters committed
650
      '(menu-item "Add filter by size less than..." ibuffer-filter-by-size-lt))
Colin Walters's avatar
Colin Walters committed
651
    (define-key-after map [menu-bar view filter filter-by-size-gt]
652 653
      '(menu-item "Add filter by size greater than..."
        ibuffer-filter-by-size-gt))
Colin Walters's avatar
Colin Walters committed
654
    (define-key-after map [menu-bar view filter filter-by-content]
655 656
      '(menu-item "Add filter by content (regexp)..."
        ibuffer-filter-by-content))
Colin Walters's avatar
Colin Walters committed
657
    (define-key-after map [menu-bar view filter filter-by-predicate]
658 659
      '(menu-item "Add filter by Lisp predicate..."
        ibuffer-filter-by-predicate))
Colin Walters's avatar
Colin Walters committed
660
    (define-key-after map [menu-bar view filter pop-filter]
661
      '(menu-item "Remove top filter" ibuffer-pop-filter
662
        :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers)))
Colin Walters's avatar
Colin Walters committed
663 664
    (define-key-after map [menu-bar view filter or-filter]
      '(menu-item "OR top two filters" ibuffer-or-filter
665 666 667 668
        :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers
                     (cdr ibuffer-filtering-qualifiers))
        :help
        "Create a new filter which is the logical OR of the top two filters"))
Colin Walters's avatar
Colin Walters committed
669
    (define-key-after map [menu-bar view filter negate-filter]
670
      '(menu-item "Negate top filter" ibuffer-negate-filter
671
        :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers)))
Colin Walters's avatar
Colin Walters committed
672 673
    (define-key-after map [menu-bar view filter decompose-filter]
      '(menu-item "Decompose top filter" ibuffer-decompose-filter
674 675 676
        :enable (and (featurep 'ibuf-ext)
                     (memq (car ibuffer-filtering-qualifiers) '(or saved not)))
        :help "Break down a complex filter like OR or NOT"))
Colin Walters's avatar
Colin Walters committed
677
    (define-key-after map [menu-bar view filter exchange-filters]
678
      '(menu-item "Swap top two filters" ibuffer-exchange-filters
679 680
        :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers
                     (cdr ibuffer-filtering-qualifiers))))
Colin Walters's avatar
Colin Walters committed
681 682
    (define-key-after map [menu-bar view filter save-filters]
      '(menu-item "Save current filters permanently..." ibuffer-save-filters
683
        :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers)
Paul Eggert's avatar
Paul Eggert committed
684
        :help "Use a mnemonic name to store current filter stack"))
Colin Walters's avatar
Colin Walters committed
685
    (define-key-after map [menu-bar view filter switch-to-saved-filters]
686 687 688 689
      '(menu-item "Restore permanently saved filters..."
        ibuffer-switch-to-saved-filters
        :enable (and (featurep 'ibuf-ext) ibuffer-saved-filters)
        :help "Replace current filters with a saved stack"))
Colin Walters's avatar
Colin Walters committed
690
    (define-key-after map [menu-bar view filter add-saved-filters]
691 692 693 694
      '(menu-item "Add to permanently saved filters..."
        ibuffer-add-saved-filters
        :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers)
        :help "Include already saved stack with current filters"))
Colin Walters's avatar
Colin Walters committed
695
    (define-key-after map [menu-bar view filter delete-saved-filters]
Colin Walters's avatar
Colin Walters committed
696
      '(menu-item "Delete permanently saved filters..."
697 698
        ibuffer-delete-saved-filters
        :enable (and (featurep 'ibuf-ext) ibuffer-saved-filters)))
Colin Walters's avatar
Colin Walters committed
699

700
    (define-key-after map [menu-bar view filter-groups]
701
      (cons "Filter Groups" ibuffer-mode-groups-popup))
702

Colin Walters's avatar
Colin Walters committed
703 704 705 706
    (define-key-after map [menu-bar view dashes2]
      '("--"))
    (define-key-after map [menu-bar view diff-with-file]
      '(menu-item "Diff with file" ibuffer-diff-with-file
707
        :help "View the differences between this buffer and its file"))
Colin Walters's avatar
Colin Walters committed
708 709
    (define-key-after map [menu-bar view auto-mode]
      '(menu-item "Toggle Auto Mode" ibuffer-auto-mode
710
        :help "Attempt to automatically update the Ibuffer buffer"))
Colin Walters's avatar
Colin Walters committed
711
    (define-key-after map [menu-bar view customize]
712
      '(menu-item "Customize Ibuffer" ibuffer-customize
713
        :help "Use Custom to customize Ibuffer"))
Colin Walters's avatar
Colin Walters committed
714 715 716 717 718 719

    (define-key-after map [menu-bar mark]
      (cons "Mark" (make-sparse-keymap "Mark")))

    (define-key-after map [menu-bar mark toggle-marks]
      '(menu-item "Toggle marks" ibuffer-toggle-marks
720
        :help "Unmark marked buffers, and mark unmarked buffers"))
Colin Walters's avatar
Colin Walters committed
721 722
    (define-key-after map [menu-bar mark mark-forward]
      '(menu-item "Mark" ibuffer-mark-forward
723
        :help "Mark the buffer at point"))
Colin Walters's avatar
Colin Walters committed
724 725
    (define-key-after map [menu-bar mark unmark-forward]
      '(menu-item "Unmark" ibuffer-unmark-forward
726
        :help "Unmark the buffer at point"))
Colin Walters's avatar
Colin Walters committed
727 728
    (define-key-after map [menu-bar mark mark-by-mode]
      '(menu-item "Mark by mode..." ibuffer-mark-by-mode
729
        :help "Mark all buffers in a particular major mode"))
Colin Walters's avatar
Colin Walters committed
730 731
    (define-key-after map [menu-bar mark mark-modified-buffers]
      '(menu-item "Mark modified buffers" ibuffer-mark-modified-buffers
732
        :help "Mark all buffers which have been modified"))
Colin Walters's avatar
Colin Walters committed
733 734
    (define-key-after map [menu-bar mark mark-unsaved-buffers]
      '(menu-item "Mark unsaved buffers" ibuffer-mark-unsaved-buffers
735
        :help "Mark all buffers which have a file and are modified"))
Colin Walters's avatar
Colin Walters committed
736 737
    (define-key-after map [menu-bar mark mark-read-only-buffers]
      '(menu-item "Mark read-only buffers" ibuffer-mark-read-only-buffers
738
        :help "Mark all buffers which are read-only"))
Colin Walters's avatar
Colin Walters committed
739 740
    (define-key-after map [menu-bar mark mark-special-buffers]
      '(menu-item "Mark special buffers" ibuffer-mark-special-buffers
741
        :help "Mark all buffers whose name begins with a *"))
Colin Walters's avatar
Colin Walters committed
742 743
    (define-key-after map [menu-bar mark mark-dired-buffers]
      '(menu-item "Mark dired buffers" ibuffer-mark-dired-buffers
744
        :help "Mark buffers in dired-mode"))
Colin Walters's avatar
Colin Walters committed
745 746
    (define-key-after map [menu-bar mark mark-dissociated-buffers]
      '(menu-item "Mark dissociated buffers" ibuffer-mark-dissociated-buffers
747
        :help "Mark buffers with a non-existent associated file"))
Colin Walters's avatar
Colin Walters committed
748 749
    (define-key-after map [menu-bar mark mark-help-buffers]
      '(menu-item "Mark help buffers" ibuffer-mark-help-buffers
750
        :help "Mark buffers in help-mode"))
751
    (define-key-after map [menu-bar mark mark-compressed-file-buffers]
752 753 754
      '(menu-item "Mark compressed file buffers"
        ibuffer-mark-compressed-file-buffers
        :help "Mark buffers which have a file that is compressed"))
Colin Walters's avatar
Colin Walters committed
755 756
    (define-key-after map [menu-bar mark mark-old-buffers]
      '(menu-item "Mark old buffers" ibuffer-mark-old-buffers
757
        :help "Mark buffers which have not been viewed recently"))
Colin Walters's avatar
Colin Walters committed
758 759
    (define-key-after map [menu-bar mark unmark-all]
      '(menu-item "Unmark All" ibuffer-unmark-all))
760

Colin Walters's avatar
Colin Walters committed
761 762
    (define-key-after map [menu-bar mark dashes]
      '("--"))
763

Colin Walters's avatar
Colin Walters committed
764 765
    (define-key-after map [menu-bar mark mark-by-name-regexp]
      '(menu-item "Mark by buffer name (regexp)..." ibuffer-mark-by-name-regexp
766
        :help "Mark buffers whose name matches a regexp"))
Colin Walters's avatar
Colin Walters committed
767 768
    (define-key-after map [menu-bar mark mark-by-mode-regexp]
      '(menu-item "Mark by major mode (regexp)..." ibuffer-mark-by-mode-regexp
769
        :help "Mark buffers whose major mode name matches a regexp"))
Colin Walters's avatar
Colin Walters committed
770
    (define-key-after map [menu-bar mark mark-by-file-name-regexp]
771 772 773
      '(menu-item "Mark by file name (regexp)..."
        ibuffer-mark-by-file-name-regexp
        :help "Mark buffers whose file name matches a regexp"))
Colin Walters's avatar
Colin Walters committed
774

775
    map))
Colin Walters's avatar
Colin Walters committed
776

777 778
(defvar ibuffer-mode-operate-map
  (let ((operate-map (make-sparse-keymap "Operate")))
Colin Walters's avatar
Colin Walters committed
779 780 781 782 783 784 785 786
    (define-key-after operate-map [do-view]
      '(menu-item "View" ibuffer-do-view))
    (define-key-after operate-map [do-view-other-frame]
      '(menu-item "View (separate frame)" ibuffer-do-view-other-frame))
    (define-key-after operate-map [do-save]
      '(menu-item "Save" ibuffer-do-save))
    (define-key-after operate-map [do-replace-regexp]
      '(menu-item "Replace (regexp)..." ibuffer-do-replace-regexp
787
        :help "Replace text inside marked buffers"))
Colin Walters's avatar
Colin Walters committed
788 789
    (define-key-after operate-map [do-query-replace]
      '(menu-item "Query Replace..." ibuffer-do-query-replace
790
        :help "Replace text in marked buffers, asking each time"))
Colin Walters's avatar
Colin Walters committed
791 792
    (define-key-after operate-map [do-query-replace-regexp]
      '(menu-item "Query Replace (regexp)..." ibuffer-do-query-replace-regexp
793
        :help "Replace text in marked buffers by regexp, asking each time"))
Colin Walters's avatar
Colin Walters committed
794 795 796 797 798 799
    (define-key-after operate-map [do-print]
      '(menu-item "Print" ibuffer-do-print))
    (define-key-after operate-map [do-toggle-modified]
      '(menu-item "Toggle modification flag" ibuffer-do-toggle-modified))
    (define-key-after operate-map [do-revert]
      '(menu-item "Revert" ibuffer-do-revert
800
        :help "Revert marked buffers to their associated file"))
Colin Walters's avatar
Colin Walters committed
801 802
    (define-key-after operate-map [do-rename-uniquely]
      '(menu-item "Rename Uniquely" ibuffer-do-rename-uniquely
803
        :help "Rename marked buffers to a new, unique name"))
Colin Walters's avatar
Colin Walters committed
804 805 806 807
    (define-key-after operate-map [do-delete]
      '(menu-item "Kill" ibuffer-do-delete))
    (define-key-after operate-map [do-occur]
      '(menu-item "List lines matching..." ibuffer-do-occur
808
        :help "View all lines in marked buffers matching a regexp"))
Colin Walters's avatar
Colin Walters committed
809 810
    (define-key-after operate-map [do-shell-command-pipe]
      '(menu-item "Pipe to shell command..." ibuffer-do-shell-command-pipe
811
        :help "For each marked buffer, send its contents to a shell command"))
Colin Walters's avatar
Colin Walters committed
812 813
    (define-key-after operate-map [do-shell-command-pipe-replace]
      '(menu-item "Pipe to shell command (replace)..." ibuffer-do-shell-command-pipe-replace
814
        :help "For each marked buffer, replace its contents with output of shell command"))
Colin Walters's avatar
Colin Walters committed
815 816
    (define-key-after operate-map [do-shell-command-file]
      '(menu-item "Shell command on buffer's file..." ibuffer-do-shell-command-file
817
        :help "For each marked buffer, run a shell command with its file as argument"))
Colin Walters's avatar
Colin Walters committed
818 819
    (define-key-after operate-map [do-eval]
      '(menu-item "Eval..." ibuffer-do-eval
820
        :help "Evaluate a Lisp form in each marked buffer"))
Colin Walters's avatar
Colin Walters committed
821 822
    (define-key-after operate-map [do-view-and-eval]
      '(menu-item "Eval (viewing buffer)..." ibuffer-do-view-and-eval
823
        :help "Evaluate a Lisp form in each marked buffer while viewing it"))
824

825
    operate-map))
826 827

(define-key ibuffer-mode-groups-popup [kill-filter-group]
828 829
  '(menu-item "Kill filter group"
	      ibuffer-kill-line
830 831
	      :enable (and (featurep 'ibuf-ext)
			   ibuffer-filter-groups)))
832
(define-key ibuffer-mode-groups-popup [yank-filter-group]
833 834
  '(menu-item "Yank last killed filter group"
	      ibuffer-yank
835 836
	      :enable (and (featurep 'ibuf-ext)
			   ibuffer-filter-group-kill-ring)))
837

838
(defvar ibuffer-name-map
Colin Walters's avatar
Colin Walters committed
839 840 841 842
  (let ((map (make-sparse-keymap)))
    (define-key map [(mouse-1)] 'ibuffer-mouse-toggle-mark)
    (define-key map [(mouse-2)] 'ibuffer-mouse-visit-buffer)
    (define-key map [down-mouse-3] 'ibuffer-mouse-popup-menu)
843
    map))
Colin Walters's avatar
Colin Walters committed
844

845 846 847 848 849
(defvar ibuffer-filename/process-header-map
  (let ((map (make-sparse-keymap)))
    (define-key map [(mouse-1)] 'ibuffer-do-sort-by-filename/process)
    map))

850
(defvar ibuffer-mode-name-map
Colin Walters's avatar
Colin Walters committed
851 852 853
  (let ((map (make-sparse-keymap)))
    (define-key map [(mouse-2)] 'ibuffer-mouse-filter-by-mode)
    (define-key map (kbd "RET") 'ibuffer-interactive-filter-by-mode)
854
    map))
Colin Walters's avatar
Colin Walters committed
855

856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
(defvar ibuffer-name-header-map
  (let ((map (make-sparse-keymap)))
    (define-key map [(mouse-1)] 'ibuffer-do-sort-by-alphabetic)
    map))

(defvar ibuffer-size-header-map
  (let ((map (make-sparse-keymap)))
    (define-key map [(mouse-1)] 'ibuffer-do-sort-by-size)
    map))

(defvar ibuffer-mode-header-map
  (let ((map (make-sparse-keymap)))
    (define-key map [(mouse-1)] 'ibuffer-do-sort-by-major-mode)
    map))

871
(defvar ibuffer-mode-filter-group-map
872 873 874 875
  (let ((map (make-sparse-keymap)))
    (define-key map [(mouse-1)] 'ibuffer-mouse-toggle-mark)
    (define-key map [(mouse-2)] 'ibuffer-mouse-toggle-filter-group)
    (define-key map (kbd "RET") 'ibuffer-toggle-filter-group)
876
    (define-key map [down-mouse-3] 'ibuffer-mouse-popup-menu)
877
    map))
878

879 880 881 882 883
(defvar ibuffer-restore-window-config-on-quit nil
  "If non-nil, restore previous window configuration upon exiting `ibuffer'.")

(defvar ibuffer-prev-window-config nil
  "Window configuration before starting Ibuffer.")
Colin Walters's avatar
Colin Walters committed
884 885 886

(defvar ibuffer-did-modification nil)

887 888 889 890 891
(defvar ibuffer-compiled-formats nil)
(defvar ibuffer-cached-formats nil)
(defvar ibuffer-cached-eliding-string nil)
(defvar ibuffer-cached-elide-long-columns 0)

Colin Walters's avatar
Colin Walters committed
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
(defvar ibuffer-sorting-functions-alist nil
  "An alist of functions which describe how to sort buffers.

Note: You most likely do not want to modify this variable directly;
use `define-ibuffer-sorter' instead.

The alist elements are constructed like (NAME DESCRIPTION FUNCTION)
Where NAME is a symbol describing the sorting method, DESCRIPTION is a
short string which will be displayed in the minibuffer and menu, and
FUNCTION is a function of two arguments, which will be the buffers to
compare.")

;;; Utility functions
(defun ibuffer-columnize-and-insert-list (list &optional pad-width)
  "Insert LIST into the current buffer in as many columns as possible.
The maximum number of columns is determined by the current window
width and the longest string in LIST."
  (unless pad-width
    (setq pad-width 3))
  (let ((width (window-width))
	(max (+ (apply #'max (mapcar #'length list))
		pad-width)))
    (let ((columns (/ width max)))
      (when (zerop columns)
	(setq columns 1))
      (while list
	(dotimes (i (1- columns))
	  (insert (concat (car list) (make-string (- max (length (car list)))
920
						  ?\s)))
Colin Walters's avatar
Colin Walters committed
921 922 923 924 925 926 927 928 929 930 931 932 933
	  (setq list (cdr list)))
	(when (not (null list))
	  (insert (pop list)))
	(insert "\n")))))

(defsubst ibuffer-current-mark ()
  (cadr (get-text-property (line-beginning-position)
			   'ibuffer-properties)))

(defun ibuffer-mouse-toggle-mark (event)
  "Toggle the marked status of the buffer chosen with the mouse."
  (interactive "e")
  (unwind-protect
934 935 936 937 938 939 940 941 942
      (let ((pt (save-excursion
		  (mouse-set-point event)
		  (point))))
	(ibuffer-aif (get-text-property (point) 'ibuffer-filter-group-name)
	    (ibuffer-toggle-marks it)
	  (goto-char pt)
	  (let ((mark (ibuffer-current-mark)))
	    (setq buffer-read-only nil)
	    (if (eq mark ibuffer-marked-char)
943
		(ibuffer-set-mark ?\s)
944
	      (ibuffer-set-mark ibuffer-marked-char)))))
Colin Walters's avatar
Colin Walters committed
945 946 947 948 949 950 951 952 953 954 955
    (setq buffer-read-only t)))

(defun ibuffer-find-file (file &optional wildcards)
  "Like `find-file', but default to the directory of the buffer at point."
  (interactive
   (let ((default-directory (let ((buf (ibuffer-current-buffer)))
			      (if (buffer-live-p buf)
				  (with-current-buffer buf
				    default-directory)
				default-directory))))
     (list (read-file-name "Find file: " default-directory)
956 957
	   t)))
  (find-file file wildcards))
Colin Walters's avatar
Colin Walters committed
958 959 960 961 962 963 964

(defun ibuffer-mouse-visit-buffer (event)
  "Visit the buffer chosen with the mouse."
  (interactive "e")
  (switch-to-buffer
   (save-excursion
     (mouse-set-point event)
965
     (ibuffer-current-buffer t))))
Colin Walters's avatar
Colin Walters committed
966 967 968 969

(defun ibuffer-mouse-popup-menu (event)
  "Display a menu of operations."
  (interactive "e")
970 971
  (let ((eventpt (posn-point (event-end event)))
	(origpt (point)))
Colin Walters's avatar
Colin Walters committed
972
    (unwind-protect
973
	(if (get-text-property eventpt 'ibuffer-filter-group-name)
974 975 976
	    (progn
	      (goto-char eventpt)
	      (popup-menu ibuffer-mode-groups-popup))
977
	  (let ((inhibit-read-only t))
978
	    (ibuffer-save-marks
979 980 981 982 983 984 985
	      ;; hm.  we could probably do this in a better fashion
	      (ibuffer-unmark-all ?\r)
	      (save-excursion
		(goto-char eventpt)
		(ibuffer-set-mark ibuffer-marked-char))
	      (save-excursion
		(popup-menu ibuffer-mode-operate-map)))))
986
      (setq buffer-read-only t)
987
      (if (= eventpt (point))
988
	  (goto-char origpt)))))
989

990 991 992 993 994 995 996 997
(defun ibuffer-skip-properties (props direction)
  (while (and (not (eobp))
	      (let ((hit nil))
		(dolist (prop props hit)
		  (when (get-text-property (point) prop)
		    (setq hit t)))))
    (forward-line direction)
    (beginning-of-line)))
Colin Walters's avatar
Colin Walters committed
998

999 1000 1001 1002 1003
(defun ibuffer-customize ()
  "Begin customizing Ibuffer interactively."
  (interactive)
  (customize-group 'ibuffer))

1004
(defun ibuffer-backward-line (&optional arg skip-group-names)
Colin Walters's avatar
Colin Walters committed
1005 1006
  "Move backwards ARG lines, wrapping around the list if necessary."
  (interactive "P")
1007
  (or arg (setq arg 1))
Colin Walters's avatar
Colin Walters committed
1008 1009 1010
  (beginning-of-line)
  (while (> arg 0)
    (forward-line -1)
1011 1012 1013
    (when (and ibuffer-movement-cycle
	       (or (get-text-property (point) 'ibuffer-title)
		   (and skip-group-names
1014 1015
			(get-text-property (point)
					   'ibuffer-filter-group-name))))
Colin Walters's avatar
Colin Walters committed
1016
      (goto-char (point-max))
1017
      (beginning-of-line))
1018