summaryrefslogtreecommitdiff
path: root/docs
Commit message (Collapse)AuthorAge
* A diff reads as the code it changes: hunks in their file's language, added ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | and removed rows tinted A .diff or .patch pane, and a command pane whose output is a diff (`git diff`, `git show`, `diff -u`; told by a `diff --git` line, or `---`/`+++` with a `@@` under them, in its first rows), colour each hunk's code in the language of the file its section names (`+++ b/<path>`, `--- a/<path>` for a deleted file), with tree-sitter, as highlightLocations does for results. src/diff.zig walks a unified diff by its `@@` counts, so a removed line that reads `--- x` is no header. Each side of a hunk is parsed as one text (context and removed lines the old side, context and added lines the new), so a string or comment across lines colours as it does in the file; a side no line takes its colours from is not parsed. A section's hunks share a parse, in pieces of about 40 lines (a hunk past 80 is cut), only those in view, and each piece's colours are kept by its bytes, so scrolling back and a terminal's every repaint parse nothing again. Added and removed lines carry a flag in their style byte; the painter tints their rows to the pane's edge, a little way from the page toward the theme's ANSI green or red, and draws the prefix in that hue pushed to read on it. A file in no known language keeps the old line colours. A command pane is read once its command has finished: its rows are copied once (File.DiffOutput, dropped when the pane runs again), so no frame dumps the scrollback, and painted over what git printed. A running command is shown as it prints. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A path typed with a leading ~ is the home directory, at every entry point ↵Gabriel Schneider2 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]>
* pane/new takes rows from a pane in another column before refusing ENOSPC, as ↵Gabriel Schneider2 days
| | | | | | | | | | | | | 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 Schneider2 days
| | | | | | | | | | | | | | 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 Schneider2 days
| | | | | | | | | | | 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 Schneider2 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]>
* fs.md gives the msize as 64 KiB, documents the Newcol refusal for tags that ↵Gabriel Schneider2 days
| | | | | | | | | | | | | 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 Schneider2 days
| | | | | | | | | | | | | | | | and Save path alike Whether a Save made missing directories depended on how the name had come about. Config's pane did, a name written into a missing directory did (since kkrqxtsp), and `Save path` and every other name did not, failing ENOENT instead. There is now one rule: a Save makes the parent directories of the file it writes, a pane's own or a terminal's scrollback included, and the make_dirs flag is gone. A directory it cannot make still fails the write with why, as fs.py's /nonexistent-pardes-dir case shows. fs.py now also saves into missing directories by Save path and by a written name. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* DumpConfig's lines that set nothing start with #, and a line starting with # ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | 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 Schneider2 days
| | | | | | | | | | | | | 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 Schneider2 days
| | | | | | | | | | | | | | | 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 Schneider2 days
| | | | | | | | | | | | | | | | | | | 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 Schneider2 days
| | | | | | | | | | | | | | | | | 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]>
* Release Pardes 0.7Gabriel Schneider2 days
|\ | | | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]>
| * lapis_plain: lapis on flat grounds, with its framed and shadowed tags and ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | its file-name shadow No dot grid under the text and no stripes behind the focused tag; every colour, the gold frames and vermilion shadows of the plaques, the rules, the scroll column's checker and the title shadow stay lapis's. It follows lapis in the ring and the Themes picker. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | fs.md and the 9P skill say what the language server words do over 9PGabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | 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 Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | 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 Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | 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 Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | | | 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 Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | 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 Schneider2 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 word at /tagexec or a column's exec that makes, acts on and focuses no ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | 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]>
* | DumpConfig prints each setting as the ctl word that sets it, reads ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | unsupported for one the frontend lacks, and includes LocationsConfig The report meant to be feedable back as configuration, but several lines were not. Shell and Font each took three to six lines of "requested", "effective" and "pending". The transition read "Panel transition PanelSlide", with no Panel word. WindowOpacity and TaglineSize carried "(pending)" and "(build-time only)". A GUI-only toggle such as Ligatures was left out on the tty, and LocationsConfig was missing altogether. Now every line up to a blank one is a word and its value: - Shell <path>; - Font <name>:<size>; - one on/off line for each Panel word; - `unsupported` for a setting this frontend does not have; - LocationsConfig as it would be typed. After the blank line comes what is in effect but set by no word, phrased so that none of it starts with a ctl word. The test checks that each line before the blank one starts with a setting word. The GUI scripts that read the font lines (font_size.py, appearance_gallery.py) now read the new ones. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | Pane, column and workspace tags take one set of write checks, and a refused ↵Gabriel Schneider2 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]>
* Release Pardes 0.6Gabriel Schneider2 days
|\ | | | | | | | | | | Merge: audit top-five cuts + tag sweeps + Config/DumpConfig (on the audit bug fixes C9, C2). Co-Authored-By: Claude Opus 5.5 <[email protected]>
| * Config opens the startup file, DumpConfig the settings report, and the ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | workspace tag reads Dump Themes Config Debug Exit Config (SPC f c) opens init, found as the settings report finds it (opts.startup_config_path: $XDG_CONFIG_HOME/pardes/init or ~/.config/pardes/init, and the macOS and Windows paths config.md gives). A pane that already holds it is gone to instead; a file on disk is looked at; with none, an empty pane is named for it, and Save makes its directory and any above it first (File.make_dirs, fs.makeDirs) before writing. Without a configuration directory it says so and opens nothing. The report Config used to open, the startup path and every live setting, is DumpConfig, in a +DumpConfig pane. No alias keeps the old meaning. The workspace tag's default words put Themes where NextColor was, NextColor staying a builtin, and Config beside it. A tag the user edited is kept as it was: a dump stores only an edited one (topbar_custom), and a restore puts back only that. theme.snap types NextColor onto the workspace tag to click it, and tagnav's walk back to Dump takes five long-word steps. The rest of the re-recorded goldens differ in the workspace words and their widths only. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | The PDF benches share their clock, fatal exit, hash, count parser and effect ↵Gabriel Schneider2 days
| | | | | | | | | | | | | | | | drain, and lspprobe is lspbench's probe subcommand B4: test/bench_util.zig holds what pdf_bench, pdf_pointer_bench, pdf_scroll_bench and pdf_sections_bench each copied (nowNs x4, fatal x3 named per bench, mix x3, parsePositive/parseCount x3, drainEffects x2). They stay four entry points: pdf_bench links its own mupdf module (with its C source and c_heap) where the others link the core's, which one executable cannot import under one name, and their reports and identities are each bench's own. pdf_sections_bench had rotted since the pane's cursor and selections moved to its body and the render revision became next_raster_revision; it builds and runs again. C6: tools/lspprobe.zig is lspbench's `probe` subcommand (zig build lspbench -- probe <kind> <file> <line>:<col>), and the lspprobe build step goes; docs/lsp.md names the new command. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | Zig files go to zls as a child process through the protocol client, as every ↵Gabriel Schneider2 days
|/ | | | | | | | other language does: the in-process ZLS backend goes lsp_zls.zig (1,522 lines), the zls dependency, build.zig's zls wiring and the import graph it baked into the options only for it, and main.zig's reference go. lsp_client's table gains a zls row (PARDES_LSP_ZIG overrides it); Hover, Rename, Diagnostics, WsSymbols, Lspinfo and gd answer through it (checked with lspprobe and the snapshots against zls 0.16.1-dev). What changes for a user: zls must be on PATH; a completion's rows are zls's candidates at the cursor, where the linked analyser gave each one's declaration; document symbols carry no signature. The Zig snapshots (lsp, lspcomplete, lspcompletemoved, lspdebug, lsprelpath) run the real zls now: lspdebug reads the client's explain and report, lsprelpath spells gr's rows where it spelled a completion's, and their goldens are recorded again (stable over three runs). Lspinfo still opens with its backend line. The ReleaseFast tty binary is 105.35 MB to 96.28 MB, the Debug one 296.5 MB to 245.9 MB. docs/lsp.md, web.md, design.typ and the README say so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Terminal.zig is terminal.zig: a file of functions and no fields takes a ↵Gabriel Schneider2 days
| | | | | | | | namespace's lowercase name The last of the deferred renames, now that the tty and theme agents have landed: panes.terminal at its importers, the alias lines in Text.zig and File.zig and panes.zig's own uses following. dump.zig's Terminal struct, a dump record, is not this. The served sources list and docs/design.typ name the new file. test/perf.zig's references change, so the three perf baselines take its new harness id with their numbers as recorded. No behaviour changes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* tag_layer.zig folds into Layer.zig, whose TagHit its two functions work onGabriel Schneider2 days
| | | | | | Two functions (sameCell, columnAt) on Layer.TagHit, 32 lines with their imports, used by edit.zig, mouse.zig and look.zig: they sit with the type now, called Layer.sameCell and Layer.columnAt. docs/design.typ names Layer.zig in its place. No behaviour changes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Mini.zig is mini.zig: a file of functions and no fields takes a namespace's ↵Gabriel Schneider2 days
| | | | | | | | lowercase name The naming the split agreed on, deferred until now; panes.mini is its name at its importers. File.zig keeps its alias line (const Mini = panes.mini) so the file another agent is working in changes by that line alone. The served sources list and docs/design.typ name the new file. No behaviour changes; test/perf.zig's two references change, and since the perf harness is keyed by its own text, its three baselines are recorded again (under other agents' builds, so a little slower). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* shader_build.zig is ShaderBuild.zig: a file that is a struct (its fields are ↵Gabriel Schneider2 days
| | | | | | | | the post chain's builds) takes a type's name The naming the split agreed on: a file with fields is a type, TitleCase, as Messages.zig and Layer.zig are. Its importers bind it as ShaderBuild; comments and docs/render-pipeline.md name the new file. 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 Schneider2 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]>
* A Dump makes every directory missing on the way to its DumpDir, as a fresh ↵Gabriel Schneider2 days
| | | | | | | | HOME needs outPath made only the last directory, so on a HOME with no ~/.local/share the default DumpDir failed no such directory. It now makes each missing parent, as mkdir -p; the known-wrong line in docs/divergences.md goes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* pardes NEWFILE in a pane opens a pane named it in the session, as acme's B ↵Gabriel Schneider2 days
| | | | | | | | does, and a start with no terminal says so A name that did not exist yet failed resolveOs, so the launch fell through to starting an editor of its own, which on a pty with no controlling terminal (a detached session's) ended in a NoDevice error trace. A new name's directory is now resolved and the name kept: the launch reads pane/new and writes that path to the pane's name, so Save creates the file, and --wait waits on that pane (the git commit case). A standalone start whose /dev/tty will not open prints why and exits 1. fs.py covers both; the known-wrong line in docs/divergences.md goes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A dump holds every column a session may, 16, not 6Gabriel Schneider2 days
| | | | | | 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 Schneider2 days
| | | | | | 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 Schneider2 days
| | | | | | | | 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 Schneider2 days
| | | | | | | | a write to pane/new, is its error alone, and every refusal is said in words The one-failure rule is a write's. A refused remove, pane/new's open refused for want of a slot, and an OTRUNC open's refused truncation (data's after a failed addr) also logged an err, and a reply carrying only an errno reached the client as the C library's text (Operation not permitted). tree.handle now gives such a reply Plan 9's words, chosen so 9ns maps each back to its errno (EPERM's to EACCES, as Plan 9's does), and serveFs logs errs for writes only, not a write to pane/new, which is only read. docs/fs.md and the 9P skill say so, and that a look miss quotes what was written. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A name written whole with no newline is checked with its write, as the docs ↵Gabriel Schneider2 days
| | | | | | | | 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 Schneider2 days
| | | | | | | | 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 Schneider2 days
| | | | | | | | 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 Schneider2 days
| | | | | | 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 Schneider2 days
| | | | | | 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]>
* A refused Delcol changes nothing: no +Unsaved opens, no focus movesGabriel Schneider2 days
| | | | | | Delcol's refusal opened +Unsaved, placing a pane in the layout it was refusing to change. Its unsaved records and notice say which panes; the list pane is left to the refusals of the other words. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The docs say how a follower sees repeats, what caps Newcol, that Restore ↵Gabriel Schneider2 days
| | | | | | starts undo afresh, where dot ends after data and sel, and where $ sits on a CRLF line Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A tag write past the limit is refused whole, naming itGabriel Schneider2 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]>
* Mini with no argument is wrong #args, EINVAL; Find, Grep and Mini say their ↵Gabriel Schneider2 days
| | | | | | | | names capitalised Mini needs a file but did not say so, so a bare Mini ran and failed EIO. It now requires its argument, refused wrong #args (EINVAL) as every such word is. Its failures, Find's and Grep's start with the builtin's own name (Mini:, Find:, Grep:), as the others' do. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* pty/run takes one line a run, its answer read before the nextGabriel Schneider2 days
| | | | | | Two lines -- in one write, or as bash writes them, a line at a time on one open -- each ran, and the first's answer was lost under the second's. A write with more than one line, or a next line before the last answer is read, is now refused, EINVAL. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* pty/ctl exec on a command pane is refused: a command pane does not restartGabriel Schneider2 days
| | | | | | exec on a finished command pane ran its line again, silently, with no header, footer or records. It is now refused, EINVAL, invalid exec: a command pane does not restart. Co-Authored-By: Claude Opus 5.5 <[email protected]>