[[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 "") 'ibuffer-previous-line) (define-key ibuffer-mode-map (kbd "") '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 "") 'ibuffer-previous-line) (define-key ibuffer-mode-map (kbd "") 'ibuffer-next-line) (define-key ibuffer-mode-map (kbd "") 'ibuffer-previous-header) (define-key ibuffer-mode-map (kbd "") 'ibuffer-next-header) -- brust == 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 Commands, Overview|Icicles Search]] features, including accessing search hits directly, in any order. == IBuffer on old Emacs == Ibuffer is part of Emacs since version 22. If you don't have '''[::Ibuffer]''', you can get it from GIT:ibuffer.el (there's also a probably out-of-date [http://gna.org/projects/ibuffer 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 == * [https://www.emacswiki.org/emacs/Comments_on_IbufferMode Comments on IbufferMode] * BufferMenuPlus, which also provides highlighting and other enhancements of BufferMenu. ---- CategoryBufferSwitching