My Emacs IBuffer Configuration

Buffer grouping in Emacs

I recently came across a Reddit post titled How to group buffers that are important to visit later which discusses various methods for buffer grouping in Emacs.

In the comments, which are typically engaging, some users mentioned using the built-in bookmarks package, while others recommended the easysession package or alternative approaches for effective buffer grouping.

Additionally, there were mentions of the built-in ibuffer package, which I personally use for buffer grouping. In this post, I’ll share my IBuffer configuration to demonstrate how I leverage it for this purpose.

Some ideas in my configuration are inspired by an excellent post, GNU Emacs configuration by Protesilaos Stavrou, a renowned Emacs expert. All of his posts are well worth reading for their insightful and practical Emacs advice.

Prettifying the IBuffer Window

To make my IBuffer window visually appealing, I use an icon set provided by the external all-the-icons-ibuffer package.

;; Prerequisites
(use-package all-the-icons-ibuffer :ensure t
  :hook (ibuffer-mode . all-the-icons-ibuffer-mode))

IBuffer Configuration

(use-package ibuffer :ensure nil
  :config
  (setq ibuffer-expert t)
  (setq ibuffer-display-summary nil)
  (setq ibuffer-use-other-window nil)
  (setq ibuffer-show-empty-filter-groups nil)
  (setq ibuffer-default-sorting-mode 'filename/process)
  (setq ibuffer-title-face 'font-lock-doc-face)
  (setq ibuffer-use-header-line t)
  (setq ibuffer-default-shrink-to-minimum-size nil)
  (setq ibuffer-formats
        '((mark modified read-only locked " "
                (name 30 30 :left :elide)
                " "
                (size 9 -1 :right)
                " "
                (mode 16 16 :left :elide)
                " " filename-and-process)
          (mark " "
                (name 16 -1)
                " " filename)))
  (setq ibuffer-saved-filter-groups
        '(("Main"
           ("Directories" (mode . dired-mode))
           ("C++" (or
                   (mode . c++-mode)
                   (mode . c++-ts-mode)
                   (mode . c-mode)
                   (mode . c-ts-mode)
                   (mode . c-or-c++-ts-mode)))
           ("Python" (or
                      (mode . python-ts-mode)
                      (mode . c-mode)
                      (mode . python-mode)))
           ("Build" (or
                     (mode . make-mode)
                     (mode . makefile-gmake-mode)
                     (name . "^Makefile$")
                     (mode . change-log-mode)))
           ("Scripts" (or
                       (mode . shell-script-mode)
                       (mode . shell-mode)
                       (mode . sh-mode)
                       (mode . lua-mode)
                       (mode . bat-mode)))
           ("Config" (or
                      (mode . conf-mode)
                      (mode . conf-toml-mode)
                      (mode . toml-ts-mode)
                      (mode . conf-windows-mode)
                      (name . "^\\.clangd$")
                      (name . "^\\.gitignore$")
                      (name . "^Doxyfile$")
                      (name . "^config\\.toml$")
                      (mode . yaml-mode)))
           ("Web" (or
                   (mode . mhtml-mode)
                   (mode . html-mode)
                   (mode . web-mode)
                   (mode . nxml-mode)))
           ("CSS" (or
                   (mode . css-mode)
                   (mode . sass-mode)))
           ("JS" (or
                  (mode . js-mode)
                  (mode . rjsx-mode)))
           ("Markup" (or
                   (mode . markdown-mode)
                   (mode . adoc-mode)))
           ("Org" (mode . org-mode))
           ("LaTeX" (name . "\.tex$"))
           ("Magit" (or
                     (mode . magit-blame-mode)
                     (mode . magit-cherry-mode)
                     (mode . magit-diff-mode)
                     (mode . magit-log-mode)
                     (mode . magit-process-mode)
                     (mode . magit-status-mode)))
           ("Apps" (or
                    (mode . elfeed-search-mode)
                    (mode . elfeed-show-mode)))
           ("Fundamental" (or
                           (mode . fundamental-mode)
                           (mode . text-mode)))
           ("Emacs" (or
                     (mode . emacs-lisp-mode)
                     (name . "^\\*Help\\*$")
                     (name . "^\\*Custom.*")
                     (name . "^\\*Org Agenda\\*$")
                     (name . "^\\*info\\*$")
                     (name . "^\\*scratch\\*$")
                     (name . "^\\*Backtrace\\*$")
                     (name . "^\\*Messages\\*$"))))))
  :hook
  (ibuffer-mode . (lambda ()
                    (ibuffer-switch-to-saved-filter-groups "Main")))
)

IBuffer. Click or tap to view the full-size picture.

Since I use the ibuffer command frequently, I’ve bound it to the <F5> key for quick access.

(global-set-key [(f5)]  #'ibuffer)

Casual IBuffer

Another valuable resource for enhancing IBuffer is the Casual project, a suite of excellent Emacs packages developed by Charles Choi. As outlined in the Casual User Guide, its goals are to provide a keyboard-driven menu UI toolkit for common Emacs commands, to enable casual discovery and use of infrequently used commands, and to serve as a frequently used interface for supported modes.

The Casual IBuffer package specifically provides an intuitive user interface for Emacs IBuffer, enhancing its functionality and ease of use.

;; Requires `transient' package.
;; https://kickingvegas.github.io/casual/
(use-package casual :ensure t)

;; IBuffer
(keymap-set ibuffer-mode-map "C-o" #'casual-ibuffer-tmenu)
(keymap-set ibuffer-mode-map "F" #'casual-ibuffer-filter-tmenu)
(keymap-set ibuffer-mode-map "s" #'casual-ibuffer-sortby-tmenu)

Casual IBuffer. Click or tap to view the full-size picture.

Happy emacsing!

— The Emacs Cat.