diff options
| -rw-r--r-- | .agents/skills/pardes-9p/SKILL.md | 34 | ||||
| -rw-r--r-- | docs/fs.md | 28 | ||||
| -rw-r--r-- | src/fs-help.txt | 2 |
3 files changed, 49 insertions, 15 deletions
diff --git a/.agents/skills/pardes-9p/SKILL.md b/.agents/skills/pardes-9p/SKILL.md index 39f80497..2892b134 100644 --- a/.agents/skills/pardes-9p/SKILL.md +++ b/.agents/skills/pardes-9p/SKILL.md @@ -96,7 +96,7 @@ $m/pane/new open it to make a pane (a scratch named <dir>/+New), read names it empty, else taking the bottom half of its last pane (ctl `Placement pardes`: the old rules); a session holds 64 panes (16 on the board): past that, every route that opens one fails with `no space for a pane: 64 max` (ENOSPC), and so does one whose column - has no rows left (each pane keeps its tag and 2 rows: `no space for a pane in that column`); rmdir $m/pane/<n> closes it; a column's last pane leaves the column EMPTY + has no room (each pane keeps its tag and 2 rows: `no space for a pane in that column`); rmdir $m/pane/<n> closes it; a column's last pane leaves the column EMPTY (focus reads empty, the log says only del), and the session's LAST pane QUITS it $m/pane/<n>/errors write-only: text appended to the +Errors pane of the pane's directory $m/os/ the host filesystem @@ -145,7 +145,9 @@ active pane from the root and at that pane from `$m/pane/<n>/look` and made, or the pane it focused or acted on: an open's own last write's, or, on an open that never wrote, the session's last. With other clients about, write and read one open (`exec 3<>$m/look; echo x >&3; cat <&3; exec 3<&-`). -Each command line runs once whole, however a mount cuts a big write; a last +A read is a stream: once read, a second read on the same fd gives EOF (on +an open that wrote, until its next write); open again, or seek to 0, to read +it again. Each command line runs once whole, however a mount cuts a big write; a last line with no newline runs when the open closes, and an Edit block still open then fails there (an `err`, ``unmatched `{'``), changing nothing. A command that fails is reported in the editor, not as a write error, so inspect the resulting pane, index, message @@ -210,6 +212,22 @@ env printf 'Edit ,x/foo/{\ni/</\na/>/\n}\n' > $pane/ctl `p` and `=` print to the directory's `+Errors`. Not there: `b B D e r w f X Y`, `< | >`, and `\1`-`\9` in `s`. +> **sam gotchas** (as sam does them, pardes too) +> - `$-1` is the last line when the text ends in a newline (`a\nb\n`: `b\n`), +> but the one before it when it does not (`a\nb`: `$` is on `b`, so `a\n`). +> - A line past the end is the empty line there, not an error: `N+1` at the +> last line is `#<len>,#<len>`; only the line after that is out of range. +> - `^` and `$` match at the text's end too: `/^/` from the end finds the +> empty place after a final newline. +> - `2,1` is no error: it is `#<start of 2>,#<end of 1>`, an empty range at +> line 2's start (only a range whose end is before its start is refused). +> - `y` yields the stretch before the first match too, empty if the text +> starts with one: `,y/a/` on `abc` gives `` and `bc`. +> - `c/&/` puts a literal `&`; only `s` expands `&` to the match. +> - `line:col` columns count bytes from 1: `12:0` is refused +> (`a column counts from 1`); a tool's character column is the same only +> on an ASCII line. + | Operation | Shell | Python client | |---|---|---| | Read text | `cat $pane/body` | `client.read(pane + '/body')` | @@ -220,7 +238,8 @@ env printf 'Edit ,x/foo/{\ni/</\na/>/\n}\n' > $pane/ctl | Delete that range | `: > $pane/data` | truncate `data` (open with OTRUNC) | A write leaves `addr` just past what it wrote, so a second `echo x > data` -inserts after the first: write `addr` again before each replacement. +inserts after the first: write `addr` again before each replacement. A read +of `data` or `xdata` moves `addr` past what it read, as in acme. Truncating `data` is pardes's own (acme ignores OTRUNC and always inserts). | Read the selection | `cat $pane/dot` (offsets), `cat $pane/sel` (text) | the same two reads | | Select the addressed range | `cp $pane/addr $pane/dot` | `client.write(pane + '/dot', client.read(pane + '/addr'))` | @@ -329,12 +348,15 @@ or `line:col` inside a rune snaps back to its start, a match covers the runes it touches, and a combining mark or a CRLF's `\r` is addressable alone. A Restore puts a new editor under every client: the Restore write is answered, then every connection is hung up (their fids name the old -editor's panes); dial again, and the new log names the restored panes then -`restore <path>` -- the authority, since a slow client may see the cut +editor's panes); dial again, and the new log has a `new` for each restored pane, then +`restore <path>`, then `restored <old> <new>` for each pane and +`restoredcol <old> <new>` for each column -- `restore <path>` the authority, since a slow client may see the cut before the answer. A 9ns older than cloud9 2a7137c could fail the Restore write with ECONNRESET although the Restore went ahead; trust the log. `Dump` writes `pardes-<date>-<time>.zon`, the time in UTC, under `DumpDir` (`$XDG_DATA_HOME/pardes`, else `~/.local/share/pardes`) and logs -`dump <path>`. +`dump <path>`. A relative `Restore <path>` is looked for in `DumpDir` first, +then in the directory pardes started in; a bare `Restore` takes the last dump +this session wrote (none yet: refused, name one). Read the event implementation before building an interceptor. Close handles in `finally`, and disconnect after a socket timeout. The service shares sixteen connection slots (the next client's version gets `too many connections`) @@ -111,7 +111,9 @@ Existing Plan9port/v9fs clients need a userspace bridge for QUIC. keep their tag and 2 rows; a terminal's pty follows its pane on every resize /commands every builtin: word, `arg` if it takes one, `root` or `pane` (the ctl that takes it), a setting's values /layout one line per column, left to right: serial index x width current|notcurrent - empty|full pane-serials...; then active <serial>: the active column, where + (the column with the keyboard now) empty|full pane-serials...; then active + <serial>: acme's activecol, which the keyboard leaving for another column's + tag does not move, so the two can differ -- the active column, where pane/new and a look place a pane next (- when there is none) /tag the workspace tag; > replaces it, >> appends, one line /tagexec write a word: a middle click on it in the workspace tag; read as /exec @@ -123,7 +125,7 @@ Existing Plan9port/v9fs clients need a userspace bridge for QUIC. 64 panes (16 on the board); at that, every route that would open one -- this open, look, exec, New, Tty -- fails with `no space for a pane: 64 max` (ENOSPC through 9ns, which has no word for ENFILE) and an err - record, and look reads back empty; a column with no rows left for one + record, and look reads back empty; a column with no room for one (each pane keeps its tag and 2 rows) refuses it the same way, `no space for a pane in that column` (docs/tags.md) /pane/<n>/ name body tag ctl addr dot limit data xdata sel dirty mark scroll @@ -160,7 +162,9 @@ unsaved text, a `+New` scratch of 100 bytes or more too, in one line, `<name>, <name>: Modified (Exit again to discard)`, and a second `Exit` with nothing edited since quits, throwing that text away; a scratch or a command's output under 100 bytes is not asked about, as acme's winclean -asks about no small unnamed window; `Restore`, which replaces every pane, +asks about no small unnamed window (so a scratch's `dirty` of 1 in `/index` +blocks nothing until it holds 100 bytes: it has no file to be out of step +with, and a few lines typed to try something are not work to lose); `Restore`, which replaces every pane, asks the same first -- `Dump` writes `pardes-<date>-<time>.zon` (UTC) in `DumpDir` (default `$XDG_DATA_HOME/pardes`, else `~/.local/share/pardes`) and logs `dump <path>`, and `Restore` with no path takes the last one; a @@ -402,7 +406,10 @@ pane a look focused or the pane an exec acted on (even one it closed), one per line; a look that found text answers the pane the text is selected in, not the hits buffer it opened. -The answer belongs to the open, as /net/tcp/clone's does: an open that +Reads are a stream: once an open has read the answer, a second read on it +gives EOF (on an open that wrote, until its next write); open it again, or +seek to 0, to read it again. The answer belongs to the open, as +/net/tcp/clone's does: an open that wrote reads what its own last write touched, from the start after each write, whatever offset the read comes at (a shell's `exec 3<>look` shares one offset between its write and its read, as with `pty/run`); an open @@ -540,7 +547,8 @@ whole buffer. Truncating `data` is pardes's own: acme ignores OTRUNC there (editors/acme/fsys.c:543) and every write inserts. And as in acme a write leaves `addr` just past what it wrote, so a second `echo x > data` deletes the empty range there and inserts after the first rather than replacing it -again; write `addr` before each replacement. +again; write `addr` before each replacement. A read of `data` or `xdata` +moves `addr` past what it read, as acme's does. `addr` belongs to the pane rather than to a client and keeps what was written until someone writes another, so writing an address and reading it back evaluates it, which is what acme(4) promises of its own `addr`. Unlike acme, @@ -645,9 +653,12 @@ the `del` of a terminal whose shell exited by itself, `ask <serial> <what> <choices>` when a pane asks a question (answered by `answer` on its ctl), `answer <serial> <choice|->` when it is answered, by key or ctl, `-` for taken back or for its pane closing with the question standing, -and `save <serial> <name>`, +`changed <serial>` when a pane's file changed on disk under its unsaved +edits (below), and `save <serial> <name>`, `dump <path>` when a Dump is written and `restore <path>` in a Restore's -new log after its panes' `new`s, then `restored <old> <new>` for each pane, +new log after its panes' `new`s (a relative Restore path is looked for in +`DumpDir`, then in the directory pardes started in; a bare Restore takes the +last dump this session wrote), then `restored <old> <new>` for each pane, mapping the serial it had to the one it has now, and `restoredcol <old> <new>` for each column, and `msg <serial|-> <text>` for every line the editor says (with `verbose` on, that includes each @@ -668,7 +679,8 @@ itself, is counted rather than repeated (`err 3 addr: no match for regexp (x4)`: four in all, counting the first), so a client retrying a failing write does not push the rest out of the ring. A record a follower has already read is never rewritten: the next repeat is a line of its own -carrying the running total, `(x5)`, and counting goes on from there. Through a kernel mount a client sees only an errno, which 9ns reads from the +carrying the running total, `(x5)`, and counting goes on from there, so a +follower sees each count as a new line. Through a kernel mount a client sees only an errno, which 9ns reads from the error's words (cloud9's 9ns/src/nine.zig, `enameToErrno`): a malformed write -- an unknown or ill-formed control message, `bad address syntax`, `bad regular expression` -- is EINVAL; a lock another open holds, EBUSY; a pane diff --git a/src/fs-help.txt b/src/fs-help.txt index be618be9..60ce4d4e 100644 --- a/src/fs-help.txt +++ b/src/fs-help.txt @@ -5,7 +5,7 @@ index one line per pane: serial, kind (text|term|pdf|image), dirty flag, n status pid, version and pane count look write a line: a right click on it at the active pane; read: the serials it touched (this open's) exec write a line: a middle click, an editor command word or a shell line; read the same (every exec file) -log events: new del rename save newcol delcol run exit send ask answer dump restore restored restoredcol msg err +log events: new del rename save newcol delcol run exit send ask answer changed dump restore restored restoredcol msg err screen rendered screen as JSON, frozen from open to close listeners the session's dial addresses focus the serial of the pane with the keyboard (empty on a column tag); write a serial to give it the keyboard |
