26

GitHub - alphapapa/bufler.el: A butler for your buffers. Group buffers into wor...

 4 years ago
source link: https://github.com/alphapapa/bufler.el
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

README.org

Bufler.el

dont-tread-on-emacs-150.png

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.

Screenshots

In the default Emacs theme:

images/default-theme.png

This screenshot compares Bufler and Ibuffer showing the same buffers with the default settings. Note how Bufler allows commands to be applied to an entire group of buffers: for example, pressing k in the Bufler list would kill all the buffers in the group Project: ~/src/emacs/bufler.el (and, of course, since it calls kill-buffer, any unsaved ones would ask to be saved first).

images/vs-ibuffer-doom-one.png

Contents

Installation

Use quelpa-use-package, like this:

(use-package bufler
  :quelpa (bufler :fetcher github :repo "alphapapa/bufler.el"))

Usage

Commands

Run one of these commands. You can customize settings in the bufler group.

buflerShow the Bufler buffer list. bufler-modeEnable the Bufler workspace mode, which allows each frame to have a chosen workspace from Bufler’s groups. bufler-switch-bufferSwitch to a buffer selected from the frame’s workspace. With prefix, select from all buffers and change the frame’s workspace. bufler-frame-workspaceSet the frame’s workspace. Setting the workspace is done automatically by 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-buffer-workspaceSet the current buffer’s workspace name. With prefix, unset it. Note that, in order for a buffer to appear in a named workspace, the buffer must be matched by an auto-workspace group before any other group.

Bindings

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.

  • 14 Cycle section levels at point.
  • M-1M-4 Cycle top-level sections.
  • RET Pop to buffer.
  • f Make a new frame for the group at point.
  • g Refresh Bufler list.
  • k Kill buffers.
  • s Save buffers.
  • w Set workspace name.

Defining groups

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 either a lambda function which takes a single argument, a buffer, or a list of such functions. Each buffer is matched against these functions in order until it does not match any more functions at that level. 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 lambdas all the way down.

This seems somewhat difficult to explain, so please see the examples. Once you get the hang of it, it’s powerful and flexible.

For convenience, the macro bufler-defgroups provides a sort of DSL, a concise vocabulary for defining groups. For example, 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 version-control project,
   ;; grouping them by directory.
   (auto-project))
  ;; Group remaining buffers by directory, then major mode.
  (auto-directory)
  (auto-mode))

Note that the macro does not set the variable bufler-groups, it merely expands a groups form, so you should use, e.g. (setf bufler-groups (bufler-defgroups ...)) to actually set the groups.

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).

Meta typesThese types compose multiple of the other types into a single group.
  • 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-typesThese types automatically create groups for the buffer’s attribute of this type.
  • auto-directory Buffer’s directory.
  • auto-file Buffer’s file name.
  • auto-hidden Whether the buffer is hidden.
  • 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-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.
Regexp typesThese types match a value against a buffer’s attribute and group buffers which match.
  • 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.
Other types
  • 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.

Helm support

Bufler does not require nor depend on Helm, but it provides optional support for it in helm-bufler.el in the form of 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:

images/helm-bufler.png

Use it like this:

(require 'helm-bufler)

(helm :sources '(helm-bufler-source))

Or you can use the source in an existing Helm command, like helm-find-files.

Prism support

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):

images/prism.png

Compared to Ibuffer

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, auto-project automatically creates groups per-project, so the user would only have to specify (auto-project), and 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.

A workflow using Bufler could be something like this:

  1. Start Emacs.
  2. Activate bufler-mode.
  3. Open some buffers, find some files, etc.
  4. When you need to switch buffers, use 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.
  5. The next time you call 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. Or if you need to select a buffer in a different group, use C-u with bufler-switch-buffer to see all buffers. (Of course, existing commands like switch-to-buffer are not affected; Bufler doesn’t interfere with other modes or commands.)
  6. Make a new frame for a different project by using bufler-list to show the list of buffer groups, then selecting a group and pressing f to make the frame, which will be automatically set to that group’s workspace.
  7. When you need to kill or save a bunch of buffers at once, use 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.

Changelog

0.2-pre

Project expanded and renamed from Sbuffer to Bufler.

0.1

First tagged release.

Credits

Development

Bug reports, feature requests, suggestions — oh my!

License

GPLv3


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK