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 = ================================================================= Pardes is tmux + vi + acme, made from scratch. The foundation is the acme model: 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 (tty mode); most are text you can move a cursor over. Modal editing (helix-style) is layered on top of that. Three modes (the BOX at the pane's top-left corner shows which): • NORMAL block cursor, keys move/edit. DEFAULT on startup. ^ INSERT keys type text at the cursor. $ TTY keys go straight to the shell. (terminals only) This tutor is in THREE parts, ordered by what's most different from editors you may know: PART 1 — the MOUSE. Acme's three buttons; nothing like Vim/Helix. PART 2 — the TTY. A terminal is just a pane; Ctrl-b (or Shift-Esc) drops into it. PART 3 — the KEYS. Helix-style modal (with the Pardes differences). PRACTICE BLOCKS (part 3): the "# keys:" line lists keystrokes (space-separated; esc/enter/bs are special, the rest type each char). The clean lines under "# before" are what you practice on; the lines under "# after" are what you should end up with. "# at: row,col" (right after # keys:) sets where the cursor starts. These blocks are also run as unit tests (generated from this file by tutor_gen). Hold j to reach part 1. ================================================================= = PART 1 — THE MOUSE (acme chording; the most different part) = ================================================================= Acme's central idea: the THREE mouse buttons each ACT on text, and the keyboard mirrors them. Pardes inherits this. (Vim and Helix have almost none of it — their mouse is selection/scroll only.) ┌─────────┬─────────┬─────────┐ │ L │ M │ R │ │ (1) │ (2) │ (3) │ ├─────────┴─────────┴─────────┤ │ │ │ ( o ) │ the wheel scrolls the pane │ │ └─────────────────────────────┘ L select a plain click also FOCUSES the pane and PINS the modal cursor where you click, so you can edit there next. A click never changes a pane's MODE (tty stays tty). M execute run the selected text: a builtin name runs it, anything else is SENT to the shell the pane runs. This is how you run a command you typed in a text mode. R look open the word under the cursor as a path: a directory opens/focuses a terminal there and ls's it; a file opens a file pane (scrolled to a ":line" suffix if present). A bare name is tried in THIS pane's directory first, then in every other open pane's, most recently used first — a name none of them holds is what becomes a search. WEB TOUCH (one finger): a tap is LOOK, the same action as R; a drag past a small movement threshold is natural scrolling. Once a gesture becomes a scroll it cannot also LOOK on release. The browser has no host filesystem or ptys: LOOK opens URLs or read-only Pardes .zig sources that were Git-tracked and embedded when the web build was made. The published launcher is a real Pardes terminal dump of `git ls-files '*.zig'`: every listed path opens, and the opened source uses tree-sitter syntax colors. A touch beginning on a tagline or pane separator instead latches a left-mouse gesture, so layout drags never scroll. Touch circles/trails and the LOOK flash appear only while the Debug builtin is on. SELECT-THEN-ACT: - MIDDLE-drag over text selects AND runs it on release (one gesture); a no-drag middle click auto-expands to the word under the cursor. - or select with the keyboard (`v` chars / `x` lines), then press Tab to execute or Enter to look — the acme chords on the keyboard. CHORDS (acme's held-button combos): 1-2 hold LEFT on a selection, tap MIDDLE: Cut it into the yank register (the snarf buffer). 1-3 hold LEFT, tap RIGHT: Paste the register over the selection, or splice it in at a bare click point. So 1-2 then 1-3 in the SAME hold = copy (Snarf): the text comes back, the register keeps it. After a chord the left release is inert. 2-1 hold a MIDDLE drag over a command, tap LEFT: the kept left selection rides along as the command's ARGUMENT. No selection in that pane? The other panes' are searched (active pane first) — a kept left selection or a v/x one, wherever it lives. 2-3 / 3-1 / 3-2 tapping the other button during a MIDDLE (execute) or RIGHT (look) drag CANCELS the gesture. In a TTY-mode shell 1-3 pastes into the program like a terminal: the click is forwarded first (if it listens for mouse) so the paste lands under it, then the register arrives bracketed. The selection a chord leaves behind is dismissed by the next left click (it doesn't stretch to the click). THE TAG: each pane has a one-line tag: its directory or file path + builtins. (The mode is the box at the tag's left end, not a word in the tag.) Every pane shows "New" for an empty temporary file in its column. File panes show "Save New Del" by default; Save writes the current file to disk, Del closes the window. Clicking a tag edits it in insert mode: type straight in, Enter looks / Tab executes the word at the cursor, Esc hands focus back to the body. `:` from the body focuses that same tag in NORMAL mode, parked at the first EDITABLE column — vim's command line with acme's words in it: `:w` is w onto "Save", Tab to execute it, and you land back in the body where you left off (the chord keys are the same here as anywhere else; `i` if you would rather type a command than walk to one). Terminal and image panes show "New Del". In that normal mode h/j/k/l do NOT move inside the tag: a tagline is a place in the LAYOUT, so they focus the neighbouring window and land on ITS tagline, still in normal mode — you walk the taglines of the screen and never drop through a body. (Same moves as SPC w h/j/k/l and Ctrl-w h/j/k/l; nothing that way = you stay put.) The ARROWS are the in-tag motion, and w/b/e/0/$/^ still walk the tag's own words. Off the TOPMOST tagline k keeps going: above it is the top bar, which is a tagline too — the screen's own — and j comes back down. The MODE + path part of a tag is live chrome, so it cannot be edited — but it CAN be selected, by motion or by dragging across it: 0 then W/E selects the path, `y` yanks it, Enter looks it. Typing or backspacing with the cursor inside it does nothing; edits only ever reach the words you own, to the right of the path. "Delcol" still exists as a command: type it in a tag or body and execute it to close the whole column. A SEPARATE bar across the top of the screen holds the window-agnostic builtins: New Newcol Find Grep Help Tutor Dump NextColor Debug Kill Middle-click "New" for an empty temporary file in this pane's column, "Newcol" for a new column, "Tutor" to spawn this tutor, "Kill" to quit. From the KEYBOARD the bar is `k` off the topmost tagline: it takes the cursor, h/l and the arrows move by character, w/b/e and 0/$ by word, Enter or Tab runs the word under the cursor exactly as a middle-click on it would, j drops back onto the tagline below and Esc leaves. There is nothing to type up here — the bar is chrome, so it has no insert mode. Debug toggles the stats overlay and NextColor cycles the theme: "helix" (the default — a near-black page and chrome that barely lifts off it, copied from helix's own), then "dark", then the acme-light yellow. The bar holds only what you reach for often — the rest of the builtins are words you execute and keys you press. Every one of them has a KEY PATH under SPC (part 3.7): "Colors" (the syntax/ansi recolor) is SPC t c, "Crt" is SPC t r, and SPC ? lists the lot. Right-click a directory in any body to open a terminal there. SEARCH: `/` in normal mode types a pattern into that pane's own tag (it stays visible while you type; Esc abandons it). Enter searches the pane — a file's text, a shell's scrollback, anything — for the pattern, plain and case-insensitive, and writes one row per hit into a "+Search" pane. That is an OUTPUT BUFFER: a file pane with no file behind it, so it has no Save, but everything else about it is an ordinary buffer you can read, edit, select and look in. It is not a document, though, and never takes a column of its own: it opens BELOW the pane that asked for it, in that pane's column, be that a file or a shell — and a file you then open from its rows goes where files go, not under the list. `n`/`N` step the rows and look each one, so the view follows along. Right-clicking a word that names no file in ANY open pane's directory searches for it — acme's button 3 — except in tty mode, where the click belongs to the program on the other end. On a shell with no search armed, n/N instead step the lookable tokens in its output. A hit in a file reads `path:LINE:COL-ENDCOL`, the ordinary look target carrying the SPAN that matched. A hit in a shell or an output buffer has no file to name, so it reads `@pN:LINE:COL-ENDCOL` — pane N, then the place in it. Looking either one goes there and SELECTS the span, which is why n/N land ON a hit rather than beside it. The range is part of the PATH syntax and not part of search: type one anywhere text lives and a look on it selects. `main.zig:412-418` is whole lines, `main.zig:412:9-21` is columns on one line, `main.zig:412:9-418:1` is the general form, and the shorter spellings still mean what they always did — `main.zig:100`, `main.zig:100:7`, `@p3:12`, all of them optional. FIND: the "Find" builtin (SPC f f) arms the same tag input, but Enter walks the pane's DIRECTORY instead of its text — `fd`, in-core — and writes one matching PATH per row into the same "+Search" buffer. Rows are look targets like any other, so n/N step them and each found file opens; the match is on the name, plain and case-insensitive, ".git" is skipped. LAYOUT: columns split the screen; windows stack within a column. Panes abut with no wasted gap — a pane's own trailing edge (its last column, or last row above the next tag) IS the resize handle: hover it and a dashed line overlays that edge (keeping the underlying colors) to mark the drag. - drag a column's right edge to resize it against its neighbour - drag a window's bottom edge to resize it against the one below; either window may shrink to just its tagline (the tag row then IS the handle) — re-enlarging brings the body back intact - drag the move box (top-left of a pane; brighter when the pane is focused, and coloured by the theme) to MOVE a window between columns / reorder - the scrollbar is the gutter below the box: left-click scrolls UP to that point, right-click scrolls DOWN - the FIRST file/image/tutor you open takes a new leftmost column of its own (nothing is displaced, the other columns just narrow); every later one splits below a doc already open, so docs share that column - closing a window (Del, or its shell exiting) hands focus back to the window you were in before it, not to whichever one comes first (Mouse actions are hard to unit-test from text; native gestures are covered by the e2e suite. Browser touch and embedded-source LOOK are driven through real Chromium input by `zig build web-snap`.) ================================================================= = PART 2 — THE TTY (a terminal is just a pane) = ================================================================= This is the headline difference from Vim/Helix: there is no "open a terminal in a split" that's 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, and dropping into tty REUSES the shell's own prompt model rather than layering an editor cursor on top. On a terminal pane: NORMAL (•) prompt rows are HIDDEN — a clean acme-style page. You navigate it with the same h/j/k/l/w/b/e as a file. INSERT (^) same clean page; keys type an insertion overlay (the command you're composing). Prompts still hidden. TTY ($) the REAL shell — prompts + typed input shown, and keys go straight to the pty as terminal input. ESC: insert -> normal; from body NORMAL it hops between the last document and last terminal (the same Toggleterm as SPC w t). In raw TTY it still goes to the program. Ctrl-b: toggles TTY on a terminal by default; SHIFT-ESC is the same toggle, where the host reports modifiers on Escape. Those are the ONLY ways in or out. Use `pardes --tty-toggle=g` (or another letter) to make Ctrl-g the toggle instead. Entering is tty-native: if the shell is at a prompt and your modal cursor sits on the input line, it first moves the shell's REAL cursor to that spot — - empty input -> shell cursor at the prompt START - typed text -> shell cursor at/after the char you were on via the shell's OSC 133 semantic prompt (ghostty promptClickMove; our rc opts in with cl=line). The shell moves its own cursor with arrow keys it understands — Pardes doesn't fake one on top. ENTER / TAB (in normal) are NOT a way into tty — they're the acme mouse chords on the keyboard: Enter = "look" (open the path under the cursor), Tab = "execute". Both act on the selection if one is active. So the flow is: navigate the hidden-prompt page in normal, hit the tty toggle where you want to keep typing, and you're IN the live shell at that spot. No separate "terminal mode cursor" to reconcile. (The cursor positioning is enterTty's promptClickMove; it needs a live shell at a prompt. Mouse/tty behavior is exercised by the e2e suite.) ================================================================= = PART 3 — THE KEYS (helix-style modal, Pardes differences) = ================================================================= Same core as Helix and Vim: a block cursor you move with h/j/k/l, motions w/b/e, and you enter insert with i/a/o. The differences: - Selection is LINE-first: `x` grows a line selection downward. There's also `v` for a CHARACTER range. No multi-cursor. d/c/y act on whichever selection is active (else the current line). - NO verb+noun (Vim's dw, cw). Motions only MOVE. To delete a word, select it (`v` then motions, or `x` for whole lines) then `d`. - A plain ESC never reaches tty; it only does insert -> normal. Dropping a terminal into the live shell is the tty toggle (Ctrl-b by default, or Shift-Esc; see Part 2). - Enter / Tab in normal mirror the mouse: Enter = look (open the path under the cursor), Tab = execute. `:` runs a command from the tag (see Part 1). `u` undo, `U` redo. - Editing a file pane MUTATES real content; a terminal pane yanks rendered text and pastes it as an insertion run (shell output can't be deleted, only pasted text can). PRACTICE: run the keys on the "# before" lines; you should get the "# after" lines. (These blocks are unit tests too.) ----------------------------------------------------------------- = 3.1 MOVING THE CURSOR (h j k l) = ----------------------------------------------------------------- k * h = left, l = right h l * j = down, k = up (also: arrow keys) j The cursor sits ON a character (block). Motions only move. # keys: l l l # before abcdef # after abcdef ----------------------------------------------------------------- = 3.2 ENTERING INSERT: i a A I o O = ----------------------------------------------------------------- `i` insert at cursor. `a` insert AFTER the cursor. `A` insert at end of line. `I` insert at first non-blank. `o` open line BELOW + insert. `O` open line ABOVE + insert. (All match Vim and Helix.) # keys: i X esc # before bcdef # after Xbcdef Cursor on 'b' (col 0). `i` inserts before 'b'. # keys: a Z esc # before abc # after aZbc Cursor on 'a' (col 0). `a` inserts after 'a'. # keys: A Z esc # before abc # after abcZ `A` jumps to end then inserts — appends 'Z'. # keys: I Z esc # before abc # after Zabc `I` goes to the first non-blank ('a'), inserts before it. # keys: o line2 esc # before line1 # after line1 line2 `o` makes a blank line below, enters insert, "line2" typed, Esc. # keys: O top esc # before bot # after top bot ----------------------------------------------------------------- = 3.3 WORD MOTIONS: w b e (W B E long) = ----------------------------------------------------------------- `w` next word start, `b` prev word start, `e` next word END. W/B/E treat punctuation as part of the word. Same as Vim & Helix. # keys: w i Z esc # before foo bar # after foo Zbar `w` from 'f'(col0) lands on 'b'(col4). Insert before 'b'. # keys: e i Z esc # before foo bar # after foZo bar `e` from 'f' lands on 'o'(col2, end of "foo"). Insert before it. # keys: b i Z esc # at: 0,4 # before foo bar # after Zfoo bar Cursor on 'b'(col4, "bar"). `b` -> start of previous word = 'f'(col0). ----------------------------------------------------------------- = 3.4 LINE BOUNDS: 0 $ ^ g g G = ----------------------------------------------------------------- `0` start of line, `$` end, `^` first non-blank. `gg` first line, `G` last line. Same as Vim/Helix. # keys: $ i Z esc # before abcde # after abcdZe `$` to last char 'e', insert before it. (Cursor ON a char, so "end" = last char, not past it.) # keys: 0 i Z esc # before abcde # after Zabcde # keys: ^ i Z esc # before abcde # after Zabcde ----------------------------------------------------------------- = 3.5 LINE SELECTION + EDIT: x d c y p = ----------------------------------------------------------------- The Pardes difference is LINE-first selection: `x` grows a line selection downward; d/c/y act on it. `v` is still available for a character range when you need one. `x` start/extend a line selection `d` delete the selected lines (yanked) `c` clear the line + insert (change) `y` yank the selection (or current line) `p` paste the yank as a new line below # keys: x d # at: 1,0 # before keep gone # after keep Cursor on "gone" (row 1). `x` selects it, `d` deletes it. # keys: x x d # at: 1,0 # before a b c # after a `x` selects "b", `x` extends to "c", `d` removes both. # keys: x y j p # before orig dupe # after orig dupe orig `x` selects "orig", `y` yanks it, `j` to "dupe", `p` pastes below. # keys: x c typed esc # before old # after typed `x` selects "old", `c` clears it to an empty line + insert, type. # keys: c Q esc # at: 0,1 # before ab # after aQ No selection: cursor on 'b'(col1). `c` deletes 'b' + insert; type 'Q'. ----------------------------------------------------------------- = 3.6 VIEWPORT + PANES = ----------------------------------------------------------------- zt / zz / zb scroll so the cursor is at top/center/bottom Ctrl-d / Ctrl-u half-page down / up Ctrl-f full page down. (Ctrl-b pages up on a file pane; on a terminal it is the default tty toggle. If you start with --tty-toggle=g, Ctrl-g takes that role.) Ctrl-w h/j/k/l focus the pane left/down/up/right (SPC w h/j/k/l does the same; Ctrl-w also reaches a tty pane, where SPC belongs to the shell) Esc hop between the last document and last terminal (body normal mode; the same builtin as SPC w t) Alt-n new terminal below the active one Alt-c move the active terminal into a fresh column (No practice blocks: these are viewport/layout, not text edits.) ----------------------------------------------------------------- = 3.7 SPC — THE LEADER = ----------------------------------------------------------------- Every builtin has a NAME you can execute anywhere text lives, and a KEY PATH you can press. SPC in normal mode starts the path; the keys you have typed so far show at the right edge of the pane's tag until the sequence fires. Esc abandons it — so does any key that leads nowhere, rather than leaving the next keystroke armed. SPC ? Help: every builtin and the keys that run it SPC k Kill (quit) SPC d Del (close this pane) SPC f s/f f/f n Save / Find / New SPC h t Tutor (this file) SPC c n / c d Newcol / Delcol SPC t d/c/n/r Debug / Colors / NextColor / Crt toggles SPC t p/l/a Petscii / Palette / Ascii: an image pane's renderer — glyph art instead of pixels, the C64 palette or the terminal's own 16, and whether letters join the matcher's glyph set SPC s d / s r Dump / Restore the session SPC w h/j/k/l Left/Down/Up/Right: focus the pane that way SPC w t Toggleterm: hop between the last document you looked at and the last terminal, and back `?` works at ANY depth: SPC ? lists everything, SPC h ? lists only what the "h" group holds. Help writes into a "+Help" OUTPUT BUFFER, the same kind of pane "/" search results land in — so it opens below the pane you asked from, never in a column of its own — and ordinary text, so the names in it are live: middle-click "Tutor" and it opens. (No practice blocks: these run builtins, not text edits.) ================================================================= = SUMMARY = ================================================================= MOUSE (acme): L select/focus+pin M execute R look(open) select-then-act: middle-drag, or v/x then Tab chords: 1-2 cut 1-3 paste (both in one hold = snarf) 2-1 = middle-exec with the left selection as argument file tag = path + "Save New Del"; other tags show "New Del" top bar = New Newcol Find Grep Help Tutor Dump ... Debug Kill (keyboard: k off the topmost tagline) WEB TOUCH: one-finger tap = LOOK; drag = natural scroll LOOK opens URLs or embedded tracked .zig source (read-only) published TTY dump lists every source; tree-sitter colors it tag/separator start = left drag; touch HUD requires Debug TTY: a terminal IS a pane; Ctrl-b (or Shift-Esc) toggles the shell, landing its cursor where you navigated (prompt start if the input is empty, mid-text otherwise) KEYS (helix): h j k l w b e 0 $ ^ gg G v x d c y p i a I A o O u undo U redo Enter=look Tab=execute : = the tag as a command line (arrows/words move in it, hjkl walk to the neighbouring TAGLINE, y/Enter act on the selection; the mode+path selects but never edits; k off the TOPMOST tagline = the top bar, j back down) zt zz zb Ctrl-d/u Ctrl-f Ctrl-w hjkl Alt-n/c Esc = last document <-> last terminal (body normal) SPC = the leader: a key path runs a builtin (SPC ? lists them; SPC k Kill, SPC d Del, SPC f s Save, SPC f f Find, SPC f n New, SPC w hjkl focus, SPC w t file <-> terminal) vs Helix: no multi-cursor; selection is LINE-first (x), plus v chars. vs Vim: no verb+noun (dw); motions only move; body-normal Esc hops focus. vs both: a terminal is just a pane; the same keys edit text and navigate the shell screen, and the tty toggle reuses the shell's own prompt to position you precisely. To spawn THIS tutor again from anywhere: middle-click "Tutor" in the top bar (next to Help), or press SPC h t. Quit the tutor: this is a file pane — `:q` isn't wired; close the window (middle-click "Del" in its tag), "Kill" (top bar) to quit everything, or Ctrl-c the app.