summaryrefslogtreecommitdiff
path: root/src/tutor.txt
Commit message (Collapse)AuthorAge
* Docs for 0.24: Ctrl-i's fallbacks (SPC j i, SPC j o, the side buttons), a ↵Gabriel Schneider120 min.
| | | | | | terminal's text edited as a copy, a tag's typed path surviving Esc, Get's order of refusals, the init file's errors when saved, --wait and --detach in words; the CHANGELOG's 0.24 section, the directory window moved there from 0.23 Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Round 40's doc findings: tutor 3.1 comes back with Esc from +Help, 5.2 ↵Gabriel Schneider2 hours
| | | | | | sweeps an anchored regex to Part 7's heading, 6.1 selects a name with m i W, 1.3 says a new terminal lists its directory; the guide's search row says n walks +Search and Enter moves the pane; a pane ctl's line has no newline, as acme's; a TODO(round40) on editing a tag's path Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The tutor opens with its title alone, and the slogan lines go: setup's ↵Gabriel Schneider12 hours
| | | | | | opening, the guide's and reference's "carry" framings, the tutor's "Two carry the rest" Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The guide answers a first session: n walks a build's errors from its command ↵Gabriel Schneider12 hours
| | | | | | pane, a finished one is already normal, why make wants the project root, opening beside, a builtin's argument by mouse, 12G, and SPC ? is Help everywhere; the tutor's tagline and button names match the site, and the cheatsheet's tree gains data, look and exec Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Show, don't tell: the guide, the tutor, scripting, setup and the landing ↵Gabriel Schneider14 hours
| | | | | | lead show an example first and cut the prose it makes redundant; the reference's 9P tree and REPLs name Look and Exec Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The guide, the cheatsheet and the tutor point to helix's keymap for every ↵Gabriel Schneider14 hours
| | | | | | key, and say where pardes differs Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Builtins are written by name: each chapter and the tutor define Look and ↵Gabriel Schneider15 hours
| | | | | | Exec once and then say Look and Exec; the cheatsheet draws every mouse button as its icon; one-button clicks (Alt is B2, Super is B3) are in the guide and cheatsheet; building says how to send patches to the list Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The docs call pardes's scripting interface a virtual filesystem, served over ↵Gabriel Schneider15 hours
| | | | | | 9P, and the guide opens on look and execute as the core idea Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Scripts find the session as m=\$PARDES_MOUNT, else 9p; SPC q quits; upper ↵Gabriel Schneider15 hours
| | | | | | keeps a selection's newline and its tag words once; the reference takes line files, init errors, dumps, dials and Save on +Tutor Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The docs give back the day-one lines the trim cut, the tutor becomes ↵Gabriel Schneider15 hours
| | | | | | exercises on a +Tutor copy, the README builds the GUI and says what a terminal needs, and Shift-Esc says it needs the kitty keyboard protocol Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The docs trimmed to their path: a guide with Words you'll see and one Where ↵Gabriel Schneider15 hours
| | | | | | commands run and panes go table, scripting's first tag word Fmt and eight traps, setup as the one home of the pager and the servers, a scannable cheatsheet, an honest README, the edge cases moved to the reference, and the pager's colours Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Shift-Esc always backs out: in every mode and pane it goes to the previous ↵Gabriel Schneider18 hours
| | | | | | | | | | | | | | | pane, as Esc does from normal, and a raw program never sees it; Ctrl-b alone toggles raw Shift-Esc switched a terminal in normal or insert mode into raw, so the one key meant to get out of anything got a script or a person into a program instead. It is now handled before any mode: an open prompt is closed, insert mode left, a pending count dropped, and Last runs, the pane keeping its mode (a raw terminal stays raw). Ctrl-b is the only switch between raw and normal. The keymap's two chords become one, back_out; the cheatsheet row, the guide's mode table and the tutor say so, and the tty and builtins goldens are re-recorded. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The tutor follows the guide's order, points at its sections, and no longer ↵Gabriel Schneider28 hours
| | | | | | teaches $ as line end or the terminal tag's old words; a test checks the words, paths, chords and tags it names Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Config opens the startup file, DumpConfig the settings report, and the ↵Gabriel Schneider28 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | 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]>
* A pane's last row of text is no resize handle; the grip is, and the GUI's ruleGabriel Schneider28 hours
| | | | | | | | | | | | | | | A press on a pane's last row began a seam drag, so the row could not be clicked or swept like the rest of the text (rsearch dragged the handle out of the way first). Now no row of text is a handle: in the GUI a press on the 2 px rule between two panes drags their seam, and anywhere the grip does, as acme's button moves a window -- dragged up or down its own column it moves the pane's top, either pane down to its tag alone (acme's coldragwin), dragged down inside itself too. The hover hint over a last row is gone; column edges resize as they did. Scripts that dragged a seam drag a grip instead and match their goldens; six goldens lost the hint or moved a cursor to the clicked text, re-recorded by name. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* $ keeps the selections a shell command exits 0 on, and line end is glGabriel Schneider28 hours
| | | | | | | | | | | | | $ was a second key for line end, which helix never meant: in helix it is shell_keep_pipe. It now arms the pipe prompt with a $ marker, runs the command once per range with that range's text on stdin, and keeps the ranges it exits 0 on; the primary stays if kept, else the last kept range takes over, and keeping none changes nothing. The runner's answer is all or nothing, so the command runs in a subshell whose status is echoed as its output. Line end stays on helix's own gl and End; the snapshots, tutor and docs that pressed $ for it press gl. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Exit quits and Kill stops commands, as in acmeGabriel Schneider28 hours
| | | | | | | | | | | | | | | | 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]>
* Ask from the keyboard which neighbour a closed pane's rows go toGabriel Schneider28 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | Del takes a side: `Del k` gives the closed pane's rows to the nearest expanded pane above it, `Del j` to the one below, each falling back to the other side when it has none. DelAbove and DelBelow are those two lines, with no path of their own under SPC. A bare Del started from a key -- SPC d, Enter on the tag word, a row run from an output buffer -- on a pane with expanded panes both above and below asks instead of guessing. The question is a prompt like Save's or a search's (Pane.Prompt.del_side), so it is painted on the pane's notice band by the same path, and the next key answers it before any mode sees it: k or Up, j or Down, anything else keeps the pane, as does a click. Only a key press sets Pardes.can_ask, so a click, a 9P ctl or event write, a startup line, a restore and a shell exiting all close the pane at once, the rows going where layout.absorbVWeight has always sent them. A collapsed pane is not asked about (it has only a tag row to give), and collapsed neighbours are passed over (layout.expandedNeighbor, which Collapse now uses too). removePane and absorbVWeight take the recipient; every other caller passes null. Three scripts that closed a middle pane with SPC d answer k, which is where the rows went before, and their goldens are unchanged. delask.snap covers the question, Esc, j, a clicked DelBelow and a clicked Del. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
* Make a pane by opening /pane/new, and a Plan 9 idiom passGabriel Schneider28 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The Tcreate that replaced acme's /new was a step away from the idiom dressed up as a step toward it. A pane is named by a server-assigned serial, so the create ignored the client's name: `mkdir /pane/foo` succeeded and left you /pane/12. A mkdir that does not make the directory you named is worse than the read-with-side-effect it replaced, and it broke in the shell workflow that motivated the change. `create` is out of the declared features, so Tcreate is EPERM again; Tremove stays, since `rm` to close a pane is unambiguously right. /pane/new is now opened, not created: the open makes the pane, the read of that fid answers its serial, two reads agree, and closing it leaves the pane. That is /net/tcp/clone's mechanism (kernel/network/ip/devip.c, in ipopen), not acme's, and the difference is deliberate. acme allocates during the walk and lands inside the new window, so /dev/new/body works in one step, and it can afford to list `new` because a Plan 9 directory read carries every entry's stat and nothing walks. A kernel or FUSE mount walks and stats each name a listing gave it, so allocate-on-walk would make a pane per `ls -l`. Allocating on open keeps `new` listed -- a stat is not an open -- at the cost of the one-step new/body. `new` stays unreachable from an editor path, because that resolution serves Look hover previews. The idiom pass behind it, read out of the Plan 9 tree at ~/05-genizah/principia-softwarica rather than recalled: Rerror carries a string, not an errno (man 5 error: `ename[s]`), and acme names every refusal. The five refusals pardes shares with acme now say what they mean; the generic sites keep their bare errno rather than invent strings acme does not have. body and tag declare DMAPPEND, which they had always behaved as (acme(4): "always appended; the file offset is ignored"), checked first against Linux's fs/9p, which never maps the bit. excl stays unset everywhere, because acme sets DMEXCL on nothing. Blocking reads, per-object addr scope and the readable pane ctl were already right. Real stat sizes and qid versions stay: acme reports length 0 and version 0 for everything, and Linux clients need better. One bug fell out of it. open reset the addr range, so `echo '#0,#5' >addr; cat addr` answered `0 0` and `cp addr dot` copied zeros. acme(4) makes the contract explicit -- "a regular expression may be evaluated by writing it to addr and reading it back" -- and acme gets away with resetting on the 0-to-1 open only because its clients hold the fid across both. A shell cannot: that is two opens. The register is cleared by truncating it now. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
* Plan 9 idiom for the control filesystem, and the regressions a624a56 leftGabriel Schneider28 hours
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The 9P tree stops being a command language wearing a filesystem. /new created a pane as a side effect of a *read*; it is now Tcreate in /pane, with Tremove to close, which cloud9's engine has always supported and the editor never declared: tree.zig now says `features = .{ .create = true, .remove = true }`. Eleven pane ctl verbs become files that can be read as well as written -- dot, limit, dirty, mark, scroll, look, exec -- leaving ctl with `get`, the one verb no file would say better. Root /ctl splits into a read-only /status and the /look and /exec files whose write IS the click. stat carries real sizes where it used to answer 0, and qid versions track a pane's revision, so a client can poll for change without re-reading the body. Commit a624a56 moved raw-tty keys to an early-return branch that knew only Ctrl-B and bare Escape, and in the same edit deleted the paste branch below it. That cost Shift-Escape (the unconditional way out of tty mode) and both paste chords: Ctrl-V and Ctrl-Shift-V reached the child as keystrokes, so an agent CLI running in a pane took Ctrl-V for its image-paste binding and answered "No image found in clipboard". Both are restored, with tests. Nested detection was not subtly broken but deleted: 60367d8 removed nested.zig's process-ancestry walk and left "am I inside pardes" derived from PARDES_FORWARD_LOOK, which read "0" both for --nested and for "the listener did not come up". PARDES_PID now answers that question on its own, checked with kill(pid, 0); PARDES_9P and PARDES_PANE answer how to reach it; the flag is gone. The posted-9P registry also self-heals now -- a session that aborts cannot unlink its own socket, so posting sweeps entries whose target refuses a connection, symlinks only and on a definite ECONNREFUSED only. Elsewhere: tty scrolling is sticky-bottom, following new output only from the last row, with typing and entering raw mode snapping back to live; the boot layouts are a Boot enum instead of a chain of ifs, and the bare tty startup (Boot.tty, which main.zig names) opens an empty text pane under the shell while tests keep Boot.tty_shell; builtins announce themselves on the message row under a Verbose setting that is on by default; Config prints each setting the way you would type it back, so WindowOpacity 70 rather than "WindowOpacity: 70%"; LocationsConfig opens its window only when called bare; every tagline puts the word that closes the thing last, and a column now outlives its panes -- closing the last one leaves an empty pane, and only Delcol, newly on the column tagline, takes the column away. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
* Flatten the 9P control tree and move it out of fs.zigGabriel Schneider28 hours
| | | | | | | | | | | | | | | The served tree loses the self/ level: /index /ctl /new /log /screen /listeners /pane/<n>/... /os, with /src only in -Dembed-sources=true builds (default off, on for esp32p4). ctl speaks the editor's own language with two lowercase verbs, look TEXT and exec TEXT, plus acme's addr verbs; the new/ factory directory becomes one clone file; cons is gone (exec Msg); name and sel are files; stats report real lengths, modes and mtimes; /log streams pane new/del/rename/save events. The tree code lives in src/ninep/ (tree, pane, ctl, addr, pty, events, screen, sources); fs.zig keeps host access, mounts, resolution and find/grep. Same engine and transports. README (fs-help.txt) and docs rewritten; tests updated and extended. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Add Linux Tty9p mounted terminals and forward raw TTY keysGabriel Schneider2026-09-15
|
* trunk: resume before the Reload experimentGabriel Schneider2026-09-15
| | | | Empty marker on the last pre-Reload change. Keep the Reload experiment on reload (3801914), its first change on reload-start (200a1fc), and the unfinished performance investigation on reload-perf-wip.
* Refactor panes and filesystem; replace FUSE with 9PGabriel Schneider2026-09-07
| | | | | | Consolidate pane, layout, memory and host code. Serve 9P by default over Unix sockets, with runtime mounts and optional TCP/QUIC transports. Remove FUSE and obsolete proof-of-concept examples. Fix highlighting and terminal-history performance, expand differential and stress-test infrastructure, sort navigation results while preserving the next occurrence, add syntax-colored Braille minimaps, remove SPC-k, and document 9P interaction as a repository skill.
* tutor: half the length, and the parts people actually ask aboutGabriel Schneider2026-08-27
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1297 lines to 498. The tutor had grown to the point where the things a newcomer needs first were buried in the middle of a helix reference, and two subsystems it never mentioned at all. REORDERED by what is most different from editors people arrive from, and each part now earns its place: 1 THE MOUSE acme's three buttons and the chords, trimmed 2 PANES NEW. Moving between them, in one place 3 THE TTY Ctrl-b, Shift-Esc, and what plain Esc does 4 DETACHED NEW. The core outliving the terminal showing it 5 THE KEYS the helix half, cut hard, practice blocks kept 6 THE REST PDFs, images, the language backend, scripting PANES was scattered across 3.12, part 2 and the summary; it is one section now, because "how do I get out of this pane" is the question that actually gets asked. Ctrl-w hjkl, Esc, Shift-Esc, Ctrl-o/Ctrl-i, Alt-n, Alt-c, and the three panes that have their own claim on Escape. THE TTY gains the rule the old text got wrong. It said Esc "goes to the program" in raw tty, full stop. It has not for a while: at a shell PROMPT plain Esc hops away like Shift-Esc, and only a program that has TAKEN the tty (vim, a pager) keeps it. That is `takesCommandLine` in pardes.zig, and it is the difference between the toggle feeling obvious and feeling arbitrary. DETACHED did not exist in the tutor at all. `--detach`, `--attach`, the Attach/Detach words and their chords, why the pane shells belong to the session and never stop, why N frontends share ONE screen at the smallest common grid, and that `--fs`/`--fs9` work in a daemon now. THE KEYS lost the most: thirteen subsections became six, roughly thirty practice blocks became six. What went is the enumeration a reference does better; what stayed is the handful of blocks that teach the one idea helix users do not arrive with -- motions SELECT, so `wd` is what `dw` was -- plus the count rule, which is the other thing that surprises. Part 6 documents `pty/`, `--fs9` and the `9p` word, none of which the tutor knew about. The first seven lines are byte-identical on purpose: test/snapshots/ tutor.golden pins them, and it regenerated unchanged. ALSO REGENERATED: test/snapshots/builtins.golden, which had been stale since the `9p` word was added a few changes ago -- one more builtin shifts every row of the `SPC ?` listing below it. Nothing was wrong with the code; the golden had simply not been updated with the feature. All 95 snapshot scripts pass.
* acmefs: pardes --fs serves acme's control filesystem over raw Linux FUSEGabriel Schneider2026-08-25
|
* builtins + config: Save reaches every pane holding text of its own, and ↵Gabriel Schneider2026-08-25
| | | | takes a path argument
* syntax + pdf_pane + file_pane: prose grammars paint, pdf Esc cancels, gj/gk ↵Gabriel Schneider2026-08-25
| | | | walk wrapped rows
* animation: six character-motion panel transitions, composed in the core so ↵Gabriel Schneider2026-08-25
| | | | backends agree
* term_pane + builtins: terminal pane work, builtins/config additions, snapshotsGabriel Schneider2026-08-18
|
* nested + pardes: snapshot updates and small behavior fixes across panesGabriel Schneider2026-08-18
|
* file_watch + builtins + config: richer watch semantics, new builtins, config ↵Gabriel Schneider2026-08-18
| | | | docs
* animation: core publishes transition records; gui evaluates via shaders, tty ↵Gabriel Schneider2026-08-18
| | | | over grid cells
* big slow change: prebuilt shaders (SPIR-V/Metal), core gui reflow, docs, web ↵Gabriel Schneider2026-08-18
| | | | + snapshot refresh
* shaders: -Dprebuilt-shaders, so a gui build needs no Vulkan SDKGabriel Schneider2026-08-12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | glslc is the one build input that wants a tool a stock machine does not have, and it is also the input that changes least often: eight GLSL files that have outlived several rewrites of everything around them. Asking every machine that wants to run the SDL shell for shaderc is the wrong trade. The SPIR-V is now COMMITTED, under shaders/prebuilt/, and -Dprebuilt-shaders embeds that copy instead of shelling out. The default stays the honest one -- compile the shaders that are actually in the tree -- because the flag trades a dependency for a freshness problem: with it on, the .glsl sources are not build inputs at all, so editing one changes nothing. `zig build shaders` is the other half, and it is deliberately independent of -Dplatform: it recompiles every shader and writes the result back into the tracked directory, so whoever changes a shader refreshes the cache on a machine that has the compiler and commits the diff. `jj diff shaders/prebuilt` after it is the freshness check -- empty means the cache was already current. The shader list is also spelled once now (gui_shaders): the eight embeds, the eight glslc runs and the refresh step all read it, so adding a shader is a name there plus the @embedFile in gui.zig, not three edits in two places. Verified: -Dplatform=gui -Dprebuilt-shaders builds with glslc absent from PATH, and image-harness passes on that binary -- real SDL GPU pipelines built from the committed SPIR-V, 512 source pixels read back. The default gui build still runs the eight glslc steps; tty runs none. The committed bytes are identical to a fresh glslc run, and `zig build shaders` is idempotent.
* docs: the tutor taught three keystrokes wrong, and the rest had driftedGabriel Schneider2026-08-12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The documentation had gone stale in the ordinary way -- claims that were true when they were written and that nothing since had been obliged to re-read. Some of them were load-bearing. THE TUTOR. It still said there is no multi-cursor, that NextColor cycles three themes, and that its practice blocks "are also run as unit tests (generated from this file by tutor_gen)" -- a tool that appears nowhere in the tree, and nothing anywhere parses a `# keys:` block. Left alone, that claim is what makes the next wrong block survive. Three of those blocks WERE wrong, and all three for one reason: since the helix motion model landed, w/e/f/t SELECT the range they cross, so `i` after one inserts at the SELECTION'S START. `w i Z esc` on "foo bar" gives "Zfoo bar", not the "foo Zbar" the file promised. They were written against a vim reading of the same keys. Every block in the file has now been run through `zig build hxdiff` against the real core and matches byte for byte, and the trap itself is written down in 3.3 rather than left to be rediscovered. The tutor gains a PART 4 for everything added since it was written -- PDF panes, the in-process ZLS backend, themes and fonts, the startup file -- and PART 3 gains counts (and which keys ignore one), f/F/t/T, the whole g table (bare `G` is a no-op; `ge` is the START of the last line), multiple cursors and the s/S regex pair, `m`, `]`/`[`, `|`, insert mode, and all fifty leader paths. THE REST. design.typ's line table claimed 7,626 lines against a real 38,048, and its rows did not sum to its own total; its Event/Effect boundary contract -- the part a shell author writes against -- named four variants that do not exist and omitted fourteen that do. lsp.md's probe count. config.md's theme-name rules, which as written could not reach a zed theme at all. helix-keys.md's Skipped section, holding five families that have since landed. macos.md's menu bar, undocumented, along with sixteen other claims. web.md on what the browser build can actually do. SOURCE COMMENTS that had rotted alongside them: `tag_normal` is a space, not the `•` its own comment describes; Wrap is ON by default, not off; a FontSel row is SELECTED by n and RUN by Tab, not run by n; the SPC paths in lsp.zig lost their `l` group prefix when the language group moved; and the differential suites are 481 and 561 cases, not 360 and 440. TWO THINGS FOUND BY DOCUMENTING THEM, both left standing and written down rather than papered over. Typing `[^\n]` at an s/S prompt panics: the live preview compiles every prefix, and `[^\` indexes an empty slice in mvzr's parseCharSet. Both the tutor and a waiver recommended that pattern as the workaround for `.` matching a newline; they now say what it costs and what would make it sayable. And `Exec` is a builtin, so an `Exec` line in the startup config types that command into a shell before the first frame -- the tutor said nothing in that file is ever sent to one. Nine adversarial reviews over two rounds, each with the hxdiff harness to execute what it doubted. The second round exists because the first round's fixes needed checking too, and it caught three regressions of my own -- one of them a probe count I had "corrected" away from the truth. Verified: unit-test, snap 87/87, hxdiff 481/0, hxparity 561/0, mupdf-check. docs/design.pdf regenerated. The tutor's first seventeen lines are byte- identical, which is what tutor.golden pins.
* clipboard, n/N and the tty prompt: three things that were half-wiredGabriel Schneider2026-08-12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Three changes that all turned out to be the same shape -- a feature that worked in one direction, or for one pane kind, and quietly did not in the others. CLIPBOARD. Every register write emitted set_clipboard, so deleting one character threw away whatever the desktop was holding; multi-cursor yank took the join's early return and emitted nothing at all, so the same key reached the clipboard on one cursor and not on two. Nothing could READ the clipboard: the SDL shell had no SDL_GetClipboardText anywhere in it, and the tty shell never asked for OSC 52, so `p` from another application was dead in both. Now it is helix's split. y/d/c/p/P/R and the acme chords are the DEFAULT REGISTER and nothing else; the system clipboard is five words on helix's own letters -- SPC y, SPC Y, SPC p, SPC P, SPC R -- spelled as builtins so they land in Help and are executable like every other verb. The one exception is the tag `y` chord, which still mirrors out because a tag is always insert, so SPC cannot be pressed there, and copying the path out is the whole point of the chord. Reading is a new read_clipboard effect answered by an ordinary Event.paste, so the round trip is honest about being one: SDL and NSPasteboard answer inside the same drain, the browser answers a promise, and a terminal answers over OSC 52 or -- far more often -- refuses. A refused read is a paste that does not happen, and the request dies at the next keystroke rather than landing minutes late in whatever pane is focused by then. The tty shell also enables BRACKETED PASTE now and coalesces paste_start..paste_end into one event. Before this a paste arrived as a flood of individual key presses: plausible in insert mode, and in normal mode every pasted character ran as a command. n/N. They stepped the armed results buffer and immediately Looked each row, so you could not walk past a hit without opening it. They are a MOTION now: select the next look-able text, open nothing, and let Enter decide. What they step is the largest whitespace-delimited run look.resolve can act on (look.lookableSpan, wrapper punctuation peeled), over a RING of panes -- every pane that has performed a look, most recent first, then the output buffers that have not, newest first, and only if both are empty the pane in front of you. N is the exact inverse of n, computed rather than remembered: both directions ask the same question about the same spans and compare against the column the walk parks on, so x presses one way and x back land exactly where you started, pane boundaries and the ring's seam included. A ring rather than a list with two ends because a shell's cursor sits at the prompt, below everything it has printed, so a walk that could not come round would have nowhere to go on the very first press -- which is the case n/N were written for. One motion everywhere, no pane-kind or buffer-kind special case. The only thing a buffer may change is the GRAIN of what a step selects, and it does it with one flag rather than a branch: output_pane.Traits.commands (renamed from `executes`, which named one reader's behaviour rather than the fact) makes a row select WHOLE, because a ThemeSel line is a word to run and has no path inside it to pick out. `]d`/`[d` are not n/N -- they are helix's diagnostic motions, their job is to ARRIVE, and they still reach searchStep. THE TTY PROMPT. Leaving raw tty blanked the prompt row, and the command you had typed at that prompt shares the row, so it went too -- a shell out of tty read as output only. OSC 133 marks the row CELL by cell, so the two are separable: config.tty_blank = .prompt cuts the prompt's own columns and leaves the command, left-hugged at column 0 in line with the output under it rather than in a bay of blanks. .prompt_and_input is the old behaviour, kept. Because the row is now something you can put a cursor in, enterTty adds the hidden prompt width back before asking ghostty to walk the shell's own cursor to it -- the modal column on a cut row is short by exactly that much. Verified: unit-test 186/186 (nine new), snap 87/87 (new ttyprompt.snap), hxdiff 481 and hxparity 561 with 0 mismatches, tty and gui both build. And against the real binaries rather than the harness: in a pty, SPC y emits OSC 52 carrying exactly the selection while plain y emits nothing, SPC p issues the read and pastes the reply, and a bracketed paste of "dd..." inserts text instead of deleting two lines. In a real SDL window, SPC y then SPC p round trips through the system clipboard while the default register holds different text. Setting tty_blank back to .prompt_and_input reproduces all 86 old goldens byte for byte.
* Esc alternates between the last two panes; Toggleterm is goneGabriel Schneider2026-08-10
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Esc ran Toggleterm, which hopped between the newest DOC and the newest TERMINAL. That distinction never earned its keep. It made Esc unpredictable — which of three panes you landed on depended on their kinds, not on where you had been — and it could not alternate between two files at all, which is the case you hit most. Editing two files, Esc did nothing. The replacement already existed. Last (SPC j j) is "the pane you were in before this one, whichever it was": it walks the jump stack for the newest entry naming a different pane and restores its line and column. So Esc, and Shift-Esc in tty, now run Last, and Toggleterm is deleted rather than renamed — a third implementation of "go to the other pane" was the thing to avoid. SPC w t goes with it; the w group is the four directional moves, and the jump group already had SPC j j. Held down, Esc alternates. Two files, a file and its shell, a file and a +Search — all the same, because Last has no notion of kind to get wrong. This depends on the swap in the same series: Last reads the stack backwards, and until hopping stopped appending, the pane you came from could fall off it. windownav.snap needed only its keys and prose changed — its golden did not move at all, which is the useful evidence here: for the one scenario the old builtin handled well, Last produces an identical focus sequence. Coverage for what it did not handle is new: a unit test opens a second FILE by looking its name and asserts Esc alternates between two panes of the SAME kind, which is the case that used to be a no-op. Docs follow: tutor.txt, docs/helix-keys.md, docs/design.typ, and the builtin index goldens, which are now one row shorter. 75/75 snapshots, both unit suites, and the macOS ABI build all pass.
* show New in every pane tag and enforce builtin-first Exec fallbackGabriel Schneider2026-08-10
|
* prioritize useful topbar commands and put Kill lastGabriel Schneider2026-08-10
|
* add New builtin for an empty temporary file in the calling columnGabriel Schneider2026-08-10
|
* normal Esc toggles document/terminal focusGabriel Schneider2026-08-10
|
* the mode is a character in the layout box, not a word in the taglineGabriel Schneider2026-08-01
|
* a Look path can name a range, and search selects what it foundGabriel Schneider2026-08-01
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | file:LINE:COL-ENDLINE:ENDCOL, with the two short forms people actually type reading naturally: file:412:9-21 on one line, file:412-418 whole ones. Ends are inclusive. A path feature, not a search feature — a ranged path typed in a tag or middle-clicked out of a shell's output selects just the same; search is only its first consumer. The dash is the fussy part. `-` was already a file char, so a ranged word survives click expansion whole, but a range needs a number on BOTH sides or my-file:10, build-2 and 2026-07-30 would stop being paths. Table-driven test in look.zig for exactly that. Selecting goes through the cellRange/setPaneRange pair the multi-cursor work left, and hxOff clamps both ends, so a stale range selects what still exists rather than crashing or reaching past EOF — pinned with an 8:6-400:9 range in a nine-line file. Producers: / search, Grep, and five LSP sites through a new spanRow — goto, references, rename tokens and both symbol lists were throwing away real protocol ranges at path:line:col. Left alone deliberately: Find rows are bare paths with nothing to span, a jump is a spot not a span, and the diagnostic and format paths only ever have a point, where half a range would be worse than none. One knock-on worth knowing: n now leaves an EXPLICIT selection, so a topbar execute chords it. grep.snap's no-match step was silently becoming `Grep TARGET`; it runs from the leader path now, which never chords, and the dedicated chord steps stayed where they were.
* k off the topmost tagline focuses the TOPBAR: row 0 is a tagline tooGabriel Schneider2026-08-01
|
* tag columns are the WHOLE rendered tag: h/j/k/l walk taglines, the path ↵Gabriel Schneider2026-08-01
| | | | selects but never edits
* an output pane is not a document: +Search/+Help split below the pane that ↵Gabriel Schneider2026-08-01
| | | | | | | | | | | | | | | | | | | | asked, never into a column of their own placeDoc classified any file pane as a doc, so a +Search opened from a lone shell took layoutInsertColumn(0) - a whole new leftmost column, shoving every existing column sideways - and an open results list was then eligible as the split parent for a real file, stacking documents under the list. An output buffer has no file behind it and no Save; it is the result list belonging to the pane that asked for it. Now it is that on both sides of the rule: it splits below from_id whatever kind of pane that is (a source that died falls back to stackDocLeft, the same last resort a full column bar uses), and it is skipped when a real doc hunts for its split parent, so a file opened from a search row joins the docs instead of the results. Real docs are untouched: fsearch/rsearch/look-file/tutor/lookpanes all pass unchanged. psearch is the proof - its results snap was two columns (the shell pushed to x=70, its gutter run at 70-71) and is now one 140-wide column with the +Search stacked below at the same x origin.
* look resolves against every open pane's directory: clicked pane first, then ↵Gabriel Schneider2026-08-01
| | | | most-recently-focused, search only when all fail
* helix theme, now the default: near-black page, chrome one grey-ramp step off itGabriel Schneider2026-08-01
| | | | | | | | Colors lifted from the user's own helix theme (~/.config/helix/themes/pardes.toml, pinned against a real hx render through a pty). Theme gains box/box_dim so a restrained theme can turn the accent down; the hardcoded gray.* overlay greys were the dark theme's own fields spelled twice and are gone. The old default is still one NextColor away.
* trim the taglines: image renderer toggles and Colors/Crt become leader-onlyGabriel Schneider2026-08-01
| | | | | | | | | | | | | | | | | | | The image tag spelled out `Petscii <C64|Term> Ascii` and actOnSelection matched those words by hand before the builtin dispatch. They are three real Builtins now (SPC t p/l/a), so the by-word matching is gone, the tag is a plain `img <path> Del`, and with nothing live left in it the image early-returns in curTail, enterTagEdit and the tag-click guard go too — an image tag edits like every other pane's. Colors and Crt leave the topbar for SPC t c / SPC t r: set-once display switches should not spend width in a bar you read every frame. NextColor stays, it is the one you cycle repeatedly. Both remain full builtins. The snap scripts that clicked those words now press the leader instead, and images.snap finally exercises the palette and ascii toggles for real: its old clicks at x=57 landed on the neighbouring shell's tag, so that toggle had never been covered. The test PPM grew to 512x512 with LCG noise so the ASCII bitmaps actually win cells and dropping them visibly changes the art.