summaryrefslogtreecommitdiff
path: root/src/builtins.zig
Commit message (Collapse)AuthorAge
* Petscii, Palette, Ascii, PdfFit and PdfTint take the state their tag word ↵Gabriel Schneider3 days
| | | | | | | | | | | | | names, set rather than flipped: `Petscii on`, `Palette terminal`, `PdfFit width` Each could only flip, so a script had to read the tag to know which way a write would go. Each now takes an optional argument, the value its tag word shows (on|off for Petscii and Ascii, commodore|terminal for Palette, width|height for PdfFit, disabled|filtered|full for PdfTint), and sets it; bare, it flips as before. Anything else is refused with what it takes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Restore and ThemeFile failures say why in words, a ZON one with its line: ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | never FileTooLarge, ParseZon or a bare `parse zon` Restore read failures named the Zig error (FileTooLarge, NotAFile, ReadFailed), a file that is no dump said `not a pardes dump (ParseZon)`, and a ThemeFile that did not parse said `parse zon`. Messages.errorWords says an error in words (the few that read badly spelled out plainly, the rest spaced and lower case, as reportError did), and zonWhy gives the parser's first error with its line: `not a pardes dump: line 1: expected ...`, `theme file x.zon: line 3: ...`. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A terminal's kitty graphics draw as glyph art where pixels cannot, and by ↵Gabriel Schneider3 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]>
* The reference is fs.md's per-file semantics, errors and limits in Typst, ↵Gabriel Schneider3 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 Schneider3 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]>
* Attach in a detached session is refused with words: bare is wrong #args, a ↵Gabriel Schneider3 days
| | | | | | | | | | | | | name no session has is "no such session" A detached session's core has no frontend loop to take an Attach, so the word was asked and never answered: a ctl write of it succeeded and nothing happened. The core now knows it is a detached session's, and Attach there says why: bare names no session but itself, a name with no session behind it is said so, and one that is a session is told to be attached from a frontend. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* An edit that changes nothing, an empty range deleted or a range replaced by ↵Gabriel Schneider3 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 builtin for one kind of pane is refused on another with why: Petscii, ↵Gabriel Schneider3 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 Schneider3 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 Schneider3 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]>
* A Restore logs and names the whole path of the dump it reads, not the name ↵Gabriel Schneider3 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 path typed with a leading ~ is the home directory, at every entry point ↵Gabriel Schneider3 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]>
* Kill with a name and nothing running says "Kill: nothing running" and ↵Gabriel Schneider3 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]>
* Save makes the directories its file goes in, always: for the pane's own name ↵Gabriel Schneider3 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 prints each setting as the ctl word that sets it, reads ↵Gabriel Schneider3 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]>
* Config opens the startup file, DumpConfig the settings report, and the ↵Gabriel Schneider3 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]>
* Terminal.zig is terminal.zig: a file of functions and no fields takes a ↵Gabriel Schneider3 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]>
* Mini.zig is mini.zig: a file of functions and no fields takes a namespace's ↵Gabriel Schneider3 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]>
* A 9P error past 128 bytes keeps its reason: the path in it gives up its ↵Gabriel Schneider3 days
| | | | | | | | middle to … An Rerror carries 128 bytes (Plan 9's ERRMAX) and the engine cut longer text there, and a builtin's failure was first clipped between words to 256 with ...: either way the end, which says why, was what went. tree.handle now fits a long reason by cutting the middle of its longest path, else of the whole text, on a character boundary, and reportFailure fills its buffer the same way. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A refused Delcol changes nothing: no +Unsaved opens, no focus movesGabriel Schneider3 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]>
* Mini with no argument is wrong #args, EINVAL; Find, Grep and Mini say their ↵Gabriel Schneider3 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]>
* Every catch unreachable, orelse unreachable and syscall assert outside tests ↵Gabriel Schneider3 days
| | | | | | | | is a real refusal or says why it cannot fire A sweep for round 23's crash: a run's answer (pty/run) was bufPrint'd into 48 bytes with catch unreachable, so a foreground program's long name (macOS gives up to 32 bytes) panicked; it now cuts at the room, keeping its newline, in 96 bytes. The rest were numbers into buffers sized for them, a braille codepoint, pthread calls on the queue's own mutex, and pdf_view's resolved outline entries: each now carries a one-line comment saying why it cannot fire. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Not-found failures say it once, in plain words: grep: pattern not found, ↵Gabriel Schneider3 days
| | | | | | | | callers not found The ENOENT that 9ns reads from a failure's words came from a tacked-on suffix, grep: no match, not found, definition: nothing found, not found, no shell "x", not found. They now say it once: grep: pattern not found, find: name not found, Callers: callers not found, definition: not found, shell "x" not found (...). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A ThemeFile that cannot be read or is no theme fails its write, and a bad ↵Gabriel Schneider3 days
| | | | | | | | path says why The theme is read when the host performs the request, after the write had been answered, so a missing file or a bad theme only showed a message; and a path not ending .zon said only invalid theme path. Load failures are now the waiting write's (late, as a Save's), and the path refusal says a theme file is a .zon. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A buffer whose file was deleted on disk is dirty, and Del asks firstGabriel Schneider3 days
| | | | | | A file deleted under an open buffer left dirty 0 and let Del, Exit and the rest throw the only copy of its text away unasked. It now counts as dirty, as acme's does, and the refusals ask about it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A builtin or setting this build lacks is refused GUI-only, from an exec tooGabriel Schneider3 days
| | | | | | On a terminal, Fonts written to an exec was no builtin there, so it ran as a shell command and ended exit 127; ctl said unknown control message. Both now say Fonts is GUI-only, invalid here (a builtin another platform's build has, not in this build). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A refusal over unsaved panes keeps its list in +Unsaved and shows a short noticeGabriel Schneider3 days
| | | | | | | | | | | Exit's refusal (and Restore's, Del's, Delcol's, get's) put its full text on a notice that went: a long list of names, gone before it was read. The list now goes into one +Unsaved pane, filled again by each refusal, a row a pane (`<name>: Modified`) and the `Exit again to discard` line; the notice is short, `3 unsaved panes — Exit again to discard`. The 9P `unsaved` records and the write's err are as they were. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* ThemeSel is Themes and FontSel is Fonts; the old words still work in init ↵Gabriel Schneider3 days
| | | | | | | | | | | | files and dumps The user asked for the plainer words. Every use is renamed: the builtins, leader paths, /commands, the docs and tutor, tests, and the themesel golden, re-recorded. An init file's ThemeSel or FontSel runs the new word and says `ThemeSel: renamed to Themes`, as ColumnTags is said; a dump naming an output pane by the old word restores it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Recent lists the files opened lately, closed ones too, and a jump back to a ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | closed file reopens it A file closed by accident, its path forgotten, could not be found again: the jumplist dropped closed panes. Every file opened (a look, a Save of a scratch, a Restore, a rename) goes first in a list of 200, kept once, its dot noted when it closes, kept across sessions in $XDG_STATE_HOME/pardes/ recent. `Recent` (SPC f r) shows it in a reused +Recent, each row `path:line:col open|closed` a look reopens; /recent reads `open|closed <path>`. The jumplist keeps a closed file's entries, +Jumps marks them `(closed)`, and Back to one opens the file at its place. acme has no such thing; its dump and Load are the nearest. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A tag write refuses NUL and the other control characters; a Dump that fails ↵Gabriel Schneider3 days
| | | | | | | | | | | | says so A NUL written into a tag went into the dump, which the host then could not write, and Dump said nothing: a success that wrote nothing. Tag writes, the workspace's, a column's and a pane's, refuse control characters but tab and newline, DEL, C1 and bytes not UTF-8, EINVAL; and Dump reports any failure of its own instead of swallowing it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Grep and Find count the rows they found, so a hit opens its +Search and a ↵Gabriel Schneider3 days
| | | | | | | | | | | | miss fails Round 18 made a search that found nothing fail, but grep and find never counted their rows (only a pane search did), so every Grep read as a miss. Both count the lines they wrote now; a Find or Grep that finds nothing fails alike, `find: no match, not found` / `grep: ...`, ENOENT, and opens no empty +Search. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The docs: data writes replace their range, restored command panes show their ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | exit, the tag's default words, empty matches at #0, errors' fallback, tagexec and event readers, Find finds names Dogfood round 18 found these false: `>>` on data replaces the addressed range (acme's data write deletes then inserts); a restored command pane shows the `exit N` it ended with; the default tag words are `Save Tty Collapse Del`; `file:0/^/` passes over the empty match at #0; `errors` with no room logs msg records; a pane's tagexec never goes to an event reader; a scratch is named with `(pane N)` in a refusal; and /commands said Find searched the pane, where it finds file names. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A builtin failure over something not there answers ENOENT: Unmount of a name ↵Gabriel Schneider3 days
| | | | | | | | | | not mounted `Unmount nothere` failed EIO with `not mounted`. It says `no such mount nothere` now, and a builtin's failure that says `no such` (this, Tty's `no such directory`) answers ENOENT, the errno 9ns reads from those words. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Grep with no hit says grep: no match, and a pane directory that is not there ↵Gabriel Schneider3 days
| | | | | | | | | | | is passed over Grep walks every pane's directory; one not there (a scratch named into a directory not made yet) failed the whole search with `file not found`. Such a root is passed over now, and a search that finds nothing says `grep: no match` and opens no empty +Search. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Mount dials its peer at once and fails if none answers; a peer out of reach ↵Gabriel Schneider3 days
| | | | | | | | | | | | | is said as `dial failed: <reason>` Mount took any well-formed dial and nothing was found out until the first look through it, which then said `look: look: dial`. Mount now probes the peer (version, attach, its root) with the turn out, and fails its write, mounting nothing, when none answers; the dial errors read as words, `no answer`, `timed out`, `hung up`, and a look through a peer gone since names its path: `look: /n/peer/f: dial failed: no answer`. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A refusal over unsaved panes logs each as `unsaved <serial> <name>`, and its ↵Gabriel Schneider3 days
| | | | | | | | | | | | err never cuts a list Exit's refusal joined every name into one err, cut at the record's cap in mid-name, so a script could not tell which panes held it up. Each pane is now an `unsaved` record before the err, and the err names the one pane or counts them: `4 unsaved panes: Modified (Exit again to discard)`. Restore, Del and Delcol refuse the same way. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Every builtin says what it does in /commands, and a test holds each to itGabriel Schneider3 days
| | | | | | | | | 87 of the listed words had no description: settings have no doc comment to read, so each now carries a one-sentence doc, and the builtins without one got theirs. Exit's no longer names an internal function, and Repl's first sentence is short enough to be read whole. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A clicked Exit's refusal names every unsaved pane in one line, as a ctl ↵Gabriel Schneider3 days
| | | | | | | | | | write's does Under the one rule a click fails its write too, but only a ctl write assembled the `<a>, <b>: Modified (Exit again to discard)` line: a click failed with the first pane's name alone. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* One rule for failing builtins: the write fails, one err, no msgGabriel Schneider3 days
| | | | | | | | | | | | | | | | A builtin that failed through a ctl failed the write and logged its err, but through look, exec, tagexec or a column's exec it only said so on the message row, logged as a msg, and the write succeeded. Now every click write runs its builtin as a ctl line does (ctl.captured): a failure fails the write, with its words (EINVAL for malformed input, else EIO or what the words name), logs one err and no msg or announcement. get's Modified and a look miss are shown but logged once, as their err. A control character's refusal names its reason, a failed click reads back nothing, and look never reads back a pane closed since. The special case for a cut-short Edit through exec goes (the rule covers it); fs.md's table of exceptions becomes the one rule, as does the skill. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* An Edit block cut short through exec is an err, not a msgGabriel Schneider3 days
| | | | | | | | | An exec write does not fail for what its command says, so an a/c/i text or { group cut short by a write that ended early was only a msg, easy to miss. Over 9P, that failure (a truncated write, not a command's) is now logged as an err record naming exec; the pane still says it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* /commands takes each word's own doc comment, whole, without citationsGabriel Schneider3 days
| | | | | | | | | | | Repl showed Joincol's first line and Joincol another's, because a comment had drifted above the wrong declaration in builtins.zig; Kill's was cut mid-sentence and Exit's cited exec.c:892. The drifted line is back on Joincol, a parenthesis citing source (.c, .zig) is dropped, and the first sentence is kept whole up to 240 bytes, then cut between words with an ellipsis. A test checks every description opens its own word's comment. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Every refusal over unsaved text names a scratch by its pane tooGabriel Schneider3 days
| | | | | | | | | | | Exit, Restore, Del and Delcol share one list (warnModifiedIn), but it was built in 256 bytes, so with a few long paths a +New scratch near the end fell off Exit's and Restore's, which list every pane; and several +New panes were indistinguishable. The list is built in 1024 bytes (the write's error is still cut to fit, between words), and a scratch is named with its serial, /dir/+New (pane 12), the same everywhere. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Repl's unknown-language refusal names a few whole and points to the restGabriel Schneider3 days
| | | | | | | | | The refusal listed every language and was clipped to fit, ending mid-word. It now names six, those that start as the word did first (pithon: python), says how many more, and points at docs/tags.md, which lists them all. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Tty and Shell refuse a directory: not a shellGabriel Schneider3 days
| | | | | | | | | | A directory passes access(X_OK), so Tty /etc made a pane whose shell exited 127 and Shell /etc was taken. The shell lookup now refuses a directory, and both say "not a shell: /etc is a directory" (Tty and Shell share one refusal, host_io.Shell.refusal). shellset's golden takes the shared wording (re-recorded by name). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Shell refuses a name that is no executable, and bare restores the defaultGabriel Schneider3 days
| | | | | | | | | | | Shell took any word and the host quietly ran another shell at the next spawn. It now refuses a path or name that is not executable ("Shell: x: no executable by that name", failing a ctl write, logged err), a bare Shell goes back to the default, and a default $SHELL that is not executable falls back to /bin/sh. shellset's golden takes the refusal on the message row (re-recorded by name). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The default Shell is $SHELL, else /bin/shGabriel Schneider3 days
| | | | | | | | | | With no Shell set, pardes ran fish, which a box may not have and a user may not use. The default is now the user's login shell ($SHELL), else /bin/sh; an explicit Shell still overrides it. The tests pin their own shell (snapshots bash, the python suites /bin/sh or bash) and pass with SHELL unset; the Config report and docs say where the default comes from. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Undo and Redo with nothing left say so, and the write succeedsGabriel Schneider3 days
| | | | | | | | | A pane's Undo or Redo with no step left did nothing and said nothing. It now says "Undo: nothing to undo" (or Redo's) as a message, not a failure, so a ctl write of it still succeeds as acme's silent Undo does. The docs give the 256-step history. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A pane renamed but never edited closes on the first DelGabriel Schneider3 days
| | | | | | | | | | | The GUI golden's wide-glyph pane, renamed and never edited, was refused by Del as modified, and every frame after it kept the pane. A rename marks a pane dirty, but its text is what it loaded: the check now asks whether the text was ever edited (its first edit keeps a hash of what it had), not only whether it is dirty, as get's refusal does. Tests that faked an edit by the dirty mark alone now fake the hash too. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A desktop session holds 64 panes, and every route that finds none free says soGabriel Schneider3 days
| | | | | | | | | | | | | Sixteen panes was far too few for a real session. MAX_PANES is now 64 on a desktop and stays 16 on the board; the 48 more slots cost about 3.7 KB each in fixed tables (the core 1.33 to 1.45 MB, its surface 19 to 72 KB), and a pane itself (84 KB and its terminal) is allocated only when it opens. At the cap, pane/new fails with `pane/new: no pane slots: 64 max` and an err record rather than a bare ENFILE, a 9P look or exec that would open a pane fails its write with the same words and reads back empty, and New, Tty, Tutor and Alt-n say it on the message row (their ctl writes fail with it). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Del and Delcol refuse unsaved text once, as acme's doGabriel Schneider3 days
| | | | | | | | | | | | acme's Del asks winclean first and Delcol colclean (exec.c del, delcol): unsaved text is warned about, and the same word again closes. pardes closed at once. Both now refuse once through the one-warning-per-word mechanism Exit uses, from keys, tags, exec and ctl alike. A pane dirty only by a rename, or an empty one that never held a file, has no text to lose and is not asked about, and a scratch or a command's output under 100 bytes is not either, as acme's winclean passes a small unnamed window. Co-Authored-By: Claude Opus 5.5 <[email protected]>