summaryrefslogtreecommitdiff
path: root/src/ninep/pane.zig
Commit message (Collapse)AuthorAge
* An edit that changes nothing, an empty range deleted or a range replaced by ↵Gabriel Schneider5 days
| | | | | | | | | | | what it holds, makes no undo step A shell's : > data on an empty address, echo abc > data over abc, or Edit s/d/d/ each pushed an undo step and a new revision, so Undo spent a press on nothing and the pane read as edited. The splice of the 9P writes and the Edit builtin now see the text is unchanged and stop. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A refused write to dot after a shell's truncation changes nothing: the ↵Gabriel Schneider5 days
| | | | | | | | | | | | truncation waits for the write, as limit's does echo /nomatch/ > dot truncated dot to an empty range at the top before the write was refused, so a failed address still moved the selection and scrolled. The truncation is now held until the write that follows it: that write sets dot, or, refused, leaves it as it was. A truncation with no write after it (: > dot) empties it when its open goes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* name refuses a directory, EISDIR, when written, not at the Save that could ↵Gabriel Schneider5 days
| | | | | | | | | | | | only fail `name ~`, `name /` or `name foo/` renamed the pane to a directory, and only its Save failed later. A name ending in `/`, the root, or one naming a directory that is there is now refused at once, with words a mount reads as EISDIR (`name: <path> is a directory, not a file`). The ctl word name and a forwarded `pardes ~` go through the same check. fs.md says so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* An addr, dot or limit pair out of order or past the text is refused as the ↵Gabriel Schneider5 days
| | | | | | | | | | | | address form is, not clamped `#5,#2` and `#2,#99` were refused (addresses out of order, address out of range), but the pair form `5 2` became 5..5 and `2 99` became 2..end, silently a different range from the one asked for. A pair is now checked the same way: past the text is out of range, and an end before its start is out of order. fs.md says so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A tag rewrite counts its text without the newline it drops: echo of exactly ↵Gabriel Schneider5 days
| | | | | | | | | | | | 4096 bytes fits `echo <4096 bytes> > tag` wrote 4097 bytes and was refused "over 4096 bytes", although a rewrite drops that one trailing newline and would have held exactly 4096. The limit now counts a truncating write's text without the newline it drops, for a pane's, a column's and the workspace's tag. An append still counts its newline, which it keeps. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A 9P write scrolls only the view: dot moves as acme's textinsert moves it, ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | never to the end of the write writeData, flushBatch and writeBody showed what they wrote with showOffset, which put the cursor at the write's end. The cursor is dot's head, so a data write or a body append moved dot there, and a `sel` write after it replaced the wrong text. showOffset now scrolls the view to the offset and leaves the cursor, pinned, where it was. Dot shifts only by the rule it already followed, acme's: an insert before dot shifts it, one at its start or inside it grows it, one at its end or after it leaves it. The test covers each case, then a body append followed by a sel write. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A path typed with a leading ~ is the home directory, at every entry point ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | that takes one, through one helper Only DumpDir (dump.zig) and ShaderBuild expanded `~/`, each its own way. So a look at `~/notes.txt`, `name ~/x`, `Save ~/x`, ThemeFile, Restore and a quoted `pardes '~/x'` all took `~` as a directory of that name under the pane's. There is now one rule, filesystem.expandHome. A leading `~`, alone or before `/` or `:`, is $HOME, else the passwd entry's home; `~user` is that user's (getpwnam). As in a shell, it applies even beside a file named `~`, and `./~` names that file. Every entry point runs its typed path through it: - look, B3 and 9P, before any parsing, so `~/x:12`, `~/x:12:3` and `~/x:/re/` all work; - name, and a tag's rename; - Save <path>; - ThemeFile, DumpDir, Restore and ShaderBuild's shader files; - the forwarding launch. Recent rows are not shown with `~` and need nothing. How names are shown is unchanged. Tests: expandHome's cases, and HOME unset (passwd), with HOME passed in rather than set, since setenv moves the environ a spawned child reads. fs.py covers Save into missing directories under `~`, `name ~/x`, a look at `~/x:3`, and a forwarded `pardes '~/x'`. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A tag write over the limit is refused "no space: over 4096 bytes", so its ↵Gabriel Schneider5 days
| | | | | | | | | | | err record says tag: once The refusal's text began with "tag: ", and the log's err record puts the file's name before the reason. So the record read `err - col/1/tag: tag: no space: over 4096 bytes`. The text is now the reason alone, as the control-character refusal's is, and the record names the file once. 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 Schneider5 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]>
* pardes NEWFILE in a pane forwards even when its directory is missing, and ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | Save makes the directories fs.md said FILE must already exist, while `pardes new.txt` in fact forwarded, making a pane named for it that Save creates. With a missing directory (`pardes notes/new.txt`) the launch gave up forwarding and started a nested editor inside the pane. Now the name is made absolute as written and forwarded the same way. A name written to a pane's name file that goes into a directory not there has its Save make the directories, as Config's pane does. A Save <path> into a missing directory still fails ENOENT. The Forwarding section now says what a new FILE does. fs.py launches one into a missing directory and saves it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A failure naming a long path keeps its reason, and name refuses a component ↵Gabriel Schneider5 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 Schneider5 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]>
* Pane, column and workspace tags take one set of write checks, and a refused ↵Gabriel Schneider5 days
| | | | | | | | `>` write leaves the tag as it was A column's or the workspace's tag took any length, so a write past 4096 bytes went in and a later Dump failed on it (bad dump tag), and a truncating open wiped any tag before the write after it could be refused. The column and workspace tags now refuse what a pane tag refuses: the 4096-byte limit (ENOSPC, tag: no space: over 4096 bytes) as well as the control characters they already did. A truncation of any of the three is held until the write after it is known to fit, and done with it; a refused write drops it; a close or read with no write after it does it then (so `: > tag` still clears). A test runs a truncating write too long, a control character and a bare truncation at each kind, and Dumps after. docs/fs.md says so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* An append to a body through 9P costs its own bytes, not five passes over the ↵Gabriel Schneider5 days
| | | | | | | | whole body: 60 KB appends go from 35.7 to 2.1 ms each Round 25 measured bulk body writes at about 8 ms a write. There is no frame wait in it: a profile of open, write, clunk in a loop found the flush of each close walking the whole body five times. dotOf, setDot and showOffset turned the cursor between offsets and rows by counting every newline from the top; setContent found the line index's changed span by comparing old and new byte for byte, and hashed the new text to see whether it was back to the saved one. The rows now come from the file's line index by binary search (checked against the counting at every offset), a splice tells setContent the span it changed, and the text is hashed only when its length is the saved text's. Measured over 9P on a Debug build: 60 KB appends 35.7 to 2.1 ms, 8 KB 5.3 to 0.8 ms, 1 KB 1.3 to 0.9 ms. What is left is two copies of the text an edit (the splice's and the undo snapshot's). The perf gate gains body-appends, 64 appends of 8 KB on the 50k-line file, and its three baselines are recorded again. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Terminal.zig is terminal.zig: a file of functions and no fields takes a ↵Gabriel Schneider5 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]>
* A tag write past the limit says tag: no space: over 4096 bytes, which 9ns ↵Gabriel Schneider5 days
| | | | | | | | maps to ENOSPC as the docs say The tree answers ENOSPC, but through a mount 9ns maps the words, and tag: over 4096 bytes carried none it knows, so a shell saw EIO. The words now hold no space; docs/fs.md says ENOSPC again. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Writes held before the shell's clock is first seen no longer overflow its ↵Gabriel Schneider5 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 tag write past the limit is refused whole, naming itGabriel Schneider5 days
| | | | | | A write to tag longer than the room left was cut and applied in part. It now changes nothing and fails ENOSPC, tag: over 4096 bytes; the docs give the limit. 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 Schneider5 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]>
* A ctl or exec line with no newline runs with its write and fails it, unless ↵Gabriel Schneider5 days
| | | | | | | | it needs more A last line with no newline was held to the close, so printf bogus > ctl answered 0 and failed only in the log, Edit ,s/zzz/y/ too. A write shorter than its Twrite is the whole of what was written (acme takes each write whole): its tail runs then and a failure is the write's. It is held only when the parser says it needs more -- an open { block, an a/c/i text -- or when the write filled its Twrite and may go on (the listener tells the core the room, msize less its header). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Every catch unreachable, orelse unreachable and syscall assert outside tests ↵Gabriel Schneider5 days
| | | | | | | | is a real refusal or says why it cannot fire A sweep for round 23's crash: a run's answer (pty/run) was bufPrint'd into 48 bytes with catch unreachable, so a foreground program's long name (macOS gives up to 32 bytes) panicked; it now cuts at the room, keeping its newline, in 96 bytes. The rest were numbers into buffers sized for them, a braille codepoint, pthread calls on the queue's own mutex, and pdf_view's resolved outline entries: each now carries a one-line comment saying why it cannot fire. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A name refused for a leading blank says a blank at its startGabriel Schneider5 days
| | | | | | Both ends said a blank at its end. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A second line written to name is refused EINVAL, in one write or on the same ↵Gabriel Schneider5 days
| | | | | | | | open bash writes printf 'a\nb\n' a line at a time, so each line arrived as a whole name on the held open and renamed the pane twice. An open that has named its pane now refuses a further line, as a two-line write already was. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A buffer whose file was deleted on disk is dirty, and Del asks firstGabriel Schneider5 days
| | | | | | A file deleted under an open buffer left dirty 0 and let Del, Exit and the rest throw the only copy of its text away unasked. It now counts as dirty, as acme's does, and the refusals ask about it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* After a failed address, one that goes from it (., +, -) says there is noneGabriel Schneider5 days
| | | | | | addr kept the old address under a failed one, and an address written relative to it went from that old one. Such an address now fails with no address: the last one written to addr failed, until one that stands alone is written. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A PDF's body reads the text layer of the page it showsGabriel Schneider5 days
| | | | | | The body of a PDF pane read as empty. It now reads MuPDF's text extraction of the page shown, the text search and n/N already use, read-only (a write is refused, as round 22's body refusal made it). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Two opens writing one body are separate undo steps, however they interleaveGabriel Schneider5 days
| | | | | | The join mark a write left was the pane's, so another open's write joined the first open's step. Writing opens of body, data and xdata now get an open record, the mark names the open that set it, and another open's write starts its own step (the pane's one history: each turn the opens take is a step). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A name cut across writes on one open is one name, applied onceGabriel Schneider5 days
| | | | | | Each write to name was taken as a whole name, so a name a client wrote in two pieces renamed the pane twice, the first time to half a name. name's writes are now held per open, as exec's and ctl's lines are, until the newline or the close. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A language server question that finds nothing, cannot be answered or has no ↵Gabriel Schneider5 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 keeps only files on disk, and its cap never drops an open oneGabriel Schneider5 days
| | | | | | A renamed scratch never saved and a /virtual/ pane were recorded as recent files, and at 200 the oldest entry went even when that file was open. Opens, renames and closes now record a path only when it is a file on this host, and the cap drops the oldest closed entry. A name with a newline is not written to the kept list, where it would read back as two. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The writes of one open of data, body or xdata are one undo stepGabriel Schneider5 days
| | | | | | bash line-buffers its stdout, so printf 'x\ny\nz\n' > data arrives as three writes and took three Undos. A write now leaves the join mark a truncation already left, so the next write on the file joins its step until the open is released; a truncation and any other edit start a step of their own. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Recent lists the files opened lately, closed ones too, and a jump back to a ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | closed file reopens it A file closed by accident, its path forgotten, could not be found again: the jumplist dropped closed panes. Every file opened (a look, a Save of a scratch, a Restore, a rename) goes first in a list of 200, kept once, its dot noted when it closes, kept across sessions in $XDG_STATE_HOME/pardes/ recent. `Recent` (SPC f r) shows it in a reused +Recent, each row `path:line:col open|closed` a look reopens; /recent reads `open|closed <path>`. The jumplist keeps a closed file's entries, +Jumps marks them `(closed)`, and Back to one opens the file at its place. acme has no such thing; its dump and Load are the nearest. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A tag write refuses NUL and the other control characters; a Dump that fails ↵Gabriel Schneider5 days
| | | | | | | | | | | | says so A NUL written into a tag went into the dump, which the host then could not write, and Dump said nothing: a success that wrote nothing. Tag writes, the workspace's, a column's and a pane's, refuse control characters but tab and newline, DEL, C1 and bytes not UTF-8, EINVAL; and Dump reports any failure of its own instead of swallowing it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* /index shows names as the log does, one line of UTF-8, and a newline in a ↵Gabriel Schneider5 days
| | | | | | | | | | | | name as \n /index printed a name as it was, so a directory with a newline in it split its row in two, and bytes not UTF-8 went through; the log turned the newline into a space, silently another name. Both now show a name one way: a newline `\n`, other controls, DEL and C1 a space, bytes not UTF-8 `\xNN`. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Every EINVAL a write gets says why; DEL in an exec or look line is a control ↵Gabriel Schneider5 days
| | | | | | | | | | | | character An empty name, a word written to log other than follow, a data, sel, dot or dirty write to a pane with no text, a truncate other than to zero, and a control character in a look line written through a held open were refused with no words, logged as `Invalid argument`. Each says its reason now; and DEL is refused in exec and look lines as in names. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A name write is one name, refused with its reason otherwise; a log record is ↵Gabriel Schneider5 days
| | | | | | | | | | | | | one line of UTF-8 A name took a second line, DEL, a C1 control or bytes that are not UTF-8, which then went into /index and /log as they were and split or garbled a reader's lines. `name` strips one trailing newline and refuses the rest, saying which (`bad character in file name: not UTF-8`); and the log turns DEL and C1 into spaces, as it did control characters, and escapes bytes that are not UTF-8 as `\xNN`. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A rename alone does not make a pane dirtyGabriel Schneider5 days
| | | | | | | | | Any rename marked the pane dirty (saved revision one back), while the guards ask only whether its text was ever edited: /index said dirty for a pane Exit let go without asking. The name is no edit now, so /index, the guards and Restore agree; Save writes under the new name all the same. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A name written with a blank at either end is refused, not quietly trimmedGabriel Schneider5 days
| | | | | | | | | | `name` trimmed blanks off both ends, so `trailing.zig ` named another file than the one written without a word. acme refuses any blank in a name, `bad character in file name` (xfid.c:650); pardes takes one inside (it names files with spaces) and now refuses one at an end, and a control character, in acme's words. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A pane from pane/new is the session's directory's scratch, not the last ↵Gabriel Schneider5 days
| | | | | | | | | | active pane's No pane asked for it, so borrowing the directory of whichever pane last had the keyboard named it after an accident; acme's new window has acme's directory. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A chorded record written back with its two follow-ups runs once, with its ↵Gabriel Schneider5 days
| | | | | | | | | | | | | argument Writing a chorded exec's three records back as read ran the argument and its location as shell commands. The first record (flag 8) now takes the next record as its argument when it comes in the same write, else the one kept from the click (or, with none kept, waits for it); its two follow-up records, however they are written, are consumed as its, never run. Tested written back together and one per write. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A pane has a tagexec: a word run as a click in its tagGabriel Schneider5 days
| | | | | | | | | | The workspace had /tagexec and a column its exec, but a pane's own tag could be clicked only by an event record. pane/<n>/tagexec runs each line as a click in that pane's tag (never redirected to its event reader, as a header's is not) and reads back what it touched. The README, fs.md and the skill list it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A chorded exec an event reader holds is told its argument, and runs with itGabriel Schneider5 days
| | | | | | | | | | | | With event open, a 2-1 chord's exec went out as one record with flag 8 and nothing after it: the argument was freed unsaid. As acme does (exec.c:150-190), two records follow it, the argument's text and where it came from (file:#q0,#q1, empty when not known), and the pane keeps the argument, so the record written back runs with it (acme's own write-back, xfid.c:842, passes none; the reader was told, so it runs as the click would have). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* +Errors with no room anywhere logs its text rather than fail the EditGabriel Schneider5 days
| | | | | | | | | Edit's p and = put their output in +Errors, and when its column had no room the placement refusal failed the whole Edit. +Errors now tries every column with room, the last first, and with none its text is logged as msg records, a line each; the Edit succeeds. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* addr reads empty after a failed address instead of failingGabriel Schneider5 days
| | | | | | | | With no address after a failed write, a read of addr itself failed (EIO through a mount), which reads as a broken file rather than as no address. It now reads empty, as an unset limit does; data and xdata still refuse. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A limit write that fails keeps the limit it hadGabriel Schneider5 days
| | | | | | | | | A shell's > truncates limit, which lifted it, before the write; a write that then failed left no limit at all. The truncation now keeps the old limit until that open's write, and a failed write puts it back; a bare truncation still lifts it once its open is released. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Addresses snap to runes, not grapheme clustersGabriel Schneider5 days
| | | | | | | | | | sam and acme address runes; pardes snapped #n, line:col, dot and data's reads to grapheme clusters, so a lone combining mark or a CRLF's \r could not be addressed. #n, line:col, a search's match, dot (both ways) and data now land on rune boundaries (modal.runeStart and friends), and the tty's cell drawing is untouched. The README, fs.md and the skill say so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Columns are named by stable serials over 9P, as panes areGabriel Schneider5 days
| | | | | | | | | | | /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]>
* The tree serves the layout: /layout, /tag and /col/<n>/tagGabriel Schneider5 days
| | | | | | | | | | | | | 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 write to a closed pane's file says it is gone, and a terminal says why it ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | takes no name `echo Del > pane/6/exec` just after pane 6 closed failed EACCES: the shell's lookup failed, it tried to create the file, and the engine refused every Tcreate as a permission error. pardes now takes Tcreate itself: refused as before (acme's fsyscreate refuses it too), ENOENT in a pane that has closed. Renaming a terminal was refused with only EPERM; it now says a terminal is named by its shell's directory, worded so a mount still maps it to EPERM. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A truncating write to tag drops the one newline that ends itGabriel Schneider5 days
| | | | | | | | | `echo X > tag` stored X and a trailing newline, which drew an empty tag row. After a truncation the newline ending each write is held back until more text follows or the open is released, so the one ending the whole of it is dropped and any other stays; `>>` keeps what it is given. Co-Authored-By: Claude Opus 5.5 <[email protected]>