summaryrefslogtreecommitdiff
path: root/docs/fs.md
Commit message (Collapse)AuthorAge
* The reference is fs.md's per-file semantics, errors and limits in Typst, ↵Gabriel Schneider27 hours
| | | | | | with the settings table, and says what the pane ctl's Left, Right, Up and Down do Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Docs say how a look resolves a relative path: the looking pane's directory, ↵Gabriel Schneider27 hours
| | | | | | | | | | | then each jump-list pane's, most recent first fs.md's look section and tags.md said nothing of where a relative path is looked for, so a look that found a file in a directory visited an hour ago, or not in an open pane never visited, was a surprise. The order is written as look.zig's resolveLookTarget has it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Docs give a look miss's real words, that event is one reader's, the real cap ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | | on held reads, Dump's Restore word, a reused command pane's runs, and the one-write trap fs.md's look misses now read as the editor says them (<path>:99 has no line 99, has no page N); event says a second reading open fails file in use; held reads say the 64 state-holding opens are the real cap, under the 128 a connection may park; Dump says it adds a Restore word to the workspace tag; a reused command pane's body is said to keep each run under a % line, with how to take the last. The 9P skill gains the trap that bash's printf to a mounted ctl arrives one write per line. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Edit's w and the other left-out sam commands fail EIO in words, never ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | EOPNOTSUPP, and /os refuses a rename or a chmod as not permitted, EACCES "w is not supported in pardes" read through a mount as EOPNOTSUPP, as if the file system lacked an operation, and a chmod under /os was answered "invalid truncate", EINVAL. An Edit command pardes leaves out now says so in words 9ns reads as EIO, and a rename or mode change of an /os file is "permission denied", EACCES. fs.md's Failure section and /os entry say both. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* name takes any byte a file name can hold, controls, edge blanks and bytes ↵Gabriel Schneider27 hours
| | | | | | | | | | | | not UTF-8 included, so what name reads writes back as it was A pane opened on a file whose name held a tab, a control byte or bytes not UTF-8 read that name from its name file, and the same bytes written back were refused. Only what no file name holds is refused now: a second line and a NUL. The ctl word name still refuses a second blank after the word, as a line's words are split at blanks. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Views generated by each read stat 0, as acme's do: data, xdata, index, ↵Gabriel Schneider27 hours
| | | | | | | | | | | | layout, recent and listeners; fs.md says which files have real lengths A stat of index, layout, recent or listeners built the whole view to count it, and data and xdata reported the body's length though a read answers what addr selects. Those now stat 0, as screen and pane/new already did, and fs.md lists the files whose length is real and says to read the rest to the end. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A diff line looks up the path and line it names, as any look doesGabriel Schneider27 hours
| | | | | | | | | | | | | | | | | | | | | | | | 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 Schneider27 hours
| | | | | | | | | | | | 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]>
* Docs say what Rename, a look at a missing or unreadable file, Restore, a ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | PDF's body and one open's undo step do, and the PDF tag in its order fs.md said Rename lists the places; it says its count and lists none. It now also says a look at no such file is a logged miss while an unreadable one fails the write, that Restore brings no jump list back, that a PDF's body is read-only page text no address reaches, and that one open's writes are one undo step only while nothing else edits the pane between them. tags.md listed the PDF tag's words out of order. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* fs.md says a body write to a terminal is typed input, never a bracketed pasteGabriel Schneider27 hours
| | | | | | | | | | | A write to a terminal's body goes to its child as typed keys: no bracketed-paste marks around it, even when the program set 2004, so a newline in it is Enter and a shell runs each line. fs.md did not say which, and a script cannot guess. It does now, and a test writes to a terminal whose program asked for bracketed paste and checks the bytes sent are only the ones written. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Save path logs a save record naming the path it wroteGabriel Schneider27 hours
| | | | | | | | | | | 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]>
* name refuses a directory, EISDIR, when written, not at the Save that could ↵Gabriel Schneider27 hours
| | | | | | | | | | | | 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]>
* fs.md says that in a > to a tag cut into several writes, those taken before ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | a refused one stand A `>` to a tag that a client sends in several writes is checked a write at a time. When a later one is refused, the earlier accepted ones stay in the tag. Buffering the whole open to apply it or none would cost more than it saves, so fs.md now says what happens: each write stands on its own, and only the refused one changes nothing. A test covers a truncation, an accepted write, then a refused one. 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 Schneider27 hours
| | | | | | | | | | | | 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]>
* An empty range written back to event acts on the word a click there expands ↵Gabriel Schneider27 hours
| | | | | | | | | | | | to, as acme's expand does `ML960 960` or `MX1 1` written back with no text acted on the empty range between the offsets: a look of nothing, an exec of nothing. A click at a point expands to the word or file name under it, and acme's written-back event does the same. It now expands with look.expandedWord, as a no-drag click does, on its line of the body or tag. fs.md says so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* fs.md says a line held to the close reports its failure only as the log's ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | | | | err, and that a script needing the result ends its write with a newline fs.md said an Edit block never ended "fails at the close" with ``unmatched `{'``, which reads as the close failing. The close reports no error (round 24's decision: no clunk-time errors), and the write that sent the block had already succeeded. The failure is only the log's err record. The same holds for the tail of a 4096-multiple write that the close runs. fs.md now says so, gives both err texts, and tells a script that needs a line's result to end its write with a newline. tree.zig's "an Edit block still open when its open closes fails there with an err and changes nothing" is the test. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A 9P look keeps its leading blanks: an indented line, or blanks alone, is ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | | | | looked for as written Every line written to look or exec went through Messages.next, which trimmed blanks from both ends. A look of ` indented` then found the first bare `indented`, and a diff's blank context line ` ` looked at nothing. A look's line is now its text: only its `\r` and newline go. lookAt keeps the blanks for the word search too; it expands `~` only for a look that starts with one, and the path, address and command readings trim for themselves as before. runSearch keeps a pattern's blanks, since a builtin's argument comes trimmed already. An exec line is trimmed as before. fs.md says so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
*-. Release Pardes 0.9Gabriel Schneider27 hours
|\ \ | | | | | | | | | 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 Schneider27 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 write of a multiple of 4096 bytes holds the partial line it ends with, as ↵Gabriel Schneider27 hours
|/ / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | one that fills its Twrite does: a burst through a mount no longer runs its cut lines as two commands selfmount's 1000-line burst reported 943 lines, on main too. The log ring was not losing records: a follower opened before the burst heard exactly 943 and no `lost`, and the burst itself exited 1 with `err 1 exec: wrong #args in control message "Msg"`. `seq ... > exec` through the mount arrives as stdio's 4096-byte writes, each shorter than a Twrite. The rule that such a write is whole ran each one's cut last line at once, so both halves of the line ran as commands (hence `exit 127` records). At 12288 bytes the cut left a bare `Msg`, which was refused and failed the write and the rest of the burst. A write of a multiple of 4096 bytes is where a writer's buffer (stdio, a page cache) filled, so it may go on: its unended tail now waits for the next write or the close, like one that fills its Twrite. `printf Save > exec` stays whole at once. fs.md says so, the 9P fuzzer's model of served lines follows it, and a unit test cuts a `Msg` at 4096 bytes. A follower does not lose records silently: a ring that outruns one already reads it `lost N` first (documented, tested). selfmount now follows the log from before the burst, so it checks every line heard once, in order, or a loss said, not a fresh open of a 64 KiB ring. It passed 3 in 3 and joins the gates with the new 9ns. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | A path typed with a leading ~ is the home directory, at every entry point ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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]>
* | pane/new takes rows from a pane in another column before refusing ENOSPC, as ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | acme's placement does A pane/new whose column had no room was refused "no space for a pane in that column", even with another column holding a tall pane that could give rows. acme takes rows wherever a window has them before saying there are none. pane/new now tries the other columns as +Errors already did: an empty one, else its tallest pane's bottom half, last column first. It is refused only when no pane anywhere can give the rows. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | Kill with a name and nothing running says "Kill: nothing running" and ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | | | succeeds, as bare Kill does Bare `Kill` with nothing running is a message, not a failure: a script's Kill has nothing left to do. `Kill make` in the same state failed the write with "no running command has that first word", as though make were the mistake. With nothing running at all, named or not, Kill is now the message. It still fails when commands run but none has the word. The two tests that used `Kill zzz` as a builtin that always fails now use `Unmount zzz`. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | An event record written back without its trailing newline is taken, as every ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | | | | | | | | | | other line file's last line is `printf 'MX0 10' > event` was refused as a malformed record, while exec, look and every ctl take a last line with no newline. The event file now does too: a write not ending in a newline is read as though it did, and the write still counts the bytes that came. 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 Schneider27 hours
| | | | | | | | | | | | | | | | | | | | | | 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]>
* | fs.md gives the msize as 64 KiB, documents the Newcol refusal for tags that ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | would not fit, and says how 16 columns is really reached The docs said msize 8192, but the editor has offered 65536 since the bulk write work. They also told a reader to reach 16 columns without saying it needs a 160-cell window, or that Newcol halves the column it is run from. The "the panes' tags would not fit" refusal was not documented at all. The column paragraph now says all three, and that a refused Newcol logs its err alone. docs/cloud9.md's options line gives the current numbers. 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 Schneider27 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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]>
* | DumpConfig's lines that set nothing start with #, and a line starting with # ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | | | runs as nothing at an exec, a ctl or the init file DumpConfig's information lines ("Platform: tty", "Startup config: ...") began with words. Written back, as the report means to be, or clicked, each ran as a shell command or failed as an unknown control message. Each now starts with `# `. A line starting with `#` is a comment, as in a shell: it runs as nothing, silently, at an exec, at the root's, a pane's or a column's ctl, and in the init file. Documented in fs.md and config.md. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | winsize refuses fewer than 2 rows, saying so, and its range reads 1x2 to ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | 4096x4096 as the docs say `winsize 20 1` was taken and quietly raised to 2 rows, so the write succeeded with a size other than the one asked for. The range refusal also said "1x1 to 4096x4096", although fs.md says at least 2 rows. One row is now refused with "invalid winsize: at least 2 rows", and the range text starts at 1x2. size already refused anything under 20x6 with a text that names it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | With no pane at all, the root look opens its file and the root exec runs its ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | command in the session's directory /look and /exec run at the active pane, and with every pane closed they failed ENOENT, "file does not exist", about a file the writer never named. Now an exec runs as the workspace tag's would, in the session's directory: a builtin at the stand-in, a command in a command pane. An empty window's click now runs a command line too, not only session words. A look runs from a scratch made as New makes one, which also makes the column. That scratch is dropped, unannounced, when the look went to another pane, so opening a file leaves only the file. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | A connection holds up to 128 reads, the next refused "too many reads ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | waiting: 128", and a mount beside 40 held event reads still answers Two limits met. pardes parked 32 reads per connection and refused the next with EAGAIN's C string, "Resource temporarily unavailable". 9ns kept 32 tags and 31 workers, each pinned by a held read. So 31 followers through one mount took every worker, and `cat layout` then queued for ever: the whole mount deadlocked. cloud9 (705be665, pushed to sr.ht and pinned here) now refuses in words past the cap. Its 9ns window is 256, so a mount always has workers past what pardes holds. pardes raises its cap to 128. fs.md documents the limit beside held reads. selfmount.py holds 40 event reads through the mount and reads layout beside them. It times out with the 9ns installed before this change and passes with the new one. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | pardes FILE in a pane whose session answers never falls back to a nested ↵Gabriel Schneider27 hours
|/ | | | | | | | | | | | | | | | | editor: the refusal is printed, exit 1, and no stray pane is left When the environment named a live session that answered, several failures broke out of forwarding and started a whole editor inside the pane that asked: a refused name, a pane the session has not, a failed look write. Its screen was drawn over the shell. Now, once the session answers (Client.probe), every refusal is printed as `pardes: <file>: <why>`, in the session's own words (the Rerror, now kept by the client), and the launch exits 1, as acme's B does. A new name the session refuses deletes the pane made for it, so no empty +New is left. A missing environment or a session that does not answer still starts a separate editor. fs.py checks a refused name and a stale PARDES_PANE. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* fs.md and the 9P skill say what the language server words do over 9PGabriel Schneider27 hours
| | | | | | | | | | | Hover, Rename, Diagnostics, Symbols, Lspinfo and Lspwhy work through exec like any builtin, but neither fs.md nor the SKILL named them. So a script did not know they act at the cursor (set with addr and dot=addr), where their answers land (+Hover, +Search, +Lsp), that the write waits for the answer, or that Lspwhy explains the last query. Each now says so briefly, the SKILL with a short example. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A column's and the workspace's tag read with no trailing newline, as a ↵Gabriel Schneider27 hours
| | | | | | | | | | | pane's does A pane tag read back its text alone, but a column tag and /tag appended a newline and gave a stat size one byte longer. So `$(cat tag)` agreed across the three kinds while `cat tag | wc -c` and a byte compare did not. All three now read the text alone, and fs.md says so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A builtin that takes no argument, written with one to an exec, is refused ↵Gabriel Schneider27 hours
| | | | | | | | | | | | wrong #args as at a ctl At a ctl, `Config extra` and `DumpConfig extra` were refused with `wrong #args`. Written to an exec, the builtin match missed, since the word takes no argument, and the line ran as a shell command named Config, which did nothing and said nothing. An exec now refuses it with the ctl's words. A setting word keeps its value (`Verbose off`). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* acme's Tab, Indent, Local, Incl and Abort are refused as acme words pardes ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | has not, never run as shell commands The five were missing from the refused list, so at an exec or a ctl a typed `Indent on` fell through to the shell as a command named Indent. pardes has no equivalent for any of them: its tabs and indentation follow the file, commands always run in the pane's directory, and there is no include path or abort. They now get the same "invalid: acme's X is not a pardes builtin" as Zerox or Send. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A pattern anchoring some alternatives with ^ and not others is refused with ↵Gabriel Schneider27 hours
| | | | | | | | | | | | why, not a bare bad regular expression `^def|x` and `foo$|^zèbre` were refused with a bare "bad regular expression", the same words as a syntax error, so a script could not tell what to change. They now say "an alternation anchors every branch with ^ or none (^a|^b, not ^a|b)", through addr and Edit alike. fs.md states the rule and that a `$` does not count toward it (`foo$|bar` is fine). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* pardes NEWFILE in a pane forwards even when its directory is missing, and ↵Gabriel Schneider27 hours
| | | | | | | | | | | | | | | | 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 word at /tagexec or a column's exec that makes, acts on and focuses no ↵Gabriel Schneider27 hours
| | | | | | | | | | | | pane reads back nothing Newcol written to /tagexec read back `1`, the pane with the keyboard, which the word never touched. That was a pane word's fallback (a pane's exec answers the pane it ran at) applied to a tag no pane owns. A word in a column's or the workspace's tag now answers the pane it made, refilled, went to or focused, and otherwise nothing. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Pane, column and workspace tags take one set of write checks, and a refused ↵Gabriel Schneider27 hours
| | | | | | | | `>` 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]>
* A tag write past the limit says tag: no space: over 4096 bytes, which 9ns ↵Gabriel Schneider27 hours
| | | | | | | | 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]>
* A dump holds every column a session may, 16, not 6Gabriel Schneider27 hours
| | | | | | Dump of a session with more than 6 columns failed bad dump columns, since dump.zig's max_cols was 6 while a session holds MAX_COLS. It is MAX_COLS now; the limit's lines in docs/fs.md and docs/divergences.md go. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The docs and the 9P skill say each fact once, in the file that owns it, and ↵Gabriel Schneider27 hours
| | | | | | say only what a live session does Co-Authored-By: Claude Opus 5.5 <[email protected]>
* pardes --wait (-w) in a pane returns only once the pane its file landed in ↵Gabriel Schneider27 hours
| | | | | | | | is deleted, so it can be $EDITOR A launch inside a pane forwards its file to the session's look and returned at once, so fish's Ctrl-O (edit_command_buffer), git commit and crontab -e read their still-unedited file back and went on. With --wait, as acme's E against B and read the way plan9port's E reads acme's log, it finds the pane /index names the file by (the one already showing it, if open), follows /log on one connection with 'follow new', reads /index once more to catch a Del that came first, and then blocks with no deadline until that pane's del record: exit 0, or 1 when the connection ends with the session. The 9P client's one-shot requests keep their 2 s deadline; its new follow takes it for the setup only. Outside pardes nothing changes. --help, docs/fs.md, the README and the 9P skill say to set EDITOR='pardes --wait', which GIT_EDITOR follows. Tested in fs.py (it returns within 50 ms of the Del, a second -w waits on the same pane, one whose session is killed exits 1) and end to end: fish 4.8 in a detached session, echo hi, Ctrl-O, the waiting launch idle in poll, the line edited over 9P, Save, Del, and fish ran echo edited. 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 Schneider27 hours
| | | | | | | | 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]>
* A name written whole with no newline is checked with its write, as the docs ↵Gabriel Schneider27 hours
| | | | | | | | now say, not at the close Round 24's no-newline rule (uwzuqzxp) already covers name, a lines file; the 9P monkey's close_runs_only_line_files repros were from a binary before it. This pins it with a test and corrects docs/fs.md, which still said such a name waited for the close. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A class with non-ASCII runes matches them: [éa-z] is taken as (é|[a-z]), a ↵Gabriel Schneider27 hours
| | | | | | | | range up to 256 runes spelled out mvzr's classes hold bytes, and it refused a multibyte member as a bad expression. Rewriting the class before compiling, as ^a|^b already is, needs no mvzr patch; runes that differ only in their last byte go as one alternative (\xc3[\xa0-\xbf] for [à-ÿ]) so a 256-rune range fits the 512-operation limit, which counts the pattern as rewritten. A wider range and [^é] are refused, naming why. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A pane's ctl reads acme's fields in acme's order, the undo and redo flags ↵Gabriel Schneider27 hours
| | | | | | | | included, then pardes's own Where plan9port's line has whether Undo and Redo have a step, pardes's had current, so a client reading acme's fields by position read a word for a flag. The two flags now follow the tab width, as in plan9port's winctlprint, and current|notcurrent and a REPL's id come after them. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A pane's ctl takes acme's ctl words, done by the files that replace themGabriel Schneider27 hours
| | | | | | name, put, clean, dirty, del, delete, dot=addr, addr=dot, limit=addr, mark, nomark, show and cleartag were unknown control messages. Each is now done by the file or builtin that replaces it (name, Save, dirty, Del, a Del that does not ask, dot and addr and limit, mark, the tag), checked with the rest of the write before any runs; dump, dumpdir, font, menu and nomenu are refused, EINVAL, saying where pardes does it or that it has no such thing. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* acme's words run as pardes's or are refused, never as shell commands: Put savesGabriel Schneider27 hours
| | | | | | Put, Get, Delete, Snarf, Cut, Paste, Zerox, Sort, Putall, Load, ID and Send written to exec or tagexec each ran as a shell command that exited 127, the write answering 0 -- a Put that looked like a save. Put now runs Save and Delete a Del that does not ask; the rest are refused, EINVAL, invalid: acme's X is not a pardes builtin (with where pardes does it, where it does), in exec and ctl alike. Co-Authored-By: Claude Opus 5.5 <[email protected]>