summaryrefslogtreecommitdiff
path: root/docs/helix-keys.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/helix-keys.md')
-rw-r--r--docs/helix-keys.md31
1 files changed, 17 insertions, 14 deletions
diff --git a/docs/helix-keys.md b/docs/helix-keys.md
index 81bc0248..dcd5b7cb 100644
--- a/docs/helix-keys.md
+++ b/docs/helix-keys.md
@@ -13,21 +13,20 @@ single key — it is the anchor-only divergence every insert-mode edit shares �
and is described in the Files list at the bottom instead.
Code map, by SYMBOL — line numbers rot, names do not. Body-normal key
-RECOGNITION is `src/normal_input.zig`: a pure state machine over `Role` (one
+RECOGNITION is `modal.Normal` in `src/modal.zig`: a state machine over `Role` (one
per bound command, matched against `src/config.zig`'s chord lists by
`Pardes.normalInput`), a `Prefix`, a `MatchSub` and a count, emitting a
semantic `Action` that both the text and PDF adapters consume. It knows
nothing about panes or text. `src/pardes.zig` then EXECUTES: `Key`,
`handleKey` (intercept order is load-bearing, see the comment there),
-`handleNormal` (marshals `Pane`'s compact fields in and out of
-`normal_input.State` through `paneNormalState` / `putPaneNormalState`),
+`handleNormal` (parses directly into `Pane.normal`),
`executeNormalAction`, `setPaneRange` (helix range → pane state),
`enterInsert`, `handleInsert` / `insertKey`, `insertTab`, `normalDelete`,
-`normalYank`, `normalPaste`, `normalChange`, `replaySels`, `multiOnce`. Undo
-and redo are per pane kind, in `file_pane` and `term_pane`. Pure text math:
+`normalYank`, `pasteText`, `normalChange`, `replaySels`, `multiOnce`. Undo
+and redo live in `panes.File` and `panes.Terminal`. Pure text math:
`src/modal.zig` (the `hx*` family is the helix-semantics layer: gap offsets +
ranges over the flat text). Differential harness: `test/hxdiff.zig` +
-`test/hxcases/*.jsonl` + `test/hxcases/regen.sh` — see "Differential testing"
+`test/hxcases/*.jsonl` — see "Differential testing"
at the bottom.
## Global semantic divergences (read first)
@@ -94,7 +93,7 @@ language-backend queries, and the shell pipe.
| `w` `b` `e` | select to next word start / prev word start / next word end | full helix model incl. landing conventions (block cursor one before the next word after `w`) and newline/punct/EOF edges | helix-verified |
| `W` `B` `E` | long-word (WORD) variants | same | helix-verified |
| `Home` / `End` | line start / line end | matches `goto_line_start` / `goto_line_end` | helix-verified |
-| `0` / `$` / `^` | line start / line end / first non-ws | `0` and `^` are pardes extras — helix leaves those two unbound (it spells them `gh`/`gs`). `$` is NOT unbound in helix: it is `shell_keep_pipe` (`keymap/default.rs`), and taking it for line-end is a deliberate divergence — see the `$` row in C. `0` is a count digit while a count is pending | pardes-specific (`$`: deliberate) |
+| `0` / `$` / `^` | line start / line end / first non-ws | `0` and `^` are pardes extras — helix leaves those two unbound (it spells them `gh`/`gs`). `$` is NOT unbound in helix: it is `shell_keep_pipe` (`keymap/default.rs`), and taking it for line-end is a deliberate divergence — see the `$` row in C. It is the one shell command still unimplemented: it needs a per-selection verdict, where the runner's answer is atomic. `0` is a count digit while a count is pending | pardes-specific (`$`: deliberate) |
| `G` | bare `G` is a **no-op**; `<n>G` = goto line n | vim-ism removed (phase 5): helix `goto_line` only acts with a count; `ge` is goto-last-line | helix-verified |
| `gg` / `<n>gg` | goto first line / line n | | helix-verified |
| `ge` | goto last content line | matches `goto_last_line` (ignores the trailing empty line) | helix-verified |
@@ -137,6 +136,9 @@ language-backend queries, and the shell pipe.
| `=` | `format_selections` — writes a `- old` / `+ new` diff into `+Lsp` | deliberate divergence: the seam returns ROWS, not edits, so this SHOWS the formatting instead of applying it. Not in the corpus, so there is no waiver to name — the query leaves the core as an effect the headless harness has no shell to perform | out of corpus |
| `Ctrl-o` / `Ctrl-i` | jumplist back / forward — the `Back` / `Forward` builtins, also on `SPC j o` / `SPC j i`, with `SPC j l` rendering the stack as a buffer | helix binds both keys (`jump_backward` / `jump_forward`) but to a POSITION jumplist; pardes' stack is over panes and focus, so the keys agree and the semantics do not. `Ctrl-i` and Tab are the same byte under the legacy encoding; there Tab keeps meaning execute, and the pair only separates where the host speaks the kitty keyboard protocol | pardes-specific |
| `\|` | pipe every selection through `/bin/sh -c`: its bytes in on stdin, its stdout replacing them, one undo across all cursors | helix's own key and meaning; the command is typed into the pane's tag after a bare `\|` marker rather than into a popup | out of corpus |
+| `A-\|` | the same, and the output is DISCARDED — the text is not touched at all | helix `shell_pipe_to`. For a command run for its effect. Marker `\|-` | out of corpus |
+| `!` | run with NO stdin, insert the output BEFORE each selection | helix `shell_insert_output`. Runs ONCE and every cursor gets that one answer, as helix does — ten cursors and `date` give ten identical stamps. Marker `!` | out of corpus |
+| `A-!` | the same, appended AFTER each selection | helix `shell_append_output`. Marker `!+` | out of corpus |
## B. To implement
@@ -144,13 +146,10 @@ Status: `todo` → set to `done (phase N)` as rows land. All rows verified
against keymap.md. Edit ops on terminal panes obey the immutable-output
rule (typed runs only) — same as `d`/`c` today.
-Phase 2's recognition state is now `normal_input.State`: a count (accumulator,
+`Pane.normal` holds `modal.Normal.State`: a count (accumulator,
capped 0xffff), a `Prefix` (`g` `z` `m` `f` `F` `t` `T` `r` `]` `[`), a
`MatchSub` (m-mode's `i`/`a`/`s`/`r`/`d`) and one `held_char` for `mr`'s
-`<from>`. `Pane` keeps the same four fields it always did — `count`,
-`pending`, `pending2`, `pending_ch` — but purely as compact per-pane storage,
-marshalled in and out by `paneNormalState` / `putPaneNormalState`; the
-comments on them say so. `find_op`/`find_ch` (the `Alt-.` repeat target) stay
+`<from>`. `find_op`/`find_ch` (the `Alt-.` repeat target) stay
on `Pane`, because the parser emits `repeat_find` without remembering what was
found. Pure text math in `modal.zig`: `findChar`, `matchBracket`,
`paragraphFwd`/`paragraphBwd`/`paragraphRange`, textobject/surround ranges,
@@ -376,7 +375,7 @@ Files (all in `test/hxcases/`):
immutable) or doc-marked terminal no-ops. tty case texts keep motions
inside the content (the tty motion surface trims trailing blank rows,
so ge/G-to-last-line style assertions stay off tty).
-- `goldens.jsonl` — checked-in helix results, regenerated by `regen.sh`
+- `goldens.jsonl` — checked-in helix results, regenerated by `zig build hxdiff-update`
(runs the `hx-harness` binary from the helix checkout; override with
`$HX_HARNESS`). Only needed when cases change — the diff itself runs
offline.
@@ -414,7 +413,11 @@ Run it:
# "editing a shell pane behaves like editing a
# file" cannot drift. The case's own "pane" field
# is ignored; exemptions in parity-waivers.jsonl
- sh test/hxcases/regen.sh # regenerate goldens
+ zig build hxdiff-live # compare a fresh reference without changing goldens
+ zig build hxdiff-update # update goldens only after the live comparison passes
+
+Set `-Dhelix-harness=/path/to/hx-harness` or `HX_HARNESS`; otherwise these
+steps look for `hx-harness` on PATH.
The helix half (`hx-harness`) lives on the `pardes-harness` branch:
a full headless `Application` with LSP/tree-sitter/auto-pairs/word-