summaryrefslogtreecommitdiff
path: root/src/layout.zig
Commit message (Collapse)AuthorAge
* Delcol on the last column leaves the window, empty but for its workspace ↵Gabriel Schneider30 hours
| | | | | | | | tag, as acme's does The last column's Delcol ended the session. The window now stays, with only the workspace tag; Newcol, and New (which makes the column it goes in), start it again. A word run with no pane at all runs with a stand-in that is no pane, the root ctl takes session words, and pane/new makes its scratch in the session's directory. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A column takes panes until their minimums fill it, not until none can be halvedGabriel Schneider30 hours
| | | | | | | | | | Placement halved the tallest pane or refused, so 11 panes filled 48 rows that hold 16 at their tag and two rows each: the refusal did not match the documented arithmetic. When no pane can be halved but the minimums with the new pane's fit, the column's rows are shared out again; and a refused pane's removal leaves no pane under its minimum. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* `size` is refused only when the panes' own minima do not fit, so it is monotonicGabriel Schneider30 hours
| | | | | | | | | | | | The check read how the weights shared the rows after the resize, not whether the rows could hold every pane's tag and two rows: a pane the proportional squeeze took short made `size` refuse, growing included, and refuse sizes it took a moment before. It now asks layout.minRows, the minimum placement asks, per column; a size they fit is taken, and a pane the resize took under its minimum gets its rows back. An out of range size says `invalid size`, which 9ns reads as EINVAL, as the doc had. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A terminal keeps its tag and two body rows through drags, squeezes and a ↵Gabriel Schneider30 hours
| | | | | | | | | | | | | | | smaller window A terminal of one body row loses its prompt's mark and reads busy for ever. Placement already refused to make one that short; now layout never leaves one there either: a grip drag stops at the floor, and a column squeezed by weights or by the window takes the rows from its other panes. Text panes keep acme's way and can still be dragged to their tag, since acme has no terminals to follow. The shrinktag, splitparent and cornerdrag goldens are re-recorded for it, shrinktag's re-grab moved to where the grip now is. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A new pane with no room under the last goes last all the sameGabriel Schneider30 hours
| | | | | | | | | | | | | A pane from pane/new or New takes the bottom half of its column's last pane, as acme's coladd does (cols.c:62-65); when that pane is too short to give it a tag and 2 rows, the fallback halved the tallest pane and put the new one under it, mid-column (the 7 9 8 found). It now goes last all the same, with half the tallest pane's rows (its tag measured at the column's width). Tty from a pane's ctl already follows acme's makenewwindow (the active column first, util.c:456-467); fs.md now says so rather than beside that pane. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* size says its limits, keeps every pane its rows, and ptys follow their panesGabriel Schneider30 hours
| | | | | | | | | | | | size refused an out-of-range line without saying the range, took a size too small for the panes (leaving bodies of no rows), and a terminal squeezed to its tag kept a pty of its old size. The refusal now names 20x6 to 4096x4096 (a bare size is EINVAL like any malformed line), a size that would leave any pane less than its tag and 2 rows is refused and undone, and a terminal's pty is resized with its pane down to one row (only a folded or unplaced one keeps its grid). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* No placement leaves a pane shorter than its tag and two rowsGabriel Schneider30 hours
| | | | | | | | | | | | | | | | Placement could split a pane down to a tag and one row, or give a new one less. Every placement now checks the pane it made and each pane it shrank against its tag (wrapped at its width) plus two rows: where they lack the room, the column's tallest pane is halved instead, and where none can give it the new pane is refused with "no space for a pane in that column" (ENOSPC over 9P) and closed at the step's end, once its maker is done with it. splitBelow and splitParent leave two body rows (a boot layout, split before any row exists, is as before). Re-recorded by name: lookpanes (panes one or two rows lower) and splitparent (the 6-row squeeze now refuses); fs.py closes the scratches and long-named panes it no longer needs, since its 24-row session filled. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Columns are named by stable serials over 9P, as panes areGabriel Schneider30 hours
| | | | | | | | | | | /col/<n> named a column by its index, which shifts when a column left of it closes: exactly what scripts trip on. A column is now /col/<serial>, its serial kept while it lives and never reused; /layout lines give serial and index (`<serial> <index> ...`), active names the serial, /index's last field is the column's serial, and the log says newcol and delcol with serials. Docs, the skill and the tree's README say so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A pane's last row of text is no resize handle; the grip is, and the GUI's ruleGabriel Schneider30 hours
| | | | | | | | | | | | | | | A press on a pane's last row began a seam drag, so the row could not be clicked or swept like the rest of the text (rsearch dragged the handle out of the way first). Now no row of text is a handle: in the GUI a press on the 2 px rule between two panes drags their seam, and anywhere the grip does, as acme's button moves a window -- dragged up or down its own column it moves the pane's top, either pane down to its tag alone (acme's coldragwin), dragged down inside itself too. The hover hint over a last row is gone; column edges resize as they did. Scripts that dragged a seam drag a grip instead and match their goldens; six goldens lost the hint or moved a cursor to the clicked text, re-recorded by name. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The tree serves the layout: /layout, /tag and /col/<n>/tagGabriel Schneider30 hours
| | | | | | | | | | | | | A script could not see where the panes sit or edit the tags a person clicks in. /layout lists each column, its index, x and width in cells, current or not, empty or full, and its panes' serials, then the active column; /tag is the workspace tag and /col/<n>/tag a column's, read and written as a pane tag is (one line: a newline written in is a space, and a truncating write drops the one ending it); /index's lines end with the pane's column; the log says newcol <n> and delcol <n>. acme serves no column files, and the docs say so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A column can be empty, as acme's can; new panes go where acme's ↵Gabriel Schneider30 hours
| | | | | | | | | | | | | | makenewwindow puts them Newcol makes an empty column; closing a column's last pane leaves it empty with the keyboard on its tag; Delcol and Joincol alone take a column away; the session's last pane closing quits. The +New stand-in and replaceStillborn / stillborn_joiner are gone. Every new pane goes through exec.placeNew, which follows acme's makenewwindow (active column, empty column whole, blank space, halving the biggest) or, with Placement pardes, the old rules. ColumnTags is gone: column tags are always shown. A grip drag shows acme's box cursor. Co-Authored-By: Claude Opus 5.5 <[email protected]>
*-. Trial merge: 9P + helix + renderGabriel Schneider30 hours
|\ \
| | * Move the frame into draw.zig and the transitions out of layout.zigGabriel Schneider30 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Pure moves, no behaviour change. draw.zig holds the whole core frame in order: render, the pane, tag, header and notice painters it calls, and the character-effect composition (Pardes.render stays a declaration alias). Presentation.zig is the panel presentation state as a file struct, and animation.zig the easing curves, transition kinds, tracks and boxes, the character effects' sources and the generic displayed-value transition, all of which lived in layout.zig. layout.zig keeps only layout.
| * | A selection's other ranges live out of line, made at the second range and ↵Gabriel Schneider30 hours
| |/ | | | | | | | | | | | | | | | | | | | | | | | | | | freed at one The ranges beside the primary were an inline array in every Text, which at 1024 grew each pane by about 60 KiB. They are now allocated when a second range appears (Text.reserveSels) and given back when the selection is one range again (Text.dropSels); a column's or the workspace's tag allocates from Text.gpa, any other text from its pane's. A refused tag edit restores them by copy. The Pane size budget is back to 128 KiB, and a test holds that a single cursor allocates nothing for them. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* / Focus on a closed pane goes to the pane that takes its place, never to the ↵Gabriel Schneider30 hours
|/ | | | | | | | one focused before Dogfood closed a pane in one column and focus jumped to another column, only because that pane was focused last. Now removePane decides for every route (Del, a ctl del, a command pane's end, a 9P remove, a stillborn scratch replaced): the pane that grew into the rows, or the scratch standing in an emptied column; removeColumn gives it to the pane level with it in the column that takes the width. Closing an unfocused pane leaves focus alone. The per-caller focus lines in Del and replaceStillborn are gone, and so is prevFocus. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* File the tag code into tagline.zig and draw tags beside bodiesGabriel Schneider30 hours
| | | | | | | | | | | With tags reduced to Texts, what is left of them is the computed prefix, the default and saved tails, entering and leaving a tag and the headers: that goes to tagline.zig, as acme keeps the tag half of a window in wind.c. Tag and header drawing moves next to body drawing in body_layer.zig, and the tag hit helpers go to tag_layer.zig with the Hit they read, where sameCell now also tells the lines of a taller tag apart. The docs describe the tag as a Text. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Make the column and workspace tags Texts with the pane tag's keysGabriel Schneider30 hours
| | | | | | | | | | | | | The headers had their own one-line editor with its own keys: Enter always executed, h/l and J/K moved between headers and panes, Ctrl-c/x/v cut and pasted, and TagLine refused a newline that 9P accepted. They are now Texts like a pane's tag, with no prefix and a default until edited, so normal and insert mode, undo and the look and execute keys are the body's. Moving between them is the window keys' job: Up from a pane with nothing above it reaches its column's tag and then the workspace's, Down comes back, and Left and Right walk the column tags. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Give a pane's body its own Text holding the cursor, selections, mode and undoGabriel Schneider30 hours
| | | | | | | | | | | acme keeps what edits a text in its Text (dat.h:171-190) and the window holds a body and a tag of that type. The cursor, the selections, the modal state and the edit-buffer undo move off Pane into Text.zig, Pane holds them as its body, and the edit and normal-mode operations take the Text they edit. Nothing changes in behaviour; this is the step that lets the tag become a second Text. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Move saving and loading a whole editor out of pardes.zig into dump.zigGabriel Schneider30 hours
| | | | | | | | | | | | | | | | | | | Pure move, no behaviour change (acme keeps dump and load in rows.c): dumpState, restore, initFromDump and initDump go verbatim to the end of dump.zig, after the dump format they read and write. Inside dump.zig the moved code's `dump.` prefix drops, so `Pane` there is the dump record; the one editor pane it names is spelled `pardes.panes.Pane`, and its other `panes.X` references become `pardes.panes.X` because dump.zig's own tests use `panes` as a local name. The methods become free functions taking `p: *Pardes`: `p.dumpState()` becomes `dump.dumpState(p)`, `core.restore(bytes)` becomes `dump.restore(core, bytes)` and `Pardes.initFromDump(..)` becomes `dump.initFromDump(..)`, in pardes.zig, the shells, layout.zig, Terminal.zig, builtins.zig and the tests (38 receiver rewrites plus the initFromDump calls). The tag-tail restore helpers stay with the tag code. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Ask from the keyboard which neighbour a closed pane's rows go toGabriel Schneider30 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | Del takes a side: `Del k` gives the closed pane's rows to the nearest expanded pane above it, `Del j` to the one below, each falling back to the other side when it has none. DelAbove and DelBelow are those two lines, with no path of their own under SPC. A bare Del started from a key -- SPC d, Enter on the tag word, a row run from an output buffer -- on a pane with expanded panes both above and below asks instead of guessing. The question is a prompt like Save's or a search's (Pane.Prompt.del_side), so it is painted on the pane's notice band by the same path, and the next key answers it before any mode sees it: k or Up, j or Down, anything else keeps the pane, as does a click. Only a key press sets Pardes.can_ask, so a click, a 9P ctl or event write, a startup line, a restore and a shell exiting all close the pane at once, the rows going where layout.absorbVWeight has always sent them. A collapsed pane is not asked about (it has only a tag row to give), and collapsed neighbours are passed over (layout.expandedNeighbor, which Collapse now uses too). removePane and absorbVWeight take the recipient; every other caller passes null. Three scripts that closed a middle pane with SPC d answer k, which is where the rows went before, and their goldens are unchanged. delask.snap covers the question, Esc, j, a clicked DelBelow and a clicked Del. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
* Light a held column grip, and rail its landing beside the rule where the GUI ↵Gabriel Schneider30 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | shows it The column grip worked in the GUI but showed nothing anyone could see. Driving the real SDL window with pixel mouse events, press, drag and release all reach the core and reorder or resize the column; the feedback is what failed. The grip kept its muted color while held, and a reorder's insertion rail was drawn in the gutter cell at the destination edge. The GUI paints that cell as the column's scroll rail, and at the window's left edge, the common case of moving the right column first, the dashes were lost in it. From the leftmost column, a drag short of a neighbour's middle shows no rail, rightly, since nothing would move, but nothing said the grip was even held. A held grip now lights in column_box, the accent its muted color is mixed from, and the rail takes that color. The rail runs in the seam cell left of where the column's rule will land, where a border drag's rail runs, for a reorder and a left-edge move alike; at the window's left edge, which has no seam, it runs just past the scroll rail, leaving column 0's grip and pane boxes whole. A carried column's pointer aims at a place, not a word, so the column tags no longer light the word under it, and a release snaps the layout as a border drag's does rather than animating it. The preview and the release both ask layout.columnDrop where the column goes, so the rail stands where the release puts the edge, and the drag no longer carries its unused column index. The GUI test feed takes ESC]777;mouse;<down|up|motion>;<button>;<x>;<y> in window pixels and dispatches it as an SDL event. test/column_grip.py uses it to drive the grip through the same pixel-to-cell and tag hit path as a hand on the mouse, and checks the grip, the rail and the result against GPU captures and the 9P grid. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
* Center tagline bands, frame anchors evenly, fill to the window edge, and ↵Gabriel Schneider30 hours
| | | | | | | | | | | | | | | | | | resize columns from their grip Every tag band (workspace, column, pane) is centred in its row, so text sits at one baseline offset. Anchors are inset from the column rule by that same margin, so they are square and the band frames them on the left, top and bottom; the pane mark moves to stay centred. When the window is not a whole number of cells, the bands, rules, spines and scroll thumbs at the right and bottom edges run on through the leftover pixels. A column grip dropped short of another column's place now moves the column's left edge, with a dashed rail preview, sharing setColumnPairWidth with the border drag. A release still on the grip changes nothing, and a pair too narrow for two MINW columns is left alone. PARDES_TEST_PAD adds leftover pixels to a test-mode window and capture.
* Make the macOS shell a first-class hostGabriel Schneider30 hours
| | | | | | | | | | | | | | | | | | | | | Pty children are exec'd with their own TERM/COLORTERM/TERM_PROGRAM instead of inheriting a .app launch's empty environment, and ttyTaken finally answers on darwin — libproc walks the tty's foreground process group — so Escape reaches the child and Exec stops believing every pane sits at its prompt. The occupancy suite runs on both platforms now. The workspace tag row moves into the native menu bar as a Builtins menu. -Dworkspace-tag (default off for -Dplatform=macos, on everywhere else) drives it, and Pardes.topBarHeight replaces the TOPBAR_H constant so the core stops reserving the row. The view pins every variable-font axis to the file's own default (Maple Mono came up Thin otherwise), shapes ligatures, carries per-shape pointer cursors, and draws the look-hover affordance as refracted glass. Tag rows fill edge to edge, with the anchor box painted back on top of that fill and its mode glyph centred on the same square. Theme accents re-saturated across the set. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
* Reorder columns using aligned and distinctly colored tag gripsGabriel Schneider2026-09-15
|
* Separate tag text geometry from physical pane gripsGabriel Schneider2026-09-15
|
* Add optional compact tagline styling for source contextGabriel Schneider2026-09-15
|
* Remember tag cursors and reserve uppercase pane navigationGabriel Schneider2026-09-15
|
* trunk: resume before the Reload experimentGabriel Schneider2026-09-15
| | | | Empty marker on the last pre-Reload change. Keep the Reload experiment on reload (3801914), its first change on reload-start (200a1fc), and the unfinished performance investigation on reload-perf-wip.
* Refactor panes and filesystem; replace FUSE with 9PGabriel Schneider2026-09-07
Consolidate pane, layout, memory and host code. Serve 9P by default over Unix sockets, with runtime mounts and optional TCP/QUIC transports. Remove FUSE and obsolete proof-of-concept examples. Fix highlighting and terminal-history performance, expand differential and stress-test infrastructure, sort navigation results while preserving the next occurrence, add syntax-colored Braille minimaps, remove SPC-k, and document 9P interaction as a repository skill.