[[zh:ibuffer模å¼]]
Ibuffer is an advanced replacement for BufferMenu, which lets you operate on buffers much in the same manner as [[DiredMode|Dired]]. The most important Ibuffer features are highlighting and various alternate layouts. Ibuffer is part of Emacs since version 22.
You could use the following key binding to start using it:
(global-set-key (kbd "C-x C-b") 'ibuffer)
== Appearance ==
Screenshot of Ibuffer mode as it appears in Emacs 27.1 (released 2020 August):
[[image:IbufferModeScreenShot]]
== Search all marked buffers ==
* '''`M-s a C-s'''' - Do incremental search in the marked buffers.
* '''`M-s a C-M-s'''' - Isearch for regexp in the marked buffers.
* '''`U'''' - Replace by regexp in each of the marked buffers.
* '''`Q'''' - Query replace in each of the marked buffers.
* '''`I'''' - As above, with a regular expression.
* '''`0'''' - Run occur on the marked buffers.
== Hide certain buffers ==
Here's how to hide all buffers starting with an asterisk.
(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 `='.
== Filter Groups ==
Ibuffer has [[Gnus]]-like grouping. Each "Filter" is collapsable, and contains buffers related to it.
{{{
;; '(("Group Title"
;; ("Label" (type . value))))
(setq ibuffer-saved-filter-groups
'(("MyList"
("Unsaved" (modified)) ; All unsaved buffers
("Stars" (starred-name)) ; Group *starred*
("Start" (name . "*scratch\\*")) ; By regexp
("Dired" (mode . dired-mode)) ; Filter by mode
("Org" (filename . ".org")) ; By filename
("Scheme" (directory . "~/scheme*")) ; By directory
("Gnus" (or ; Or multiple!
(saved . "gnus")
(derived-mode . bbdb-mode))))))
;; Tell ibuffer to load the group automatically
(add-hook 'ibuffer-mode-hook
(lambda ()
(ibuffer-switch-to-saved-filter-groups "MyList")))
}}}
Then ##M-x dired##, then ##M-x ibuffer## and you'll see your [[Dired]] buffer in a group! All your dired buffers will be put here. This group is collapsable, if you don't want to see those buffers.
* ##C-h v ibuffer-filtering-alist## -- List of accepted filter types
* ##C-h v ibuffer-saved-filters## -- List of values for the ##saved## type.
* ##C-h v ibuffer-saved-filter-groups## -- List of currently-defined filter groups.
* ##C-h m## (From in ibuffer) -- tutorial
* See IbufferFilters for more
If any file is not filtered, it is put into a "Default" filter at the bottom of the list.
##filename## accepts [RegularExpression regexp]; if your filter string is only a partial directory name, all files within that directory will be grouped:
("journal" (filename . "~/journal/"))
== 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:
(defun ibuffer--remove-column-titles-after (_format)
"Remove column headers from Ibuffer buffer."
(save-excursion
(set-buffer "*Ibuffer*")
(let ((inhibit-read-only t))
(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))))
(advice-add 'ibuffer-update-title-and-summary :after #'ibuffer--remove-column-titles-after)
== Group by version-control parent directory, and show vc status ==
[https://github.com/purcell/ibuffer-vc 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 ==
[https://github.com/svend/ibuffer-tramp This extension] (based on [https://github.com/purcell/ibuffer-vc 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
[new]
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.
[new]
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-hook 'my-ibuffer-hook)
[new]
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)))I added a little more code to the above code so that the bottom summary line also showed total size in human readable form.
(defun ajv/human-readable-file-sizes-to-bytes (string)
"Convert a human-readable file size into bytes."
(interactive)
(cond
((string-suffix-p "G" string t)
(* 1000000000 (string-to-number (substring string 0 (- (length string) 1)))))
((string-suffix-p "M" string t)
(* 1000000 (string-to-number (substring string 0 (- (length string) 1)))))
((string-suffix-p "K" string t)
(* 1000 (string-to-number (substring string 0 (- (length string) 1)))))
(t
(string-to-number (substring string 0 (- (length string) 1))))
)
)
(defun ajv/bytes-to-human-readable-file-sizes (bytes)
"Convert number of bytes to human-readable file size."
(interactive)
(cond
((> bytes 1000000000) (format "%10.1fG" (/ bytes 1000000000.0)))
((> bytes 100000000) (format "%10.0fM" (/ bytes 1000000.0)))
((> bytes 1000000) (format "%10.1fM" (/ bytes 1000000.0)))
((> bytes 100000) (format "%10.0fk" (/ bytes 1000.0)))
((> bytes 1000) (format "%10.1fk" (/ bytes 1000.0)))
(t (format "%10d" bytes)))
)
;; Use human readable Size column instead of original one
(define-ibuffer-column size-h
(:name "Size"
:inline t
:summarizer
(lambda (column-strings)
(let ((total 0))
(dolist (string column-strings)
(setq total
;; like, ewww ...
(+ (float (ajv/human-readable-file-sizes-to-bytes string))
total)))
(ajv/bytes-to-human-readable-file-sizes total))) ;; :summarizer nil
)
(ajv/bytes-to-human-readable-file-sizes (buffer-size)))
;; Modify the default ibuffer-formats
(setq ibuffer-formats
'((mark modified read-only locked " "
(name 20 20 :left :elide)
" "
(size-h 11 -1 :right)
" "
(mode 16 16 :left :elide)
" "
filename-and-process)
(mark " "
(name 16 -1)
" " filename)))
== 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)
Another way to do this is to add the names of the groups to be hidden to `ibuffer-hidden-filter-groups' in `ibuffer-mode-hook':
(add-hook 'ibuffer-mode-hook
(lambda ()
(ibuffer-switch-to-saved-filter-groups "default")
(setq ibuffer-hidden-filter-groups (list "Helm" "*Internal*"))
(ibuffer-update nil t)
)
)
== 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 "