From 9da20917b6f4cf98fd9b5c2c0a904e4f6a8380a9 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Tue, 7 Jul 2026 09:48:05 -0300 Subject: helix diff testing and feature parity --- transactions.txt | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 transactions.txt (limited to 'transactions.txt') diff --git a/transactions.txt b/transactions.txt new file mode 100644 index 00000000..b1233d3d --- /dev/null +++ b/transactions.txt @@ -0,0 +1,59 @@ +Selection anchors through insert-mode edits, and the transaction model +======================================================================= + +The one place the helix differential suite shows a real structural gap +(waiver "wiX-edit-drops-sel" in test/hxcases/waivers.jsonl): helix keeps a +selection ALIVE across insert mode, pardes drops it on the first edit. + +What helix does +--------------- +A selection doesn't die when you enter insert mode. Every edit is a +Transaction — a structured delta (retain N, insert "...", delete N) — and +all stored positions are MAPPED through it, the selection anchor included. +Insert a char before the anchor and it slides right by one; delete a line +above it and its row shifts up. Esc back to normal mode and the old +selection is still there, coordinates adjusted to cover the same logical +text. + +Example ("alpha beta" + keys w i X ): + after w: anchor (0,0), cursor on the space (0,5), "alpha " selected + i, type X: buffer is "Xalpha beta" + after esc: helix — anchor (0,1), selection still spans "alpha " (remapped) + pardes — selection gone, anchor == cursor +Final text, cursor, and mode agree on both sides; only the anchor differs. + +What pardes does today +---------------------- +No transaction layer. handleInsert mutates the buffer directly at ~23 +distinct sites (char inserts, newline, backspace incl. the line-join case, +Ctrl-w/Alt-d word kills, Ctrl-u/Ctrl-k line kills, multi-line paste, and +the terminal run-splice variants). Keeping the anchor alive would mean +hand-written row/col shift arithmetic at every one of those sites — 23 +error-prone edit paths to maintain for state nothing reads: d/c/y take a +fresh selection from the next motion, and the acme Enter/Tab chords only +act on EXPLICIT selections (v/x/n/N), which never enter insert mode. Hence +the waiver instead of a fix. + +Why we might adopt the transaction model anyway +----------------------------------------------- +A small transaction layer (edits as deltas + one mapThroughEdit(pos, edit) +helper applied at each mutation site) would buy, in rough order of value: + - "." repeat-last-insert (currently deferred in docs/helix-keys.md for + exactly this reason: no edit log to replay) + - delta-based undo/redo instead of whole-buffer snapshots (pushUndo + dupes f.content per edit op today — fine for small files, O(file) per op) + - the waived anchor parity for free (selections survive insert mode, + remapped like helix) + - any future position-carrying state (marks, jumplist, multiple + selections) gets remapping for free instead of per-site arithmetic + +Upgrade path, if/when +--------------------- +1. Define the delta type in modal.zig (pure, unit-testable): a list of + (retain, insert, delete) spans, plus mapThroughEdit for a (row,col). +2. Make the ~23 handleInsert mutation sites EMIT a delta and apply it in + one place, instead of splicing content inline. +3. Undo becomes a log of inverse deltas; "." becomes a replay of the last + insert session's deltas; drop the y-anchor waiver and its harness case. +Adopt only when one of the consumers above is actually wanted — the delta +layer alone is machinery without a user. -- cgit v1.3