All Projects → alphapapa → Bufler.el

alphapapa / Bufler.el

Licence: gpl-3.0
A butler for your buffers. Group buffers into workspaces with programmable rules, and easily switch to and manipulate them.

Labels

Projects that are alternatives of or similar to Bufler.el

Evil Multiedit
Multiple cursors for evil-mode, based on iedit
Stars: ✭ 200 (-9.91%)
Mutual labels:  emacs
Dotfiles
Ninrod's sharpened dotfiles for emacs, vim, zsh, tmux. Since '15.
Stars: ✭ 208 (-6.31%)
Mutual labels:  emacs
Atom One Dark Theme
Atom One Dark - An Emacs port of the Atom One Dark theme from Atom.io.
Stars: ✭ 217 (-2.25%)
Mutual labels:  emacs
Company Sourcekit
Completion for Swift projects via SourceKit with the help of SourceKitten
Stars: ✭ 203 (-8.56%)
Mutual labels:  emacs
Uncledavesemacs
My personal ~/.emacs.d
Stars: ✭ 204 (-8.11%)
Mutual labels:  emacs
Doct
DOCT: Declarative Org Capture Templates for Emacs
Stars: ✭ 210 (-5.41%)
Mutual labels:  emacs
Hackernews.el
Hacker News client for Emacs
Stars: ✭ 200 (-9.91%)
Mutual labels:  emacs
Awesome Elisp
A curated list of emacs-lisp development resources
Stars: ✭ 221 (-0.45%)
Mutual labels:  emacs
Verb
Organize and send HTTP requests from Emacs
Stars: ✭ 205 (-7.66%)
Mutual labels:  emacs
Homebrew Emacs Head
GNU Emacs formula for the Homebrew package manager
Stars: ✭ 214 (-3.6%)
Mutual labels:  emacs
Toc Org
toc-org is an Emacs utility to have an up-to-date table of contents in the org files without exporting (useful primarily for readme files on GitHub)
Stars: ✭ 202 (-9.01%)
Mutual labels:  emacs
Elfeed Org
Configure the Elfeed RSS reader with an Orgmode file
Stars: ✭ 203 (-8.56%)
Mutual labels:  emacs
Github Review
Github code reviews with Emacs.
Stars: ✭ 210 (-5.41%)
Mutual labels:  emacs
Literate Calc Mode.el
🧮 Literate programming for M-x calc
Stars: ✭ 201 (-9.46%)
Mutual labels:  emacs
Emacs Bash Completion
Add programmable bash completion to Emacs shell-mode
Stars: ✭ 217 (-2.25%)
Mutual labels:  emacs
Lsp Treemacs
lsp-mode ❤️ treemacs
Stars: ✭ 200 (-9.91%)
Mutual labels:  emacs
Fsautocomplete
F# language server using Language Server Protocol
Stars: ✭ 208 (-6.31%)
Mutual labels:  emacs
Live Py Plugin
Live coding in Python with PyCharm, Emacs, Sublime Text, or even a browser
Stars: ✭ 222 (+0%)
Mutual labels:  emacs
Vimish Fold
Vim-like text folding for Emacs
Stars: ✭ 220 (-0.9%)
Mutual labels:  emacs
Modalka
Modal editing your way
Stars: ✭ 212 (-4.5%)
Mutual labels:  emacs

#+TITLE: Bufler.el

#+PROPERTY: LOGGING nil

Note: This readme works with the org-make-toc https://github.com/alphapapa/org-make-toc package, which automatically updates the table of contents.

#+HTML:

#+HTML:

