summaryrefslogtreecommitdiff
path: root/src/ninep
Commit message (Collapse)AuthorAge
* A write to sel leaves the text it wrote selected, as acme's wrsel does, so ↵Gabriel Schneider5 days
| | | | | | | | | | | cat sel reads it back; one open's writes run on from the last The selection collapsed to a point after the write, so sel read back nothing. What is written is now dot, and the next write of the same open goes at its end and grows it (acme's wrselrange), so a shell's several writes make one selection; another open's write replaces it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* pardes - keeps one +Pager per directory, refilled, named so from its first ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | | | | log record; streams the text in bounded writes; never loses it; handles \r, NUL and BEL as a terminal does Each paged command made another +Pager until placement failed, and then git's text was lost with exit 0; a 130 MB page timed out half written and dirty; a directory whose name held a newline left a stray +New; and the log said new +New then rename. The root ctl's `pager <dir>` now makes the directory's +Pager (named before it is announced, placed without the keyboard) or empties the one there; the text goes into it a line-ended 8 MiB chunk a write, one undo step, up to the file limit and its note, and is left clean. A directory a ctl line cannot name pages into the session's. Any failure prints the text to stderr with why and exits 1. A carriage return keeps a progress line's last state and CRLF is a newline; NUL, BEL, SO and SI go; empty stdin makes no pane. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* An event record is delivered in pieces to reads shorter than it, so a bash ↵Gabriel Schneider5 days
| | | | | | | | | | | | | read loop on event works A read shorter than the record waiting was refused EINVAL, and bash's read, a byte at a time on a file it cannot seek in, failed on the first record. A short read now takes the record's front and the next read the rest, as log and pty/data already did and acme allows. A unit test reads two records a byte at a time; selfmount runs a bash read on event through the mount. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A bare :N or :N:M look addresses the pane itself, its line N (column M), ↵Gabriel Schneider5 days
| | | | | | | | | | | | | from every way a look comes; a PDF's :0 has no page 0 A look of `:12` had no path to resolve, so it fell through to a word search for the text ":12" and found nothing. A digit-led address with no path now names the looking pane, as `:/re/` already did: its look, the root's (the keyboard's pane), Look, B3 and an event write-back all reach it, a terminal's logical lines included. On a PDF, :0 is the has-no-page miss rather than a refusal. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A terminal's kitty graphics draw as glyph art where pixels cannot, and by ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | | | | | choice: Petscii on the pane, TermImages for new ones Under an outer terminal without kitty graphics a tty pardes cannot pass a terminal pane's images on, so it draws them itself as an image pane's Petscii does: each row of an image is matched to C64-palette glyph art over the cells it covers (GlyphArt.renderRect, the exact-grid half of GlyphArt.render), cached while it is on screen. yazi is still told the kitty protocol works, so it keeps sending its previews. The same art is a choice anywhere: the Petscii builtin now takes a terminal pane too (PaneKind.picture), flipping its images between pixels and glyphs, and a terminal holding images, or drawing them as glyphs by choice, says petscii:on|off in its tag as an image pane does. TermImages real|petscii (default real) is what a new terminal starts with; it is in DumpConfig, /ctl and the reference. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* pardes - reads stdin into a +Pager pane, and is a terminal's PAGER and ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | | GIT_PAGER, Pager pardes|off to opt out; command panes page through cat A paging command in a terminal, or run through its pty/run, sat in less, and a pty/run never answered. `pardes -` now reads stdin to its end, strips terminal escapes (colour, OSC, overstrike), and shows it: inside a session as a clean <cwd>/+Pager pane made through pane/new and back at once, outside one as a new editor whose first pane it is, as `vim -` does. A terminal's shell gets PAGER and GIT_PAGER set to this pardes's own path and `-` where the user's environment sets neither; `Pager off`, a setting in /ctl, init and DumpConfig, leaves terminals started after it to the environment. A command pane's one-shot shell keeps cat, its output being a pane already. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A refusal's +Unsaved goes in the session's directory when the active pane's ↵Gabriel Schneider5 days
| | | | | | | | | | | directory is not there Exit or Restore refused over a pane named into a directory that does not exist made +Unsaved in that missing directory, where its rows could not be looked at and a Save of it could only fail. The list now goes in the session's directory when the asking pane's is not on disk. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A ctl refusal quotes the offending word alone, everywhere: wrong #args in ↵Gabriel Schneider5 days
| | | | | | | | | | | | control message "Newcol", not "Newcol 2" Some refusals quoted the whole line, arguments and all ("Newcol 2", "Verbose maybe", "lock x"), others the word alone ("Theme", "Mount"), so a script matching one could not match the other. Every ctl refusal, the root's, a pane's and a column's, now quotes the message's word alone, and one too long to quote whole gives up its middle. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A look at a file it may not read says which: "look: <path>: permission denied"Gabriel Schneider5 days
| | | | | | | | | The refusal said "look: permission denied", leaving the script to guess which of the paths it looked at was locked. A file or image that will not open is now named in the failure, its path cut in the middle when long. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* An event reader whose pane closes reads EOF, not ENOENTGabriel Schneider5 days
| | | | | | | | | | A script following a pane's event in a loop ended in an error when the pane went, though nothing had gone wrong: the pane was simply done. A read on an event open whose pane has closed now answers no bytes, the end a pipe's reader sees when its writer goes, so cat and while-read end cleanly. pty/data keeps acme's answer. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* /index and the log escape a control byte, DEL or C1 in a name as \xNN, as ↵Gabriel Schneider5 days
| | | | | | | | | | | they do a byte not UTF-8, so the name decodes to what it is A control byte in a name read as a space, so /index could not be decoded back to the name the name file now accepts (\x07 and a space read the same). Every byte a name holds that is not printable UTF-8 is now \xNN there; a message's text keeps spaces. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A builtin refused when its record is written back through event fails that ↵Gabriel Schneider5 days
| | | | | | | | | | | | write, EIO and its err, as fs.md says A Del refused over unsaved text, written back by an event reader, said so on the message row and answered the write ok, so the script that wrote it could not tell. The write-back now captures failures as an exec write does: the first one fails the write with its words and the errno they read as. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* One diff-aware expansion for a click, a 9P whole-line look and an empty ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | event write-back; a blank context line resolves to its path:line The mouse expanded a diff line by its kind (a header or a hunk line's prefix to the line's address, a hunk line's code to words), but an empty look written back to event used the plain word expansion, so ML on a `+` took nothing, and a 9P look of a blank context line (` `) was refused as whitespace. look.diffClick is now the one answer: the mouse, the whole-line look and the event write-back all ask it, and a blank context line is a line like any other. A test asks all three on each kind of line. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* log stats 0, and pardes re-pins cloud9 whose 9ns opens such a file direct ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | and nonseekable: fs.md's follow recipe with cat works through a mount The log stated the length an open would freeze, a length a mount's kernel could take as its end, and a splicing cat read it from the kernel's offset. log now stats 0, as the other streams and generated views do, and the re-pinned cloud9's 9ns opens any file stating 0 FOPEN_DIRECT_IO | FOPEN_NONSEEKABLE. A look at such a file (the mounted index) reads a regular file that will not seek as a stream rather than refusing it as a pipe. selfmount runs the recipe, exec 3<>log; echo follow >&3; cat <&3, through the mount and hears a record made after it started. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The reference is fs.md's per-file semantics, errors and limits in Typst, ↵Gabriel Schneider5 days
| | | | | | 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]>
* Mount with no dial is wrong #args, and a dial that is no address says bad ↵Gabriel Schneider5 days
| | | | | | | | | | | | dial address, both EINVAL Mount name alone failed "Mount name dial: missing argument" and a malformed dial "Mount: bad dial", both EIO, though each is a malformed request. They now say wrong #args and bad dial address (with the forms a dial takes), and a builtin failure in those words answers EINVAL, as 9ns reads them. 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 Schneider5 days
| | | | | | | | | | | | | 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 Schneider5 days
| | | | | | | | | | | | 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 Schneider5 days
| | | | | | | | | | | | 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 Restore brings back clean a pane whose file was never on disk, such as ↵Gabriel Schneider5 days
| | | | | | | | | | | | Config's new init; only a file that existed when dumped is said deleted A restored pane whose path was not on disk was marked deleted on disk, so Config's not-yet-written init came back dirty and asked before Del, Exit or Restore. The dump now records whether the file was on disk (older dumps read as yes), and only one that was and is gone is said deleted. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A shell's > into an empty pane's body is one undo step, as into any otherGabriel Schneider5 days
| | | | | | | | | | The truncation of an empty body is no edit and pushes no step, but it still marked the open's writes as joining the step it would have pushed, so the text written after it had no undo step at all. A truncation that changed nothing (of body, data or xdata) now leaves the step to the write that follows. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* :N on a PDF turns to page N, from the pane and from the root's look; @pN:N ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | answers ok with no err; an address in a pane with no text names the pane A PDF pane took :N as a word to search for, and @p<pdf>:N failed as "is no text to address" after the page had nothing to do with it, an err in the log for a look that meant something. A PDF's address is now its page: :N turns to it, one past the last is the has-no-page miss, and a byte offset or a pattern is refused saying a PDF's address is a page. The refusal for any other textless pane named an empty path when the look was a bare :addr; it names the image or @p<serial> now. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A shell command from the workspace's or a column's tag runs as a command ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | pane in the session's directory, never typed into the terminal with the keyboard A command clicked in a header tag, or written to /tagexec or a column's exec, was typed into the active terminal when it sat at an empty prompt, so it ran in that pane's directory and left no run or exit record. It now always gets a command pane of its own in the session's directory, as acme's row and column tags have no directory but the session's. tags.md writes the rule down: pane words act on the column's active pane, a column's words on the column, shell commands as their own panes, and over 9P a pane's word is refused. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A pane's tagexec goes to the event reader holding the pane as an x record, ↵Gabriel Schneider5 days
| | | | | | | | | | | | as acme's tag clicks do, not run past it A real click in a held pane's tag was already told to the reader, but the same click written to the pane's tagexec ran at once, so a script holding the pane could not intercept it. The line is now an x record (l for a look), done when the reader writes it back. A column's or the workspace's tag is still no pane's and runs as before. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Recent and /recent keep PDFs and images as they keep files, and an open ↵Gabriel Schneider5 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]>
* DumpConfig writes a setting this shell cannot show as a "# Word unsupported" ↵Gabriel Schneider5 days
| | | | | | | | | | | comment, GripWidth among them on the tty, so the whole report writes back to /ctl The report said it could be written back as is, but "Lift unsupported" and the tty's "GripWidth 100" were each refused by the root ctl, and "DumpDir (none)" would have named a directory "(none)". Those lines are now comments, and a test writes every line of the report back. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Every setting's bad-value refusal names what it takes: InactiveDim 0-100, ↵Gabriel Schneider5 days
| | | | | | | | | | | | MessageLinger 0-60000 milliseconds, a path's limit, a font's form A setting that chooses among words named them, but one that takes a number, a path or a font said only "bad value" over 9P and "does not take that value" from a tag, leaving the range to be guessed. The refusal, both ways, now says its range or what it takes, from one table beside the words. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A look's miss cuts a long path in its middle with the Rerror cutter, keeping ↵Gabriel Schneider5 days
| | | | | | | | | | | | the file's name, never mid-word at 64 bytes "is no text to address" cut the path at 64 bytes, often mid-word and losing the file's name, and the other misses cut theirs at 256 from the end, losing it too. Every miss now goes through fitErr, the cutter an Rerror uses, which gives up the middle of the longest path so the start and the name at the end both stay. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* 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]>
* Jumplist fills its one +Jumps again, as Recent does, never opening a secondGabriel Schneider5 days
| | | | | | | | Each Jumplist opened another +Jumps below the asking pane, so a few clicks stacked stale copies of the list. Recent's refill of its own pane is now shared, and Jumplist uses it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* After a ThemeFile, the root ctl and DumpConfig say ThemeFile and its path, ↵Gabriel Schneider5 days
| | | | | | | | | | | so what they report writes back Both said Theme and the name inside the .zon, which no Theme knows, so writing the report back to /ctl failed with "no theme". While a loaded ThemeFile is the theme in effect they now say the word that loaded it. A Dump carries the line too, so a Restore reloads the file. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A builtin for one kind of pane is refused on another with why: Petscii, ↵Gabriel Schneider5 days
| | | | | | | | | | | | | Palette, Ascii, Filter, Togglettymode, the Pdf words, Mode and TreeContext Each of these did nothing, silently, on the wrong kind of pane, so a ctl or exec write of Palette to a text file answered ok as if it had acted. A builtin now declares the one kind it is for (needs), the registry reads it, and runBuiltinFrom refuses the rest before dispatch, as Repl and Edit already refused theirs. Mode and TreeContext, which take more than one kind, say their own refusal. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Save and Save path on a PDF or image pane are refused, "a PDF pane has no ↵Gabriel Schneider5 days
| | | | | | | | | | | | text to save", never a silent success A bare Save on a PDF or an image did nothing, and `Save path` returned without writing, both answered as done. Such a pane shows a file it does not hold as text, so there is nothing of its own to write. Save now refuses it with why ("Save: a PDF pane has no text to save", or an image pane's), and so fails the write that asked. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Joincol is refused, as Newcol is, when the joined column cannot give each ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | pane its tag and 2 rows Joincol moved every pane of the keyboard's column into the next one whether they fit or not. Two columns of two panes in a 12-row window became one column of four, wanting 12 rows where 10 were free, a layout that `size` then refused as it stood. Joincol now tries the join in place first (layout.joinFits: the panes and width moved, minimaFit asked, everything put back, nothing dropped or logged). A join that does not fit is refused, "Joincol: no space: the joined column cannot give each pane its tag and 2 rows". 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 Schneider5 days
| | | | | | | | | | | 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 Schneider5 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 rename (mv) of a pane's directory or any file of the tree is refused as ↵Gabriel Schneider5 days
| | | | | | | | | | | | | not permitted, EPERM, not an EIO cloud9's engine passes a wstat that changes a name to the backend, and the tree's setattr ignored the name: the rename answered as done, the name did not change, and a mount then gave `mv` EIO. The tree names its own files, so a setattr with a name is now refused, "rename not permitted", which 9ns reads as EPERM. A pane's buffer is still renamed through its name file. 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]>
* A pane refused for want of room spends no pane serial, as a refused Newcol ↵Gabriel Schneider5 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]>
* fs.md says that in a > to a tag cut into several writes, those taken before ↵Gabriel Schneider5 days
| | | | | | | | | | | | | 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 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 Restore logs and names the whole path of the dump it reads, not the name ↵Gabriel Schneider5 days
| | | | | | | | | | | | | as typed `Restore x.dump.zon` read the DumpDir's x.dump.zon but logged `restore x.dump.zon`, and `~/d.zon` logged the tilde. A follower could not tell which file was restored. The builtin now resolves the name once (fs.restorePath: `~` expanded, a relative name the DumpDir's when one is there, else the current directory's) and hands that path to the host, which reads it and logs `restore <path>`. Its messages name it too. 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]>
* An empty range written back to event acts on the word a click there expands ↵Gabriel Schneider5 days
| | | | | | | | | | | | 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]>
* A focus moved over 9P tells the programs that asked for focus reports, as a ↵Gabriel Schneider5 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]>
* A 9P look keeps its leading blanks: an indented line, or blanks alone, is ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | 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]>
* A restored pane whose file is gone from disk comes back dirty, and Del asks ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | before throwing its text away A dump keeps a pane's text. Restored after its file was deleted, the pane came back clean: the watch's baseline read of the missing file failed quietly, and Del closed it without a word. Its text was then nowhere at all. Restore now checks the file: a local path with nothing on disk comes back as one deleted on disk, as the watch would have said. It says so once, logs `changed N deleted`, and is dirty, so Del, Exit and Restore ask first. 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 write of a multiple of 4096 bytes holds the partial line it ends with, as ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | 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]>