sloshUsing it

Panes and tabs#

A tab is a tree of splits. Panes keep running in every tab; only the one you are looking at is drawn.

Arranging#

`` ╭────────────╮ ╭─────────────────╮ │ ▬ server │ │ ▬ agent [!] │ ╰────────────╯ ╰─────────────────╯ ``

The mouse#

Every mouse verb starts from the same list of rects the drawing filled in, so nothing you click can disagree with what is on screen.

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.

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 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; arrows, C-n/C-p or tab to move, C-u to clear what you typed, enter to go. A dot marks where you already are.

The finder searches what this session has; C-a w lists what is on disk — every project under your roots, open or not (workspaces). A project you have not opened yet has no pane for the finder to match.

Panes that were given a command#

Split off a shell, do something, type exit: it closes, like a terminal should. But a pane that was told to run something — from a layout or the control API — keeps what it printed when that something exits, with two lines saying what ran and how it ended, and two buttons:

 [ran: npm run dev]
 [process exited: status 3]
╰ exited: status 3 ───────────────────────────────[re-run]─[close]─╯

The command is written down because [re-run] is one button. Without it, pressing it is a guess — most of all in a tab that a project's layout built, where the command was never typed into that pane to be scrolled back to. A pane running the session's shell has no command to name and gets the exit line alone.

[re-run] (or C-a r) runs the same command again in the same pane, keeping the previous run above it in the scrollback. So the two notes turn a pane you re-run into a log of what ran rather than a pile of identical epitaphs — and a command that failed while you were looking elsewhere still has its error message when you get back, while a mistyped command in a fresh session no longer closes it.

Which panes stay is one setting, keep_dead: commands (the default), all, or none.

Small terminals#

When the panes no longer fit, the tab becomes a list of one-line headers with the focused pane open below them — and returns to exactly the layout you had when there is room again. Nothing is stored and restored: the arrangement is recomputed from the tree every frame, and the list is what that function returns when the room runs out.

min_pane is where that starts happening; min_split is the smaller pane a split is willing to create. A split is refused when either floor would be broken — including the axis it does not divide, since splitting cannot improve that one: a pane already too short for two rows has no room for two columns either, whatever its width says.

Text, images, bells#