PARDES TUTOR tmux + vi + acme, from scratch. The model is acme's: EVERYTHING is text, editable and executable the same way. Modal editing (helix-style) lives on top of that. Press j until you reach the introduction. ================================================================= = INTRODUCTION = ================================================================= A pane is just text on screen. There is no separate "buffer" type — what you see is what you edit. Some panes happen to be live terminals; most are text you move a cursor over. Modal editing is layered on top. Three modes (the BOX at the pane's top-left corner shows which): NORMAL block cursor, keys move and edit. The box is BLANK. ^ INSERT keys type text at the cursor. $ TTY keys go straight to the shell. (terminals only) A bare `pardes` opens one shell already in TTY. Give it a file or a directory and you start in NORMAL. SIX PARTS, ordered by what is most different from editors you know: 1 — THE MOUSE. Acme's three buttons; nothing like vim. 2 — PANES. Moving between them. Esc, Shift-Esc, Ctrl-w. 3 — THE TTY. Raw input, prompt-aware Esc, and the mode tag. 4 — DETACHED. The core outliving the terminal showing it. 5 — THE KEYS. Helix-style modal, and where it differs. 6 — THE REST. PDFs, images, the language backend, scripting. PRACTICE BLOCKS (part 5): the "# keys:" line lists keystrokes (space-separated; esc/enter/bs are special, the rest type each char). The lines under "# before" are what you practice on; "# after" is what you should end up with. They are here to be TYPED and nothing runs them. What pins the real behaviour is `zig build hxdiff`, which replays test/hxcases against goldens recorded from a real helix, and `zig build hxparity`, which runs each case twice — once in a file pane, once in a shell — and demands the two agree. Hold j to reach part 1. ================================================================= = PART 1 — THE MOUSE (acme chording) = ================================================================= Three buttons, three verbs: LEFT select, and focus the pane. Also pins the cursor. MIDDLE EXECUTE the word or selection (a builtin, or a shell line). RIGHT LOOK: open the file, directory or URL under the pointer. CHORDS — hold one button and click another without letting go: 1-2 (hold left, click middle) CUT the left selection 1-3 (hold left, click right) PASTE over it both, in one hold SNARF (copy) 2-1 (hold middle, click left) execute the middle word WITH the left selection as its argument Every tag with text leads with Save; a terminal also has Togglettymode and Filter. Tty opens a terminal; New belongs to each column tag. Images show "Tty Del Collapse"; PDFs also have PdfSections and PdfTint. Every pane has Collapse: hide its body, then execute again to expand it. The top bar is: Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Exit Reach it from the keyboard with `k` off the topmost tagline; `j` comes back down. KEYBOARD EQUIVALENTS, because the buttons are not the only way in: Enter = LOOK (right button) Tab = EXECUTE (middle button) Both act on the selection when there is one. Neither is a way into TTY. ================================================================= = PART 2 — PANES: MOVING BETWEEN THEM = ================================================================= Panes live in columns. Everything here works in any mode, because getting OUT of a pane must work from inside a pane that owns its keys. FOCUS A NEIGHBOUR Ctrl-w h/j/k/l focus the pane left / down / up / right SPC w h/j/k/l the same, in body normal mode only Use Ctrl-w in a terminal: there SPC belongs to the shell. GO BACK Esc hop to the pane you were in BEFORE this one. Held down it alternates between two. This is the `Last` builtin, also SPC j j. Ctrl-o walk the jump history BACK (the `Back` builtin) Ctrl-i walk it FORWARD (`Forward`; SPC j l shows the stack as a buffer) Ctrl-i and Tab are the same byte on an old terminal. Where they are, Tab keeps meaning execute and Ctrl-i does nothing — the right way round, since Tab-executes is the older and more used of the two. WHEN Esc MEANS SOMETHING ELSE Three panes have their own claim on Escape, so there is a second spelling that always leaves: Shift-Esc leave this pane, whatever Escape means inside it in INSERT Esc returns to normal. Press it again to hop. in a PDF Esc cancels the selection and the search highlights and stays in the document. Shift-Esc hops out. in raw TTY Esc goes to the program — vim gets its Escape. Shift-Esc hops out. But see part 3: at a shell PROMPT, plain Esc hops too. Shift-Esc needs a terminal that reports modifiers on Escape (the kitty keyboard protocol). Where the host does not, it arrives as a plain Escape and means whatever Escape means in that pane. MAKE AND MOVE PANES Alt-n new terminal below the active one Alt-c move the active pane into a fresh column — any pane, not just a terminal. A no-op if it is alone in its column, or if the sixth column already exists. New in a column tag: a new scratch pane Newcol in the top bar: a pane in a new column Tty new terminal in the calling pane's directory Togglettymode in a terminal tag: switch editor/raw mode (Ctrl-B) Joincol delete this column, move its panes to the one right Del in a pane's own tag: close it. From the keyboard, between two panes, it asks which one gets the space: k or j DelAbove close it, giving the space to the pane above (Del k) DelBelow close it, giving the space to the pane below (Del j) A new file opens in a new COLUMN only if both panes would still get 100 columns of width. Otherwise it stacks in the one you are in. ================================================================= = PART 3 — THE TTY (a terminal is just a pane) = ================================================================= There is no "open a terminal in a split" separate from "edit a file in a split". A TERMINAL IS A PANE. The same modal keys that edit a file navigate the terminal's screen. On a terminal pane: NORMAL ( ) the PROMPTS are gone — a clean acme page — but the command you typed at each one stays, pulled to the left edge, because that is the part worth reading. Navigate with the same h/j/k/l/w/b/e as a file. INSERT (^) the same page; keys type an insertion overlay. TTY ($) the REAL shell. Prompts back, keys straight to the pty. ENTERING TTY Ctrl-b toggle raw TTY/editor mode on a terminal pane Shift-Esc also enters raw TTY from editor mode Togglettymode in the pane tag switches modes in either direction `pardes --tty-toggle=g` chooses Ctrl-g for toggling instead. Entering TTY moves the shell's real cursor to the place you selected on its prompt input line, using its OSC 133 prompt marks. RAW INPUT Ctrl-b switches to editor mode. Other keys go to the child, including Ctrl-o, Ctrl-w, Alt shortcuts, and modified Escape. The two paste chords are the exception: Ctrl-V types the yank register at the program and Ctrl-Shift-V types the desktop clipboard. Plain Esc at a detected shell prompt hops to the previous pane. While a program owns the terminal, Esc goes to that program too. Use the Togglettymode tag to leave raw input in place. Desktop paste events still feed the child. On Linux, Tty9p (SPC n 9 from editor mode) opens a terminal with this session mounted through kernel v9fs. It asks sudo in that pane, then starts your normal shell. $PARDES_MOUNT names its mounted tree. `Filter` in a terminal's tag toggles a pane-local, theme-keyed palette. ================================================================= = PART 4 — DETACHED SESSIONS (the core outlives the terminal) = ================================================================= A pardes session is a core — the text, the undo history, the layout, the pane shells — and a frontend that draws it. Normally they are one process. They do not have to be. STARTING ONE pardes --detach a session named by this process's pid pardes --detach=work ...named `work` pardes --attach become a frontend of the one session there is pardes --attach=work ...of the session called `work` pardes-gui --attach=work an SDL window is a frontend too And from inside a running editor, as ordinary acme words — type one in a tag and execute it, or press its chord: Attach hand this window to the session there is (SPC s a) Attach work ...to `work` Detach leave the session, and leave it running (SPC s D) WHAT MAKES IT DIFFERENT FROM tmux The pane shells belong to the SESSION, not to the frontend. Attach, detach, kill the terminal, attach from another one, and the build that was running in pane 3 is still running and has been scrolling into the core the whole time. Nothing is replayed to you; it never stopped. `Attach` switches IN PLACE. The window, the terminal and the process stay; what changes is where the state lives. Only on a successful handshake does the frontend give up its own core — so a failed attach costs you nothing. `Detach` is the smaller half: only the frontend that ran it leaves. The session, its shells and every other attached frontend are untouched, so leaving is a SUCCESS — the terminal prints where to come back to and exits 0. In a session with nothing to detach from it says so on the message row and does nothing. MORE THAN ONE FRONTEND N frontends attached to one session all see the SAME screen, at the smallest common grid — `screen -x`, not N sessions. Two windows of different sizes converge on the smaller and the larger letterboxes. WHAT A DAEMON CAN ALSO DO A detached session serves acme's control filesystem like any other: pardes --detach=work 9P on the session's default unix socket Every native session is scriptable over 9P — see part 6. The socket lives in $XDG_RUNTIME_DIR (else ~/.local/state/pardes), created 0700, never /tmp: it carries keystrokes into a live editor. ================================================================= = PART 5 — THE KEYS (helix-style modal) = ================================================================= Same core as helix: a block cursor you move with h/j/k/l, motions that SELECT what they cross, and an edit that acts on the selection. There is no verb+noun — the motion already selected, so `wd` is what `dw` was in vim. ----------------------------------------------------------------- = 5.1 MOTION AND COUNTS = ----------------------------------------------------------------- k h left, l right, j down, k up (also arrows) h l w/b/e word forward/back/end (W/B/E long) j 0 line start, $ end, ^ first non-blank gg first line, ge START of the last line f/F/t/T find a character forward/back Bare G does NOTHING. `ge` is the start of the last line. # keys: l l l # before abcdef # after abcdef A number typed FIRST is a count, and only some keys take one: the motions, f/F/t/T and the `Alt-.` that repeats them, gg/gj/gk/g|, `x`, `o`/`O`, `>`/`<`, `p`/`P`, Ctrl-a/Ctrl-x, ]p/[p and ]space/[space, and the cursor-list keys C, Alt-C and )/(. Everywhere else it is swallowed: `3d` deletes once, `3i` types once. `0` is always line-start and never the start of a count. Ctrl-d/u/f/b ignore counts: a page is a page. # keys: 3 l i Z esc # before abcdef # after abcZdef ----------------------------------------------------------------- = 5.2 ENTERING INSERT = ----------------------------------------------------------------- `i` at the cursor. `a` after it. `I` first non-blank. `A` end of line. `o` open below. `O` open above. Esc returns to normal. # keys: i X esc # before abc # after Xabc # keys: o line2 esc # before line1 # after line1 line2 ----------------------------------------------------------------- = 5.3 MOTIONS SELECT = ----------------------------------------------------------------- w/b/e and f/F/t/T leave a SELECTION behind them. So `i` after a motion types at the selection's START, not where the cursor stopped. `;` collapses a selection to a single cursor first. # keys: w ; i Z esc # before one two # after one Ztwo ----------------------------------------------------------------- = 5.4 SELECT AND EDIT = ----------------------------------------------------------------- x select the LINE (again: extend by one more) v character-wise select, then move d delete the selection c change it y yank it p / P paste after / before u undo U redo > < indent / outdent Ctrl-a / Ctrl-x increment / decrement Selection is LINE-first here — `x` — with `v` for characters. That is the main divergence from helix. # keys: x c typed esc # before replace me # after typed ----------------------------------------------------------------- = 5.5 THE REST, IN ONE PLACE = ----------------------------------------------------------------- s / S regex, one cursor per match, previewing as you type. C , ( ) Alt-s Alt-- Alt-_ _ work the resulting LIST. m i / m a textobjects: w W p, the bracket pairs, the three quotes m s/r/d surround add / replace / delete; mm jump to the match ] [ step by paragraph, blank line, diagnostic | filter every selection through /bin/sh -c (savable file panes only) : the tag as a command line / case-insensitive SUBSTRING search, one hit per line — not a regex. The regex lives on s and S. n / N select the next/previous LOOK-able text, across panes, as a ring. Enter opens what you land on. VIEWPORT zt zz zb scroll so the cursor is at top / center / bottom zj zk scroll one line, cursor pushed along Ctrl-d/u half page down / up Ctrl-f full page down. Ctrl-b pages up on a FILE pane; on a terminal it is the tty toggle (part 3). ----------------------------------------------------------------- = 5.6 SPC — THE LEADER = ----------------------------------------------------------------- Nearly every builtin has a NAME you can execute anywhere text lives and a KEY PATH you can press. SPC in body normal mode starts the path; what you have typed shows on the pane's message row until it fires. Esc abandons it, and so does any key that leads nowhere. SPC ? list every path SPC d Del Exit (quit) remains available in the topbar. SPC f s Save SPC f f Find SPC f n New SPC y Y p P R the system clipboard SPC w h/j/k/l focus a neighbouring pane SPC j j the pane before this one SPC j o/i back / forward SPC s a Attach SPC s D Detach SPC t * the toggles SPC l * the language SPC h t this tutor ================================================================= = PART 6 — THE REST = ================================================================= NOT TEXT .pdf the real document through MuPDF. j/k scroll it, `/` searches it, Esc cancels selection and highlights, Shift-Esc leaves. PdfFit / PdfTint / PdfSections sit in its own tag. images pixels where the shell has them, petscii glyphs where it does not (SPC t p / l / a). LANGUAGE — ZLS, compiled in, .zig only. Nothing runs in the background and nothing is cached: gd gD gy gi gr, the ten SPC l words, ]d/[d and ]D/[D, `=` for a format diff, and Tab after a dot in insert. THE CONTROL FILESYSTEM — the extension mechanism, and there is no plugin API, no interpreter and no rebuild. A program that opens files IS an extension. pardes the 9P socket opens by default A directory per pane holding `name`, `body`, `tag`, `addr`, `dot`, `data`, `sel`, `dirty`, `event`, `pty/` and the rest, plus `index`, `status`, `look`, `exec` and `log` at the root. Every pane shell receives `$PARDES_9P` (the socket) and `$PARDES_PANE` (its serial): /pane//body /index /pane/new open it to make a pane; rmdir closes one /look /exec `FILE:12` and `Save`, as the mouse does A terminal pane also has `pty/`: /pane/3/pty/ctl winsize, sig /pane/3/pty/data terminal input/output Over 9P the same tree answers plan9port, from anywhere: 9p -a $XDG_RUNTIME_DIR/pardes-9p-work.sock ls / 9p -a $XDG_RUNTIME_DIR/pardes-9p-work.sock read index ...and pardes is a 9P CLIENT too, so one session can read another's: pardes --mount=peer=work /n/peer/pane/1/body Look opens the other session's body TWO THINGS WORTH KNOWING. While a program holds a pane's `event` file open, MIDDLE AND RIGHT CLICKS IN THAT PANE BELONG TO IT: pardes reports them and performs nothing, so that pane's tag can carry the program's own words. The keyboard is never suppressed, and the clicks come back when it exits. And writing an event record back — `origin type q0 q1` — makes pardes perform the Look or Exec it names. That is arbitrary command execution by design. The socket sits in the user's private runtime directory. docs/fs.md describes the filesystem and mount paths. ================================================================= = SUMMARY = ================================================================= MOUSE L select/focus M execute R look(open) 1-2 cut 1-3 paste both in one hold = snarf 2-1 = execute the middle word with the left selection keyboard: Enter = look, Tab = execute PANES Ctrl-w h/j/k/l focus a neighbour (SPC w h/j/k/l in a body) Esc the pane you were in before this one Shift-Esc leave, whatever Escape means in here Ctrl-o / Ctrl-i jump history back / forward Alt-n new terminal below Alt-c pane into a new column TTY a terminal IS a pane Ctrl-b toggles raw input; Shift-Esc enters from editor mode Togglettymode in the tag switches modes in either direction Esc goes to the program — except at a shell PROMPT, where it hops to the previous pane Ctrl-b switches to editor mode Ctrl-V types the register, Ctrl-Shift-V the clipboard All other keys belong to the child DETACHED pardes --detach[=name] the core, no terminal pardes --attach[=name] a frontend for it Attach / Detach the same, as words (SPC s a / s D) the pane shells belong to the SESSION and never stop N frontends share ONE screen at the smallest common grid the default 9P socket works in a daemon too KEYS h j k l w b e 0 $ ^ gg ge f F t T v x d c y p i a I A o O u undo U redo motions SELECT, so `i` types at the selection's start and `;` collapses first a leading NUMBER is a count on motions, x, o/O, > <, p P, Ctrl-a/x and ]space — not on the other edits bare G does nothing; `ge` is the START of the last line s / S regex cursors; m i/a textobjects; m s/r/d surround ] [ paragraph, blank line, diagnostic; | pipe a selection / is a case-insensitive SUBSTRING search, not a regex SPC is the leader (SPC ? lists every path) SCRIPTING 9P is served by default on $PARDES_9P /pane//{name,body,tag,ctl,addr,data,sel,event,pty/} a script holding `event` owns that pane's middle and right clicks; writing a record back runs it vs HELIX selection is LINE-first (x), v for characters; `/` is a substring search, not a regex. vs VIM no verb+noun — the motion already selected, so `wd` is what `dw` was; Esc hops focus; bare G is a no-op. vs BOTH a terminal is just a pane, and the core can outlive the terminal that is showing it. Spawn this tutor again: middle-click "Tutor" in the top bar, or SPC h t. Quit: this is a file pane — `:q` is not wired. Close it with Del in its tag, "Exit" in the top bar to quit everything, or Ctrl-c the app. "Kill" does not quit: it stops the commands pardes started, as acme's does.