summaryrefslogtreecommitdiff
path: root/src/pardes.zig
Commit message (Collapse)AuthorAge
* A diff line looks up the path and line it names, as any look doesGabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | The look on a diff line was its own resolver: a walk up to .git/.jj from the diff's directory, its own "no such file here" and "deleted by this diff". A review tool's cached patch, in no repository, missed every file though the session's terminals sat in the checkout. Now a diff line only expands and transforms. Its expansion (what the hover shows) is the whole line for a header, a `@@` line, or a hunk line pointed at on its prefix, and its text is the look address the line names (look.diffAddress): `path` for `diff --git`/`---`/`+++`, `path:c` for `@@ -a,b +c,d @@`, `path:N` for a hunk line's new line (a removed line's, the new line now where it was). That text goes through the regular look exactly as if selected by hand: same resolution, placement and errors. A 9P look of a whole diff line takes the same transform. Kept: the line classification, hunk arithmetic, git prefix stripping and timestamp cutting (diff.zig). Gone: the repo-root walk, its messages, Target.old_side and deletesAhead, and the click's row stash (Pardes.diff_look). A test compares a B3 on a cached patch's line with a look of the hand-selected `entry/src/entry.rs:2` in the same session. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Recent and /recent keep PDFs and images as they keep files, and an open ↵Gabriel Schneider2 days
| | | | | | | | | | | | file's row is where its dot is now Only text files were recorded, so a PDF read yesterday was not there to find again, and an open file's row showed the place it last closed at, stale by however far it had moved since. A PDF is kept at its page and reopened there from its row; an image by its path; an open one's row reads its pane's place at the time of the listing. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A look at a PDF's page past its last is a miss, "has no page N", never the ↵Gabriel Schneider2 days
| | | | | | | | | | | | last page in its place manual.pdf:999 on a twelve-page PDF showed page 12 and said nothing, so a stale or mistyped page number looked like a place found. It is now the miss a line past a file's end is, whether the PDF is open (it stays on its page) or not (nothing opens). A restore or a start-up page past the end still lands on the last. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A Rename the language server finds nothing for says so, "Rename: nothing ↵Gabriel Schneider2 days
| | | | | | | | | | here to rename", and fails the write that asked it An empty answer to a rename returned without a word, so Rename on a place with no symbol looked like a rename that worked. It is now the not-found failure every other query gives. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The jump list never holds two entries in a row the same: when the one ↵Gabriel Schneider2 days
| | | | | | | | | | | | between them goes, they are one A closed pane's entry dropped from between two visits to the same place, or a closed file's entry reopened beside its own, left twin entries, and Back spent a press going nowhere while Jumplist listed the place twice. The compaction that drops dead entries now folds a twin into the one before it, keeping the current entry on the one kept. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Save path logs a save record naming the path it wroteGabriel Schneider2 days
| | | | | | | | | | | Save of a pane's own file logged `save <serial> <name>`, and so did a scratch's `Save path` (the pane takes that name). A `Save path` that writes a copy of a file pane, or a terminal's scrollback, elsewhere logged nothing, so a follower could not tell the file was written. It now logs `save <serial> <path>` with the path written, once the host has written it (events.noteLogAs). fs.md's log table says so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A terminal's word looks refill the directory's one +Search, as +Lsp is ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | shared, rather than stacking one per word Each word looked for in a terminal (clicked, or written to look), where no file of that name was, opened another +Search in the same directory, one per word, until the column filled. Such a search now refills the directory's +Search, as the file searches and the +Lsp answers already share theirs. A `/` search keeps a +Search per pattern, which n and N walk across (psearch.snap), so the sharing is marked on the word look alone (Pardes.word_look). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A pane refused for want of room spends no pane serial, as a refused Newcol ↵Gabriel Schneider2 days
| | | | | | | | | | | spends no column serial A pane/new, look or exec refused ENOSPC made its pane before placing it. The refusal closed the pane unannounced, but its serial was gone, so the next pane skipped one. When sync removes a refused pane that holds the newest serial, it now puts the counter back. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A focus moved over 9P tells the programs that asked for focus reports, as a ↵Gabriel Schneider2 days
| | | | | | | | | | | | click does A program that set DECSET 1004 heard `CSI O` and `CSI I` when the keyboard moved by a click, a key or the window's focus, because update() checks after each event. A /focus write went through serveFs, which never did, so the program kept believing it had focus until the next input event. serveFs now runs the same check once a request has settled. Co-Authored-By: Claude Opus 5.5 <[email protected]>
*-. Release Pardes 0.9Gabriel Schneider2 days
|\ \ | | | | | | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]>
| | * A program that asked for focus reports (1004) hears CSI I when its pane ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | takes the keyboard and CSI O when it gives it up, to another pane, a tag or another window The core has a window-focus event now, from SDL's window focus and from the tty's own focus reports (vaxis turns 1004 on outside); the detached wire carries it: version 10. The test shell's ESC]777;mouse;focus;<1|0> fakes the window's. Co-Authored-By: Claude Opus 5.5 <[email protected]>
| | * A program that tracks the mouse gets its clicks, drags and moves over its ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | grid, in the format it chose; Shift keeps pardes's select, execute and look, and chrome is never the program's Presses and releases under 1000, drags with a button down under 1002, every move once per cell under 1003, X10 presses under 9, in raw terminal input only. A press the program took keeps its drag and release, reported clamped to the grid's edge wherever the pointer goes. The press also makes the pane the active one. docs/tags.md says so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
| | * A mouse event carries Shift and Alt as well as Ctrl, from SDL and from the ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | tty's input; a program's wheel report carries them as xterm counts them, and Shift keeps the wheel pardes's own scroll The reports are ghostty's encoder now (shift+4, meta+8, ctrl+16), with the mode and format ghostty tracks. The detached wire carries the two new bits: version 9. The test shell's ESC]777;mouse takes an optional fifth field of modifiers. Co-Authored-By: Claude Opus 5.5 <[email protected]>
| * | A right click on a diff line opens the place it names: its file, the hunk's ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | new line, the line itself In a diff pane (a .diff/.patch file, or a command pane's diff output), the look's own expansion, which its hover shows, takes a whole line for a `diff --git`, `---`, `+++` or `@@` line wherever the pointer is on it, markers included, and for a hunk line when the pointer is on its `+`, `-` or space. Then the look opens the file (a/ b/ dropped, timestamps cut) at the line from the hunk header and the lines above it: `@@` the hunk's first new line, context and added lines their own, a removed line the new line now where it was. `diff --git` and `+++` open the new file; `---` the old one, unless the `+++` under it names another. On a hunk line's code the expansion is its words, the prefix never one of them, and looks as ever. Other panes are untouched. Paths resolve in the repository (walking up to `.git` or `.jj` from the diff's directory, or a command pane's), then that directory. A file not here opens nothing and says `Look: b/x: no such file here`, or `deleted by this diff`. A 9P look writing a whole line of the diff does the same. Co-Authored-By: Claude Opus 5.5 <[email protected]>
| * | A diff reads as the code it changes: hunks in their file's language, added ↵Gabriel Schneider2 days
|/ / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | and removed rows tinted A .diff or .patch pane, and a command pane whose output is a diff (`git diff`, `git show`, `diff -u`; told by a `diff --git` line, or `---`/`+++` with a `@@` under them, in its first rows), colour each hunk's code in the language of the file its section names (`+++ b/<path>`, `--- a/<path>` for a deleted file), with tree-sitter, as highlightLocations does for results. src/diff.zig walks a unified diff by its `@@` counts, so a removed line that reads `--- x` is no header. Each side of a hunk is parsed as one text (context and removed lines the old side, context and added lines the new), so a string or comment across lines colours as it does in the file; a side no line takes its colours from is not parsed. A section's hunks share a parse, in pieces of about 40 lines (a hunk past 80 is cut), only those in view, and each piece's colours are kept by its bytes, so scrolling back and a terminal's every repaint parse nothing again. Added and removed lines carry a flag in their style byte; the painter tints their rows to the pane's edge, a little way from the page toward the theme's ANSI green or red, and draws the prefix in that hue pushed to read on it. A file in no known language keeps the old line colours. A command pane is read once its command has finished: its rows are copied once (File.DiffOutput, dropped when the pane runs again), so no frame dumps the scrollback, and painted over what git printed. A running command is shown as it prints. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | A detached session no client watches draws no frames: yes | head -c 50M ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | through pty/run goes from over 30 s to 11 s Profiling the 50 MB run showed 70% of its time in draw.render, recolorAnsi alone 43%, walking cells through PageList.pin. The detached session drew a frame after every pty read, with no client attached to see it. A host now says whether anyone watches (Host.VTable.watched). The detached server answers whether a client is attached, and while none is the core keeps the frame owed instead of drawing it. A /screen read draws its own, and a client attaching gets one (hello sets needs_frame). Debug, 80x24: 10 MB went from 7.36 s to 2.10 s, and 50 MB from over the 30 s client timeout (about 37 s by rate) to 11.08 s. What is left is the terminal's own parsing and scrollback growth. A session a frontend shows still draws after every read. Pacing those frames is the next step if that case matters. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | Save makes the directories its file goes in, always: for the pane's own name ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | and Save path alike Whether a Save made missing directories depended on how the name had come about. Config's pane did, a name written into a missing directory did (since kkrqxtsp), and `Save path` and every other name did not, failing ENOENT instead. There is now one rule: a Save makes the parent directories of the file it writes, a pane's own or a terminal's scrollback included, and the make_dirs flag is gone. A directory it cannot make still fails the write with why, as fs.py's /nonexistent-pardes-dir case shows. fs.py now also saves into missing directories by Save path and by a written name. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | Lspwhy explains the recorded last query in its own file and place, wherever ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | | | it is run Lspwhy kept the last query's kind and argument, but ran from another pane it asked in that pane's file at its cursor. So it narrated a different lookup from the one that failed. When the pane the query was asked in is still open, Lspwhy now asks in it, at the query's offset, whichever pane it is run from. With that pane gone, it falls back to the pane it is run in. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | A Newcol refused because the panes' tags would not fit logs its err alone ↵Gabriel Schneider2 days
|/ | | | | | | | | | | | | | | | | and spends no column serial Newcol tries its column before keeping it: the new column is inserted, the panes' rows are shared out again, and where a pane would be left under its tag and two rows the column is taken back. The trial showed. insertColumn logged `newcol N` and the take-back `delcol N`, so a follower saw a column come and go around the err. Laying the column out also gave it a serial, so the next column made skipped one. The trial is now unannounced, since insert and drop have unlogged forms. A refusal puts the serial counter back where it was, after first giving every existing column its serial so the trial's is the only one spent. Only a column that stays is logged, and it gets the next serial. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Lspwhy explains the last language server query asked, its kind, argument and ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | place, not always a definition at the cursor Lspwhy said it explains how the last request was answered, but it always replayed a definition query at the current cursor. So after a failed Hover it narrated a gd somewhere else, which told nothing about the failure. Now the core remembers the last query (kind, argument, pane, offset), and Lspwhy sends it as `<kind> <arg>`, at the query's offset when asked from the same pane. The client narrates that kind: lsp.explaining reads it, and the heading names it ("the hover query at byte N"). With nothing asked yet it is a definition, as before. The effect's arg grows to 160 bytes so a 128-byte argument fits with its kind. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The Tutor pane is named +Tutor in the session's directory, not /TutorGabriel Schneider2 days
| | | | | | | | | | | Every other generated pane is named `<dir>/+<Name>`: +New, +Errors, the outputs. Tutor alone was a bare `/Tutor`, a real path at the root, so a Save would try to write there, and /index listed it as if it were a file. A scan of the other generated panes found no other bare absolute name. The three snapshot goldens that show the Tutor tag were re-recorded by name (tutor, builtins, leader). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A failure naming a long path keeps its reason, and name refuses a component ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | | | over 255 bytes A Save of a 3000-byte path failed with the record "err 2 ctl: Save…", which lost the reason. The first cause was reportError, which formatted into 256 bytes, so the operation's path filled the buffer before the reason was written. The second was the waiting write's late failure, which took the first 256 bytes of the message row, never its end. Now reportError has room for the longest path. reportFailure also keeps the words fitted as an err is (fitErr: the path gives up its middle, the reason stays), and the late failure of a Save, a Dump, a shell or a ThemeFile takes those words. fs.md already said a name holds up to 255 bytes a component, but a longer one was taken and only failed later at Save. Now it is refused when written. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Nothing about a pane is logged before its new, and the boot terminal's new ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | carries the session directory, not / and a rename A pane named in the update that made it (Config's init file, a look renamed on open) logged `rename N <name>` before `new N`, so a follower met a serial it had never seen. The boot shell, started with no directory, was announced as `new 1 /` and renamed once its shell spoke. Now noteLog drops the rename of a pane not yet announced, since its new carries the name, and announces a pane first for any other record about it. A terminal whose shell has not said where it is is named by the session's directory, where it was started, and the shell saying so is no rename. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Release Pardes 0.6Gabriel Schneider2 days
|\ | | | | | | | | | | Merge: audit top-five cuts + tag sweeps + Config/DumpConfig (on the audit bug fixes C9, C2). Co-Authored-By: Claude Opus 5.5 <[email protected]>
| * Config opens the startup file, DumpConfig the settings report, and the ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | workspace tag reads Dump Themes Config Debug Exit Config (SPC f c) opens init, found as the settings report finds it (opts.startup_config_path: $XDG_CONFIG_HOME/pardes/init or ~/.config/pardes/init, and the macOS and Windows paths config.md gives). A pane that already holds it is gone to instead; a file on disk is looked at; with none, an empty pane is named for it, and Save makes its directory and any above it first (File.make_dirs, fs.makeDirs) before writing. Without a configuration directory it says so and opens nothing. The report Config used to open, the startup path and every live setting, is DumpConfig, in a +DumpConfig pane. No alias keeps the old meaning. The workspace tag's default words put Themes where NextColor was, NextColor staying a builtin, and Config beside it. A tag the user edited is kept as it was: a dump stores only an edited one (topbar_custom), and a restore puts back only that. theme.snap types NextColor onto the workspace tag to click it, and tagnav's walk back to Dump takes five long-word steps. The rest of the re-recorded goldens differ in the workspace words and their widths only. Co-Authored-By: Claude Opus 5.5 <[email protected]>
| * A middle or right sweep over a column's or the workspace's tag runs or looks ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | for what it swept, as a pane tag's does Both headers acted on the press: a middle or right press ran, or looked for, the word under it (or the header's selection when it was on that) at once, so a drag had nothing left to do. A sweep of `echo SWEPT` in a column tag ran a bare `echo`. They have done so since the headers were drawn apart from the panes; it is no regression, and the -l/Restore allocator fix (ompukopz) does not touch it. Now a press on a header holds a HeaderSweep (the column by its serial, or the workspace), which the drag extends, held to the header's row and text as a pane tag's sweep is. It is painted in its button's tint meanwhile, and the release runs what it swept in that header's context; a release that has not moved runs the word or selection a click always did. The other of middle and right cancels it (acme 2-3/3-2); the select button is inert, as a header's command already takes the held selection as its argument. Running on the release, a builtin from a header is announced as one from a pane tag is: the press used to set the announcement and the release clear it at once. find, restore, theme, topbarexec, ttyhelp, tutor and windowops re-recorded for that badge alone. headersweep.snap sweeps the column and workspace tags with the middle button and a word part with the right one, and cancels a sweep; headersweep-restored.snap sweeps both after Dump and Restore. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | Dumps and init files from before 0.0.4 load no more of their old tag ↵Gabriel Schneider2 days
|/ | | | | | | | formats, and three orphan test scripts go A2: a restored pane's tag tail comes from the dump's tag_tail, which every dump since 0.0.4 writes; the 27 earlier default tails that were recognised to upgrade, restoreTail, tailClass, savedPrefix and restoreTailAt, pdf_view's and image's legacySavedPrefix, a terminal's TTY tag prefix and its raw output tail replay, and the ThemeSel, FontSel and ColumnTags words (init lines and dumped output names) go, with their tests; the CHANGELOG says so. A4: test/fs_soak.py, referenced nowhere (monkey9p.py does its work). A6: test/column_grip.py and test/look_placement.py, referenced nowhere; the six review scripts docs/ui-review.md names stay. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A session restored from a dump is built as a fresh one is: its column and ↵Gabriel Schneider2 days
| | | | | | | | workspace tags take several selections, and its 9P files have a time dump.initDump copied Pardes.init's construction and had drifted from it: it never gave the column and workspace tags their allocator, so after -l or Restore they could not hold more than one selection, and never set fs.started, so every 9P mtime read 0. Pardes.create is now the one construction, allocators, tags, the tree's clock and the mounts, that init and initDump both start from. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Terminal.zig is terminal.zig: a file of functions and no fields takes a ↵Gabriel Schneider2 days
| | | | | | | | namespace's lowercase name The last of the deferred renames, now that the tty and theme agents have landed: panes.terminal at its importers, the alias lines in Text.zig and File.zig and panes.zig's own uses following. dump.zig's Terminal struct, a dump record, is not this. The served sources list and docs/design.typ name the new file. test/perf.zig's references change, so the three perf baselines take its new harness id with their numbers as recorded. No behaviour changes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* locations_config.zig and locations_cache.zig fold into locations.zig, the ↵Gabriel Schneider2 days
| | | | | | | | Locations setting and cache beside what uses them Config (75 lines) was re-exported from locations.zig already, and Cache (213) served only its format; locations.zig is 683 lines with them. The cache's own Result, which would be ambiguous beside locations' Result in one file, is Cache.Hit, what its comment already called it. pardes.zig, dump.zig and main.zig import locations.zig. No behaviour changes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* tag_layer.zig folds into Layer.zig, whose TagHit its two functions work onGabriel Schneider2 days
| | | | | | Two functions (sameCell, columnAt) on Layer.TagHit, 32 lines with their imports, used by edit.zig, mouse.zig and look.zig: they sit with the type now, called Layer.sameCell and Layer.columnAt. docs/design.typ names Layer.zig in its place. No behaviour changes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Newcol shares a column's rows out again when its narrower tags would leave a ↵Gabriel Schneider2 days
| | | | | | | | pane under its tag and two rows, or is refused A seeded sweep of placements (New, pane/new, Edit =, Tty, look, Delcol, deletes, refusals included) over screens 6 to 40 rows high found no refused placement that leaves a pane short since lyltlqnz and lrpzwyom; the pane a row short came from Newcol, which halves a column's width so long tags wrap onto more rows, raising those panes' minimums with no rows moved. Newcol now shares each such column's rows out again, and where a column has not the rows for every minimum there is no new column (Newcol: no space for a column: the panes' tags would not fit), as a size too small is refused. The sweep, 300 seeds, is the test; a user's drag or a tag grown by editing may still take a pane under, as before. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Only a write logs an err: a refused open or truncation, create or remove, or ↵Gabriel Schneider2 days
| | | | | | | | a write to pane/new, is its error alone, and every refusal is said in words The one-failure rule is a write's. A refused remove, pane/new's open refused for want of a slot, and an OTRUNC open's refused truncation (data's after a failed addr) also logged an err, and a reply carrying only an errno reached the client as the C library's text (Operation not permitted). tree.handle now gives such a reply Plan 9's words, chosen so 9ns maps each back to its errno (EPERM's to EACCES, as Plan 9's does), and serveFs logs errs for writes only, not a write to pane/new, which is only read. docs/fs.md and the 9P skill say so, and that a look miss quotes what was written. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Writes held before the shell's clock is first seen no longer overflow its ↵Gabriel Schneider2 days
| | | | | | | | first step A 9P write served before a detached host's first pump holds its batch stamped at time 0, so nextWake said to wake at 20 ms while advance, seeing the clock for the first time, set stepped_ns days later and counted due - stepped_ns back past zero: an integer-overflow panic. It was what the 64 KiB msize trial hit in fs-test (restore detached space, the connection closing at the first write's clunk), a race any msize can lose. A batch's wake is now never before the next frame. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A write to addr, limit or mark asks for no frame, so its close is not held ↵Gabriel Schneider2 days
| | | | | | | | behind one Every write that changes a pane set needs_frame, an addr write too, so the editor drew a whole frame after each and the clunk that followed waited for the turn while it did: 0.5 ms (Debug) to 1.2 ms a clunk, what made addr and event write-back 4-10x acme's. An address, a limit and the mark flag are nothing drawn; their writes no longer ask for a frame. Clunk after an addr write: 0.518 -> 0.015 ms (Debug tty, fs.py client). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* An open's writes in a row to one place go in as one edit: a 10 MB body write ↵Gabriel Schneider2 days
| | | | | | | | is linear Each body or data write copied and hashed the whole buffer, so a write the mount cut in 8 KB pieces was quadratic: 10 MB took 50 s and a 1 MB insert into 10 MB 11 s, holding the editor's turn. An open's appends to body, or inserts going on at data's address, are now held and put in as one splice (one copy, one undo step, one line-starts pass) before any other request, the close, or the editor's step once the writes pause 20 ms. fs.py-driven: 2 MB 2.19 -> 0.16 s, 10 MB 50.17 -> 0.78 s, 1 MB data into 10 MB 11.49 -> 0.26 s. A body-2m case (2 MB in 256 KB writes on one open) joins the perf gate: 84023 -> 15785 us; baselines re-recorded. Co-Authored-By: Claude Opus 5.5 <[email protected]>
*-. Merge: 9P round 23 + perf fixes + input garbage fixes + Crt docGabriel Schneider2 days
|\ \
| | * Function keys, Insert and the keypad reach a terminal pane as their terminal ↵Gabriel Schneider2 days
| |/ | | | | | | sequences
* | Delcol on the last column leaves the window, empty but for its workspace ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | 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]>
* | Back at the oldest place says nothing further back, and Forward at the ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | newest nothing further on A step past either end of the jumplist did nothing, silently. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | Not-found failures say it once, in plain words: grep: pattern not found, ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | callers not found The ENOENT that 9ns reads from a failure's words came from a tacked-on suffix, grep: no match, not found, definition: nothing found, not found, no shell "x", not found. They now say it once: grep: pattern not found, find: name not found, Callers: callers not found, definition: not found, shell "x" not found (...). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | A new file, once saved, shows in /recent, openGabriel Schneider2 days
| | | | | | | | | | | | A pane named for a file not yet on disk is not kept in Recent (round 22), and its Save did not add it, so the file stayed out of /recent while open. A Save that puts a file on disk now records it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | A Tty started by a shell's path keeps the path in its Tty+ wordGabriel Schneider2 days
|/ | | | | | The tag said Tty+<basename>, so a click on it looked the bare name up on the usual paths and found nothing, or another program. A shell given as a path now keeps the path in the word. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The theme's chrome is worked out once, not per grapheme; still post passes ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | let the GUI rest; a perf gate somtrmsz's contrast floors made ChromeTheme.fromTheme run its focus-tint and separator searches (pow calls each), and Output's RowDecoration.styleAt called it for every grapheme of every highlighted row: the 50k-line file's render went from 0.11 ms to 13 ms. Pardes.bodyChrome now keeps the theme's chrome, worked out again only when the theme differs; recolorSyntax asks for it once a decorated row, and a plain row (nearly every row of a file) never asks. ReleaseFast, medium fixture, median us, before -> after (main): render 13150 -> 76 (111), key-down 14658 -> 79 (110), wheel 13589 -> 76 (109), open 14891 -> 2095 (2055), edit-char 16703 -> 3006 (1251; the rest of that gap is editing and tree-sitter, not this). Post.animating asked for frames whenever the window had focus and any pass was ready, so a still pass kept the GUI drawing at the display's rate (Bloom: 49% of a core idle, in a hidden test window). A pass now says whether it moves on its own: the CRT (its hum and dither) and a Shadertoy file whose source reads iTime, iFrame or iDate (shader_build.readsTime; the flag rides the wire's post message); Bloom, Vignette and Grain are still. Bloom idle: 49% -> 1.2%, as with no pass. zig build perf-gate: the 50k-line file's gestures, each's fastest sample within 3x of the recorded baseline's (test/perf-baseline-<platform>- <optimize>.json, recorded from this build), run with every unit-test. On the regressed code it fails at 180x for render.
* A Jumplist entry is (closed) only while no pane has its file openGabriel Schneider2 days
| | | | | | A closed file's entries stayed closed after the file was opened again another way (a look, Recent), so Jumplist said (closed) of an open file and a step onto it reopened it. They are now that pane's as soon as a pane shows the file. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* +Unsaved drops a pane once it has closedGabriel Schneider2 days
| | | | | | The list kept a pane's Modified row after the pane was closed (discarded), so it named text there was no longer anything to lose of. A pane's closing now takes its row out. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The workspace tag's Restore word names the last dump, and the dump a Restore ↵Gabriel Schneider2 days
| | | | | | | | came from Once the workspace tag was edited, its own text kept the Restore <path> of the dump at that time, stale after the next Dump; and a Restore dropped the path altogether (the new session had no last dump). A new dump now swaps the old path in the tag's own text, and a Restore points the word at the dump it read. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Back or Forward over a closed file deleted since skips it and goes on, saying soGabriel Schneider2 days
| | | | | | A jumplist entry for a closed file no longer on disk tried to reopen it, failed as a look, and left the step stuck there. Its entries now go, the message row says <path>: deleted, skipped, and the same step is taken over what is left. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A language server question that finds nothing, cannot be answered or has no ↵Gabriel Schneider2 days
| | | | | | | | room fails, and so does a write to an image's or PDF's body Callers or Callees with nothing found, Hover or Lspwhy with no room for its pane, and a question asked of no file's pane said nothing, the 9P write succeeding; a body write to an image or PDF pane went nowhere. A write that asks a language server now waits for its answer (turn.lsp_answers), and what fails there -- nothing found, no answer, a backend's @none why, a placement with no room (ENOSPC) -- fails the write and logs its err. No diagnostics is said, not failed. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Recent goes on across a Restore, and is kept after itGabriel Schneider2 days
| | | | | | A Restore makes a new session, which never loaded the kept list, and saveRecent gives up until it has: Recent was empty after a Restore and nothing opened afterwards was kept. The new session now takes the old one's list (a boot from a dump reads the kept file). Co-Authored-By: Claude Opus 5.5 <[email protected]>