diff options
Diffstat (limited to 'docs/helix-keys.md')
| -rw-r--r-- | docs/helix-keys.md | 31 |
1 files changed, 18 insertions, 13 deletions
diff --git a/docs/helix-keys.md b/docs/helix-keys.md index e43bc6b4..214a1280 100644 --- a/docs/helix-keys.md +++ b/docs/helix-keys.md @@ -29,8 +29,8 @@ layer: gap offsets + ranges over the flat text). Differential harness: collapse) — the checked-in helix goldens are the ground truth, verified case-by-case by `zig build hxdiff`. Motion-created ranges live in `pane.vsel` marked IMPLICIT (`vsel.explicit = false`); `v` extend mode, - `x`/`X`, terminal `n`/`N` (lookStep) and file `n`/`N` (searchStep) set - EXPLICIT ones. `d`/`c`/`y`/`~`/… act on the active selection either + `x`/`X` and `n`/`N` (the look-ring walk, `lookWalk`) set EXPLICIT ones. + `d`/`c`/`y`/`~`/… act on the active selection either way — that is the point of the model. The pardes-specific chords (normal-mode Enter look / Tab execute) act on EXPLICIT selections only and fall back to the word under the @@ -55,7 +55,10 @@ Parity column (phase 5): **helix-verified** = matched field-by-field (text/mode/cursor/anchor) against the helix goldens by `zig build hxdiff`; **pardes-specific** = key helix leaves unbound (or a deliberate pardes binding) — cannot mismatch a golden; **waived** = corpus-covered divergence -with a reason in `test/hxcases/waivers.jsonl`. +with a reason in `test/hxcases/waivers.jsonl`; **out of corpus** = helix's +own key and meaning, but the work leaves the core as an EFFECT the headless +differential has no shell to perform — the clipboard commands, and nothing +else. | Key | Behavior (pardes today) | Notes / quirks vs helix | Parity | | --- | --- | --- | --- | @@ -80,9 +83,9 @@ with a reason in `test/hxcases/waivers.jsonl`. | `x` / `<n>x` | select current line / extend one (n) line(s) down, char-range through the newline, cursor ON the `\n` | col-0 vim-ism removed (phase 5); matches `extend_line_below`, mode stays normal | helix-verified | | `d` | delete selection (implicit or explicit); bare cursor = the 1-wide selection | always yanks (`Alt-d` noyank in B); terminals: drops typed runs only | helix-verified | | `c` | change (delete + insert mode); linewise selections open a fresh indented line | same shape as `d` | helix-verified | -| `y` | yank selection; bare cursor yanks the 1-wide selection (char under cursor) | line-yank vim-ism removed (phase 5); yank keeps selection AND cursor (helix). Also emits `set_clipboard` (OSC 52 out) | helix-verified | +| `y` | yank selection; bare cursor yanks the 1-wide selection (char under cursor) | line-yank vim-ism removed (phase 5); yank keeps selection AND cursor (helix). Writes the DEFAULT REGISTER and nothing else — the system clipboard is `SPC y`, which is helix's own split and so moves this row TOWARDS helix, not away: a `d` of one character can no longer clobber what the desktop was holding | helix-verified | | `u` / `U` | undo / redo | restores the pre-edit selection (helix); snapshot granularity, no `Alt-u`/`Alt-U` history walking (skipped) | helix-verified | -| `p` (normal) | paste the core's yank register after the selection | helix default-register semantics; yank still mirrors OUT via OSC 52 (`set_clipboard`) but `p` never reads the system clipboard back — most terminals refuse the OSC 52 read, which left `p` a silent no-op | helix-verified | +| `p` (normal) | paste the core's yank register after the selection | helix default-register semantics, and only the register — nothing on this path reads or writes the system clipboard. `SPC p` is the word that does, and on a tty its read is OSC 52, which most terminals refuse: an honest no-op there rather than a paste of the wrong text | helix-verified | | `Esc` (body normal) | clear a pending modal prefix / exit select mode, keeping the selection, then run `Last`: hop to the pane you were in before this one, whichever kind it was, exactly like `SPC j j` — so held down it alternates between two panes, two files as readily as a file and its shell | Pardes-specific focus binding layered on helix's cleanup. A leader path, tag, topbar or search owns Esc while it is active; raw tty forwards it | pardes-specific (cleanup helix-verified) | | `Esc` (insert) | back to normal mode, cursor right after the insertion (no vim left-step) | | helix-verified | | `Enter` (normal) | acme **look** chord: EXPLICIT selection, else file-ish word under cursor | pardes-specific, keep (helix normal-mode Enter unbound). Covers helix `gf`. Implicit motion residue falls back to the cursor word | pardes-specific | @@ -92,9 +95,11 @@ with a reason in `test/hxcases/waivers.jsonl`. | `Ctrl-w` + `h/j/k/l`/arrows | directional pane focus prefix — normal/tty modes only | pardes' own window handling (helix window mode skipped, section C). Runs the SAME `Left`/`Down`/`Up`/`Right` builtins `SPC w h/j/k/l` runs; kept alongside the leader because a pane in raw **tty** mode never sees `SPC` (the shell owns it), so this is the only keyboard way out of one. Insert mode owns `Ctrl-w` = delete-word-back, so a tag being TYPED into swallows it; from a tag in normal mode (`:`) it moves focus to the neighbour's BODY, while the bare letters `h/j/k/l` there move to its TAGLINE (next row) | pardes-specific | | `Alt-n` | new terminal below (any mode) | shadows helix `Alt-n` TS sibling-select — skipped anyway (tree-sitter) | pardes-specific | | `Alt-c` | move active terminal to a fresh column (any mode) | helix `Alt-c` is change-noyank; the pardes window op wins (do-not-touch contract). `Alt-d` + `i` covers the behavior | waived (`alt-c-window-op`) | -| `Space` (normal, body) | the pardes LEADER: a key path from here runs a BUILTIN with no arguments — the same builtins the topbar and the tags hold. `SPC k` Kill, `SPC d` Del, `SPC f s` Save, `SPC f n` New (an empty temporary file focused in the calling pane's column), `SPC f f` Find (fd over the pane's directory, results into `+Search`), `SPC f g` Grep (grep -R over the CONTENTS of every pane's directory, the ones another pane already covers dropped, rows relative to the asking pane's own directory, results into `+Search`; like Find it takes an ARGUMENT — `Grep foo` executed, or a selection chorded onto the word, searches that and skips the input), `SPC h t` Tutor, `SPC c n`/`SPC c d` Newcol/Delcol, `SPC t d/c/n/r` Debug/Colors/NextColor/Crt, `SPC t t` ThemeSel (the whole theme ring as `Theme <name>` rows in an output buffer — the one list whose rows are COMMANDS, so n/N execute each row instead of looking it and stepping is a live preview), `SPC t p/l/a` Petscii/Palette/Ascii (an image pane's renderer toggles — the words its tag used to spell out, so the bar stays a bar), `SPC s d`/`SPC s r` Dump/Restore, `SPC w h/j/k/l` Left/Down/Up/Right (directional pane focus — the `Ctrl-w` prefix's four moves as builtins), `SPC j o`/`SPC j i`/`SPC j j`/`SPC j l` Back/Forward/Last/Jumplist (the jump stack: walk it back, walk it forward, hop to the pane before this one — what body-normal Esc runs — and read the stack as a clickable buffer). `?` at ANY depth opens the Help builtin listing what the prefix can still reach (`SPC ?` = all, `SPC h ?` = the docs group), into a `+Help` output buffer. The pending path shows at the right edge of the active pane's tag; Esc — or any unmapped key — abandons it | helix spends Space on pickers/LSP (section C); pardes has neither, and acme's builtins are what a leader is for. Enum-derived: the paths, the Help lines and the execute dispatch all fold out of one `Builtin` enum at comptime. Normal mode on a BODY only — tags are always insert, tty keys belong to the program | pardes-specific | -| `/` then `n`/`N` (any pane) | pardes' own plain-substring search into a `+Search` output buffer, n/N walk the result rows and look them (EXPLICIT selections) | KEEP, do not touch; not in the corpus (helix `/` is regex search) | pardes-specific | -| `n`/`N` (terminal panes, no search armed) | lookable-token motion over scrollback (EXPLICIT selections) | KEEP, do not touch | pardes-specific | +| `Space` (normal, body) | the pardes LEADER: a key path from here runs a BUILTIN with no arguments — the same builtins the topbar and the tags hold. `SPC k` Kill, `SPC d` Del, `SPC f s` Save, `SPC f n` New (an empty temporary file focused in the calling pane's column), `SPC f f` Find (fd over the pane's directory, results into `+Search`), `SPC f g` Grep (grep -R over the CONTENTS of every pane's directory, the ones another pane already covers dropped, rows relative to the asking pane's own directory, results into `+Search`; like Find it takes an ARGUMENT — `Grep foo` executed, or a selection chorded onto the word, searches that and skips the input), `SPC h t` Tutor, `SPC c n`/`SPC c d` Newcol/Delcol, `SPC y/Y/p/P/R` the five clipboard words (next row), `SPC t d/c/n/r` Debug/Colors/NextColor/Crt, `SPC t t` ThemeSel (the whole theme ring as `Theme <name>` rows in an output buffer — rows that are COMMANDS rather than places, so a theme is previewed by EXECUTING one, Tab or a middle click; `n`/`N` do not run them, they step past to the next look-able text on the ring), `SPC t p/l/a` Petscii/Palette/Ascii (an image pane's renderer toggles — the words its tag used to spell out, so the bar stays a bar), `SPC s d`/`SPC s r` Dump/Restore, `SPC w h/j/k/l` Left/Down/Up/Right (directional pane focus — the `Ctrl-w` prefix's four moves as builtins), `SPC j o`/`SPC j i`/`SPC j j`/`SPC j l` Back/Forward/Last/Jumplist (the jump stack: walk it back, walk it forward, hop to the pane before this one — what body-normal Esc runs — and read the stack as a clickable buffer). `?` at ANY depth opens the Help builtin listing what the prefix can still reach (`SPC ?` = all, `SPC h ?` = the docs group), into a `+Help` output buffer. The pending path shows at the right edge of the active pane's tag; Esc — or any unmapped key — abandons it | helix spends Space on pickers/LSP (section C); pardes has neither, and acme's builtins are what a leader is for. Enum-derived: the paths, the Help lines and the execute dispatch all fold out of one `Builtin` enum at comptime. Normal mode on a BODY only — tags are always insert, tty keys belong to the program | pardes-specific | +| `SPC y` `SPC Y` `SPC p` `SPC P` `SPC R` | helix's clipboard menu on helix's own letters: yank the selection to the system clipboard (`ClipYank`) or the PRIMARY selection alone (`ClipYankMain`), paste the system clipboard after (`ClipPaste`) / before (`ClipPasteBefore`) the selection, replace the selection with it (`ClipReplace`) | the ONLY five words in pardes that touch the desktop's clipboard — `y`/`d`/`c`/`p`/`P`/`R` and the acme cut/paste chords are the internal register alone. Builtins rather than bare chords because a leader path names a builtin: they land in Help's index and are executable words like every other verb. One divergence: pardes keeps a single register VALUE where helix keeps one per range, so `SPC y` at N cursors joins them with newlines (`Pardes.setYank`, the divergence `msel-yank-paste` already waives). On a tty the write is OSC 52 out and the READ is OSC 52 back, which many terminals refuse or gate — so `SPC y` works there and `SPC p` can be a no-op | out of corpus | +| a paste from the OUTER terminal | one `Event.paste`, spliced in at the cursor | the tty shell enables bracketed paste and coalesces `paste_start`..`paste_end` into a single event; before that the bytes arrived as individual key presses and normal mode RAN them, which is how a pasted `d` deleted a line. The bytes deliberately never enter the yank register — clipboard and default register are separate stores in both directions | pardes-specific | +| `/` (any pane) | pardes' own plain-substring search into a `+Search` output buffer: the tag takes the pattern, Enter fills the buffer, and its rows are ordinary look targets | KEEP, do not touch; not in the corpus (helix `/` is regex search). The stepping half is the next row | pardes-specific | +| `n` / `N` (any pane) | MOTION, not a jump: move the SELECTION to the next / previous look-able text and open NOTHING. Enter — the look chord — on what it leaves selected is what opens it | KEEP, do not touch; not in the corpus (helix's `n`/`N` walk regex search hits). The text stepped is the largest whitespace-delimited run `look.resolve` can act on (`look.lookableSpan`, wrapper punctuation peeled off both ends), and the walk is a RING across PANES: every pane that has performed a Look, most recent first (`Pardes.look_src`), then the output buffers that have not, newest first, and only when both are empty the active pane. Exhausting a pane enters the next at its first (forward) / last (backward) span and the end wraps to the start, so `N` is the exact inverse of `n`. What it lands on becomes an EXPLICIT `vsel` with the cursor on its FIRST column, in the pane the walk focuses. ONE motion in every pane kind and every buffer kind — a PDF steps the `+Search` buffer its own search filled, `n` to select the row and Enter to jump. The single thing a buffer may change is the GRAIN of what a step selects, and it changes it with one flag rather than a branch: `output_pane.Traits.commands` makes a step take the WHOLE LINE, because a command list (`ThemeSel`/`FontSel`) holds words to run and there is no path inside `Theme gruvbox` to pick out. Tab on what `n` selected wears the theme, which is the same middle click on the row is. `]d`/`[d` are helix's diagnostic motions, a different binding, and they do still jump to each diagnostic (`docs/lsp.md`) | pardes-specific | | insert: printable text | file: real edit; terminal: typed run splice | | helix-verified (file) | | insert: `Enter` | newline; keeps the current full indent levels and adds one 4-space logical tab when the text before the cursor ends in `(`, `[`, `{`, or `)` (including `})`) | plain lines match `insert_newline`; delimiter heuristic is pardes-specific | helix-verified (plain) / pardes-specific (delimiter) | | insert: `Backspace` (+ `Shift-Backspace`) | delete prev char, joins lines at col 0 | matches `delete_char_backward`; `Ctrl-h` alias in B | helix-verified | @@ -139,7 +144,7 @@ Phase 2 state added to `Pane`: `count` (accumulator, capped 0xffff), | Key | Behavior | Notes | Status | | --- | --- | --- | --- | | `r<ch>` | replace selection/char with `<ch>`, newlines kept | terminals: replaces the typed-run byte under the cursor if any, else no-op (`runByteAt`) | helix-verified (phase 5) | -| `R` | replace selection (or cursor char) with the yank register; pasted text becomes the selection, head on its last char | uses the INTERNAL yank (`p.yank`), no clipboard round trip; empty register = no-op; terminals: no-op | helix-verified (phase 5) | +| `R` | replace selection (or cursor char) with the yank register; pasted text becomes the selection, head on its last char | uses the INTERNAL yank (`p.yank`), no clipboard round trip — `SPC R` is the system-clipboard twin; empty register = no-op; terminals: no-op | helix-verified (phase 5) | | `~` | switch case of selection/char, selection kept | terminals: run byte only | helix-verified (phase 5) | | `` ` `` | selection to lowercase | terminals: run byte only | helix-verified (phase 5) | | ``Alt-` `` | selection to uppercase | terminals: run byte only | helix-verified (phase 5) | @@ -276,8 +281,8 @@ text. | Key(s) | Helix behavior | Reason | | --- | --- | --- | -| `?`, `*`, `Alt-*` | rsearch / selection-as-pattern | search — pardes has its own `/` n N (plain substring into an output buffer, kept as-is); helix regex search machinery not wanted | -| `Space` mode, all rows (`f F e . b j g G k s S d D r a h ' w c C Alt-c p P y Y R / ?`) | pickers, LSP actions, clipboard menu, global search, palette | helix's space mode is pickers + LSP + a clipboard menu, none of which exist here — but the KEY is taken: pardes' own leader runs the acme builtins (section A). Clipboard: yank mirrors out via OSC 52, `p` pastes the register | +| `?`, `*`, `Alt-*` | rsearch / selection-as-pattern | search — pardes has its own `/` (plain substring into an output buffer, kept as-is) and an `n`/`N` that SELECTS the next look-able text instead of walking match hits; helix regex search machinery not wanted | +| `Space` mode, all rows but the clipboard menu (`f F e . b j g G k s S d D r a h ' w c C Alt-c / ?`) | pickers, LSP actions, global search, palette | helix's space mode is pickers + LSP, neither of which exists here — but the KEY is taken: pardes' own leader runs the acme builtins (section A). The clipboard menu is the half that DOES exist now: `<space>y Y p P R`, helix's letters on helix's leader, in section A | | Popup `Ctrl-u`/`Ctrl-d`, Completion menu, Signature help tables | LSP popups | LSP | | Picker table (all rows), Prompt table (all rows) | picker / prompt internals | pickers — pardes' tag line is its own one-line editor | | `gn` `gp` `ga` `gm` | next/prev/alternate buffer | buffer nav — pardes panes aren't a buffer list | @@ -288,7 +293,7 @@ text. | `]f [f ]t [t ]a [a ]c [c ]e [e ]T [T ]x [x` | TS unimpaired jumps | tree-sitter | | `]g [g ]G [G` | git change jumps | needs VCS diff state | | `gd gD gy gr gi`, `=`, `]d [d ]D [D`, insert `Ctrl-x` | definition/refs/format/diagnostics/completion | LSP | -| `"` `<reg>`, insert `Ctrl-r` | register select / insert | registers — single yank register only | +| `"` `<reg>`, insert `Ctrl-r` | register select / insert | registers — one yank register and no way to name a second; the system clipboard is not spelled as a register here either, it is the five `SPC` commands in A | | `Q` / `q` | record / replay macro | macros — needs replayable input log | | `Ctrl-i` `Ctrl-o` `Ctrl-s` (normal) | jumplist forward/back/save | jumplist | | `Alt-u` / `Alt-U` | undo-history earlier/later | history timeline — linear snapshot u/U covers pardes | @@ -304,7 +309,7 @@ text. | `Z` (sticky view mode) | persistent view mode | marginal; `z` one-shots suffice | | `zm` (view) | align middle horizontally | marginal even with hscroll | | `.` | repeat last insert | **deferred by decision**: needs recording the insert session's keystrokes and a replay path — a new subsystem; undo is whole-buffer snapshots with no edit log to piggyback on. Revisit after phases 2–5 if the log exists by then for another reason | -| Select/extend mode section (prose) | `v` turns all motions into extenders, `n`/`N` keep selections | implemented for motions (phase 5: `pane.select` + the fixed anchor, differential-verified — see the `v` row in A); helix's search-`n`/`N` extension doesn't apply (pardes `n`/`N` are its own search/look ops) | +| Select/extend mode section (prose) | `v` turns all motions into extenders, `n`/`N` keep selections | implemented for motions (phase 5: `pane.select` + the fixed anchor, differential-verified — see the `v` row in A); helix's search-`n`/`N` extension doesn't apply (pardes' `n`/`N` is the look-ring motion, which REPLACES the selection with the span it lands on) | ## Differential testing (phase 5) |
