aboutsummaryrefslogtreecommitdiffstats
path: root/src/config.h (follow)
Commit message (Collapse)AuthorAge
...
* sl0ptty: select-to-copy, middle-click paste, and toastssl0p2026-08-14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Drag over text, release, and it is on your clipboard — no chord, no menu, the selection is the copy. The clipboard lives on the client's machine, so the copy travels as OSC 52 and therefore works over ssh; the session keeps its own copy as the primary selection, which is what middle click pastes back. Selected cells are inverted rather than recoloured, so a selection reads the same over whatever theme the program inside is using. A program that is tracking the mouse keeps its own clicks (shift is the escape hatch), which is tested rather than assumed. Toasts: transient announcements in the bottom-right that expire on their own, stacked up to three. 'copied 13 chars', 'config reloaded', a pane's OSC 9 notification, or {"cmd":"notify","text":"..."} from an orchestrator — an agent in a pane can now say 'build finished' and have it appear. OSC 52 from a pane reaches the same clipboard. Two real bugs found on the way: - mouse events are hit-tested against what was painted, and nothing had been painted before the first frame, so a click that arrived first was dropped. Both front ends now compose once before accepting input, which is what really happens in a session anyway. - the plain leaf_new never installed the clipboard and notification handlers; only panes built from a layout file had them. Every ordinary pane was silently missing both. The test escaping traps continue to earn their comments: a real newline inside a driver argument terminates the *command* rather than reaching the shell, \a is not a driver escape (\x07 is), and an interactive shell's line editor eats a typed ESC — so a pane driven with escape sequences must not be one. 356 checks green (329 headless + 27 live).
* sl0ptty: scrollback — wheel, keyboard, and a clickable indicatorsl0p2026-08-13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | libghostty-vt already keeps the scrollback, so the work was deciding whose wheel it is: - a program tracking the mouse gets the wheel events themselves; - a full-screen program without mouse tracking (vim, less) has no scrollback of ours to show, so the wheel becomes arrow keys, which is what it means to that program; - anything else scrolls our viewport. All three are tested against real programs rather than asserted in principle. C-a PageUp/PageDown/Home/End, and scroll_lines in the config for the wheel. Typing snaps back to the live view, because reading scrollback and then typing into a screen you are not looking at is a trap. New output does not yank the viewport back — it just grows the gap, which the indicator shows. The indicator is compact, right-aligned, budgeted after the split button and before the title (a title is the thing you can most afford to lose), and clicking it returns to the bottom. Three test failures on the way, all mine and all instructive: the top of the scrollback is the shell's first prompt rather than the first line of output; typing without a newline types rather than runs; and two side-by-side panes share a screen row, so asserting on line(y) reads both frames at once. 341 checks green.
* sl0ptty: focus follows the mouse, with the guards that make it liveablesl0p2026-08-13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Hovering a pane focuses it. The feature is three lines; the reason it is not obnoxious is the guards, and each one is a test: - not while the prefix is held, so a chord cannot be hijacked by a nudge of the mouse; - not through the finder, whose rows are on top of the hit list anyway; - not during a drag, which owns the mouse until the button comes up; - not onto a collapsed pane. Only 'pane:' and 'title:' targets count, never the frame rect's 'focus:', so the pointer crossing a stack of headers does not expand three panes on its way past. Off with 'focus_follows_mouse false'; clicking still focuses either way. This needed the client to ask for ?1003 (any motion) rather than ?1002 (motion while a button is held), which fixes something that was quietly broken: a pane requesting any-event tracking could never receive hover, because the outer terminal was never asked to report it. It can now, and a pane that asked only for clicks still gets none — both tested. One real bug behind that: our decoder represents 'no button held' as MBTN_UNKNOWN, and pane_send_mouse was passing it to the encoder as a concrete button. lib-vt has ghostty_mouse_event_clear_button() for exactly this, and without it bare motion encoded to nothing at all. 320 checks green.
* sl0ptty: M8 — pane sizes as weights, resize and drag-to-reordersl0p2026-08-13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Sizes are weights now, so an even split is equal weights and resizing is not a special case of anything: the layout pass is still the same pure function of the tree and the rect, and a resized layout survives a collapse/expand cycle without anyone writing code for that. Keyboard: C-a shift-H/J/K/L (and shift+arrows) move the boundary in the direction pressed, whichever side of it the focused pane is on, which is what a person means by wider. A pane can be squeezed but never squeezed out. Mouse: one drag machine, two verbs, both starting from the hit list so neither can disagree with what is on screen. - a frame's top row is a drag handle: drop a pane on another to swap them, with the drop target highlighted while you drag; - the gap between two panes is the boundary: drag it to resize. The gap was dead space until now, and its hit rect is derived from the rects the children were just given rather than recomputed from the config — the same rule that keeps the split button honest. Any keystroke ends a drag. A release can go missing (the pointer leaves the terminal, a client detaches mid-drag) and a mouse wedged in a state the user cannot see is the worst outcome available. One test needed updating rather than the code: the frame's top row is now the drag handle, so the cell beside the split button reports title: rather than focus:. That is the intent, and the hit list said so immediately. 304 checks green (277 headless + 27 live).
* sl0ptty: M6 — the config file, and a READMEsl0p2026-08-13
D2, delivered: a hand-rolled KDL subset (kdl.c, 300 lines, no dependency) with arguments, key=value properties, children, // and /* */ comments, and ; terminators for single-line nodes. config/config.kdl documents every setting by being the defaults. Geometry, theme, the prefix and every binding now come from that file instead of being compiled in. Bindings are a table of (key, mods) -> action, so an action can be rebound, unbound with "none", or given a different prefix entirely; caps and num lock are masked out so they cannot stop a binding working. The property that matters is fail-open, applied to the mux itself rather than only to the CLI wrapper: a missing config is silent, a broken one writes the line number to stderr and keeps the compiled-in defaults, and a bad binding does not discard the rest of the file. A live session can reload, and a reload that fails to parse keeps the configuration that works instead of leaving you with half a theme. min_pane is configuration too, so the point at which a layout collapses is a preference rather than my taste — tested by making the same split collapse or not on the same terminal size. 14 parser cases as a C test, 24 config checks through the harness, and a README that shows what the thing actually looks like. 250 checks green.