summaryrefslogtreecommitdiff
path: root/src/builtins.zig
Commit message (Collapse)AuthorAge
* 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]>
* Exit and Restore name a modified +New scratch too, in one wordingGabriel Schneider3 days
| | | | | | | | | | Their refusal named only file panes, so text typed into a +New scratch went unasked about and was lost. A scratch with text counts as unsaved as a file does (acme's winclean asks about an unnamed window too). The refusal a ctl write gets now reads as the message row does, `<names>: Modified (Exit again to discard)`, instead of a second "discard them all" wording. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A failed Dump or a Restore of no dump fails its write, before any warningGabriel Schneider3 days
| | | | | | | | | | | | A Dump into a DumpDir it could not write, or a Restore of a file that is not a dump, answered a ctl write with rc 0 and only a message, and the Restore warned about unsaved panes before it ever looked at the file. The hosts' dump write now fails the waiting 9P write with EIO (the late failure a Save uses), naming the path and the reason in the log, and Restore parses the file before its unsaved-panes refusal, failing with `not a pardes dump`. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A choice setting's refusal names what it takes, and /commands lists themGabriel Schneider3 days
| | | | | | | | | | | | Bare Placement and BootShell flip, which is pardes's convention for a word that chooses (Crt does too), but nothing said so, and "bad value in control message" never said what would do. A refused value now says `takes acme, pardes` (every switch and choice setting), /commands lists each such setting's values in a fourth field, and config.md and fs.md say that bare steps to the next. Motion and ShaderAnimation stepped nowhere bare and now step like the rest. Co-Authored-By: Claude Opus 5.5 <[email protected]>
*-. Merge: 9P round 6 + empty columns + render (acme theme, grips, Lift, Motion)Gabriel Schneider3 days
|\ \
| | * acme looks like acme; every theme gets acme's button, scroll column and 2px ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | rules acme takes plan9port's own colours (acme.c iconinit, draw.h): selections #eeee9e in the body and #9eeeee in the tag, black ink; exec and look sweeps #aa0000 and #006600, white ink; a #99994c scrollbar under a #ffffea thumb; black rules; a #8888cc tag/body rule and column button. Every theme: the grip is acme's button, its tag row's full height, in one scroll column with the scrollbar (rail_px, 12 at a 17px tagline, scaled, times GripWidth, a percent, default 150; same x0/x1 to the pixel): focused clean = solid box; focused dirty = box_dirty filled to a box ring (acme's modbutton); unfocused clean = a box_border ring round the tag's ground; unfocused dirty = box_dirty a pixel inside that ring. The grid, which has no ring, marks dirty with a bold * on box_dirty in the grip's second cell and fills an unfocused grip halfway to its ring. Regions carry a dirty flag. Column buttons are the same shape, solid. 2px rules between columns and stacked panes (inside the tag band's slack), none at the window edge; a 1px tag/body rule halfway between tag and page. Theme data: tag_sel_bg, sweep_bg/fg, tag_rule, rule_px, rail_px, box_border, box_dirty. Chrome: rule_px, tag_rule, rail_px, grip_border, grip_focus_ring; a comptime guard on Chrome's layout forces a wire bump once v8 ships. Structural rules are exempt from the focus-indicator rule (docs/effects.md). Tests: acme widths; stacked rule in the slack at two tagline sizes; every grip-column pixel is band, button, ring or rule, and the button shares the scrollbar's x0/x1 (4 metrics x top/bottom x focus x dirty); the four grip states distinct in every native theme with a non-colour dirty cue in the grid; wire round-trip of the new fields. Shared files: src/colors.zig, src/surface.zig, src/body_layer.zig, src/tagline.zig, src/detached/wire.zig, docs/themes.md, docs/config.md, docs/effects.md, 21 snapshot goldens (the grip cells only), test/gui-goldens.txt. Motion flavours differ by design, and drive notice drops and pane moves
| | * Motion flavours, and Lift is shadow, rim or auto: auto on a dark page ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | recedes the other panes (InactiveDim) Motion off|crisp|smooth|bouncy|playful is one parameter set (animation.Motion) every fx animation reads. One focus spring per pane drives both the lift and the dim, at the flavour's pace; a grid snaps. Lift drops glow and surface. A shadow falls on pane bodies and rails only, capped so text and the selection keep min(contrast, 4.5); rim is a hairline along the focused tag's top. auto is a shadow on a light page; on a dark page the core recedes the unfocused panes' text (InactiveDim, ported from 2e4d97f, default 30 under auto) with the same floor. Tests: focused text contrast is never below unfocused in any style, dim or theme; the focused pane's cells and tag are untouched by a dim. Shared files: src/config.zig, src/builtins.zig, src/ninep/ctl.zig, src/surface.zig, src/detached/wire.zig, docs/config.md, test/snapshots/builtins.snap (one more wheel for the longer help).
| | * Lift takes a style: shadow, surface, rim, glow or autoGabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The user wants Lift to read on dark themes, where a shadow has nothing to darken. `Lift shadow|surface|rim|glow|auto` (`on` is auto, bare flips auto and off): surface lightens the lifted part's ground about 5.5% (Material-dark), rim is a thin soft light off its top and left edges, glow a faint halo in the theme's accent (Chrome.accent, the focused box colour), auto a shadow on a light page and surface with half a rim on a dark one (by the page's luminance). Rim and glow are the soft kernel in a light colour (no pre-warp: coloured light is laid on as is, within §8.2's budget); each style is capped per theme so text keeps min(its contrast, 4.5) (tests: darkening and lightening over the native themes). The style travels in the palette (Chrome.lift_style, one byte on the wire). Config reports and ctl reads `Lift <style>`. Shared files touched: config.zig, builtins.zig, ninep/ctl.zig, detached/wire.zig (palette byte), gui.zig. Not touched: pardes.zig, Messages.zig, mouse.zig.
| | * G1: Lift, soft elevation shadows (off by default)Gabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | `Lift` (a GUI toggle, capability lift) lifts the focused pane on a critically damped spring (animation.Spring: closed form, about 240 ms to settle, velocity kept across retargets, settled = no frames) and floats notices. The core puts the lift on the regions (Region.lift, on the wire); the GUI casts from it: a soft shadow is decor, an erf rectangle on one quad grown by 3 sigma (decor.frag, flag 0x10000000), in the quad's own space so a track's transform carries it; darken-only, the caster's rect left alone, alpha pre-warped for linear light and IGN-dithered. Cast last in its group, so a neighbour's rails and rules darken with its text; a notice's before its rule. Strength is capped per theme so text over the darkest shadow keeps min(its contrast, 4.5) (test over the native themes). Opt-in until the focus lift/dim default is decided. Feel review material: docs/effects.md. Test-mode PARDES_TEST_SERIES keeps every captured frame. Shared files touched: pardes.zig (two fields, one nextWake line), detached/wire.zig (lift on the region), config.zig, builtins.zig (capability), gui.zig. Not touched: Messages.zig, mouse.zig, tty, host_io.
| * | A document dragged beside the boot shell leaves it; BootShell replace closes ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | it as before Placement and BootShell are one kind of setting now, a word from an enum, set, flipped bare, and reported by one arm. Co-Authored-By: Claude Opus 5.5 <[email protected]>
| * | A column can be empty, as acme's can; new panes go where acme's ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | makenewwindow puts them Newcol makes an empty column; closing a column's last pane leaves it empty with the keyboard on its tag; Delcol and Joincol alone take a column away; the session's last pane closing quits. The +New stand-in and replaceStillborn / stillborn_joiner are gone. Every new pane goes through exec.placeNew, which follows acme's makenewwindow (active column, empty column whole, blank space, halving the biggest) or, with Placement pardes, the old rules. ColumnTags is gone: column tags are always shown. A grip drag shows acme's box cursor. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | | A pane's question is logged as ask, and answer on its ctl answers itGabriel Schneider3 days
|/ / | | | | | | | | | | | | | | | | | | | | A script could not answer the several-REPLs question, which only a key could. Every question a pane asks on its notice band (which REPL takes an exec, Del's side from the keyboard) is now logged as `ask <serial> <what> <choices>`, and `answer <choice>` on the pane's ctl answers it as that key would, `answer -` taking it back as Esc does. One function answers for a key and for the ctl. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | Edit runs sam's command language on a pane's body, as acme's Edit does, in ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | one undo step Over 9P a rename everywhere was a loop of addr and data writes. Edit, from a tag, a pane ctl or exec, parses sam's commands as acme's edit.c does and runs them as ecmd.c does against the text as it was, collecting the changes in order as elog.c logs them and applying them at once: addresses (the addr file's, line:col included), x y g v c a i d s p = m t, u alone, and { }. One undo step; any error, in acme's words, changes nothing, fails a ctl write and is logged. p and = print to the directory's +Errors. Left out, and said: the file commands, the pipes, \1-\9 (mvzr keeps no submatches), and changes out of sequence, which acme applies with a warning. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | An Exit or Restore refused over a ctl write names every unsaved pane, not ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | just the first Each pane got its own message, but a ctl write fails with its first error only, so a script was told about one pane, and the next Exit discarded both. The refusal now lists them all, as acme's rowclean does, and says the next one discards them all. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | A look takes acme's file:addr and :addr, and one that finds nothing changes ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | nothing A look at `file:/re/` or `:/re/` searched for the words instead of addressing, and a miss left an empty +Search pane and a cleared selection, while a hit answered the +Search pane on /look. Now an address after a colon (acme look.c:450) is evaluated in the file from its dot; a miss says no match and leaves the panes and the selection alone; a hit reads back as the pane the text is selected in. Both live in lookAt's one flow, so they are one change. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | Undo and Redo are builtins, as in acme's tags, so a pane's ctl and exec can ↵Gabriel Schneider3 days
|/ | | | | | | | step its body Over 9P there was no way to take back an edit: acme's Undo and Redo were keys only. They are now pane builtins, reached from a tag, a pane ctl and exec, and listed in /commands. They are not added to the default tags, which would change every tag. Co-Authored-By: Claude Opus 5.5 <[email protected]>
*-. Trial merge: 9P + helix + renderGabriel Schneider3 days
|\ \
| | * Post chain: Shadertoy passes compiled by glslc; Crt, Ripple and Glitch ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | rewritten as Shadertoy files Stage 9 of docs/render-pipeline.md. src/gui/Post.zig runs the chain over the finished frame: each pass reads the one before, ping-pong textures between, the last writes the window; an empty chain is the direct path. The prefix (shaders/post/prefix.glsl) is ghostty's uniform block, name for name and offset for offset (tested against a copy of its Uniforms, the selection colours by their GLSL names), at SDL GPU's bindings, y down. A user's file (Shader <path>) is compiled by glslc with compileGlsl's own flags on a thread of its own, taken in at the next loop step; errors name the file's own lines; a failed compile keeps the last good pipeline; glslc missing is said once. The bundled passes compile with the build, through the same prefix. Crt, Ripple and Glitch are Shadertoy files, rewritten: no barrel (input is identity, tested), everything in linear light and dithered, keyed to iTime. scene_effects, crt.zig and crt.frag.glsl are gone; the core keeps no clock for the chain. ShaderAnimation off|on|always drives redraw level A: the chain alone over the retained frame (34 us CPU a redraw, measured). Shared files touched: pardes.zig (nextWake loses the scene line, disableSceneEffects empties the chain, two tests), builtins.zig (one switch arm), ninep/ctl.zig (two switch arms), macos.zig (flags from the chain), gui.zig. Not touched: Messages.zig, mouse.zig, detached/*, host_io, tty.
* | | Errors are said in words, and a refusal names what it takesGabriel Schneider3 days
| | | | | | | | | | | | | | | | | | A failure read `Del k|j: InvalidArgument`, `Kill: NoSuchCommand`, `ill-formed control message`, or nothing at all. reportError now spells an error's name as words, and the refusals name their accepted forms: pty/ctl lists its verbs, a flag file takes 1 or 0, a setting word takes on or off, Del takes k, j or nothing, Repl takes - or a language. Kill with nothing to stop says so, /focus says pane, a Look that found nothing says no match, and pty/run on a command pane says it is not a shell. A ctl write's failure has room for the Repl list and is cut between words, the Repl word at a character. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | | A REPL's language is named and found as the syntax table finds one: aliases, ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | any case Repl took only the grammar's exact name, and a file's language was found by a case-sensitive suffix of its path, apart from the aliases a code fence already had. The aliases move to grammar_manifest with byName and byPath, which syntax, Repl and langOf share, so `Repl py` and a .PY file work. The line-by-line warning is for the python language, not an id that starts with python. Joincol's doc line was sitting on Repl. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | | Focus on a closed pane goes to the pane that takes its place, never to the ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | one focused before Dogfood closed a pane in one column and focus jumped to another column, only because that pane was focused last. Now removePane decides for every route (Del, a ctl del, a command pane's end, a 9P remove, a stillborn scratch replaced): the pane that grew into the rows, or the scratch standing in an emptied column; removeColumn gives it to the pane level with it in the column that takes the width. Closing an unfocused pane leaves focus alone. The per-caller focus lines in Del and replaceStillborn are gone, and so is prevFocus. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | | The web and board builds compile again: a shell's lookup and a dump's read ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | are the host's The Tty shell check sized a buffer with std.fs.max_path_bytes and the Restore check read the dump through the host filesystem, both in the core, which the wasm32-freestanding build cannot compile (no PATH_MAX, no libc). Both now run only where there is a host, as the rest of that code does. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | | Whether an exec came from a body travels with it, so every selection goes to ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | the REPL The execute key and the middle click marked a global flag that the first execute cleared, so of several selections executed at once only the first reached a bound REPL and the rest ran as commands. Where an exec came from now goes with it, as acme's execute() asks of its Text (exec.c:122,169): builtins.Ctx carries from_body, runBuiltinFrom and executeFrom take it, the gestures set it, and chordEachSel sets it for each selection. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | | A REPL takes text only while its program has the terminalGabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | A binding outlived its program: a command pane reused kept the REPL of the command before, a done command pane could be bound, a document pane (a terminal with no emulator) was accepted, and after Ctrl-D in python3 the text went to the shell, which ran import os as ImageMagick's. A command pane's binding now ends with its command and a done one is refused, a pane with no emulator is refused, and an interactive terminal's REPL is live only while a program other than its shell holds the tty (the host's tty_taken); when none of the language's REPLs is, nothing is sent or run and the pane says so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | | Tty with a shell that is not there says so, and never sets the caller's shellGabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Tty /nonexistent or Tty fsh started the host's fallback shell without a word, and when spawnTty made no pane, the argument became the calling pane's shell. Tty now looks the shell up first and fails 'Tty: no shell "fsh"' when it is neither a name on the usual paths nor a path to one; spawnTty answers the pane it made, the one given the shell, and says why when it made none. The lookup (host_io Shell.find) gives the turn up around its access() calls, since a typed path may be under a mount this editor serves, and forkShell copies the pane's shell before looking it up and checks the pane is still its own after. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | | A Restore of a dump that cannot be read fails at once, and spends no warningGabriel Schneider3 days
|/ / | | | | | | | | | | | | | | | | | | | | The dump was read only by the host after the step, where a failure went to the message row alone: a Restore written to ctl answered success, logged no err, and a second one past the unsaved-text warning did the same. Restore now reads the dump first, before the warning, and says 'Restore: <path>: no such file' (or permission denied, a directory), which fails a ctl write and so logs err. A bare Restore with no dump yet, or a name too long, says so too. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | A terminal bound as a language's REPL takes the execs made on that ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | language's files Repl python in a terminal's tag or on its ctl binds it (Repl - unbinds, Repl bare says the binding, the same word again changes nothing), with an id, python-a, python-b, in its tag. An exec made by a gesture on the body of a file in that language -- a middle click or the execute key, on any text, a single word too -- or on the REPL's own body is typed into it, bracketed if its program asked for that, else line by line with a once-said warning for Python's blank lines, then Enter; the message row says -> python-a in the tag's name tint, the log send <from> <to> <id>. Several bound for the language: the pane asks which on its notice band, as Del asks, one key answering, Esc none, nothing remembered. The gesture is known where it is dispatched (mouse.zig, the execute key), so the tag's words, Exec <text> run by name and a command word @`cmd` stay commands, and a 9P exec is never sent. A finished command pane is no REPL; bindings are not dumped. The docs spell out the escapes, the pdb and input() caveat and the no-bracketed-paste papercut. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | Kill signals a command only while it runs, and only the pane it was meant forGabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | A signal effect carried only a slot, so a Kill followed in the same step by the pane's closing and its slot's reuse signalled the new pane's child; and a command pane whose child had exited and been reaped kept a process group id another process could take. The effect now carries the pane's serial, checked as it is performed, and a host signals no command whose exit it has recorded; the core already sends Kill only to a command it has not been told is done. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | Only Tty reads Word+arg as its argumentGabriel Schneider3 days
| | | | | | | | | | | | | | | | Every builtin that takes an argument split a word at its first +, so Dump+2024.zon ran Dump with 2024.zon. A builtin now opts in with plus_arg, read by the registry, and only Tty does. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | A terminal's Tty word names its shell, Tty+fish, and a click on it opens anotherGabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | A terminal's tag said Tty whatever shell it ran. The host's acknowledgement of the shell it forked now sets the word to Tty+<shell>, tinted like the tag's name. Word+arg is taken as Word arg, one word a tag can hold and a click can take whole (+ is a word character), so Tty+fish opens a terminal on fish, as Tty fish does; Tty takes the shell as its argument, which the host forks for that pane instead of the configured one. Every snapshot whose screen shows a terminal's tag changes: 69 goldens, re-recorded by name, whose 297 changed lines are all Tty becoming Tty+bash (the harness runs bash), the cursor columns and style spans that moved with it, or that text cut at a pane's width. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | A command line runs as its own command pane unless it is clicked at a ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | shell's prompt A middle click, an exec write or a tag word that no builtin knows was typed into some terminal for the pane's directory, sharing whatever state that shell was in and answering nothing, so a misspelling vanished into a shell. Now only a line clicked at an interactive terminal's prompt is typed there. From anywhere else it runs as a command pane: a terminal whose child is $SHELL -c the line in the pane's directory, full emulation, which shows its output and then exit N from the host's reaping of the child, and stays. A finished command pane is the next command's for its directory, which runs below what it showed after a '% line' line (acme appends to +Errors and never clears it, util.c:213); a running one gets a second pane. Kill ends a command pane's whole process group, the log records run and exit, exec reads back the command pane's serial, and a line is at most 1 KB, read off the pane as the host forks rather than carried in every spawn effect. ttyForDir's search for a free shell is gone. The goldens of chordcut, cmdword and layout-open change where a file's exec now opens a command pane, and ttytaken is rewritten to exec from the terminal itself; docs/open-questions.md records the decision. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | A Restore's warning about unsaved text no longer lets the next Exit discard itGabriel Schneider3 days
| | | | | | | | | | | | | | | | | | Exit and Restore shared one warned-at revision, so a Restore a script was refused over ctl spent the warning, and the person's next Exit quit without asking, throwing the text away. The warning now records which word gave it, and only that word goes ahead on it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | Joincol with no column to the right and Theme with no such theme say soGabriel Schneider3 days
|/ | | | | | | | | | | Both did nothing without a word, from a click or a ctl write alike, and a script could not tell a no-op from success. Joincol in the rightmost column now fails 'Joincol: no column to the right'. A Theme name that is none says so and names the themes sharing its first letter, since all of them (ThemeSel lists them) are too many for a message or a refused write; a startup config line still fails quietly, as its other bad lines do. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* An Exit or Restore refusal says the same word again discards the textGabriel Schneider3 days
| | | | | | | | | | '<name>: Modified' read like a failure to retry, and a script that retried Exit or Restore threw the text away without knowing it. The refusal now names the word asking and what repeating it does, '<name>: Modified (Exit again to discard)', and the skill sets it apart from lock's 'file in use', which is the one to retry. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Restore asks about unsaved text first, as Exit doesGabriel Schneider3 days
| | | | | | | | | | | Restore replaces every pane with a dump's, so a pane edited since its last save lost that text without a word, where Exit asks. acme's Load only adds a dump's windows and so never asks; Restore now asks what Exit asks (acme's rowclean and winclean, wind.c:511-529): each modified pane says so once, and Restore again with nothing edited since goes ahead. Exit and Restore share the check and its warned-at revision, as acme's winclean clears one dirty flag for any asker. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Kill asks the host to signal at once and says when a shell has no job to signalGabriel Schneider3 days
| | | | | | | | | | | Kill queued a signal effect for later, so the job it saw running by its marks could have ended, and another started, before the signal went; and with job control off the job shares the shell's process group, so the host skipped it and Kill reported nothing. Kill now calls the host's kill_job while it holds the turn, and when the only job is the shell's own group says 'Kill: no job to signal', which also fails a write of Kill to ctl. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Exit quits and Kill stops commands, as in acmeGabriel Schneider3 days
| | | | | | | | | | | | | | | | Kill quit the editor, which in acme is Exit; acme's Kill stops the commands it started. Exit now quits as acme's does (exec.c, rowclean): it refuses once, naming each pane with unsaved text, and quits when asked again with nothing edited since (a small scratch is not asked about). Kill, bare or with names, stops the commands pardes typed into a terminal (an exec, a middle click, a pty/run) while their shell's marks say they run, by SIGTERM to the terminal's foreground job, never to the shell (acme posts the kill note, which terminates). Both are session builtins; the topbar's Kill becomes Exit, same width, and every golden's topbar row changed by exactly that word (checked line by line); the builtins script scrolls one more row for the index's new line. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A ctl write fails when a builtin it runs fails, and a missing required ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | argument is refused before anything runs A ctl write failed only on a malformed line: Mount x reported its error in the editor while the write succeeded, and a bare Mount failed only as it ran, after earlier lines of the write. acme's ctl answers a command's error (editors/acme/xfid.c:700). Builtins now declare requires_arg beside takes_arg (settings: those with a value to set), and the check refuses a bare one as wrong #args before any line runs; while a ctl runs, the first error a builtin reports fails the write, quoted with its line, and the prompt refusal quotes its line too. Docs say what a failure mid-write leaves done. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Split control messages by scope: the root ctl takes the session's builtins ↵Gabriel Schneider3 days
| | | | | | | | | | | | | | | | | | | | and reads the settings, a pane's ctl its own Every builtin could only be clicked, or written to exec, and the settings could be read only as the Config window's prose. acme keeps window verbs on a window's ctl, and webfs and upas/fs keep session settings on a root ctl. Each builtin now declares its scope (scope = .session; settings are all session, the rest pane), read by the registry. The root /ctl takes session builtins and reads every setting in the words a write takes, so its read written back changes nothing (panel and scene effects now take on/off like the toggles, to make that true); a pane's ctl takes the pane's builtins beside get, lock and unlock. Writes are checked whole and refused in Plan 9's ctl words (unknown control message "X", wrong #args ...), which 9ns now maps to EINVAL (cloud9 re-pinned at a8c7a715). A builtin that would prompt for its argument fails the write instead, and a refusal is answered at once, not after the frame. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Let s, S and | pressed in a tag answer for the tag's own textGabriel Schneider3 days
| | | | | | | | | | A tag is a text like the body, so selecting on a regex and piping act on the text they are pressed in: a prompt records the text it answers for, the tag keeps the keyboard while it is typed, and a header's prompt goes on the active pane's band. `/` still searches the body from anywhere, as acme's Look from a tag searches the body. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* File the tag code into tagline.zig and draw tags beside bodiesGabriel Schneider3 days
| | | | | | | | | | | With tags reduced to Texts, what is left of them is the computed prefix, the default and saved tails, entering and leaving a tag and the headers: that goes to tagline.zig, as acme keeps the tag half of a window in wind.c. Tag and header drawing moves next to body drawing in body_layer.zig, and the tag hit helpers go to tag_layer.zig with the Hit they read, where sameCell now also tells the lines of a taller tag apart. The docs describe the tag as a Text. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Make the column and workspace tags Texts with the pane tag's keysGabriel Schneider3 days
| | | | | | | | | | | | | The headers had their own one-line editor with its own keys: Enter always executed, h/l and J/K moved between headers and panes, Ctrl-c/x/v cut and pasted, and TagLine refused a newline that 9P accepted. They are now Texts like a pane's tag, with no prefix and a default until edited, so normal and insert mode, undo and the look and execute keys are the body's. Moving between them is the window keys' job: Up from a pane with nothing above it reaches its column's tag and then the workspace's, Down comes back, and Left and Right walk the column tags. Co-Authored-By: Claude Opus 5.5 <[email protected]>