aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-20 23:22:33 +0200
committeruser <user@clank>2026-08-20 23:22:33 +0200
commitb33e8c13ff7981effc7ec2735e6aeaaaf1705af7 (patch)
tree4933eb476b5d09e9d8131986c84bb966bca317a2 /docs
parentfuzz: libFuzzer harness for all six parser surfaces (diff)
downloadslosh-b33e8c13ff7981effc7ec2735e6aeaaaf1705af7.tar.gz
slosh-b33e8c13ff7981effc7ec2735e6aeaaaf1705af7.tar.xz
slosh-b33e8c13ff7981effc7ec2735e6aeaaaf1705af7.zip
slosh: floating panes and the drop grammar
A pane can float: lifted out of the layout, drawn over the tiled panes and under the modals, freely moved and shaped. The model is a flag and a rect on the leaf, exactly like `minimized` -- the seat in the tree is kept, layout skips it, the siblings absorb its share, and un-floating returns it home. The drawn rect is the wanted one clamped to the tab every frame, never written back, so a terminal squeeze round-trips exactly; an explicit move or resize *does* write back, because the hand is the author of the intent. Floating pops the pane to the centre: the jump is what says it happened. Painted after everything tiled, so the hit list -- searched backwards -- resolves an overlap to the float you can see: the z-order and the click order are the same list. It casts a shadow (float_shadow, one number), and `floating` joins the states table above `unfocused`, so a float is never dimmed as merely-unfocused. The hands: the title moves it, any other border resizes it (a bottom corner on both axes; the grabbed edge pins at walls and floors, never sliding the window), H J K L move a focused float, the =/+ key grows it about its centre, `-` shrinks it (its split was a refusal anyway), and hovering shows which edges a grab would take, from the same derivation the press uses. Equalize moved to `0` to free the key; `C-a f` floats (finder went to `s`, where it reads as search); `C-a F` opens a new floating shell -- the throwaway terminal; the function row f1..f12 became nameable in configs along the way. Guards throughout: the last tiled pane cannot float or minimize away, closing it lands the top float, splits are refused with their own words, floats are not swap targets. Dropping got a grammar: while a pane is carried, the pane under the pointer subdivides into a swap centre and four edge bands meaning "insert me beside this pane, on this side" -- detach_leaf + place_beside, the surgery cross-tab moves already had. Bands are thirds (the first map of quarters showed the swap owning half of each axis), the hovered band fills the half the drop would hand over, the release resolves against the painted frame's hits so it cannot disagree with the fill, and a drop between siblings along the axis is a reorder that always fits -- refusing it was refusing the most ordinary drag there is. Also: rename-pane/rename-tab as palette actions (renaming was a double-click and nothing else, the one verb the palette could not reach), and C-u clears the rename editor like it clears the picker's query. Design log in PLAN-FLOATING-PANES.md; to fold into DESIGN.md as D22/M10-11.
Diffstat (limited to 'docs')
-rw-r--r--docs/config.md4
-rw-r--r--docs/keys.md30
-rw-r--r--docs/panes.md80
3 files changed, 95 insertions, 19 deletions
diff --git a/docs/config.md b/docs/config.md
index 686ef0e..bbff38d 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -111,7 +111,7 @@ theme { frame_focus "#00ff88" } // ...but that one colour is mine
|---|---|
| geometry | `gap` `gap_aspect` `padding` `rounded` `title_align` `title_inset` `min_pane` `min_split` |
| chrome | `status_bar` `status_line` `status_pad` `hints` `version_banner` `pane_buttons` `bell_indicator` and the marks (`zoom_mark` `zoom_on_mark` `close_mark` `min_mark` `newtab_mark` `bell_mark`) |
-| behaviour | `focus_follows_mouse` `scroll_lines` `scrollback` `scrollback_bytes` `toast_ms` `hover_delay_ms` `double_click_ms` `word_separators` `anim_ms` `modal_scrim` `dim_unfocused` `keep_dead` `in_band_shaders` `shell` `editor` `shader_dir` |
+| behaviour | `focus_follows_mouse` `scroll_lines` `scrollback` `scrollback_bytes` `toast_ms` `hover_delay_ms` `double_click_ms` `word_separators` `anim_ms` `modal_scrim` `dim_unfocused` `float_shadow` `keep_dead` `in_band_shaders` `shell` `editor` `shader_dir` |
| colour | `theme { }` |
| effects | `shaders { }`, `states { }` — see [shaders](shaders.md) and [chrome](chrome.md) |
| keys | `keys { }` — see [keys](keys.md) |
@@ -178,6 +178,7 @@ by looking:
```kdl
dim_unfocused 60 // the one knob most people want
+float_shadow 110 // the shade a floating pane casts; 0 for none
states { // ...and the whole table underneath it
dead { grayscale amount=200; dim amount=90 }
@@ -187,6 +188,7 @@ states { // ...and the whole table underneath it
// while there is more content past it (`above` / `below` in expressions),
// and turn solid at the end of the buffer -- nothing more to scroll to
unfocused { dim amount=60 } // writing this replaces dim_unfocused
+ // floating { } // a float; above unfocused, so floats are never dimmed
// bell: a shimmer across the body (a soft sheen, gone within a second)
// and a chrome pass on the frame -- blinks, then a breathe -- in theme's
// bell colour, until the pane is looked at. See the chrome shaders page;
diff --git a/docs/keys.md b/docs/keys.md
index fb58532..88a3318 100644
--- a/docs/keys.md
+++ b/docs/keys.md
@@ -18,11 +18,14 @@ it did not — `+7 more, in docs/keys.md`, which is the table below.
| `\` `-` | split into columns / rows, when you mean one |
| `h` `j` `k` `l`, or arrows | move focus |
| `o` | the next pane |
-| `H` `J` `K` `L`, or shift+arrows | move the boundary between panes |
-| `=` | give every visible pane an even share |
+| `H` `J` `K` `L`, or shift+arrows | move the boundary between panes — or the pane itself, when it is [floating](panes.md#floating-a-pane) |
+| `0` | give every visible pane an even share |
| `Space` | turn the layout a quarter turn (four brings it back) |
| `z` | zoom this pane to fill the tab, and back |
| `m` | minimise it into the strip along the bottom |
+| `f` | [float](panes.md#floating-a-pane) it above the layout, and back |
+| `F` | a new floating shell — the throwaway terminal |
+| `=` (`+`) `-` | grow / shrink a focused float about its centre (`-` splits, when the pane is tiled) |
| `x` | close this pane |
| `X` | close this tab, and everything in it |
| `r` | run a finished pane's command again |
@@ -32,7 +35,7 @@ it did not — `+7 more, in docs/keys.md`, which is the table below.
| `c` | new tab |
| `Tab` `shift+Tab` | next / previous tab |
| `1`…`9` | go to that tab |
-| `f` | find a pane by name |
+| `s` | search: find a pane by name |
| `w` | the projects picker — every project under your roots, open or not ([workspaces](workspaces.md)) |
| `W` | write this tab out as this project's layout ([workspaces](workspaces.md)) |
| `p` | the command palette |
@@ -43,11 +46,12 @@ it did not — `+7 more, in docs/keys.md`, which is the table below.
| `q` | quit the session |
| `C-a` | send a literal `C-a` |
-**`x`/`X`, `p`/`P` and `w`/`W` are deliberately shifted pairs on one letter.**
-Close this pane / close this tab; run a command / tag this pane; go to a project /
-write this project down. The shifted half is the same verb on a bigger thing, or
-the thing you reach for within a moment of the other, so the shift is less to
-remember than a second letter would have been.
+**`x`/`X`, `p`/`P`, `w`/`W` and `f`/`F` are deliberately shifted pairs on one
+letter.** Close this pane / close this tab; run a command / tag this pane; go
+to a project / write this project down; float this pane / float a fresh one.
+The shifted half is the same verb on a bigger thing, or the thing you reach
+for within a moment of the other, so the shift is less to remember than a
+second letter would have been.
`X` says how many panes went with the tab, since most of them were not the one you
were looking at. On the **last** tab it refuses and points at `q` instead: a key
@@ -79,8 +83,8 @@ keys {
Modifiers are `ctrl+ alt+ shift+ super+`, or the shorthand the cheatsheet
prints: `C-` `M-` `S-`. Named keys are `left right up down enter tab escape
space backspace home end pageup pagedown delete insert backslash minus slash
-comma period`, and the arrows can be written as `←` `→` `↑` `↓` too — so a chord
-copied off the cheatsheet is a chord you can paste into a config.
+comma period f1`…`f12`, and the arrows can be written as `←` `→` `↑` `↓` too —
+so a chord copied off the cheatsheet is a chord you can paste into a config.
Anything else is the character you press. That includes the shifted ones, which
carry their own shift: `"?"` is `"shift+slash"`, `"H"` is `"shift+h"`, `"|"` is
@@ -116,10 +120,10 @@ being bound at all.
| group | actions |
|---|---|
-| panes | `split` `split-cols` `split-rows` `close-pane` `rerun` `zoom` `minimize` `rotate-layout` `clear-shaders` `pane-to-next-tab` `pane-to-prev-tab` `pane-to-new-tab` `set-purpose` |
+| panes | `split` `split-cols` `split-rows` `close-pane` `rerun` `zoom` `minimize` `float` `new-float` `rotate-layout` `clear-shaders` `pane-to-next-tab` `pane-to-prev-tab` `pane-to-new-tab` `set-purpose` `rename-pane` |
| focus | `focus-left` `focus-right` `focus-up` `focus-down` `focus-next` `finder` |
-| size | `resize-left` `resize-right` `resize-up` `resize-down` `equalize` |
-| tabs | `new-tab` `close-tab` `next-tab` `prev-tab` `select-tab-1` … `select-tab-9` |
+| size | `resize-left` `resize-right` `resize-up` `resize-down` `equalize` `float-grow` `float-shrink` |
+| tabs | `new-tab` `rename-tab` `close-tab` `next-tab` `prev-tab` `select-tab-1` … `select-tab-9` |
| projects | `workspaces` `save-workspace` |
| scroll | `scroll-up` `scroll-down` `scroll-page-up` `scroll-page-down` `scroll-top` `scroll-bottom` |
| session | `palette` `help` `edit-config` `detach` `quit` `literal-prefix` |
diff --git a/docs/panes.md b/docs/panes.md
index e400479..d0a6eb3 100644
--- a/docs/panes.md
+++ b/docs/panes.md
@@ -20,7 +20,7 @@ looking at is drawn.
- **Resize** with `C-a H J K L`: the boundary moves the way you press, whichever
side of it you are on. Sizes are *weights*, so a resized layout survives the
window changing size.
-- **`C-a =`** gives every visible pane an even share again — each split divided
+- **`C-a 0`** gives every visible pane an even share again — each split divided
between the panes behind it, so one pane beside a stack of three is a quarter
of the width rather than half of it.
- **`C-a Space`** turns the whole tab a quarter turn clockwise. Every split
@@ -52,8 +52,16 @@ nothing you click can disagree with what is on screen.
dead pane's epitaph legible — the heavy rule goes round them.
- **Drag the gap between panes** to move that boundary. Where two gaps cross,
drag the crossing to move both at once.
-- **Drag a pane by its title** onto another to swap them. Everything it could
- land on greys out; the pane in your hand keeps its colour.
+- **Drag a pane by its title** onto another to swap them — or to *place* it:
+ the pane under the pointer subdivides into a centre and four edge bands,
+ and where you let go is what the drop means. The centre trades places, as
+ it always has; a band means "insert me beside this pane, on this side",
+ and fills the half of the pane the drop would hand over, so what you see
+ is where it lands. A side there is no room for offers no band — the same
+ floor a border click's split honours — except between neighbours along the
+ same row or column, where a drop is a reorder and always fits. Everything it could land on greys
+ out; the pane in your hand keeps its colour. Between the bands and the
+ strip, the whole layout can be rebuilt without touching the keyboard.
- **...or onto a tab in the strip** to move it into that tab, or onto the `+` for a
tab of its own. The tabs light up as destinations while you carry a pane and the
one under the pointer fills; the tab it already lives in does not offer itself. A
@@ -65,7 +73,10 @@ nothing you click can disagree with what is on screen.
`slosh cmd '{"cmd":"set-name","target":"pane","id":3,"name":"agent: gbos"}'`.
An empty name hands the label back.
- **Double-click a name to rename it in place** — a pane's title or a tab in the
- strip. Enter keeps it, Escape abandons it, empty gives it back to the program.
+ strip. Enter keeps it, Escape abandons it, `C-u` clears the field (a rename
+ seeds with the current label, since it is usually an edit), empty gives it
+ back to the program. The same two verbs are in the palette as `rename-pane`
+ and `rename-tab`, for hands that are on the keyboard.
A name is not a [purpose](layouts.md#purposes): the purpose is a separate label
with a key of its own, `C-a P`, so a rename and a tag cannot be confused with
each other. The purpose editor draws in the same title cell but labels itself
@@ -81,9 +92,68 @@ nothing you click can disagree with what is on screen.
looking.
- Hovering anything says what it does, in a word, in the status line.
+## Floating a pane
+
+`C-a f` lifts a pane out of the layout and draws it on top of the tiled ones
+— below the modals — where it can be moved and shaped freely. It **pops to
+the centre of the tab**, because the jump is what says the float happened; a
+pane lifted in place would look like a pane whose neighbours flinched.
+Pressing `f` again puts it back in the seat it kept, with the layout exactly
+as it was. (`f` is what "float" sounds like; finding a pane is `C-a s`,
+search.) `C-a F` opens a **new floating shell** over whatever you are doing
+— the throwaway terminal — in the focused pane's directory; `exit` closes it
+like any shell, and un-floating lands it beside the pane it was opened over.
+
+- **Drag its title to move it, any other border to resize it** — a bottom
+ corner resizes on both axes. Hovering says so: the edge a grab would move
+ goes heavy in the resize colour with a double arrow at the grab point (a
+ corner lights both edges), and the held edges stay lit through the drag.
+ A float's border never splits: a split is a statement about the
+ arrangement, and a float is precisely not arranged.
+- **`C-a H J K L` move a focused float** instead of moving a boundary, since
+ a float has no boundary to move. **`=` (or `+`) grows it and `-` shrinks
+ it** about its own centre, so it stays under your eyes; on a tiled pane
+ `-` still splits. Equalize lives on `0` for this reason: `+` arrives as a
+ bare `=` on terminals that do not report shift for punctuation, and two
+ verbs on one key survive only until that happens.
+- **It casts a shadow** on what it covers, which is how you tell a float from
+ a tile at a glance. `float_shadow 0` in the config turns it off, and a
+ `states { floating { … } }` chain colours floats on top of that.
+- **Where you put it is where it stays.** Squeezed by a small window it is
+ clamped in; grow the window back and it is exactly where you left it. On a
+ window too small to lay out at all it becomes a row in the flat list like
+ every other pane.
+- Focusing a float raises it above other floats; minimising works as ever and
+ it comes back floating; zooming fills the tab and returns it on the way
+ out. The last tiled pane cannot float — an overlay needs something to be
+ over — and closing the last tiled pane lands the float in its place.
+- Its rect is not yet written by `dump-layout` (coming with the layout-file
+ support); `{"cmd":"float","id":N}` toggles one and `{"cmd":"new-float"}`
+ opens one from a [script](scripting.md).
+
+## Links
+
+**OSC 8 hyperlinks pass through.** A program that emits real hyperlinks —
+`ls --hyperlink`, gcc's diagnostics, delta — keeps them: the compositor
+carries the link beside each cell and re-emits it to your terminal, which
+offers it with its own gesture. Anything painted over a link (a frame, a
+modal, a floating pane) takes the link with it, so chrome is never clickable
+with a pane's URL. Links survive scrollback with the text that carries them.
+
+**Plain-text URLs are your terminal's own matcher**, running over what slosh
+paints — with one catch worth knowing. While any program owns the mouse (a
+multiplexer does), Ghostty only offers links when **shift** is added to the
+usual gesture: shift is its mouse-capture escape, and it is stripped before
+the link's own modifier is checked. So the gesture inside slosh — or tmux,
+or zellij — is **shift+cmd+hover** to highlight and **shift+cmd+click** to
+open (shift+ctrl on Linux). A URL that *wraps* onto a second row cannot be
+matched this way through any multiplexer — the screen is repainted row by
+row, so the terminal sees two hard lines — which is exactly what OSC 8
+links, which pass through whole, are for.
+
## Finding a pane
-Tabs stop being navigation somewhere around six projects. `C-a f` opens a picker
+Tabs stop being navigation somewhere around six projects. `C-a s` opens a picker
over the whole session — every tab, including panes a small window has collapsed
out of sight. Type to narrow it by pane title, tab name or
[purpose](layouts.md#purposes); arrows, `C-n`/`C-p` or tab to move, `C-u` to clear