IbufferMode

Ibuffer is an advanced replacement for BufferMenu, which lets you operate on buffers much in the same manner as Dired. The most important Ibuffer features are highlighting and various alternate layouts. Ibuffer is part of Emacs 22.

If you don’t have Ibuffer, you can get it from GIT:ibuffer.el (there’s also a probably out-of-date project at gna.org). Here’s how to install it:

    (global-set-key (kbd "C-x C-b") 'ibuffer)
    (autoload 'ibuffer "ibuffer" "List buffers." t)

See also: BufferMenuPlus, which also provides highlighting and other enhancements of BufferMenu.

Search all marked buffers

Search All Marked Buffers with Icicles

With Icicles, you can use ‘M-s i’ in Ibuffer to search all marked buffers and possibly replace search hits. You have available all of the Icicles Search features, including accessing search hits directly, in any order.

Hide certain buffers

Here’s how to hide all buffers starting with an asterisk.

    (add-to-list 'ibuffer-never-show-regexps "^\\*")

It does not contain in emacs 23.2’s ibuffer.el, use following instead – coldnew

    (require 'ibuf-ext)
    (add-to-list 'ibuffer-never-show-predicates "^\\*")

View subsets of buffers

Also try ibuffer’s “limiting” feature (‘/’), which allows you to just view a subset of your buffers.

Diff

Ibuffer can show you the differences between an unsaved buffer and the file on disk with `=’.

Gnus-style grouping

Ibuffer has an excellent implementation of Gnus-style grouping. Try this:

    (setq ibuffer-saved-filter-groups
          (quote (("default"
                   ("dired" (mode . dired-mode))
                   ("perl" (mode . cperl-mode))
                   ("erc" (mode . erc-mode))
                   ("planner" (or
                               (name . "^\\*Calendar\\*$")
                               (name . "^diary$")
                               (mode . muse-mode)))
                   ("emacs" (or
                             (name . "^\\*scratch\\*$")
                             (name . "^\\*Messages\\*$")))
                   ("gnus" (or
                            (mode . message-mode)
                            (mode . bbdb-mode)
                            (mode . mail-mode)
                            (mode . gnus-group-mode)
                            (mode . gnus-summary-mode)
                            (mode . gnus-article-mode)
                            (name . "^\\.bbdb$")
                            (name . "^\\.newsrc-dribble")))))))
    (add-hook 'ibuffer-mode-hook
              (lambda ()
                (ibuffer-switch-to-saved-filter-groups "default")))

Then M-x dired then M-x ibuffer and you should see your dired buffer in a group. Open more of them and they all endup in there. This means that when browsing buffers you can skip over the items you are used to seeing. Anything not grouped goes at the bottom of the ibuffer buffer. – PhilJackson

It looks as though the default filterings are as follows:

    predicate
    content
    size-lt
    size-gt
    filename
    name
    used-mode
    mode

Since filename can work for any part of the path, if you filter on a partial (or complete) directory, anything you have open from the directory is now grouped:

    ("journal" (filename . "/personal/journal/"))

I’m not familiar with gnus, and have been unsuccessful tracking written docs on filtering – I extracted the above from a reading of ibuf-ext.el and then onto the contents of ibuffer-filtering-alist. If there is anything out there, somebody please add it in, and edit this note. --OtherMichael

Get rid of title and summary

The last two lines of the ibuffer provide some information about each column. These two lines may be hidden by setting the ibuffer-display-summary variable to nil. The first two lines of the ibuffer are headers describing the contents of the columns. I don’t find these headers so useful and didn’t find a quick way to turn them off. So here is an advice that does the trick:

  (defadvice ibuffer-update-title-and-summary (after remove-column-titles)
   (save-excursion
      (set-buffer "*Ibuffer*")
      (toggle-read-only 0)
      (goto-char 1)
      (search-forward "-\n" nil t)
      (delete-region 1 (point))
      (let ((window-min-height 1)) 
        ;; save a little screen estate
        (shrink-window-if-larger-than-buffer))
      (toggle-read-only)))
  
  (ad-activate 'ibuffer-update-title-and-summary)

Group by version-control parent directory, and show vc status

This extension to ibuffer-mode can dynamically create filter groups for the listed files’ version-control trees, and show their status (e.g. up-to-date, modified etc.).

Group by TRAMP connection

This extension (based on ibuffer-vc) to ibuffer-mode can dynamically create filter groups for TRAMP buffers.

Sort by pathname

I’m not quite sure where to add this, but to be able to sort by pathname (thereby grouping file buffers with dired buffers). PeterMielke

Ibuffer should now use ‘dired-directory’ when appropriate. If you are able/willing to sign an assignment (see LegalMatters) then please send a patch defining an Ibuffer ‘filename’ sorter that falls back to ‘dired-directory’ for dired buffers – JohnPaulWallington.

Was it eventually added to Emacs? – DianeMurray

     (defun my-ibuffer-hook ()
    
      ;; add another sorting method for ibuffer (allow the grouping of
      ;; filenames and dired buffers
    
      (ibuffer-define-sorter pathname
         (:documentation
          "Sort the buffers by their pathname."
          :description "path")
         (string-lessp (with-current-buffer (car a)
                         (or buffer-file-name
                             (if (eq major-mode 'dired-mode)
                                 (expand-file-name dired-directory))
                             ;; so that all non pathnames are at the end
                             "~"))
                       (with-current-buffer (car b)
                         (or buffer-file-name
                             (if (eq major-mode 'dired-mode)
                                 (expand-file-name dired-directory))
                             ;; so that all non pathnames are at the end
                             "~"))))
    
      ;; add key binding
    
      (define-key ibuffer-mode-map (kbd "s p") 'ibuffer-do-sort-by-pathname))
    
    (add-hook 'ibuffer-mode-hooks 'my-ibuffer-hook)

I modified the above, works with GNU Emacs 22.0.92.1, should this work? --DavidBoon

    (define-ibuffer-sorter filename-or-dired
      "Sort the buffers by their pathname."
      (:description "filenames plus dired")
      (string-lessp 
       (with-current-buffer (car a)
         (or buffer-file-name
             (if (eq major-mode 'dired-mode)
                 (expand-file-name dired-directory))
             ;; so that all non pathnames are at the end
             "~"))
       (with-current-buffer (car b)
         (or buffer-file-name
             (if (eq major-mode 'dired-mode)
                 (expand-file-name dired-directory))
             ;; so that all non pathnames are at the end
             "~"))))
    (define-key ibuffer-mode-map (kbd "s p")     'ibuffer-do-sort-by-filename-or-dired)

Filter by pathname

I didn’t really want a new filter; I just wanted the existing filename filter to also include dired buffers. Re-defining that filter in my init file as follows did the trick:

    ;; Enable ibuffer-filter-by-filename to filter on directory names too.
    (eval-after-load "ibuf-ext"
      '(define-ibuffer-filter filename
         "Toggle current view to buffers with file or directory name matching QUALIFIER."
         (:description "filename"
          :reader (read-from-minibuffer "Filter by file/directory name (regexp): "))
         (ibuffer-awhen (or (buffer-local-value 'buffer-file-name buf)
                            (buffer-local-value 'dired-directory buf))
           (string-match qualifier it))))

Use Human readable Size column

I don’t like default “Size” column, so I write a human readable column instead of original one. – coldnew

;; Use human readable Size column instead of original one
(define-ibuffer-column size-h
  (:name "Size" :inline t)
  (cond
   ((> (buffer-size) 1000000) (format "%7.1fM" (/ (buffer-size) 1000000.0)))
   ((> (buffer-size) 100000) (format "%7.0fk" (/ (buffer-size) 1000.0)))
   ((> (buffer-size) 1000) (format "%7.1fk" (/ (buffer-size) 1000.0)))
   (t (format "%8d" (buffer-size)))))

;; Modify the default ibuffer-formats
  (setq ibuffer-formats
	'((mark modified read-only " "
		(name 18 18 :left :elide)
		" "
		(size-h 9 -1 :right)
		" "
		(mode 16 16 :left :elide)
		" "
		filename-and-process)))

Have some buffer groups collapsed by default

I have some buffer groups that i prefer do be collapsed by default. Since i found no way to have this working i adviced ibuffer like this:

(setq mp/ibuffer-collapsed-groups (list "Helm" "*Internal*"))

(defadvice ibuffer (after collapse-helm)
  (dolist (group mp/ibuffer-collapsed-groups)
	  (progn
	    (goto-char 1)
	    (when (search-forward (concat "[ " group " ]") (point-max) t)
	      (progn
		(move-beginning-of-line nil)
		(ibuffer-toggle-filter-group)
		)
	      )
	    )
	  )
    (goto-char 1)
    (search-forward "[ " (point-max) t)
  )

(ad-activate 'ibuffer)

Wraparound Cursor Movement

With this, when you press ‘up’ or `down` to the top/bottom of IBuffer, the cursor wraps around to the bottom/top, so you can continue from there.

  (defun ibuffer-previous-line ()
    (interactive) (previous-line)
    (if (<= (line-number-at-pos) 2)
        (goto-line (- (count-lines (point-min) (point-max)) 2))))
  (defun ibuffer-next-line ()
    (interactive) (next-line)
    (if (>= (line-number-at-pos) (- (count-lines (point-min) (point-max)) 1))
        (goto-line 3)))
  (define-key ibuffer-mode-map (kbd "<up>") 'ibuffer-previous-line)
  (define-key ibuffer-mode-map (kbd "<down>") 'ibuffer-next-line)

– kuanyui

With this improvement you do not need to hard code the line numbers, you just need copy, compile and run. Moreover, the keys ‘up’ and ‘down’ do the same thing but they skip the names of the filtered groups, and you can move to the beginning or the end of a group with ‘left’ and ‘right’.

  (defun ibuffer-advance-motion (direction)
        (forward-line direction)
        (beginning-of-line)
        (if (not (get-text-property (point) 'ibuffer-filter-group-name))
            t
          (ibuffer-skip-properties '(ibuffer-filter-group-name)
                                   direction)
          nil))
  (defun ibuffer-previous-line (&optional arg)
    "Move backwards ARG lines, wrapping around the list if necessary."
    (interactive "P")
    (or arg (setq arg 1))
    (let (err1 err2)
      (while (> arg 0)
        (cl-decf arg)
        (setq err1 (ibuffer-advance-motion -1)
              err2 (if (not (get-text-property (point) 'ibuffer-title)) 
                       t
                     (goto-char (point-max))
                     (beginning-of-line)
                     (ibuffer-skip-properties '(ibuffer-summary 
                                                ibuffer-filter-group-name) 
                                              -1)
                     nil)))
      (and err1 err2)))
  (defun ibuffer-next-line (&optional arg)
    "Move forward ARG lines, wrapping around the list if necessary."
    (interactive "P")
    (or arg (setq arg 1))
    (let (err1 err2)
      (while (> arg 0)
        (cl-decf arg)
        (setq err1 (ibuffer-advance-motion 1)
              err2 (if (not (get-text-property (point) 'ibuffer-summary)) 
                       t
                     (goto-char (point-min))
                     (beginning-of-line)
                     (ibuffer-skip-properties '(ibuffer-summary 
                                                ibuffer-filter-group-name
                                                ibuffer-title)
                                              1)
                     nil)))
      (and err1 err2)))
  (defun brust/ibuffer-next-header ()
    (interactive)
    (while (ibuffer-next-line)))
  (defun brust/ibuffer-previous-header ()
    (interactive)
    (while (ibuffer-previous-line)))
  (define-key ibuffer-mode-map (kbd "<up>") 'ibuffer-previous-line)
  (define-key ibuffer-mode-map (kbd "<down>") 'ibuffer-next-line)
  (define-key ibuffer-mode-map (kbd "<right>") 'ibuffer-previous-header)
  (define-key ibuffer-mode-map (kbd "<left>") 'ibuffer-next-header)

– brust


Questions

Is there any way to configure ibuffer so that switching to ibuffer puts the cursor on the most recent buffer? I’m finding that the cursor stays on the same line it was on the previous time ibuffer was invoked, which is a bit confusing when the buffers are sorted in visited order.

Thanks - dab

This works for me
  (defun my-ibuffer ()
    "Open ibuffer with cursour pointed to most recent buffer name"
    (interactive)
    (let ((recent-buffer-name (buffer-name)))
      (ibuffer)
      (ibuffer-jump-to-buffer recent-buffer-name)))
  (global-set-key [(f12)] 'my-ibuffer)

– Alexander Litvinov

That can be converted to advice, to make it more seamless.

  ;; Switching to ibuffer puts the cursor on the most recent buffer
  (defadvice ibuffer (around ibuffer-point-to-most-recent) ()
    "Open ibuffer with cursor pointed to most recent buffer name"
    (let ((recent-buffer-name (buffer-name)))
      ad-do-it
      (ibuffer-jump-to-buffer recent-buffer-name)))
  (ad-activate 'ibuffer)

Here’s a snippet using the new advice system

    (defun ninrod/ibuffer-recent-buffer (old-ibuffer &rest arguments) ()
         "Open ibuffer with cursor pointed to most recent buffer name"
         (let ((recent-buffer-name (buffer-name)))
           (apply old-ibuffer arguments)
           (ibuffer-jump-to-buffer recent-buffer-name)))
  (advice-add #'ibuffer :around #'ninrod/ibuffer-recent-buffer)

– Ninrod

This will cause an error if you ever enter ibuffer from the minibuffer. Ibuffer complains about “No buffer with name *Minibuf-1*”. Here’s my fix:

  (defadvice ibuffer (around ibuffer-point-to-most-recent) ()
             "Open ibuffer with cursor pointed to most recent (non-minibuffer) buffer name"
             (let ((recent-buffer-name
                    (if (minibufferp (buffer-name))
                        (buffer-name
                         (window-buffer (minibuffer-selected-window)))
                      (buffer-name (other-buffer)))))
               ad-do-it
               (ibuffer-jump-to-buffer recent-buffer-name)))
  (ad-activate 'ibuffer)

I set ibuffer-filter-groups like this: (setq ibuffer-filter-groups ‘((“Dired” ((mode . dired-mode)))))

but it doesn’t work. Is there an example to show how to set the varibale involved?

YeWenbin

I found this works:
    (require 'ibuf-ext nil t)
    (when (featurep 'ibuf-ext)
      (add-hook 'ibuffer-mode-hook (lambda ()
                                     (setq ibuffer-filter-groups '(
                                                                   ("*buffer*" (name . "\\*.*\\*"))
                                                                   ("TAGS" (name . "^TAGS\\(<[0-9]+>\\)?$"))
                                                                   ("dired" (mode . dired-mode))
                                                                   )))))

But How to move the Default group to display first?

Hi, see above (my original group suggestion) for the answer – PhilJackson


Use this to reverse the order of groups:
    (defadvice ibuffer-generate-filter-groups (after reverse-ibuffer-groups ()
                                                     activate)
      (setq ad-return-value (nreverse ad-return-value)))

When used with ElScreen, Ibuffer tends to remove it’s header line with tabs.

To prevent it, set ibuffer-use-header-line to nil and use the following:

  (defadvice ibuffer-update (around ibuffer-preserve-prev-header activate)
    "Preserve line-header used before Ibuffer if it doesn't set one"
    (let ((prev-line-header header-line-format))
      ad-do-it
      (unless header-line-format
        (setq header-line-format prev-line-header))))

IvanKorotkov


How can I set the number of characters that the name will truncate to? Right now, when I use uniquify to get uniqe buffer names, many of my buffer names look like this: ‘somedirectory:so…’ and I have to look at the filename column to find out that the file in questions was ‘somefile’. I would like to raise the number of chars displayed in the name column by ten och fifteen.

/Jeff

Read the documentation for ‘ibuffer-formats’ and you shall be enlightened.


I use ibuffer with the scratch buffer hidden. Sometimes I want to kill all the unhidden buffers, but then ibuffer complains about there being “No buffers!”. The relevant error code is in ibuffer-update and ibuffer-redisplay. Currently I’ve just redefined these functions with the error code commented out. Is there a better way to do this? Perhaps there could be a simple flag to determine whether ibuffer complains about killing all buffers.

/ Geoff


CategoryBufferSwitching