Announcing Casual IBuffer
08 Jul 2024 Charles Choi
One of the distinctive features of Emacs is its concept of buffers to organize work. In Emacs one doesn't directly access a file, but rather access a buffer that serves as an interface to that file. A buffer does not necessarily have a file associated with it.
It is commonplace for an Emacs user to see many (typically hundreds) of buffers open. This understandably introduces the need to manage so many buffers. This is what IBuffer aims to do.
What is IBuffer? To quote the GNU reference:
IBuffer is a major mode for viewing a list of buffers and operating on them in a way analogous to that of Dired including filtering, marking, sorting in various ways, and acting on buffers.
As of this writing, the IBuffer keymap has 132 commands. If one only resorts to using IBuffer's keybindings, this results in a very steep learning curve to use it effectively.
Casual IBuffer endeavors to address the above by overlaying a keyboard-driven menu system on IBuffer to organize and facilitate discovery of its commands. Casual IBuffer is now available on MELPA as part of the Casual Suite set of porcelains.
Using Casual IBuffer
Casual IBuffer organizes commands into three menus:
- The main menu (
casual-ibuffer-tmenu
) holding commands for marking and operating on buffers. Display, find/replace, and navigation commands are also included in this menu. - The filter menu (
casual-ibuffer-filter-tmenu
) holding commands for defining filters, filter groups, and collections of filter groups. - The sort menu (
casual-ibuffer-sortby-tmenu
) holding commands for sorting buffers.
Marking and Operating
Buffers can be marked using different criteria. Marked buffers can be operated on. Common operations include saving and deleting buffers. Note that deleting a buffer populated with a visited file is not the same as deleting the visited file.
From the main menu shown above, control of the display and find/replace operations are offered.
Note that the menu item Visit/Toggle has “do what I mean” (DWIM) behavior. If the point is currently on a filter group (described below) then pressing the return
key will toggle the visibility of items matching that filter group. Otherwise, it will visit (open) the buffer.
As with other Casual porcelains, the ability to jump to a bookmark is available.
Filtering
IBuffer is embarrasingly rich in the ways it can filter buffers. Once mastered, IBuffer filtering offers a way to create different views on your buffer list, enabling you to tailor bespoke views for different workflows. Such capability though comes with a price: you'll need to understand how IBuffer wants to organize filters.
Key is the concept of a Filter Group which is IBuffer's analog to a Dired subdirectory (subdir). But whereas a subdir only maps to a file system directory, a filter group can be constructed from a diverse set of rules to categorize a buffer.
IBuffer organizes filtering with the following taxonomy:
-
Filter rule
The smallest unit of filtering. There are many types of filter rules which are enumerated below.
- filter by major mode
- filter by derived mode
- filter by buffer name
- filter by buffer content
- filter by basename
- filter by directory name
- filter by filename
- filter by file extension
- filter by modified buffers
- filter by an arbitrary Lisp predicate
- filter by buffer size
- filter by special buffers
- filter by buffers visiting files
Casual IBuffer makes the design decision to not enumerate the above in a menu, delegating the work of filter selection to the command
ibuffer-filter-chosen-by-completion
. -
Filter
A filter is a logical combination of filter rules. Logic operators such as AND (&), OR (|) and NOT (!) are used to compose rules into a filter. A single filter rule can also be construed as a filter.
Properties of filters:
- A filter can be defined and saved for subsequent use.
- Filters are saved in the customizable variable
ibuffer-saved-filters
. - Multiple filters can be applied at the same time to a set of buffers.
- Filters are saved in the customizable variable
- Multiple filters are applied in LIFO order. Removing a filter is a “pop” operation.
- Rules that are combined with a logic operator are treated as a single element of the LIFO stack.
- To individually edit the combination, use the Decompose command to remove the logic operator first.
- A filter can be defined and saved for subsequent use.
-
Filter Group
A filter group is set of filters. The set itself is named with an identifier that is user-defined.
Properties of filter groups:
- A filter group can be defined and saved for subsequent use but with a special qualifier:
- Filter groups are only saved as a collection (more below) in the customizable variable
ibuffer-saved-filter-groups
. A filter group can not be saved individually.
- Filter groups are only saved as a collection (more below) in the customizable variable
- Multiple filter groups can be applied to partition the buffer list.
- Multiple filter groups are applied in LIFO order. Removing a filter group is a “pop” operation.
- Similar LIFO and decompose behavior applicable to a filter group is supported.
- A filter group can be defined and saved for subsequent use but with a special qualifier:
-
Filter Group Collection
A collection is a set of filter groups that can be named with a user-defined identifier. Only one collection can be applied to a buffer list at a time. However, many different collections can be defined, allowing for different views of the same buffer list.
Creating Filters
The basic procedure for making a filter that applies to the entire buffer list is as follows:
- From the Filter menu, create a filter via (SPC) Rule… and some desired combination of operators.
- Save the filter via (s) Save…. You will be prompted to provide a name for the filter. This filter will be saved in the variable
ibuffer-saved-filters
. - To recall this filter at a subsequent time, use (r) Switch to… in the Add section of the Filter menu.
Creating a Collection of Filter Groups
Here is where the taxonomy becomes significant as the IBuffer command set unfortunately does not provide much observability on edit operations to filters.
- Create a filter as described above.
- In the Add section of the Filter menu, select (g) Create Filter Group… to convert the filter into a filter group. You will be prompted to name the filter group. This group name will be enclosed by square brackets [].
- Multiple filter groups can be created by repeating steps 1 and 2 above. Note that when constructing a filter group, the IBuffer window will not provide observability of existing filter groups on the buffer list.
- You can save the set of filter groups as a collection in the Collection section with the command (S) Save…. You will be prompted to name the collection. Note that only one collection can be used at a time in IBuffer.
Out of the box, it is best to think of the IBuffer commands for editing buffer filters as a kit of parts and an arguably incomplete one at that. The Casual IBuffer filter menu (casual-ibuffer-filter-tmenu
) is my attempt to build a comprehensible filter editor UI from this kit. Whether it succeeds in being comprehensible is left to user feedback.
Sorting
The buffer list can be sorted using different criteria as shown in the screenshot above.
Sort ordering can be reversed via the Invert command.
Closing Thoughts
There is a lot of surface area to IBuffer's command set, which hopefully Casual IBuffer has made more tractable. While filter editing is currently serviceable, I think there is room for improvement which given cycles I'll try to revisit in the not too distant future. That said, I've found the utility of Casual IBuffer significant enough to publish it for general distribution. It has become core to my usage of Emacs and I suspect it will become that way for others too.