magneto: Composable Window Management for Emacs
Table of Contents
- 1. About emacs windowManagement composition
- 2. The Window Management Problem emacs problem
- 3. Composable Operations emacs architecture
- 4. Source Actions emacs source
- 5. Destination Actions emacs destination
- 6. Cursor Placement emacs cursor
- 7. Buffer Actions emacs buffers
- 8. Demo: Basic Composition emacs demonstration
- 9. Demo: Side Windows emacs demonstration
- 10. Demo: Pre-selecting with Ace-Window emacs demonstration
- 11. Embark Integration composition
- 12. Demo: Embark Workflows emacs demonstration
- 13. Workflow Examples emacs workflows
- 14. Customization Reference emacs configuration
- 15. Getting Started emacs installation
1. About emacs windowManagement composition
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 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.