diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/tutor.txt | 1489 |
1 files changed, 345 insertions, 1144 deletions
diff --git a/src/tutor.txt b/src/tutor.txt index f75734e4..f712ab85 100644 --- a/src/tutor.txt +++ b/src/tutor.txt @@ -11,1287 +11,488 @@ = 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. + 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/edit. The box is BLANK: a pane - at rest has nothing waiting to eat what you type. + 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) + $ TTY keys go straight to the shell. (terminals only) - A bare `pardes` opens one shell already in TTY — there is nothing to - edit yet. Give it a file or a directory and you start in NORMAL. + A bare `pardes` opens one shell already in TTY. Give it a file or a + directory and you start in NORMAL. - This tutor is in FOUR 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). - PART 4 — the REST. Panes that are not text (PDFs, images), the - language backend, and the chrome you can change. + 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. A terminal is a pane. Ctrl-b and Shift-Esc. + 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 3): the "# keys:" line lists keystrokes + PRACTICE BLOCKS (part 5): 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. They are here to be - TYPED, and that is all they are — nothing runs them. What pins the real - behaviour is two suites. `zig build hxdiff` replays every case in - test/hxcases against GOLDENS recorded from a real helix, and fails on - any difference that is not written down as a waiver with a reason. - `zig build hxparity` runs those cases, and a file of editing extras, - twice inside pardes — once in a file pane, once in a shell — and - demands the two agree. + 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; the most different part) = += PART 1 — THE MOUSE (acme chording) = ================================================================= - 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.) + 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. - ┌─────────┬─────────┬─────────┐ - │ L │ M │ R │ - │ (1) │ (2) │ (3) │ - ├─────────┴─────────┴─────────┤ - │ │ - │ ( o ) │ the wheel scrolls the pane - │ │ - └─────────────────────────────┘ + 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 - L select a plain click also FOCUSES the pane and, outside tty - mode, PINS the modal cursor where you click so you can - edit there next. On a DOCUMENT it also drops you into - normal mode; a terminal keeps the mode it had, so 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 the directories of the panes you have BEEN in, newest - first and each directory tried once — a name none of them - holds is what becomes a search. + Every tag with text leads with Save; a terminal also has Filter. + Images and PDFs show "New Del". The top bar is: - 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 tracked or new/nonignored when the web build was made. - The published launcher is a real Pardes terminal dump of - Git's tracked-plus-new/nonignored source list: every listed - path opens, and the opened source uses tree-sitter 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 click flash are the SDL - build's debug overlay, drawn only while the Debug builtin - is on. The browser draws no such thing. + New Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor + Debug Kill - 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. + Reach it from the keyboard with `k` off the topmost tagline; `j` comes + back down. - 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 pane the drag started in is asked first, then - the active one, then the rest — 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 if - the program asked for bracketed paste, raw otherwise. - The selection a chord leaves behind is dismissed by the next left - click (it doesn't stretch to the click). + 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. - 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. - Anything holding TEXT leads with "Save". A file pane shows - "Save New Del" and Save writes that file (an unsaved edit puts `*` after - the filename); a pane with no file of its own — a terminal, an output - buffer — needs the path, so "Save notes.txt" writes it under the pane's - own directory and a bare "Save" arms a prompt already filled in with that - directory. Del closes the window. Clicking a tag - edits it in insert mode: type straight in, Enter looks / Tab executes - body focuses that same tag in NORMAL mode, parked on the FIRST WORD of - the tail rather than in the run of layout spaces before it — vim's - command line with acme's words in it, and on a file that first word is - "Save", so a bare `:` then Tab saves. `:w<Tab>` 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). A terminal shows - "Save New Del Filter": Save writes its plaintext scrollback to the path - you give and leaves it a terminal, and Filter starts on, is local to that - terminal, and - projects every rendered foreground and background ANSI, 256-colour and - truecolour value through keys made from the current Pardes theme; run it - to restore the program's original colours. - Images and PDFs show the plain "New Del", because their bytes on disk - already are exactly what they are. An image - tag leads with "img" and a PDF's with the word "pdf", its page out of - the count, and its three commands each preceded by its current setting - (part 4.1) — all of it live chrome, like the path. - 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 path at the head 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 E - selects exactly the path, `y` yanks it, Enter looks it. (`W` would drag - the alignment spaces in with 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 - — and one more, " Restore <path>", which appears the moment a Dump has - written one. - 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 the - way a middle-click on it does (with one difference: the mouse can carry - a selection kept elsewhere as the command's argument, and the keyboard - cannot), 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 box in the - top-right corner (and, where fingers exist, the touch circles and the - LOOK flash). NextColor steps the theme RING one place — and the ring is - 228 themes, not three: ours first ("helix", the default: a near-black - page and chrome that barely lifts off it, copied from helix's own; then - "dark"; then "acme", the acme-light yellow), then every theme helix and zed - ship, generated out of vendor/themes when pardes is built and sorted by - name. At 228 a step is a BROWSE and not a way to arrive: `Theme <name>` - goes straight to one, and "ThemeSel" (SPC t t) lists all of them into a - "+Themes" buffer whose rows ARE those commands — n/N to walk, Tab to - wear the one you stopped on. The bar holds only what you reach for - often — the rest of the builtins are words you execute and keys you - press. Nearly every one has a KEY PATH under SPC (part 3.13): "Colors" - (the global syntax/ANSI master switch) is SPC t c; a terminal's Filter - setting stays remembered while Colors is off. The native GUI scene effects are - SPC t r/R/g, panel transitions are SPC a s/z/d/a/v, 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 matching LINE into a - "+Search" pane — the FIRST hit on that line, named as a location, with - the line's own text after it — and then GOES to the first of those rows. - That last part is nothing new to learn: it is the step `n` is and the - look Enter is, run for you in the list that has just answered. A pattern - that matched nothing opens its empty buffer and goes nowhere. - That is an OUTPUT BUFFER: a file pane with no file behind it, so Save - there always takes a path and asks for one when you do not give it — - and writing it out leaves the buffer exactly where it was, still the - list the next search refills. Everything else about it is an ordinary - buffer you can read, edit, select and look in. The one that does become - a file is "+New", the empty scratch, which is what it was opened for. - 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` carry on down - those rows, and walking is ALL they do: a press moves the SELECTION to the - next look-able thing and opens nothing, so you can step past nine hits - to reach the tenth without opening the nine. Enter — the look chord — - opens the one you stopped on. The walk is a RING over PANES and not - over one buffer: the panes you have looked out of come first, most - recent first, then the output buffers you have not, newest first, and - only when there is neither does it step the pane in front of you — so - n/N work on a shell that never had a search armed, and off the end - they come round to the start. A Look from a result row may move focus - into the source file; the result pane remains the walk's owner, so the - next n/N returns there instead of starting from the file that opened. - After the FIRST press `N` is `n` - backwards exactly; the first one is not a step but an arrival, since - from a cursor the walk has never stood on there is nothing yet to step - back from. - 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 - a look that resolved nothing does nothing at all rather than searching. - A hit in a file reads `path:LINE:COL-ENDCOL` and then the matching - line's own text — the location is the leading word, and the path is - spelled relative to the buffer's own directory. It is 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 an - Enter on a row n/N stepped to lands ON the 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 select them one at a time and Enter - opens the one you meant; the match is on the name, plain and - case-insensitive, and the walk skips the directories nobody means — - .git, .jj, target, node_modules, .venv, __pycache__, .zig-cache and - zig-out — and stops at 512 hits, sixteen levels down, or a hundred - thousand directory entries, whichever comes first. +================================================================= += PART 2 — PANES: MOVING BETWEEN THEM = +================================================================= - 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 document you open — a file, an image, a PDF, this tutor — - takes a new leftmost column of its own, paid for only by the column - you opened it from; every unrelated column keeps its exact rectangle. - Every later document 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 + 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. - (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`.) + 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. -================================================================= -= PART 2 — THE TTY (a terminal is just a pane) = -================================================================= + WHEN Esc MEANS SOMETHING ELSE + Three panes have their own claim on Escape, so there is a second + spelling that always leaves: - 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. + Shift-Esc leave this pane, whatever Escape means inside it - On a terminal pane: - NORMAL ( ) the PROMPTS are gone — a clean acme-style page — but the - command you typed at each one stays, pulled over to the - left edge, because that is the part worth reading. A - prompt you never typed at leaves a blank row behind. You - navigate the - page with the same h/j/k/l/w/b/e as a file. - INSERT (^) the same page; keys type an insertion overlay (the - command you're composing). - TTY ($) the REAL shell — prompts back, and keys go straight to - the pty as terminal input. - - ESC: insert -> normal; from body NORMAL it hops to the pane you - were in before this one, whichever it was (the same Last as - SPC j j) — so held down it alternates between two panes. - In raw TTY it still goes to the program. - Ctrl-b: toggles TTY on a terminal, and is the only way back OUT of it. - SHIFT-ESC gets you IN, and once in TTY it does what ESC does in - normal mode — hops away, leaving this pane in TTY so coming - back lands you in the program you left. - Use `pardes --tty-toggle=g` to make Ctrl-g the toggle instead — - any letter but `c`, which stays SIGINT. 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, - counting back the prompt columns that were hidden from you, - 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. + 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. - 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. + 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. - 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. + 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 Newcol in the top bar: a pane, or a pane in a new column + Joincol delete this column, move its panes to the one right + Del in a pane's own tag: close it - (The cursor positioning is enterTty's promptClickMove; it needs a live - shell at a prompt. Mouse/tty behavior is exercised by the e2e suite.) + 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 KEYS (helix-style modal, Pardes differences) = += PART 3 — THE TTY (a terminal is just a pane) = ================================================================= - Same core as Helix: a block cursor you move with h/j/k/l, motions - w/b/e, insert with i/a/o, and a SELECTION every edit acts on. Two - differential suites — `zig build hxdiff`, which replays these keys - against goldens recorded from a real helix, and `zig build hxparity`, - which runs them twice inside pardes and demands a file pane and a shell - agree — fail the build on any difference nobody has written a waiver - for. So where this file disagrees with helix's own - manual, helix is right and this file is the bug. The deliberate - divergences: + 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. - - Selection is LINE-first: `x` grows a line selection downward, and - an edit with nothing selected acts on the line (or the character) - the cursor is on. `v` is the CHARACTER range when you want one. - - NO verb+noun (Vim's dw, cw) — because the motion has already made - the selection. A traversal motion SELECTS what it crossed (3.3), so - `wd` is what `dw` was; `miw` then `d` deletes a word from inside it, - and `x` then `d` deletes whole lines. - - A plain ESC never reaches tty. From a BODY in normal mode it hops - to the pane you were in before this one; everywhere else it leaves - insert, or abandons a leader path, a tag, an armed input. 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. - - `/` is a plain case-insensitive SUBSTRING search (Part 1), not - helix's regex one. There IS a regex engine and it lives on `s` and - `S` alone (3.7). - - Alt-c moves this pane to a fresh column instead of helix's - change-noyank, and Ctrl-b pages up in a document but toggles tty on - a terminal. Those two are written down as waivers, not accidents. - - 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). + 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. - PRACTICE: run the keys on the "# before" lines; you should get the - "# after" lines. + THE TOGGLE + Ctrl-b in and out of raw TTY, on a terminal pane + Shift-Esc the same toggle, spelled for hosts that report modifiers + on Escape + `pardes --tty-toggle=g` makes it Ctrl-g instead — any letter but `c`, + which stays SIGINT. ------------------------------------------------------------------ -= 3.1 MOVING THE CURSOR (h j k l), AND COUNTS = ------------------------------------------------------------------ + Entering TTY is tty-NATIVE, and this is the part worth understanding. + If the shell is at a prompt and your modal cursor sits on the input + line, pardes first moves the shell's REAL cursor to that spot, counting + back the prompt columns that were hidden from you. It does that with + arrow keys the shell already understands, through the shell's own OSC + 133 semantic prompt marks — it does not fake a cursor on top. So you + navigate the clean page, hit the toggle where you want to keep typing, + and you are IN the live shell at that spot. - k * h = left, l = right - h l * j = down, k = up (also: arrow keys) - j + LEAVING + Ctrl-b back to normal on this pane + Shift-Esc hop AWAY, leaving this pane in TTY — so coming back + lands you in the program you left + Esc goes to the program... unless the leaf process is a + SHELL sitting at its prompt, in which case it hops away + exactly like Shift-Esc - The cursor sits ON a character (block). Motions only move. + That last rule is the one people ask about. A shell prompt is a pane + you can leave, so plain Esc leaves it; a full-screen program (vim, a + pager, an agent) has taken the tty, so Esc belongs to the program and + you need Shift-Esc. Pardes knows which by asking whether the pane's + leaf process is still the prompt it forked. -# keys: l l l -# before -abcdef -# after -abcdef + PASTING INTO THE PROGRAM + Ctrl-V type the DEFAULT register — what `y` put there + Ctrl-Shift-V ask the SYSTEM clipboard + SPC p and the mouse chords cannot reach here: the pty owns every + keystroke and every button. - A number typed FIRST is a count. Not everything takes one, and the set - that does is worth knowing: the motions (h/j/k/l, w/b/e, W/B/E), the - four f/F/t/T and the `Alt-.` that repeats them, `gg`/`gj`/`gk`/`g|`, - `x`, `o` and `O`, `>` and `<`, `p` and `P`, Ctrl-a and Ctrl-x, - `]p`/`[p` and `]space`/`[space`, and the three cursor-list keys `C`, - `Alt-C` and `)`/`(`. Everywhere else the - number is swallowed — `3d` deletes once, `3i` types once, `3ge` goes to - the last line like `ge`. `0` is still - line-start and never the start of a count, and Ctrl-d/u/f/b ignore one - on purpose: a page is a page. + `Filter` in a terminal's tag toggles a pane-local, theme-keyed palette. -# keys: 3 l i Z esc -# before -abcdef -# after -abcZdef +================================================================= += PART 4 — DETACHED SESSIONS (the core outlives the terminal) = +================================================================= ------------------------------------------------------------------ -= 3.2 ENTERING INSERT: i a A I o O = ------------------------------------------------------------------ + 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. - `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.) + 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 -# keys: i X esc -# before -bcdef -# after -Xbcdef + And from inside a running editor, as ordinary acme words — type one in + a tag and execute it, or press its chord: - Cursor on 'b' (col 0). `i` inserts before 'b'. + 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) -# keys: a Z esc -# before -abc -# after -aZbc + 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. - Cursor on 'a' (col 0). `a` inserts after 'a'. + `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. -# keys: A Z esc -# before -abc -# after -abcZ + `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. - `A` jumps to end then inserts — appends 'Z'. + 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. -# keys: I Z esc -# before - abc -# after - Zabc + WHAT A DAEMON CAN ALSO DO + A detached session serves acme's control filesystem like any other: - `I` goes to the first non-blank ('a'), inserts before it. + pardes --detach=work --fs the tree under $XDG_RUNTIME_DIR + pardes --detach=work --fs9 the same tree, as 9P on a unix socket -# keys: o line2 esc -# before -line1 -# after -line1 -line2 + Either, both or neither. That is what makes a daemon scriptable while + nobody is looking at it — see part 6. - `o` makes a blank line below, enters insert, "line2" typed, Esc. + The socket lives in $XDG_RUNTIME_DIR (else ~/.local/state/pardes), + created 0700, never /tmp: it carries keystrokes into a live editor. -# keys: O top esc -# before -bot -# after -top -bot +================================================================= += 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. ----------------------------------------------------------------- -= 3.3 WORD MOTIONS: w b e (W B E long) = += 5.1 MOTION AND COUNTS = ----------------------------------------------------------------- - `w` next word start, `b` prev word start, `e` next word END. - W/B/E treat punctuation as part of the word. Same letters as Vim. - - NOT the same MEANING, though, and this is the one thing to unlearn: - a word motion in helix SELECTS what it crossed. `w` from 'f' does not - just park on 'b' — it leaves "foo " selected with the cursor at its - end. That is why d needs no motion after it (3.6): the motion already - made the selection. - -# keys: w d -# before -foo bar -# after -bar - - `w` from 'f'(col0) selects "foo " up to 'b'(col4); `d` deletes it. - -# keys: e d -# before -foo bar -# after - bar + 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 - `e` selects to the END of "foo" and no further, so the space stays. + Bare G does NOTHING. `ge` is the start of the last line. -# keys: b d -# at: 0,4 +# keys: l l l # before -foo bar +abcdef # after -bar - - Cursor on 'b'(col4, "bar"). `b` selects back to 'f'(col0). +abcdef - The consequence to remember: `i` inserts at the START of whatever is - selected, not where the cursor sits. After `w` on "foo bar", `i` - types at column 0. `;` collapses the selection onto the cursor first, - so `w;i` is the vim reading of `wi`. + 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: w ; i Z esc +# keys: 3 l i Z esc # before -foo bar +abcdef # after -fooZ bar - +abcZdef ----------------------------------------------------------------- -= 3.4 LINE BOUNDS AND GOTO: 0 $ ^ and the g prefix = += 5.2 ENTERING INSERT = ----------------------------------------------------------------- - `0` start of line, `$` end, `^` first non-blank. These three MOVE - without selecting, unlike the word motions above — so `$i` really - does insert at the end of the line. - -# 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.) + `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: 0 i Z esc +# keys: i X esc # before -abcde +abc # after -Zabcde +Xabc -# keys: ^ i Z esc +# keys: o line2 esc # before - abcde +line1 # after - Zabcde - - `g` is a PREFIX, and it is helix's g rather than vim's: - - gg first line ge LAST line (what vim spells G) - Ngg line N Ng| column N - gh line start gl line end gs first non-blank - gj VISUAL line down gk VISUAL line up - gt the view's top row gc its middle gb its bottom - (top and bottom are scrolloff-clamped: three rows in, so they - land where the cursor could have scrolled to anyway) - - `G` ALONE DOES NOTHING. helix's goto_line only acts with a count, so - `12G` is line 12 and a bare `G` is a keystroke that went nowhere — - `ge` is the key that takes you to the last line — its START, the way - `gg` takes you to the first line's. - - `gj`/`gk` are the VISUAL pair: with soft wrap on (`SPC t w`, part 4.1, - on to start) one long line is drawn as several rows, and these two walk - those rows — the automatic breaks, not the newlines — keeping the column - they had inside the row. Plain `j`/`k` stay whole FILE lines, so on a - wrapped paragraph `j` jumps past every row of it and `gj` steps one. With - wrap off a line is one row and the two pairs are the same key. - - Five more gotos live under the same prefix — gd gD gy gi gr — and - they belong to the language backend, in part 4.2. - +line1 +line2 ----------------------------------------------------------------- -= 3.5 FINDING A CHARACTER: f F t T = += 5.3 MOTIONS SELECT = ----------------------------------------------------------------- - `f<char>` extends the selection forward THROUGH the next <char> on - this line, `F<char>` backwards. `t` and `T` are the same two but stop - one short of it. A count takes the Nth — `2fo` is the second `o`. - `Alt-.` repeats whichever of the four you used last. + 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. - They select, the way w/b/e do, so d is the natural next key: `fx` and - then `d` deletes everything up to and including the next x. - -# keys: f d d -# before -abcdef -# after -ef - - `fd` selects "abcd"; `d` deletes it. - -# keys: t d d +# keys: w ; i Z esc # before -abcdef +one two # after -def - - `td` stops one short, so only "abc" goes. - +one Ztwo ----------------------------------------------------------------- -= 3.6 SELECTION + EDIT: x v d c y p, and the rest = += 5.4 SELECT AND EDIT = ----------------------------------------------------------------- - 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 - `X` stretch the selection you have out to whole lines - `Alt-x` the opposite — shrink it back inside them - `v` character-range select mode; motions extend it - `;` collapse the selection onto the cursor; `Alt-;` flip its ends - `%` select the whole file - `d` delete the selected lines (yanked) - `Alt-d` delete them WITHOUT yanking - `c` clear the line + insert (change) - `y` yank the selection — and with nothing selected the selection is - the CHARACTER under the cursor, not the line, so `x` first if a - line is what you meant - `p` `P` paste the yank after / before. A LINE yank comes back as a - whole line below or above; a character yank splices in beside - the cursor - `R` replace the selection with the yank - `r<char>` overwrite every character of the selection with <char> - -# keys: x d -# at: 1,0 -# before -keep -gone -# after -keep + 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 - 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. + Selection is LINE-first here — `x` — with `v` for characters. That is + the main divergence from helix. # keys: x c typed esc # before -old +replace me # 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'. - - And the ones that rewrite a selection where it stands: - - `~` toggle case `` ` `` lowercase ``Alt-` `` uppercase - `J` join this line with the next, on one space - `>` `<` indent / unindent by four spaces (a count = that many) - `Ctrl-a` `Ctrl-x` add to / subtract from the SELECTION read as a - decimal integer. With nothing selected the selection is - one character, so `41` with the cursor on the `4` becomes - `51` — select the whole number first if you meant 42 - `Ctrl-c` comment or uncomment every line the selection touches. - The token comes from the file's EXTENSION: `//` for .zig - and .c, `#` for .py and .sh, `--` for .lua, `;` for .el, - `%` for .tex and .erl, `!` for fortran, `"` for .vim — - and `#` for any extension the table does not name, which - includes having none. In raw tty mode Ctrl-c is still the - shell's SIGINT. - `=` ask the language backend to format the selection (part 4.2) - -# keys: x ~ -# before -abc -# after -ABC - -# keys: J -# before -one -two -# after -one two - -# keys: x > -# before -abc -# after - abc - - ------------------------------------------------------------------ -= 3.7 MORE THAN ONE CURSOR: s S C , ) ( _ = ------------------------------------------------------------------ - - There IS multi-cursor, and it is helix's: a selection is a LIST of - ranges with one PRIMARY among them, and every ordinary key is - replayed once per range — type in insert and you type in all of them. - Sixty-four ranges is the ceiling; matches past it are dropped. - - The two keys that make a LIST out of one range are regex: - - `s` keep every match inside each selection, as its own cursor - `S` keep the pieces BETWEEN the matches instead - - Both arm the pane's tag the way `/` does, and both preview LIVE: the - selections redraw on every character you type. A pattern that does not - compile yet falls back to the selection you had BEFORE you pressed `s` - rather than clearing everything, which is what makes typing one - character at a time bearable — every unfinished prefix of a pattern is - one of those. Enter commits, Esc puts back exactly what you had. A pattern - with no uppercase in it matches case-blind, which is helix's smart - case. Two things differ from helix's regex: `.` matches a newline here - like any other byte, and `^`/`$` assert at the scanner's position - rather than at a line boundary. - - The keys that then work on the LIST rather than on the text: - - `C` copy the primary selection down a line; `Alt-C` up - `,` keep only the primary; `Alt-,` drop it, promote the next - `)` `(` rotate which one is primary, forward / back - `Alt-s` split every selection into one range per line - `Alt--` merge them all into one span - `Alt-_` merge only the ones that touch - `_` trim the whitespace off each; empty ones vanish - - `SPC y` joins every cursor's text for the system clipboard and - `SPC Y` takes the primary's alone (3.13). - - (No practice blocks: the "# keys:" notation has one cursor in it.) - - ------------------------------------------------------------------ -= 3.8 PAIRS AND TEXTOBJECTS: the m prefix = ------------------------------------------------------------------ - - `mm` jump to the bracket matching the one under the cursor - `mi<obj>` select INSIDE a textobject - `ma<obj>` select AROUND it — delimiters included - `ms<char>` surround the selection with <char> and its partner - `mr<a><b>` replace the enclosing <a> pair with <b>'s - `md<char>` delete the enclosing <char> pair - - The objects are `w` a word, `W` a long word, `p` a paragraph, and the - pairs `( ) [ ] { } < >` with the quotes `'` `"` and the backquote. - Quotes are LINE-SCOPED — a string does not span lines here, so - neither does the object. helix's tree-sitter objects (a function, a - class, an argument) are not in this set. For SURROUNDING, any - character at all is its own pair: `msx` wraps the selection in x's. - - `miw` and then `d` is how you delete a word without a verb+noun - grammar. - - ------------------------------------------------------------------ -= 3.9 ] AND [ : STEPPING BY THING = ------------------------------------------------------------------ - - `]p` `[p` next / previous paragraph (blank lines delimit one) - `]space` add a blank line below; `[space` above (a count = N) - `]d` `[d` next / previous diagnostic — and if no list is up yet, - asking the language backend for one is part of the press - `]D` `[D` the last / the first of them - - ------------------------------------------------------------------ -= 3.10 PIPING A SELECTION: | = ------------------------------------------------------------------ - - `|` in a file body arms the pane's tag with a bare "|" and takes a - command line. Enter runs it under `/bin/sh -c` once per selection: - the selection's bytes go in on stdin, and its stdout replaces them. - Every cursor is filtered in the same pass, and the whole thing is ONE - undo. `%` then `| sort` sorts a file. - - A pane whose BYTES ARE ITS OWN, and only that: a real file, or the - scratch that is on its way to being one. So `|` is inert in a terminal - (shell output cannot be rewritten) and in a rendered output buffer like - "+Search", whose next refill would discard the filtered rows anyway, and - in both the tag stays as it was. - - Not to be confused with EXECUTING a word, which sends it to the - pane's own shell and leaves the text alone. This one is a filter, and - what it returns lands back in the buffer. - - ------------------------------------------------------------------ -= 3.11 INSERT MODE ITSELF = ------------------------------------------------------------------ - - Backspace, Delete, Enter and Tab are what those keys ARE, not - bindings — Enter carries the previous line's indentation down with - it. The rest is helix's: - - Ctrl-h / Ctrl-j / Ctrl-d Backspace / Enter / Delete, spelled out - Ctrl-w, Alt-Backspace delete the word behind the cursor - Alt-d, Alt-Delete delete the word in front of it - Ctrl-u kill back to the start of the line - Ctrl-k kill forward to the end of it - - Ctrl-w is the WINDOW prefix in normal and tty mode; insert mode wins - it, which is helix's own arrangement — so a tag being typed into - swallows it. - - TAB has one extra job: pressed straight after a `.` in a source file - the language backend speaks, it asks what could go there (part 4.2). - Everywhere else — and when the answer comes back empty — it indents - to the next four-column stop. - - ----------------------------------------------------------------- -= 3.12 VIEWPORT + PANES = += 5.5 THE REST, IN ONE PLACE = ----------------------------------------------------------------- - zt / zz / zb scroll so the cursor is at top/center/bottom - (`zc` is `zz` spelled the other way) - zj / zk scroll the view one line, cursor pushed along - 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-o / Ctrl-i walk the jump history back / forward — the same - two builtins as SPC j o and SPC j i, and SPC j l - shows the stack itself as a buffer. (Ctrl-i and Tab - are the same byte on an old terminal; where that is - so, Tab keeps meaning execute.) - 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 to the pane you were in before this one, so - held down it alternates between two (body normal - mode; the same builtin as SPC j j). A PDF pane is the - one exception — there Esc cancels the selection and - the search highlights and stays in the document, and - Shift-Esc is the hop out (part 4.1) - Alt-n new terminal below the active one - Alt-c move the active pane into a fresh column — any pane, - not just a terminal, and a no-op if it is alone in - its column or the sixth column already exists - - (No practice blocks: these are viewport/layout, not text edits.) + 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). ----------------------------------------------------------------- -= 3.13 SPC — THE LEADER = += 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; the keys you have typed so far show on the active pane's - transient body/message row until it fires. Esc abandons it — so does any - key that leads nowhere, rather than leaving the next keystroke armed. - - The groups are shared first letters and nothing cleverer: f files, - h docs, c columns, t toggles, a animations, s session, j jumps, - l language, w windows. - - SPC ? Help: every builtin and the keys that run it - SPC k Kill (quit) SPC d Del (close this pane) - - SPC f s Save SPC f n New (empty temp file) - SPC f f Find (file NAMES) SPC f g Grep (their CONTENTS) - SPC f c Config: where the startup file is read from (4.3) - - SPC h t Tutor (this file) - SPC c n / c d Newcol / Delcol - - SPC t d Debug SPC t c Colors (syntax/ansi recolor) - SPC t n NextColor SPC t t ThemeSel (the list of 228) - SPC t r/R/g Crt / Ripple / Glitch (gui and macOS only) - SPC t f FontSel (gui and macOS only) - SPC a s/z/d/a/v PanelSlide / PanelZoom / PanelDissolve / PanelAscii / - PanelVertical - SPC a e/f/w PanelEdges / PanelFall / PanelWave - SPC a c/r/t PanelCurtain / PanelScramble / PanelType — glyphs - marching in, churning into place, and typed in - reading order - (native tty, SDL GUI, and macOS; press again to turn off) - SPC t w Wrap: soft line breaks in a file pane, ON to start - with — so this is the switch that lets a long line - run off the edge again, hscroll and all. A wrapped - row ends in "↩", in the chrome's colour, because a - break is the one thing about it you cannot see - SPC t b Tagbottom: taglines under their panes, not over - SPC t p/l/a Petscii / Palette / Ascii — an image pane's - renderer (4.1) - SPC t i/s/z PdfTint / PdfSections / PdfFit — a PDF's (4.1) - - SPC y / SPC Y the selection to the SYSTEM clipboard (every - cursor's text joined, or the primary's alone) - SPC p / SPC P paste the system clipboard after / before the - selection; SPC R replaces the selection with it - - 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 j o / j i Back / Forward: walk the jump history - SPC j j Last: the pane you were in before this one — what - body-normal ESC runs, so it alternates - SPC j l Jumplist: that same stack, as a buffer you can click - - SPC l ... the language group — part 4.2 has all ten + 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. - Those five clipboard words are helix's own letters, and the only - words in pardes that touch the desktop's clipboard at all: ordinary - y d c p P R and the 1-2 / 1-3 chords stay in pardes' own register, so - deleting a character can never throw away what you copied from a - browser. In a terminal the copy goes out as OSC 52 and the paste asks - for it back the same way — plenty of terminals refuse that read, so - there SPC y works and SPC p may honestly do nothing. - - A handful of builtins have no key path at all. Three of them take a - NAME, and a key path can never carry one: `Theme <name>`, `Font <name>` and - `Shell <name>` — the last being what the NEXT terminal you open will - run (fish, until you say otherwise; the ones already open keep what - they have). The other two are Look and Exec, which already have two - keys and two buttons between them. All five are words: write them - anywhere and execute them. - - `?` works at ANY depth: SPC ? lists everything, SPC t ? lists only - what the "t" 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.) + SPC ? list every path + SPC k Kill SPC d Del + 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 4 — THE REST = += PART 6 — THE REST = ================================================================= ------------------------------------------------------------------ -= 4.1 PANES THAT ARE NOT TEXT: PDFs and images = ------------------------------------------------------------------ - - Look at a .pdf and you get a PDF pane: the real document, rendered by - MuPDF as one continuous strip of pages and placed like any other - document (a leftmost column of its own the first time, split below a - doc after that). Its tag is live, and reads - - pdf 3/128 width PdfFit filtered PdfTint PdfSections /path/to/it.pdf - - — the page you are on out of the count, then each of the three - commands with its CURRENT setting written in front of it, then the - path. Those are ordinary words: middle-click "PdfSections" and it - runs. - - PdfFit (SPC t z) `width`, a reading column you scroll down, or - `height`, the whole page at once panned sideways - PdfTint (SPC t i) disabled -> filtered -> full -> disabled. `full` - repaints the page in the theme's two colours; - `filtered` starts from that and adds back three - quarters of each channel's distance from the - source's own luminance, so a COLOUR page keeps its - hues and a grayscale scan comes out identical to - `full`; `disabled` is the pixels as they are - PdfSections (SPC t s) the document's OUTLINE, into a - "+PdfSections" buffer below the PDF. An ordinary - row is `file.pdf:PAGE:N` and the title, indented - by depth; n/N walk them and Enter goes to that - section. An entry that is a web LINK has no page - to name, so its row is the bare URL and the title, - and looking it opens a browser. - - The modal keys work on the PAGE rather than on a cursor: j/k scroll, - Ctrl-d/u and Ctrl-f/b page, `Ngg` goes to page N, `ge` is the last - page. `/` searches the document's real text through MuPDF and n/N walk - the hits. Esc is the document's own CANCEL — it drops the selection and - the search highlights and leaves you where you were reading — so the - hop to the pane before this one is Shift-Esc here, the same chord that - leaves a raw tty. - - The rest depends on the shell being able to place real PIXELS. Where - it can, drag with the left button to select text (SPC y takes it), and - h/l pan sideways with `0` and `$` for the edges — though there is - nothing to pan while the page already fits, which in the default - `width` fit is most of the time. Where it CANNOT, there is no text - selection at all and the vertical keys step whole pages instead of - scrolling. - - PDF support is a BUILD option: `-Dmupdf` is on for the native builds - and off for the browser, and with it off a .pdf opens as the ordinary - file it is on disk. `-Djpx` (also on) is what makes a SCANNED pdf - render at all rather than as a stack of blank pages. - - An IMAGE — .png .jpg .jpeg .gif .bmp .ppm .pgm .tga — opens an image - pane. Its tag reports `petscii:on/off`, `palette:commodore/terminal`, - and `ascii:on/off` before the path, so every pane-local choice is - visible even though only the builtins mutate it. Where the shell can place real pixels it - does; where it cannot, the petscii matcher draws the picture out of - block glyphs. The three toggles all act on THAT matcher, so with real - pixels on screen only the first of them changes anything: + 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). - Petscii (SPC t p) glyph art even when real pixels were available - Palette (SPC t l) the C64's sixteen colours, or the terminal's own - Ascii (SPC t a) whether the printable ASCII bitmaps join the - matcher's glyph set. They start IN, so the first - press takes them out and leaves the blocks + 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. ------------------------------------------------------------------ -= 4.2 THE LANGUAGE BACKEND = ------------------------------------------------------------------ - - Pardes has ZLS compiled INTO it — not spawned, not spoken to over a - socket, just called. So there is no server to start and nothing to - wait for, and equally nothing kept warm: there is no cache at all, and - every query re-parses from scratch — that is once per keypress, not - once per file. It reads one language, `.zig`. On a file it does not - read, the code queries below do nothing whatsoever: no error row, no - message. (Four of them answer anyway, because they are not about this - file's code — `SPC l i` and `SPC l w` describe the backend itself, and - `SPC l S` and `SPC l D` walk the .zig files next door.) - - helix's five gotos keep helix's own letters, under `g`: + 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. - gd definition gD declaration gy type definition - gi implementation gr references - Ctrl + left click the same as gd, with the mouse + pardes --fs acme's control files over FUSE + pardes --fs9 the same tree as 9P on a unix socket - ONE answer jumps straight there. Several fill a "+Search" buffer, and - from there it is the ordinary walk: n/N step the rows, Enter opens - the one you stopped on. + A directory per pane holding `body`, `tag`, `ctl`, `addr`, `data`, + `event`, `pty/` and the rest, plus `index`, `cons` and `new/` at the + top. Every pane shell is told `$PARDES_FS` and `$PARDES_PANE`, so a + script in a pane addresses its own window with no arguments: - The rest are BUILTINS — words you can middle-click as readily as - press — under `SPC l`, each on helix's letter with the group prefix - in front of it: + echo hello >> $PARDES_FS/$PARDES_PANE/body + cat $PARDES_FS/index + echo hi > $PARDES_FS/new/body - SPC l k Hover what this thing is, into "+Hover" - SPC l r Rename arms the tag; the new name goes after the - `/`. One undo for all of it - SPC l a CodeAction the titles of what could be done, into "+Lsp" - SPC l h SelectRefs every reference, as rows - SPC l s Symbols this file's symbols, parent-qualified - SPC l S WsSymbols arms the tag; a substring match over the .zig - files under the asking file's OWN directory - SPC l d Diagnostics this file's; a clean file says so in one row - SPC l D WsDiagnostics the same over that same directory - SPC l i Lspinfo what the backend IS: its version, what it - answers, what it refuses, and the last two - dozen queries with how long each took - SPC l w Lspwhy re-runs `gd` where the cursor is now, out - loud: every step it took and where it stopped + A terminal pane also has `pty/`: - ]d / [d step the diagnostics — asking for them if none are up - ]D / [D the last / the first - = format: a "+Lsp" buffer with one row per changed line, - `- old + new` on each. It SHOWS you the - formatting; it does not apply it + echo 'winsize 100 30' >> $PARDES_FS/3/pty/ctl + echo 'sig INT' >> $PARDES_FS/3/pty/ctl + echo 'make -j8' >> $PARDES_FS/3/pty/data - Three limits worth knowing before you trust an answer. `gr`, - `SelectRefs` and `Rename` are all the same resolution underneath, and - it is THIS FILE ONLY — none of them claims a workspace. The two `S`/`D` - walks start at the asking file's directory, not at the project root, - and stop at 512 files. And a rename you did not want is one `u` away, - because it lands as a single undo. + Over 9P the same tree answers plan9port, from anywhere: - And in INSERT mode, Tab straight after a `.` asks what could go - there. What comes back is not a popup and nothing is typed for you: - it is a buffer of rows, one per candidate, each pointing at where - that candidate is DECLARED. Picking one is looking at it. An empty - answer indents instead, a moment late. - ------------------------------------------------------------------ -= 4.3 CHROME, AND THE ONE FILE PARDES READS = ------------------------------------------------------------------ + 9p -a $XDG_RUNTIME_DIR/pardes-9p-work.sock ls / + 9p -a $XDG_RUNTIME_DIR/pardes-9p-work.sock read /index - Themes: 228 of them, described in Part 1. NextColor steps the ring, - `Theme <name>` goes straight to one, ThemeSel (SPC t t) lists them - all into a buffer you walk. + ...and pardes is a 9P CLIENT too, so one session can read another's: - A native build can also wear one complete ZON file at runtime: - `ThemeFile themes/mine.zon` resolves from the pardes config directory - and, where document watching is available, reloads after every valid save. - A broken save leaves the last good colors on screen. `DumpThemes` writes - copyable references under themes/builtin; copy one out, rename it and edit - that rather than guessing the fields. + 9p work.sock /1/body the `9p` word: opens it in a pane - Fonts, on the SDL and macOS builds only — in a terminal the font - belongs to the terminal and in a browser to the page. FontSel - (SPC t f) lists every MONOSPACE face on the machine into a "+Fonts" - buffer of `Font <name>` rows. n/N step those rows and select each one - WHOLE, since a command line has no place inside it to pick out; Tab (or - a middle click) runs the row you stopped on and puts that face on. So - walking with n and pressing Tab is trying faces on, and stopping is - choosing. `Font <name>` on its own takes the font file's stem. - `TaglineSize 70` changes the tagline face and visible band to 70 percent - of the body face, live; values 1 through 100 are accepted, `Config` - reports the active value, and both native GUI renderers retain the same - body cell grid while drawing that separate role. + 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 (examples/acmefs/life.py puts Step/Run/Clear there). The + keyboard is never suppressed, and the clicks come back when it exits. - Native panel transitions are the five SPC a choices listed in 3.13. They - start off. Only one is selected; running it again turns it off. Slide and - zoom animate geometry. Dissolve switches changed cells at stable thresholds. - ASCII increments or decrements each changed printable byte toward its new - value, using fast ease-out skips for long distances and exact steps nearby; - unchanged glyphs and non-ASCII graphemes pass through. Vertical raises a pane being added - and drops a deleted pane back down inside its own box; every survivor stays - still. The native GUI scene switches Crt, Ripple - and Glitch may be combined. `EffectCode PanelAscii` (or any other - effect builtin as its argument) opens the exact backend sources that - were embedded when this binary was built. - - Before its first frame a native pardes reads ONE file: `init` inside its - `pardes` config directory — $XDG_CONFIG_HOME/pardes/init when that is - set to an absolute path, else ~/.config/pardes/init, and on macOS - ~/Library/Application Support/pardes/init. `SPC f c` opens a refreshable - "+Config" buffer containing the resolved path and every live setting: - theme, shell, requested/effective font, panel/scene effects, hover - delay, and the ordinary display toggles. The path is printed whether - or not anything is there, which is the case you ask in. (A right click - on that row opens the file when there IS one. When there is not, the - click has nothing to open and falls back to searching for the text — - pardes will not create it for you.) - - Resting the pointer over look-able text for that reported delay paints - a quiet preview of the exact operand a right click would expand. It is - only a preview: it does not focus, select, move a cursor, or run Look. - Set `look_preview_delay_frames` to null in src/config.zig to compile it - out. - - The format is one BUILTIN COMMAND per line, spelled exactly the way - you would execute it anywhere else: - - Theme gruvbox_dark_hard - ThemeFile themes/mine.zon - Shell zsh - TaglineSize 70 - Tagbottom - - Blank, unknown or malformed lines are ignored in silence, and a bad - line does not stop the ones after it. Two cautions. A word that is not - a builtin is never handed to a shell — but `Exec` IS a builtin, so - `Exec <anything>` in this file types that command into a shell before - your first frame, and `Look` will run an `` @`...` `` word the same - way. And every toggle here TOGGLES: `Wrap` in your config turns soft - wrap OFF, because it starts on. + 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 same door acme has always had, which is why the mount + sits under $XDG_RUNTIME_DIR at 0700 and why both flags are opt-in. - It cannot remap a KEY, either: the keymap is src/config.zig, compiled - in, and rebinding is an edit there and a rebuild — which is why a - wrong binding is a compile error instead of a line that quietly did - nothing. + examples/README.md is the client's guide; docs/acme-fs.md compares this + implementation with acme's file by file; docs/9p.typ is the 9P note. - The browser build reads no such file, has no ptys, and has no language - backend compiled in. It is not without a filesystem, though: LOOK - there resolves against a read-only archive of working-tree .zig sources - that was generated when the build was made. What you get is a dump, - replayed, with those sources openable. (The core still ASKS for the - rest. A host that answers gets terminals; that is the seam, not a - special case.) ================================================================= -= PART 5 — THE CONTROL FILESYSTEM (pardes --fs) = += SUMMARY = ================================================================= - Started as `pardes --fs`, this session serves plan9 acme's control - files over FUSE: a directory per pane, holding `body`, `tag`, `ctl`, - `addr`, `data`, `event` and the rest, plus `index`, `cons` and `new/` - at the top. Every pane shell gets `$PARDES_FS` (where it is mounted) - and `$PARDES_PANE` (which pane it is), so a script run in a pane can - talk to its own window with no arguments: + 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 - echo hello >> $PARDES_FS/$PARDES_PANE/body append to this pane - cat $PARDES_FS/index one line per pane - echo hi > $PARDES_FS/new/body open a pane holding "hi" + 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 - That IS the extension mechanism: no plugin API, no interpreter, no - rebuild — a program that opens files. Two things about it are worth - knowing before you use it. + TTY a terminal IS a pane + Ctrl-b or Shift-Esc toggles the shell, landing its cursor + where you navigated + Esc goes to the program — except at a shell PROMPT, where + it hops away like Shift-Esc + Ctrl-V default register, Ctrl-Shift-V system clipboard - 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 the words in that pane's tag can be the program's own - commands (examples/acmefs/life.py puts Step/Run/Clear there). The - keyboard is not suppressed, so the pane stays editable either way, and - when the program exits the clicks come back. + 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 + --fs and --fs9 work in a daemon too - 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 same door acme has always had, which is why the mount - lives under $XDG_RUNTIME_DIR at 0700 and why `--fs` is opt-in. - - examples/README.md is the client's guide; docs/acme-fs.md compares this - implementation with acme's, file by file. - -================================================================= -= SUMMARY = -================================================================= + 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) - 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 - every tag with text leads with Save (a terminal also - has Filter); images and PDFs 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 working-tree .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) - Filter in its tag toggles a pane-local, theme-keyed palette - --fs: acme's control files over FUSE: $PARDES_FS/<id>/{body,tag, - ctl,addr,data,event,...} and $PARDES_FS/{index,cons,new} - a script holding a pane's `event` open owns that pane's - middle and right clicks; writing a record back runs it - KEYS (helix): h j k l w b e 0 $ ^ gg ge f F t T v x X d c y p - i a I A o O u undo U redo Enter=look Tab=execute - w b e f F t T SELECT what they cross, so `i` after one - types at the SELECTION's start; `;` collapses first - a leading NUMBER is a count on the 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, one cursor per match, previewing as you - type; C , ( ) Alt-s Alt-- Alt-_ _ work the LIST - m i/a = textobjects (w W p, the bracket pairs and the - three quotes), m s/r/d = surround, mm = match - ] and [ = paragraph, blank line, diagnostic - | = filter every selection through /bin/sh -c (a savable - file pane only) - : = 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 zj zk Ctrl-d/u Ctrl-f/b Ctrl-o/i Ctrl-w hjkl - Alt-n Alt-c - Esc = the pane you were in before this one (body normal; - in a PDF it cancels that document's own selection and - search highlights instead, and Shift-Esc hops) - n/N = select the next/prev look-able text, across panes - (a ring); Enter opens what you landed on - 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 y/Y/p/P/R the system clipboard, - SPC w hjkl focus, SPC j j the pane before this one, - SPC t * the toggles, SPC l * the language backend) - NOT TEXT: .pdf = the real document through MuPDF — j/k scrolls it, - `/` searches it, Esc cancels selection+highlights and - Shift-Esc leaves the pane, 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 running in the - background and nothing cached: gd gD gy gi gr, the - ten SPC l words, ]d/[d and ]D/[D, `=` to see a - format diff, and Tab after a dot in insert + SCRIPTING --fs acme's files over FUSE; --fs9 the same over 9P + $PARDES_FS/<id>/{body,tag,ctl,addr,data,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), plus v for characters; `/` is - a case-insensitive SUBSTRING search, one hit per line, and - not a regex one — the regex lives on s and S; the textobjects - are w W p, the bracket pairs and the three quotes, with none - of helix's tree-sitter ones. - vs Vim: no verb+noun (dw) — because the MOTION already selected, so - `wd` is what `dw` was; body-normal Esc hops focus; bare G is - a no-op and `ge` goes to the start of the last line. - 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. + 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. - To spawn THIS tutor again from anywhere: middle-click "Tutor" in the - top bar (next to Help), or press SPC h t. + Spawn this tutor again: middle-click "Tutor" in the top bar, or 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. + Quit: this is a file pane — `:q` is not wired. Close it with Del in its + tag, "Kill" in the top bar to quit everything, or Ctrl-c the app. |
