Bufler is like a butler for your buffers, presenting them to you in an organized way based on your instructions. The instructions are written as grouping rules in a simple language, allowing you to customize the way buffers are grouped. The default rules are designed to be generally useful, so you don’t have to write your own.
It also provides a workspace mode which allows frames to focus on buffers in certain groups. Since the groups are created automatically, the workspaces are created dynamically, rather than requiring you to put buffers in workspaces manually.
This screenshot shows bufler-list
in the top window, and bufler-switch-buffer
reading a buffer with completion in the bottom window. Note how the same, recursively grouped buffers are shown in both ways.
This screenshot compares Bufler and Ibuffer showing the same buffers with the default settings. Note how Bufler provides collapsible sections to group and hide uninteresting buffers. It also allows commands to be applied to selected sections: for example, pressing k
in this Bufler list would kill the buffers in the groups compilation-mode
and completion-list-mode
(and, of course, since it calls kill-buffer
, any unsaved, file-backed buffers would ask to be saved first).
This screenshot shows Bufler Tabs Mode, which works with the new tab-bar-mode
and tab-line-mode
from Emacs 27. The tab-bar
selects the workspace, and the tab-line
selects a buffer in the current workspace.
If you’ve installed from MELPA, you’re done!
If you prefer, you may install with quelpa-use-package, like this:
(use-package bufler :quelpa (bufler :fetcher github :repo "alphapapa/bufler.el" :files (:defaults (:exclude "helm-bufler.el"))))
To install the additional helm-bufler
package, use:
(use-package helm-bufler :quelpa (helm-bufler :fetcher github :repo "alphapapa/bufler.el" :files ("helm-bufler.el")))
Bufler provides four primary, user-facing features. They complement each other, but each one may be used independently.
bufler
shows a list of buffers grouped according to the defined grouping rules. It allows manipulation of buffers and groups of buffers.bufler-switch-buffer
prompts for a buffer with completion and switches to the selected one. Buffers are presented by their “path” in the groups.bufler-mode
allows each frame to have a “workspace,” which is a buffer group selected by the user. When the mode is active, the command bufler-switch-buffer
presents only buffers from the current workspace (unless called with a prefix, in which case it shows all buffers), and the current workspace is displayed in the mode line and the frame’s title. Buffers can also be manually assigned to named workspaces.bufler-tabs-mode
uses the new Emacs 27 tab-bar
and tab-line
features to display workspaces and buffers. The tab-bar
shows top-level workspaces (and whatever the selected one is, even if not top-level), and the tab-line
shows buffers from the current workspace.A workflow using Bufler could be something like this:
bufler-mode
.M-x bufler-switch-buffer
. The buffers are presented by group with their “outline paths,” which makes it easier to find the buffer you’re looking for, since they’re organized by project, directory, mode, etc.C-u C-u M-x bufler-switch-buffer RET
and select a buffer; or b. Use M-x bufler-workspace-frame-set RET
and select a workspace; or c. Use M-x bufler RET
and press f
to focus the current frame on a workspace, or F
to open a new frame focused on a workspace.bufler-switch-buffer
in that frame, it will only offer buffers from that frame’s buffer group, making it easier to find buffers related to the current project. (Of course, existing commands like switch-to-buffer
are not affected; Bufler doesn’t interfere with other modes or commands.)C-u M-x bufler-switch-buffer
to select from all buffers in all groups.bufler-list
, put the cursor on a group you want to kill or save, and press k
or s
. If you want to see which buffers have unsaved (indicated with *
) or uncommitted (indicated with edited
) changes, you can browse through the list of buffers (enable bufler-vc-state
to show VC state for each buffer; this is disabled by default because getting up-to-date information on a buffer’s VC state can be slow).Then, you can write your own buffer-grouping rules to make them as simple or as complex as you like. They’re just Lisp functions, so you can do anything with them, but the DSL provided by the macro makes simple ones easy to write.
bufler
bufler-mode
bufler-tabs-mode
tab-bar-mode
and tab-line-mode
from Emacs 27+ to display Bufler workspaces and buffers.
bufler-switch-buffer
bufler-workspace-focus-buffer
bufler-workspace-frame-set
bufler-switch-buffer
, but this command may be used to set the workspace to a group containing other groups, after which bufler-switch-buffer
will present buffers from the selected group and its subgroups.
bufler-workspace-buffer-set
auto-workspace
group before any other group.
In the Bufler buffer list, these keys are available (use C-h m
to get the most up-to-date listing). They operate on all buffers in the section at point.
?
Show key bindings Hydra.1
– 4
Cycle section levels at point.M-1
– M-4
Cycle top-level sections.RET
Switch to buffer.SPC
Peek at buffer, keeping focus in buffer list.g
Refresh Bufler list (with prefix, force updating buffers’ VC state and grouping).f
Set the current frame’s workspace to the group at point (with prefix, unset).F
Make a new frame whose workspace is the group at point.N
Add buffers to named workspace (with prefix, remove from it).k
Kill buffers.s
Save buffers.bufler-switch-buffer
works best when completion-styles
includes the substring
style. It also works well with helm-mode
and ivy-mode
.bufler
group.See the =bufler= info page to view this information in Emacs.
The Bufler groups definition is a list stored in variable bufler-groups
. Each element of the list is a function which takes a buffer as its only argument and returns a string naming the group the buffer should be in at that level (or nil if the buffer should not be grouped by the function), or a list of such functions; each list may contain more such lists. Each buffer is matched against these functions in-order until the list of functions is exhausted. A list of functions defines a subgroup which short-circuits other groups at the same level, preventing further grouping outside of the subgroup’s functions. Ultimately, it’s functions all the way down.
If this explanation doesn’t seem clear, please see the examples. Once you get the hang of it, it’s powerful and flexible.
For convenience, the macro bufler-defgroups
provides a concise vocabulary for defining groups. Note that the macro does not set the variable bufler-groups
, it only expands a groups form, so you should use, e.g. (setf bufler-groups (bufler-defgroups ...))
to actually set the groups.
The default groups are defined like this:
(bufler-defgroups (group ;; Subgroup collecting all named workspaces. (auto-workspace)) (group ;; Subgroup collecting all `help-mode' and `info-mode' buffers. (group-or "*Help/Info*" (mode-match "*Help*" (rx bos "help-")) (mode-match "*Info*" (rx bos "info-")))) (group ;; Subgroup collecting all special buffers (i.e. ones that are not ;; file-backed), except `magit-status-mode' buffers (which are allowed to fall ;; through to other groups, so they end up grouped with their project buffers). (group-and "*Special*" (lambda (buffer) (unless (or (funcall (mode-match "Magit" (rx bos "magit-status")) buffer) (funcall (mode-match "Dired" (rx bos "dired")) buffer) (funcall (auto-file) buffer)) "*Special*"))) (group ;; Subgroup collecting these "special special" buffers ;; separately for convenience. (name-match "**Special**" (rx bos "*" (or "Messages" "Warnings" "scratch" "Backtrace") "*"))) (group ;; Subgroup collecting all other Magit buffers, grouped by directory. (mode-match "*Magit* (non-status)" (rx bos (or "magit" "forge") "-")) (auto-directory)) ;; Subgroup for Helm buffers. (mode-match "*Helm*" (rx bos "helm-")) ;; Remaining special buffers are grouped automatically by mode. (auto-mode)) ;; All buffers under "~/.emacs.d" (or wherever it is). (dir user-emacs-directory) (group ;; Subgroup collecting buffers in `org-directory' (or "~/org" if ;; `org-directory' is not yet defined). (dir (if (bound-and-true-p org-directory) org-directory "~/org")) (group ;; Subgroup collecting indirect Org buffers, grouping them by file. ;; This is very useful when used with `org-tree-to-indirect-buffer'. (auto-indirect) (auto-file)) ;; Group remaining buffers by whether they're file backed, then by mode. (group-not "*special*" (auto-file)) (auto-mode)) (group ;; Subgroup collecting buffers in a projectile project. (auto-projectile)) (group ;; Subgroup collecting buffers in a version-control project, ;; grouping them by directory. (auto-project)) ;; Group remaining buffers by directory, then major mode. (auto-directory) (auto-mode))
The following group types are available in bufler-defgroups
. Note that each one is expanded into a lambda, so they may also be called by funcall
(see example above).
group (TYPE...)
Define a subgroup matching given types, which short-circuits other groups at the same level.group-not (NAME TYPE)
Groups buffers which do not match the given type.group-and (NAME TYPE...)
Groups buffers which match all of the given types.group-or (NAME TYPE...)
Groups buffers which match any of the given types.auto-directory
Buffer’s directory.auto-file
Buffer’s file name.auto-indirect
Whether the buffer is indirect (e.g. a cloned indirect buffer).auto-mode
Buffer’s major mode.auto-project
Buffer’s version-control project directory according to project.el
.
auto-parent-project
Like auto-project
, but if the buffer’s parent directory is in a different project, use that one instead. Useful for git worktrees, where auto-project
would show each worktree as a separate project.auto-projectile
Buffer’s project as defined in the projectile
package (if installed).auto-special
Whether the buffer is special (i.e. whether its name starts with *
).auto-tramp
Whether the buffer is opened via Tramp.auto-workspace
The buffer’s named workspace, if any.filename-match (NAME REGEXP)
Match a regular expression against the buffer’s filename, if it has one.name-match (NAME REGEXP)
Match a regular expression against the buffer’s name.mode-match (NAME REGEXP)
Match a regular expression against the buffer’s major-mode.dir (DIRS DEPTH)
Groups buffers which match one of the given DIRS. DIRS may be one or a list of directory paths. DEPTH may be nil or a depth above which to produce subdirectory groups (a feature probably broken at the moment). See example above.hidden
Groups buffers which are hidden (i.e. whose names start with a space and do not visit a file).Bufler does not require nor depend on Helm, but because it uses completing-read
, it requires no special configuration to work with helm-mode
for selecting buffers.
To show Bufler’s grouped buffers in a Helm-specific command, a separate helm-bufler
package is available, which includes helm-bufler-source
, a Helm source that shows buffers in the current workspace (or when the Helm command is called with C-u
, all buffers). It looks like this when showing all buffers:
After installing the package (see installation instructions above), use it like this:
(helm :sources '(helm-bufler-source))
Bufler does not require nor depend on Ivy, but because it uses completing-read
, Bufler requires no special configuration to work with ivy-mode
for selecting buffers. For example, this shows bufler-switch-buffer
with ivy-mode
activated (in the spacemacs-dark
theme):
Bufler does not require nor depend on Prism, but you can use Prism’s level faces with Bufler by using M-x customize-option RET bufler-face-prefix RET
and choosing the Prism faces
option. For example (showing an earlier version of the package, when it was called Sbuffer):
Bufler is primarily about grouping buffers automatically and dynamically, using smart, customizeable rules. While Ibuffer provides some powerful grouping features, they are restricted to single-level grouping, and they require extensive, manual configuration. Bufler offers recursive, multi-level grouping, and a set of default groups is provided which are designed to be generally useful. Bufler presents groups in bufler-list
using the magit-section
library, which allows groups and buffers to be toggled, marked, and operated on with commands.
Ibuffer groups must be manually and individually specified. So, for example, to group project A’s buffers into one group, and project B’s into another, Ibuffer requires the user to make a group for each project. Bufler provides a set of automatic grouping rules that create groups automatically. For example, with the rule (auto-project)
, Bufler would create one group for project A’s buffers and another for project B’s. When those projects’ buffers are closed, the groups are automatically removed.
Bufler also provides optional workspace features in the form of bufler-mode
, which helps focus a frame on a group of buffers. When it’s active, the command bufler-switch-buffer
presents buffers from that frame’s selected workspace; when called with a prefix argument, it presents all buffers, and then switches the frame’s workspace to the selected buffer’s group.
Of course, Ibuffer is a mature tool with many features, so Bufler doesn’t replace it completely. Bufler is a very young project.
This release includes additional support for Emacs’s tab-bar-mode
. Basically, commands and features that formerly acted on the current frame now act on the current tab when tab-bar-mode
is active, otherwise on the current frame.
Notably, these changes are also designed to facilitate integration with Burly’s burly-tabs-mode
(e.g. when a Burly bookmark is opened in a tab-bar
tab, the tab’s Bufler workspace can be set to the workspace containing the buffer, so that bufler-switch-buffer
automatically offers buffers relevant to the tab).
Note as well that the existing bufler-workspace-workspaces-as-tabs-mode
overrides some aspects of Emacs’s tab-bar-mode
and tab-line-mode
; this functionality is still somewhat experimental and may not suit every user’s taste. But while that mode may remain disabled, Bufler’s other features are still useful with standard tab-bar-mode
. (Yes, all these names and modes and features do get confusing. The term “workspaces” is vague, encompassing a variety of ideas envisioned by a range of users. Bufler’s implementation is just one iteration of the concept.)
Additions
bufler-workspace-set
sets the workspace of the current tab-bar
tab or frame.bufler-workspace-switch-buffer-and-tab
(enabled by default) automatically switches to a buffer’s workspace’s tab, if it has one, when using bufler-switch-buffer
. (This tries to solve the age-old problem of buffers not “staying in their workspace.”)bufler-workspace-open
and bufler-workspace-save
. These open and save workspaces using Burly as a backend (which is now a dependency). (This is basically like calling burly-open-bookmark
and burly-bookmark-windows
, but integrating some bufler-workspace
features automatically.)bufler-workspace-prefix-abbreviation
, which abbreviates workspace names in tab/frame names.bufler-switch-buffer-include-recent-buffers
includes recently shown buffers in the bufler-switch-buffer
command’s list of buffers.Changes
bufler-workspace-focus-buffer
sets the workspace of the current tab-bar
tab or frame to the current buffer’s workspace.bufler-workspace-switch-buffer
offers buffers from the workspace of the current tab-bar
tab or frame.bufler-workspace-mode
’s mode-line lighter shows the path of the current tab-bar
tab or frame.Fixes
dir
buffer group uses the base buffer’s directory for indirect buffers.parent-project
expands the directory name. (#95. Thanks to Denis Smirnov for reporting.)Added
auto-parent-project
.bufler-vc-remote
, which controls the displaying of the version control state of remote files (default: off). (Fixes #41. Thanks to Tory S. Anderson for reporting.)bufler-workspace-format-path-fn
, which formats group paths for display in mode lines and frame titles (e.g. it may be customized to show just the last element).Mode
shows buffer’s major mode, sans -mode
suffix.bufler-filter-buffer-fns
, bufler-workspace-switch-buffer-filter-fns
, bufler-filter-buffer-modes
, and bufler-filter-buffer-name-regexps
. By default, more buffers will be hidden in bufler-list
and bufler-switch-buffer
, and filters may be disabled by calling those commands with universal prefix arguments.bufler-list-display-buffer-action
, which controls how the bufler-list
buffer is displayed.bufler-list-switch-buffer-action
, which controls how buffers are displayed when switched to from the buffer list. (Fixes #76. Thanks to Julian M. Burgos, Tory S. Anderson, and jcalve for reporting.)bufler-indent-per-level
, which sets the indentation applied per level of depth.bufler-sidebar
displays the Bufler list in a side window.project-current
function can be slow when called for many paths in rapid succession, as when many buffers are open).Fixed
bufler-filter-buffer-modes
had the wrong customization type.map
package (required for pcase
macro expansion).max-width
options. (Fixes #79. Thanks to Tory S. Anderson for reporting.)Changed
*xref*
buffers by default.bufler-switch-buffer
allows entering a non-existent buffer name to create a buffer and switch to it (like switch-to-buffer
).Project expanded and renamed from Sbuffer to Bufler.
First tagged release.
Bufler bufler bufler bufler bufler bufler bufler bufler.
GPLv3
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4