[[https://melpa.org/#/package-name][file:https://melpa.org/packages/sbuffer-badge.svg]] [[https://stable.melpa.org/#/package-name][file:https://stable.melpa.org/packages/sbuffer-badge.svg]]

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.

  • Screenshots :PROPERTIES: :TOC: :ignore (this) :END:

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.

[[images/default-theme.png]]

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

[[images/vs-ibuffer-doom-one.png]]

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.

[[images/workspace-tabs-mode-spacemacs-dark.png]]

  • Contents :noexport: :PROPERTIES: :TOC: :include siblings :depth 1 :force depth :END: :CONTENTS:
  • [[#installation][Installation]]
  • [[#usage][Usage]]
  • [[#compared-to-ibuffer][Compared to Ibuffer]]
  • [[#changelog][Changelog]]
  • [[#credits][Credits]] :END:
  • Installation :PROPERTIES: :TOC: :depth 0 :END:

If you've installed from [[https://melpa.org/][MELPA]], you're done!

** Quelpa

If you prefer, you may install with [[https://github.com/quelpa/quelpa-use-package][quelpa-use-package]], like this:

#+BEGIN_SRC elisp (use-package bufler :quelpa (bufler :fetcher github :repo "alphapapa/bufler.el" :files (:defaults (:exclude "helm-bufler.el")))) #+END_SRC

To install the additional =helm-bufler= package, use:

#+BEGIN_SRC elisp (use-package helm-bufler :quelpa (helm-bufler :fetcher github :repo "alphapapa/bufler.el" :files ("helm-bufler.el"))) #+END_SRC

  • Usage :PROPERTIES: :TOC: :include descendants :depth 1 :END:

Bufler provides four primary, user-facing features. They complement each other, but each one may be used independently.

  1. The command =bufler= shows a list of buffers grouped according to the defined grouping rules. It allows manipulation of buffers and groups of buffers.
  2. The command =bufler-switch-buffer= prompts for a buffer with completion and switches to the selected one. Buffers are presented by their "path" in the groups.
  3. The global minor mode =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.
  4. The global minor mode =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.

:CONTENTS:

  • [[#workflow][Workflow]]
  • [[#commands][Commands]]
  • [[#bindings][Bindings]]
  • [[#tips][Tips]]
  • [[#defining-groups][Defining groups]]
  • [[#helm-support][Helm support]]
  • [[#ivy-support][Ivy support]]
  • [[#prism-support][Prism support]] :END:

** Workflow

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. If you want to focus on a certain group's buffers: a. Use =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.
  6. 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. (Of course, existing commands like =switch-to-buffer= are not affected; Bufler doesn't interfere with other modes or commands.)
  7. When you need to switch to a buffer in a different group without changing the frame's workspace, use =C-u M-x bufler-switch-buffer= to select from all buffers in all groups.
  8. 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.

** Commands

  • =bufler= :: Show the Bufler buffer list.
  • =bufler-mode= :: Enable the Bufler workspace mode, which allows each frame to have a chosen workspace from Bufler's groups.
  • =bufler-tabs-mode= :: Enable the Bufler workspace tabs mode, which uses =tab-bar-mode= and =tab-line-mode= from Emacs 27+ to display Bufler workspaces and buffers.
  • =bufler-switch-buffer= :: Switch to a buffer selected from the frame's workspace. Without any input, switch to the previous buffer. With prefix, select from all buffers. With two prefixes, also set the frame's workspace.
  • =bufler-workspace-focus-buffer= :: Set current frame's workspace to the current buffer's workspace.
  • =bufler-workspace-frame-set= :: Set the frame's workspace. Setting the workspace may be 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-workspace-buffer-set= :: Set 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.

  • =?= 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.

** Tips

  • =bufler-switch-buffer= works best when =completion-styles= includes the =substring= style. It also works well with =helm-mode= and =ivy-mode=.
  • Customize settings in the =bufler= group.

** Defining groups :PROPERTIES: :TOC: :include descendants :END: :CONTENTS:

  • [[#default-groups-example][Default groups example]]
  • [[#group-types][Group types]] :END:

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

*** Default groups example

The default groups are defined like this:

#+BEGIN_SRC elisp (bufler-defgroups (group ;; Subgroup collecting all named workspaces. (auto-workspace)) (group ;; Subgroup collecting all help-mode' andinfo-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 inorg-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 withorg-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)) #+END_SRC

*** Group types

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 types :: These 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 types :: These types automatically create groups for the buffer's attribute of this type.
    • 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.
  • Regexp types :: These types match a value against a buffer's attribute and group buffers which match.
    • 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.
  • 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.
    • hidden Groups buffers which are hidden (i.e. whose names start with a space and do not visit a file).

** Helm support

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:

[[images/helm-bufler.png]]

After installing the package (see [[#installation][installation instructions]] above), use it like this:

#+BEGIN_SRC elisp (helm :sources '(helm-bufler-source)) #+END_SRC

** Ivy support

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-buffers= with =ivy-mode= activated (in the =spacemacs-dark= theme):

[[images/ivy-mode-spacemacs-dark-theme.png]]

** Prism support

Bufler does not require nor depend on [[https://github.com/alphapapa/prism.el][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, 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.

  • Changelog :PROPERTIES: :TOC: :depth 0 :END:

** 0.3-pre

Added

  • Group type =auto-parent-project=.
  • Option =bufler-vc-remote=, which controls the displaying of the version control state of remote files (default: off). (Fixes [[https://github.com/alphapapa/bufler.el/issues/41][#41]]. Thanks to [[https://github.com/WorldsEndless][Tory S. Anderson]] for reporting.)
  • Option =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).
  • Show an asterisk next to buffers with unsaved changes. (Thanks to [[https://github.com/ration][Tatu Lahtela]].)
  • Option bufler-name-column-width limits the width of buffer names in the buffer list. (Thanks to [[https://github.com/WorldsEndless][Tory S. Anderson]].)
  • Column Mode shows buffer's major mode, sans -mode suffix.
  • More filtering options: 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.

** 0.2

Project expanded and renamed from Sbuffer to Bufler.

** 0.1

First tagged release.

  • Credits
  • Thanks to [[https://github.com/tarsius][Jonas Bernoulli]] for [[https://github.com/magit/magit/blob/master/lisp/magit-section.el][magit-section]].
  • Thanks to [[https://github.com/magnars/dash.el][Magnar Sveen]] and [[https://github.com/Fuco1][Matus Goljer]] for [[https://github.com/magnars/dash.el][dash.el]].
  • Thanks to [[https://github.com/rejeep][Johan Andersson]] for [[https://github.com/rejeep/f.el][f.el]].
  • Thanks to [[https://github.com/jerrypnz][Jerry Peng]] for [[https://github.com/jerrypnz/major-mode-hydra.el#pretty-hydra][Pretty Hydra]].
  • Development :PROPERTIES: :TOC: :ignore (this) :END:

Bufler bufler bufler bufler bufler bufler bufler bufler.

  • License :PROPERTIES: :TOC: :ignore (this) :END:

GPLv3

  • COMMENT Export Setup :noexport: :PROPERTIES: :TOC: :ignore (this descendants) :END:

Much borrowed from Org's =org-manual.org=.

#+OPTIONS: broken-links:t *:t

** Info export options

#+TEXINFO_DIR_CATEGORY: Emacs #+TEXINFO_DIR_TITLE: Bufler: (bufler) #+TEXINFO_DIR_DESC: Group buffers into workspaces with programmable rules, and easily switch to and manipulate them.

NOTE: We could use these, but that causes a pointless error, "org-compile-file: File "..README.info" wasn't produced...", so we just rename the files in the after-save-hook instead.

#+TEXINFO_FILENAME: bufler.info

#+EXPORT_FILE_NAME: bufler.texi

** File-local variables

NOTE: Setting org-comment-string buffer-locally is a nasty hack to work around GitHub's org-ruby's HTML rendering, which does not respect noexport tags. The only way to hide this tree from its output is to use the COMMENT keyword, but that prevents Org from processing the export options declared in it. So since these file-local variables don't affect org-ruby, wet set org-comment-string to an unused keyword, which prevents Org from deleting this tree from the export buffer, which allows it to find the export options in it. And since org-export does respect the noexport tag, the tree is excluded from the info page.

Local Variables:

before-save-hook: org-make-toc

after-save-hook: (lambda nil (when (and (require 'ox-texinfo nil t) (org-texinfo-export-to-info)) (delete-file "README.texi") (rename-file "README.info" "bufler.info" t)))

org-export-initial-scope: buffer

org-comment-string: "NOTCOMMENT"

End:

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].