magneto: Composable Window Management for Emacs

magneto: Composable Window Management for Emacs

1. About   emacs windowManagement composition

magneto-banner.jpeg

Figure 1: JPEG produced with DALL-E 4o

Window management in Emacs is either too simple or too opinionated. split-window-right and split-window-below are basic primitives that require manual sequencing. purpose and shackle give you declarative rules but take away direct control. What I wanted was something in between: a small grammar of composable operations where I set the parameters I care about and let the system handle the plumbing. magneto is that grammar. Press a key to enter compose mode, set any combination of source action, destination, cursor placement, and buffer action, then press RET to execute.

2. The Window Management Problem   emacs problem

Here's a common sequence: you're looking at a file and you want to open a related file in a vertical split to the right, keeping your cursor on the original. In vanilla Emacs:

(split-window-right)       ; split
(other-window 1)           ; move to new window
(find-file "related.el")   ; open file
(other-window -1)          ; move back

Every combination of source, destination, cursor, and buffer action is a separate function you'd need to write or find.

Four commands, and you need to remember the sequence. Want to copy the current buffer instead of opening a new file? Different sequence. Want to split below instead of right? Different sequence. Want the cursor to stay in the new window? Omit the last step. Every combination of source, destination, cursor, and buffer action is a separate function you'd need to write or find.

magneto collapses this combinatorial explosion into a single composable flow. Instead of four sequential commands, you press your magneto key, then press modifiers to set whatever differs from the defaults, then execute. The number of keystrokes scales with how much you're customizing, not with the inherent complexity of the operation.

3. Composable Operations   emacs architecture

magneto operations have four independent dimensions:

Dimension Question Default
Source Action What happens to the origin window? move
Destination Where does the buffer go? fill existing
Cursor Placement Where does your cursor end up? follow (o)
Buffer Action What buffer appears in the destination? switch-buffer

Each dimension has its own keys. You press any combination of them in any order before executing with RET. Any dimension you don't set uses its default. This means the simplest magneto operation (just RET with all defaults) is equivalent to switch-to-buffer in the current window. But adding one or two keys before RET gives you dramatically different behavior.

4. Source Actions   emacs source

The source action controls what happens to the origin window after the buffer lands in its destination.

Key Action Behavior
m Move Delete the origin window (buffer leaves the original spot)
c Copy Keep the origin window (buffer is now visible in two places)
p Pull Show the previous buffer in the origin window

Move is the default and matches the most common intent: relocate a buffer. Copy is useful when you want a reference view alongside an editing view of the same context. Pull is a refinement of move, the buffer leaves, but instead of the window disappearing, it shows whatever was there before.

5. Destination Actions   emacs destination

The destination controls where the buffer ends up.

5.1. Splits

Key Direction
V Split above
v Split below
H Split left
h Split right

Uppercase keys create the split on the "before" side (above, left); lowercase on the "after" side (below, right).

5.2. Side Windows

Key Position
t Top side
b Bottom side
l Left side
r Right side

Side windows use Emacs's display-buffer-in-side-window, which means they resist delete-other-windows and stay pinned to their edge. Uppercase variants (T, B, L, R) control slot ordering when you have multiple side windows on the same edge.

5.3. Fill Existing Window

Key Action
0 Select an existing window via ace-window

Fill doesn't create a new split. It routes the buffer into a window you pick interactively. This is the default destination, so pressing RET immediately prompts you to pick a window (or uses the current one if there's only one).

6. Cursor Placement   emacs cursor

Key Behavior
o Follow: cursor moves to the destination window
O Stay: cursor remains in the origin window

This is the difference between "open this file over there and keep working here" and "open this file over there and go to it." A small distinction that eliminates a other-window call in half your workflows.

7. Buffer Actions   emacs buffers

The buffer action controls what appears in the destination window.

Key Action Description
w Buffer (consult) Switch via magneto-buffer-command (customizable, defaults to switch-to-buffer)
f Find file Call find-file interactively
x Execute command Run an extended command
C-b Switch buffer Built-in switch-to-buffer directly

Set magneto-buffer-command to #'consult-buffer if you use consult:

(setq magneto-buffer-command #'consult-buffer)

8. Demo: Basic Composition   emacs demonstration

Composing a few simple operations: split right with a file, copy to a split below, move to an existing window.

9. Demo: Side Windows   emacs demonstration

Pinning buffers to edges using side window destinations.

10. Demo: Pre-selecting with Ace-Window   emacs demonstration

Pre-selecting a destination window before composing the rest of the operation.

magneto uses ace-window's visual overlay to let you pick a window. The keys a, s, d in the compose keymap pre-select the first, second, or third window by ace-window ordering. This lets you set the destination before you've even decided what to put in it.

11. Embark Integration   embark composition

magneto includes an optional embark integration module (magneto-embark.el) that routes embark actions through magneto's compose system. The idea: when you act on an embark candidate, you often want to control where the result ends up. Without magneto, embark opens files in the current window. With magneto, you can send them to a split, a side window, or a pre-selected ace-window target.

magneto-embark-bind-keys scans all registered embark keymaps and generates magneto-routed versions of relevant actions (find-file, consult-bookmark, goto-grep, etc.). These are bound under s-o in each embark keymap. So where you'd normally press f in embark to open a file, pressing s-o f opens it through magneto's compose flow instead.

12. Demo: Embark Workflows   emacs demonstration

Routing embark actions through magneto to control destination windows.

13. Workflow Examples   emacs workflows

13.1. Expand a Layout

You're reading a file. You want to open a test file to the right and keep your cursor where you are.

Keys: magneto-compose h O f RET (then pick the file)

Breakdown: h (split right), O (stay at origin), f (find-file), RET (execute).

13.2. Side-by-Side Comparison

You want the same buffer in two windows, scrolled to different positions.

Keys: magneto-compose c h RET

Breakdown: c (copy, keep original), h (split right), RET (execute). The buffer is now in both windows. For independent scroll positions, use M-x magneto-make-indirect first to create an indirect buffer clone.

13.3. REPL Setup

You want a shell in a bottom side window that persists across delete-other-windows.

Keys: magneto-compose b x RET (then type shell)

Breakdown: b (bottom side window), x (execute-command), RET (execute). The shell opens in a persistent bottom panel.

14. Customization Reference   emacs configuration

All defaults are customizable:

Variable Default Description
magneto-default-source-action "move" Default source behavior
magneto-default-destination-action "f" Default destination (fill)
magneto-default-select-action "o" Default cursor placement (follow)
magneto-default-action-action "switch-buffer" Default buffer action
magneto-buffer-command #'switch-to-buffer Command for buffer switching
magneto-default-destination-window nil Pre-selected ace-window target

15. Getting Started   emacs installation

magneto is on GitHub. It requires Emacs 29.1+ and depends on avy and ace-window.

(use-package magneto
  :ensure (:host github :repo "chiply/magneto")
  :bind ("s-m" . magneto-compose)
  :custom
  (magneto-buffer-command #'consult-buffer))

For embark integration:

(use-package magneto-embark
  :after (magneto embark)
  :config
  (magneto-embark-bind-keys))

Bind magneto-compose to a comfortable key, press it, and start composing. The which-key popup (if you use which-key) shows all available modifiers. Press RET when you're ready. Start with the defaults and add modifiers as you learn the grammar.