Change log of Beframe (beframe.el)

Isolate Emacs buffers per frame

This document contains the release notes for each tagged commit on the project's main git repository:

The newest release is at the top. For further details, please consult the manual:

1.1.0 on 2024-05-06

This is a small release that adds some quality-of-life refinements to a stable package.

The beframe-global-buffers is more flexible

This is a user option to specify which buffers should appear in all frames. These "global" buffers are thus not associated only with the frame in which they where displayed in.

Before, the value of this user option was a list of strings that were matching buffer names literally. Now it is a list of strings which are understood as regular expressions as well as a list of symbols representing major modes.

Consider this example:

(setq beframe-global-buffers '("\\*scratch\\*" ".*notmuch.*" emacs-lisp-mode))

It matches a buffer with the literal name *scratch*, all buffers that include notmuch in their name, and all buffers whose major mode is emacs-lisp-mode or derived therefrom.

You can now more easily put all buffers in the global list, such as for email or IRC.

The beframe-prefix-map is now a command

Before, this symbol was defined as a variable, which held the value of the key bindings. Users where expected to bind this variable to a key, such as:

(define-key global-map (kbd "C-c b") beframe-prefix-map)

This would set up C-c b as a prefix for all the key bindings inside of beframe-prefix-map. However, any changes to that map would not be automatically included in the prefix. The above binding had to be evaluated again (because we were binding a fixed value directly, instead of having the indirection of a symbol that points to a value).

Now the beframe-prefix-map is implemented as a variable and a command. The variable holds the value of the key bindings, while the command is meant to be assigned to a key. For users, the change is trivial:

(define-key global-map (kbd "C-c b") 'beframe-prefix-map)

Notice the added single quote before beframe-prefix-map. While only an extra character in the user's configuration, this is a major change because any changes made to the key map will now be automatically available under the defined prefix. No need to evaluate the key binding again.

1.0.0 on 2023-11-17

beframe is in a stable state. This release formalises a set of stability enhancements and quality-of-life improvements.

The menu bar helps you discover Beframe commands

A submenu with Beframe commands is available to users of menu-bar-mode. It is available at Buffers > BEFRAME buffers. Check the original announcement, which includes screenshots:

[ As an aside, never tell a new user to add (menu-bar-mode -1) to their Emacs init file. It is not helpful. ]

The sample integration with consult can flip between recent buffers

In the manual of beframe there is a section about augmenting the consult-buffer command with a new source of beframed buffers (buffers specific to the current frame). Edgar Vincent made a change that sorts buffers by last viewed, meaning that the previous buffer is at the top of the list. The change is within the ~15 line limit and thus Edgar does not need to assign copyright to the Free Software Foundation. Discussed on the mailing list:

Refer to the manual for the code to integrate beframe with consult:

NOTE that you do not need consult to use beframe: (i) the beframe-mode makes the regular switch-to-buffer work in a beframed way and/or (ii) use the beframe-buffer-menu to get a list of the beframed buffers (call the latter command with a prefix key (C-u by default) to select a frame whose buffers you want to list).

The beframe-rename-function can take a nil value

This was always the intent, though the code did not honour it. Thanks to Karthik Chikmagalur for reporting the bug on the mailing list:

General refinements

  • Commands that prompt for a frame (e.g. beframe-assume-frame-buffers) no longer try to perform their work if a single Emacs frame is available. Instead, they return a user-error.
  • The buffer that was current when a new frame was created is no longer part of the new frame's buffer list. This means that the new frame starts clean, including only the buffer specified in the user option beframe-global-buffers.
  • The code that renames a new frame based is better at inferring the correct name. It now finds the project.el name, if available. The manual explains how to use Beframe with projects: (to me, this is a killer feature).
  • Simplified how frames are set up. This guarantees that our functions are called in the desired order.

0.3.0 on 2023-05-21

Use more descriptive names for assume/unassume commands

Beframe limits the buffer list to buffers that are visited in the current frame. I provide commands to assume (add) or unassume (remove) buffers from other frames, making for a powerful and flexible workflow:

In bulk
Assume/unassume the (i) entire buffer list of a frame, or the (ii) consolidated buffer list of all frames.
Use minibuffer completion to compile a list of buffers to assume/unassume (iii) from the given frame, or (iv) buffers from the consolidated buffer list.

The commands that operate selectively are renamed to better describe what they do. We thus have:

Deprecated name New name
beframe-assume-buffers beframe-assume-frame-buffers-selectively
beframe-assume-buffers-all-frames beframe-assume-buffers-selectively-all-frames
beframe-unassume-buffers beframe-unassume-current-frame-buffers-selectively

To avoid potential confusion, the following command aliases are discontinued:

  • beframe-add-buffers
  • beframe-remove-buffers
  • beframe-add-frame-buffers
  • beframe-remove-frame-buffers

Provide the beframe-prefix-map

This is a keymap that binds the Beframe commands to recommended keys. As with all Emacs key bindings, those are configurable.

I call it a "prefix" keymap because it is not bound anywhere and cannot be used by default. The user must explicitly bind it to a key, which will be treated as a prefix key. For example:

(define-key global-map (kbd "C-c b") beframe-prefix-map)

With the above code, C-c b becomes the prefix key that invokes Beframe commands. Type C-c b C-h to show the available key bindings (by default C-h as a suffix to an incomplete key sequence produces a Help buffer that links to all the available bindings).

The beframe-prefix-map and beframe-mode are used independent of each other.


  • Simplify how beframe-rename-function is added by the beframe-mode.
  • Refine the application of beframe-create-frame-scratch-buffer by the beframe-mode.
  • Tweak the beframe-buffer-sort-visibility function to be consistent with the style of beframe.el.
  • Rewrite parts of the manual to reference the aforementioned.

0.2.0 on 2023-03-27

There were no release notes for the initial version of Beframe. Watch the video demo I produced on 2023-02-28 to get an overview of what this package is all about:

In short: beframe your buffers, not your outlook. Oops that is for the philosophy blog! 🙃

A beframed buffer menu

The command beframe-buffer-menu produces a dedicated buffer with a list of buffers for the current frame. This is the counterpart of beframe-switch-buffer. When called with a prefix argument (C-u with default key bindings), it prompts for a frame whose buffers it will display.

Frame-specific scratch buffer

The user option beframe-create-frame-scratch-buffer allows beframe-mode to create a frame-specific scratch buffer that runs the initial-major-mode. This is done upon the creation of a new frame and the scratch buffer is named after the frame it belongs to. For example, if the frame is called modus-themes, the corresponding scratch buffer is *scratch for modus-themes*. Set this user option to nil to disable the creation of such scratch buffers.

The user option beframe-kill-frame-scratch-buffer is the counterpart of beframe-create-frame-scratch-buffer. It kills the frame-specific scratch buffer after the frame is deleted. Set this user option to nil to disable the killing of such buffers.

Assuming and unassuming buffers

Beframe makes it possible to add or remove buffers from the list of buffers associated with the current frame. This provides for a flexible workflow where buffers can be initially beframed yet consolidated into new lists on demand.

Assuming buffers

To assume buffers is to include them in the buffer list associated with the current frame.

  • The command beframe-assume-frame-buffers (alias beframe-add-frame-buffers) prompts for a frame and then copies its buffer list into the current frame.
  • The command beframe-assume-buffers (alias beframe-add-buffers) adds buffers from a given frame to the current frame. In interactive use, the command first prompts for a frame and then asks about the list of buffers therein. The to-be-assumed buffer list is compiled with completing-read-multiple. This means that the user can select multiple buffers, each separated by the crm-separator (typically a comma).
  • The command beframe-assume-buffers-all-frames prompts with minibuffer completion for a list of buffers to assume. The interface is the same as that of beframe-assume-buffers except that there is no prompt for a frame: buffers belong to the consolidated buffer list (all frames).
  • The command beframe-assume-all-buffers-no-prompts unconditionally assumes the consolidated buffer list.

Unassuming buffers

To unassume buffers is to omit them from the buffer list associated with the current frame.

  • The command beframe-unassume-frame-buffers (alias beframe-remove-frame-buffers) prompts for a frame and then removes its buffer list from the current frame.
  • The command beframe-unassume-buffers (alias beframe-remove-buffers) removes buffers from the current frame. In interactive use, the to-be-unassumed buffer list is compiled with completing-read-multiple. This means that the user can select multiple buffers, each separated by the crm-separator (typically a comma).
  • The command beframe-unassume-all-buffers-no-prompts unconditionally unassumes the consolidated buffer list, but preserves the list stored in the user option beframe-global-buffers.

Sort beframed buffers from Lisp

This is courtesy of Tony Zorman:

commit dfa4678c208e1e5c41413f2d39416f84c21f28ff Author: Tony Zorman <> Date: Sat Mar 4 11:48:17 2023 +0100

Add the ability to sort the buffer list

Some completion libraries, like consult, give the user the option to sort the list of buffers according to some strategy. For example, sorting by visibility—in the sense that one is first shown hidden buffers, then visible ones, and only then the current buffer—may be preferrable when deciding to switch buffers via consult-buffer.

Since beframe.el can be used as a consult source (see the manual), endowing beframe–buffer-list with an arbitrary sort function greatly improves the synergy between the two libraries.

beframe.el | 56 ++---------–— 1 file changed, 42 insertions(+), 14 deletions(-)

The manual explains how this works in practice: Thanks to Tony Zorman for including the reference to the sorting mechanism!