diff options
| author | Gabriel Schneider <[email protected]> | 2026-07-07 09:48:05 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-08-01 15:02:07 -0300 |
| commit | 9da20917b6f4cf98fd9b5c2c0a904e4f6a8380a9 (patch) | |
| tree | c7c8c4d1126def565eb0b1d20ad29782eb49c5e7 /test | |
| parent | b2cdd8ee719961b2f037f20bf0f88fad94ca73b4 (diff) | |
| download | pardes-9da20917b6f4cf98fd9b5c2c0a904e4f6a8380a9.tar.gz pardes-9da20917b6f4cf98fd9b5c2c0a904e4f6a8380a9.zip | |
helix diff testing and feature parity
Diffstat (limited to 'test')
| -rw-r--r-- | test/hxcases/cases.jsonl | 360 | ||||
| -rw-r--r-- | test/hxcases/goldens.jsonl | 360 | ||||
| -rwxr-xr-x | test/hxcases/regen.sh | 16 | ||||
| -rw-r--r-- | test/hxcases/smoke.jsonl | 20 | ||||
| -rw-r--r-- | test/hxcases/waivers.jsonl | 2 | ||||
| -rw-r--r-- | test/hxdiff.zig | 355 | ||||
| -rw-r--r-- | test/snapshots/fileedit.golden | 2 | ||||
| -rw-r--r-- | test/snapshots/modal.golden | 36 | ||||
| -rw-r--r-- | test/snapshots/modal.snap | 2 | ||||
| -rw-r--r-- | test/snapshots/scrolloff.golden | 8 | ||||
| -rw-r--r-- | test/snapshots/scrolloff.snap | 5 |
11 files changed, 1140 insertions, 26 deletions
diff --git a/test/hxcases/cases.jsonl b/test/hxcases/cases.jsonl new file mode 100644 index 00000000..386013bf --- /dev/null +++ b/test/hxcases/cases.jsonl @@ -0,0 +1,360 @@ +{"name": "h-basic", "pane": "file", "text": "abc def\n", "keys": "llh"} +{"name": "h-basic-tty", "pane": "tty", "text": "abc def\n", "keys": "llh"} +{"name": "h-crosses-nl", "pane": "file", "text": "ab\ncd\n", "keys": "jh"} +{"name": "h-crosses-nl-tty", "pane": "tty", "text": "ab\ncd\n", "keys": "jh"} +{"name": "l-basic", "pane": "file", "text": "abc\n", "keys": "l"} +{"name": "l-basic-tty", "pane": "tty", "text": "abc\n", "keys": "l"} +{"name": "l-crosses-nl", "pane": "file", "text": "ab\ncd\n", "keys": "lll"} +{"name": "l-crosses-nl-tty", "pane": "tty", "text": "ab\ncd\n", "keys": "lll"} +{"name": "l-count", "pane": "file", "text": "abcdef\n", "keys": "3l"} +{"name": "l-count-tty", "pane": "tty", "text": "abcdef\n", "keys": "3l"} +{"name": "h-count", "pane": "file", "text": "abcdef\n", "keys": "5l3h"} +{"name": "h-count-tty", "pane": "tty", "text": "abcdef\n", "keys": "5l3h"} +{"name": "l-clamp-eof", "pane": "file", "text": "ab\n", "keys": "9l"} +{"name": "j-basic", "pane": "file", "text": "aa\nbb\ncc\n", "keys": "j"} +{"name": "j-basic-tty", "pane": "tty", "text": "aa\nbb\ncc\n", "keys": "j"} +{"name": "j-onto-nl-cell", "pane": "file", "text": "abcdef\nab\nabcdef\n", "keys": "glj"} +{"name": "j-onto-nl-cell-tty", "pane": "tty", "text": "abcdef\nab\nabcdef\n", "keys": "glj"} +{"name": "j-sticky-col", "pane": "file", "text": "abcdef\nab\nabcdef\n", "keys": "gljj"} +{"name": "j-sticky-col-tty", "pane": "tty", "text": "abcdef\nab\nabcdef\n", "keys": "gljj"} +{"name": "j-phantom", "pane": "file", "text": "one\ntwo\n", "keys": "jj"} +{"name": "k-basic", "pane": "file", "text": "aa\nbb\n", "keys": "jk"} +{"name": "k-basic-tty", "pane": "tty", "text": "aa\nbb\n", "keys": "jk"} +{"name": "k-sticky-col", "pane": "file", "text": "abcdef\nab\nabcdef\n", "keys": "2jglkk"} +{"name": "k-sticky-col-tty", "pane": "tty", "text": "abcdef\nab\nabcdef\n", "keys": "2jglkk"} +{"name": "j-count", "pane": "file", "text": "a\nb\nc\nd\n", "keys": "2j"} +{"name": "j-count-tty", "pane": "tty", "text": "a\nb\nc\nd\n", "keys": "2j"} +{"name": "arrow-right-down", "pane": "file", "text": "abc\ndef\n", "keys": "<right><down>"} +{"name": "arrow-right-down-tty", "pane": "tty", "text": "abc\ndef\n", "keys": "<right><down>"} +{"name": "arrow-left-up", "pane": "file", "text": "abc\ndef\n", "keys": "j<right><left><up>"} +{"name": "arrow-left-up-tty", "pane": "tty", "text": "abc\ndef\n", "keys": "j<right><left><up>"} +{"name": "w-basic", "pane": "file", "text": "alpha beta\n", "keys": "w"} +{"name": "w-basic-tty", "pane": "tty", "text": "alpha beta\n", "keys": "w"} +{"name": "w-punct", "pane": "file", "text": "foo.bar baz\n", "keys": "w"} +{"name": "w-punct-tty", "pane": "tty", "text": "foo.bar baz\n", "keys": "w"} +{"name": "w-punct-run", "pane": "file", "text": "foo.bar baz\n", "keys": "ww"} +{"name": "w-punct-run-tty", "pane": "tty", "text": "foo.bar baz\n", "keys": "ww"} +{"name": "w-count", "pane": "file", "text": "one two three four\n", "keys": "2w"} +{"name": "w-count-tty", "pane": "tty", "text": "one two three four\n", "keys": "2w"} +{"name": "w-eol-cross", "pane": "file", "text": "ab cd\nef\n", "keys": "www"} +{"name": "w-eol-cross-tty", "pane": "tty", "text": "ab cd\nef\n", "keys": "www"} +{"name": "w-from-empty-line", "pane": "file", "text": "\nabc\n", "keys": "w"} +{"name": "w-skips-blank", "pane": "file", "text": "aa\n\nbb\n", "keys": "ww"} +{"name": "w-skips-blank-tty", "pane": "tty", "text": "aa\n\nbb\n", "keys": "ww"} +{"name": "w-eof-collapse", "pane": "file", "text": "alpha\n", "keys": "ww"} +{"name": "b-basic", "pane": "file", "text": "alpha beta\n", "keys": "wwb"} +{"name": "b-basic-tty", "pane": "tty", "text": "alpha beta\n", "keys": "wwb"} +{"name": "b-bof-noop", "pane": "file", "text": "alpha\n", "keys": "b"} +{"name": "b-bof-noop-tty", "pane": "tty", "text": "alpha\n", "keys": "b"} +{"name": "b-from-nl-cell", "pane": "file", "text": "ab\ncd\n", "keys": "llb"} +{"name": "b-from-nl-cell-tty", "pane": "tty", "text": "ab\ncd\n", "keys": "llb"} +{"name": "b-count", "pane": "file", "text": "a bb ccc dddd\n", "keys": "gl2b"} +{"name": "b-count-tty", "pane": "tty", "text": "a bb ccc dddd\n", "keys": "gl2b"} +{"name": "e-basic", "pane": "file", "text": "alpha beta\n", "keys": "e"} +{"name": "e-basic-tty", "pane": "tty", "text": "alpha beta\n", "keys": "e"} +{"name": "e-from-mid", "pane": "file", "text": "alpha beta\n", "keys": "le"} +{"name": "e-from-mid-tty", "pane": "tty", "text": "alpha beta\n", "keys": "le"} +{"name": "e-count", "pane": "file", "text": "a bb ccc dddd\n", "keys": "2e"} +{"name": "e-count-tty", "pane": "tty", "text": "a bb ccc dddd\n", "keys": "2e"} +{"name": "e-cross-blank", "pane": "file", "text": "aa\n\nbb\n", "keys": "ee"} +{"name": "e-cross-blank-tty", "pane": "tty", "text": "aa\n\nbb\n", "keys": "ee"} +{"name": "W-basic", "pane": "file", "text": "foo.bar baz\n", "keys": "W"} +{"name": "W-basic-tty", "pane": "tty", "text": "foo.bar baz\n", "keys": "W"} +{"name": "B-basic", "pane": "file", "text": "foo.bar baz\n", "keys": "WB"} +{"name": "B-basic-tty", "pane": "tty", "text": "foo.bar baz\n", "keys": "WB"} +{"name": "E-basic", "pane": "file", "text": "foo.bar baz\n", "keys": "E"} +{"name": "E-basic-tty", "pane": "tty", "text": "foo.bar baz\n", "keys": "E"} +{"name": "f-basic", "pane": "file", "text": "abcabc\n", "keys": "fc"} +{"name": "f-basic-tty", "pane": "tty", "text": "abcabc\n", "keys": "fc"} +{"name": "f-count", "pane": "file", "text": "abcabc\n", "keys": "2fc"} +{"name": "f-count-tty", "pane": "tty", "text": "abcabc\n", "keys": "2fc"} +{"name": "f-cross-line", "pane": "file", "text": "one\ntwo\n", "keys": "fw"} +{"name": "f-cross-line-tty", "pane": "tty", "text": "one\ntwo\n", "keys": "fw"} +{"name": "f-notfound-noop", "pane": "file", "text": "abc\n", "keys": "fz"} +{"name": "f-notfound-noop-tty", "pane": "tty", "text": "abc\n", "keys": "fz"} +{"name": "f-digit-arg", "pane": "file", "text": "a4b\n", "keys": "f4"} +{"name": "f-digit-arg-tty", "pane": "tty", "text": "a4b\n", "keys": "f4"} +{"name": "f-repeat-same-target", "pane": "file", "text": "abcabc\n", "keys": "fafa"} +{"name": "t-basic", "pane": "file", "text": "abcabc\n", "keys": "tc"} +{"name": "t-basic-tty", "pane": "tty", "text": "abcabc\n", "keys": "tc"} +{"name": "t-twice-skips-edge", "pane": "file", "text": "abcabc\n", "keys": "tctc"} +{"name": "t-twice-skips-edge-tty", "pane": "tty", "text": "abcabc\n", "keys": "tctc"} +{"name": "F-backward", "pane": "file", "text": "abcabc\n", "keys": "glFa"} +{"name": "F-backward-tty", "pane": "tty", "text": "abcabc\n", "keys": "glFa"} +{"name": "T-backward", "pane": "file", "text": "abcabc\n", "keys": "glTa"} +{"name": "T-backward-tty", "pane": "tty", "text": "abcabc\n", "keys": "glTa"} +{"name": "alt-dot-repeat-f", "pane": "file", "text": "abcabc\n", "keys": "fc<A-.>"} +{"name": "alt-dot-repeat-f-tty", "pane": "tty", "text": "abcabc\n", "keys": "fc<A-.>"} +{"name": "alt-dot-repeat-t", "pane": "file", "text": "abcabc\n", "keys": "tc<A-.>"} +{"name": "alt-dot-repeat-t-tty", "pane": "tty", "text": "abcabc\n", "keys": "tc<A-.>"} +{"name": "alt-dot-count", "pane": "file", "text": "axbxcxd\n", "keys": "fx2<A-.>"} +{"name": "alt-dot-count-tty", "pane": "tty", "text": "axbxcxd\n", "keys": "fx2<A-.>"} +{"name": "G-count", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "5G"} +{"name": "G-count-tty", "pane": "tty", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "5G"} +{"name": "G-count-clamp", "pane": "file", "text": "one\ntwo\n", "keys": "99G"} +{"name": "G-count-clamp-tty", "pane": "tty", "text": "one\ntwo\n", "keys": "99G"} +{"name": "G-bare-noop", "pane": "file", "text": "aa\nbb\ncc\n", "keys": "jG"} +{"name": "G-bare-noop-tty", "pane": "tty", "text": "aa\nbb\ncc\n", "keys": "jG"} +{"name": "count-multidigit", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "10j"} +{"name": "count-multidigit-tty", "pane": "tty", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "10j"} +{"name": "G-count-resets-col", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "3l5G"} +{"name": "G-count-resets-col-tty", "pane": "tty", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "3l5G"} +{"name": "gg-basic", "pane": "file", "text": "aa\nbb\ncc\n", "keys": "jjgg"} +{"name": "gg-basic-tty", "pane": "tty", "text": "aa\nbb\ncc\n", "keys": "jjgg"} +{"name": "gg-count", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "3gg"} +{"name": "gg-count-tty", "pane": "tty", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "3gg"} +{"name": "ge-basic", "pane": "file", "text": "aa\nbb\ncc\n", "keys": "ge"} +{"name": "ge-basic-tty", "pane": "tty", "text": "aa\nbb\ncc\n", "keys": "ge"} +{"name": "ge-col0", "pane": "file", "text": "alpha beta\n", "keys": "wwge"} +{"name": "ge-col0-tty", "pane": "tty", "text": "alpha beta\n", "keys": "wwge"} +{"name": "gh-basic", "pane": "file", "text": "abc\n", "keys": "llgh"} +{"name": "gh-basic-tty", "pane": "tty", "text": "abc\n", "keys": "llgh"} +{"name": "gl-basic", "pane": "file", "text": "abc def\n", "keys": "gl"} +{"name": "gl-basic-tty", "pane": "tty", "text": "abc def\n", "keys": "gl"} +{"name": "gl-empty-line", "pane": "file", "text": "\nabc\n", "keys": "gl"} +{"name": "gl-empty-line-tty", "pane": "tty", "text": "\nabc\n", "keys": "gl"} +{"name": "gs-basic", "pane": "file", "text": " abc\n", "keys": "llgs"} +{"name": "gs-basic-tty", "pane": "tty", "text": " abc\n", "keys": "llgs"} +{"name": "gs-allws-noop", "pane": "file", "text": " \nx\n", "keys": "gs"} +{"name": "gs-allws-noop-tty", "pane": "tty", "text": " \nx\n", "keys": "gs"} +{"name": "gbar-count", "pane": "file", "text": "abcdef\n", "keys": "4g|"} +{"name": "gbar-count-tty", "pane": "tty", "text": "abcdef\n", "keys": "4g|"} +{"name": "gbar-clamp", "pane": "file", "text": "ab\n", "keys": "9g|"} +{"name": "gbar-clamp-tty", "pane": "tty", "text": "ab\n", "keys": "9g|"} +{"name": "gbar-nocount", "pane": "file", "text": "abcdef\n", "keys": "llg|"} +{"name": "gbar-nocount-tty", "pane": "tty", "text": "abcdef\n", "keys": "llg|"} +{"name": "gj-basic", "pane": "file", "text": "abcdef\nab\nabcdef\n", "keys": "glgjgj"} +{"name": "gj-basic-tty", "pane": "tty", "text": "abcdef\nab\nabcdef\n", "keys": "glgjgj"} +{"name": "gk-basic", "pane": "file", "text": "aa\nbb\ncc\n", "keys": "jjgk"} +{"name": "gk-basic-tty", "pane": "tty", "text": "aa\nbb\ncc\n", "keys": "jjgk"} +{"name": "home-basic", "pane": "file", "text": "abc def\n", "keys": "w<home>"} +{"name": "home-basic-tty", "pane": "tty", "text": "abc def\n", "keys": "w<home>"} +{"name": "end-basic", "pane": "file", "text": "abc def\n", "keys": "<end>"} +{"name": "end-basic-tty", "pane": "tty", "text": "abc def\n", "keys": "<end>"} +{"name": "end-empty-line", "pane": "file", "text": "\nabc\n", "keys": "<end>"} +{"name": "end-empty-line-tty", "pane": "tty", "text": "\nabc\n", "keys": "<end>"} +{"name": "gt-noscroll", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "5jgt"} +{"name": "gt-noscroll-tty", "pane": "tty", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "5jgt"} +{"name": "gc-noscroll", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "gc"} +{"name": "gb-noscroll", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "5jgb"} +{"name": "gt-after-zz", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "15jzzgt"} +{"name": "gc-after-zz", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "15jzzgc"} +{"name": "gb-after-zz", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "15jzzgb"} +{"name": "gt-count", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "15jzz2gt"} +{"name": "ctrl-d-basic", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "<C-d>"} +{"name": "ctrl-d-small", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "<C-d>"} +{"name": "ctrl-d-sticky", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "5l<C-d>"} +{"name": "ctrl-u-back", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "20j<C-u>"} +{"name": "ctrl-f-page", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "<C-f>"} +{"name": "ctrl-f-small", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "<C-f>"} +{"name": "ctrl-b-page", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "20j<C-b>"} +{"name": "pgdn-basic", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "<pagedown>"} +{"name": "pgup-basic", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "25j<pageup>"} +{"name": "pgup-noop-in-view", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "5j<pageup>"} +{"name": "pgup-noop-in-view-tty", "pane": "tty", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n", "keys": "5j<pageup>"} +{"name": "v-ctrl-d-extends", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "v<C-d>"} +{"name": "zt-then-gt", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "12jztgt"} +{"name": "zz-then-gt", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "15jzzgt"} +{"name": "zb-then-gt", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "12jzbgt"} +{"name": "zc-alias-zz", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "15jzcgt"} +{"name": "zj-snaps-cursor", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "zj"} +{"name": "zj-noop-in-band", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "10jzj"} +{"name": "zk-bottom-snap", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "20jzk"} +{"name": "z-ctrl-d-alias", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "z<C-d>"} +{"name": "z-pgdn-alias", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "z<pagedown>"} +{"name": "v-reports-select", "pane": "file", "text": "alpha beta\n", "keys": "v"} +{"name": "v-reports-select-tty", "pane": "tty", "text": "alpha beta\n", "keys": "v"} +{"name": "v-extend-w", "pane": "file", "text": "alpha beta gamma\n", "keys": "vww"} +{"name": "v-extend-w-tty", "pane": "tty", "text": "alpha beta gamma\n", "keys": "vww"} +{"name": "v-anchor-fixed-crossing", "pane": "file", "text": "abcdef\n", "keys": "llvhhh"} +{"name": "v-anchor-fixed-crossing-tty", "pane": "tty", "text": "abcdef\n", "keys": "llvhhh"} +{"name": "v-exit-keeps-sel", "pane": "file", "text": "alpha beta\n", "keys": "vwv"} +{"name": "v-exit-keeps-sel-tty", "pane": "tty", "text": "alpha beta\n", "keys": "vwv"} +{"name": "v-esc-keeps-sel", "pane": "file", "text": "alpha beta\n", "keys": "vw<esc>"} +{"name": "v-esc-keeps-sel-tty", "pane": "tty", "text": "alpha beta\n", "keys": "vw<esc>"} +{"name": "v-gl-extends", "pane": "file", "text": "abc def\n", "keys": "vgl"} +{"name": "v-gl-extends-tty", "pane": "tty", "text": "abc def\n", "keys": "vgl"} +{"name": "v-gg-extends", "pane": "file", "text": "aa\nbb\ncc\n", "keys": "jjvgg"} +{"name": "v-gg-extends-tty", "pane": "tty", "text": "aa\nbb\ncc\n", "keys": "jjvgg"} +{"name": "v-find-extends", "pane": "file", "text": "abcabc\n", "keys": "vfcfc"} +{"name": "v-find-extends-tty", "pane": "tty", "text": "abcabc\n", "keys": "vfcfc"} +{"name": "v-x-extends-line", "pane": "file", "text": "ab\ncd\nef\n", "keys": "vjx"} +{"name": "v-x-extends-line-tty", "pane": "tty", "text": "ab\ncd\nef\n", "keys": "vjx"} +{"name": "v-j-phantom-blocked", "pane": "file", "text": "one\ntwo\n", "keys": "vjj"} +{"name": "w-esc-keeps-sel", "pane": "file", "text": "alpha beta\n", "keys": "w<esc>"} +{"name": "w-esc-keeps-sel-tty", "pane": "tty", "text": "alpha beta\n", "keys": "w<esc>"} +{"name": "semi-collapse", "pane": "file", "text": "alpha beta\n", "keys": "w;"} +{"name": "semi-collapse-tty", "pane": "tty", "text": "alpha beta\n", "keys": "w;"} +{"name": "altsemi-flip", "pane": "file", "text": "alpha beta\n", "keys": "w<A-;>"} +{"name": "altsemi-flip-tty", "pane": "tty", "text": "alpha beta\n", "keys": "w<A-;>"} +{"name": "altsemi-flip-x", "pane": "file", "text": "one\ntwo\ncc\n", "keys": "x<A-;>"} +{"name": "altsemi-flip-x-tty", "pane": "tty", "text": "one\ntwo\ncc\n", "keys": "x<A-;>"} +{"name": "percent-select-all", "pane": "file", "text": "one\ntwo\n", "keys": "%"} +{"name": "percent-then-d", "pane": "file", "text": "one\ntwo\n", "keys": "%d"} +{"name": "x-selects-line", "pane": "file", "text": "one\ntwo\nthree\n", "keys": "x"} +{"name": "x-selects-line-tty", "pane": "tty", "text": "one\ntwo\nthree\n", "keys": "x"} +{"name": "x-extends", "pane": "file", "text": "one\ntwo\nthree\n", "keys": "xx"} +{"name": "x-extends-tty", "pane": "tty", "text": "one\ntwo\nthree\n", "keys": "xx"} +{"name": "x-count", "pane": "file", "text": "a\nb\nc\nd\n", "keys": "2x"} +{"name": "x-count-tty", "pane": "tty", "text": "a\nb\nc\nd\n", "keys": "2x"} +{"name": "x-empty-line", "pane": "file", "text": "a\n\nb\nc\n", "keys": "jx"} +{"name": "x-empty-line-tty", "pane": "tty", "text": "a\n\nb\nc\n", "keys": "jx"} +{"name": "x-last-line", "pane": "file", "text": "one\ntwo\n", "keys": "jx"} +{"name": "x-then-w-drops", "pane": "file", "text": "aa\nbb cc\n", "keys": "xw"} +{"name": "x-then-w-drops-tty", "pane": "tty", "text": "aa\nbb cc\n", "keys": "xw"} +{"name": "x-then-d", "pane": "file", "text": "one\ntwo\nthree\n", "keys": "xd"} +{"name": "X-bare", "pane": "file", "text": "abc\ndef\n", "keys": "lX"} +{"name": "X-bare-tty", "pane": "tty", "text": "abc\ndef\n", "keys": "lX"} +{"name": "X-from-v", "pane": "file", "text": "abc\ndef\nghi\n", "keys": "lvjX"} +{"name": "X-from-v-tty", "pane": "tty", "text": "abc\ndef\nghi\n", "keys": "lvjX"} +{"name": "X-keeps-direction", "pane": "file", "text": "abc\ndef\nghi\n", "keys": "jlvkX"} +{"name": "X-keeps-direction-tty", "pane": "tty", "text": "abc\ndef\nghi\n", "keys": "jlvkX"} +{"name": "X-noop-when-full", "pane": "file", "text": "abc\ndef\n", "keys": "XX"} +{"name": "altx-shrink", "pane": "file", "text": "abc\ndef\nghi\n", "keys": "lv2j<A-x>"} +{"name": "altx-shrink-tty", "pane": "tty", "text": "abc\ndef\nghi\n", "keys": "lv2j<A-x>"} +{"name": "altx-single-line-noop", "pane": "file", "text": "abcdef\n", "keys": "lvll<A-x>"} +{"name": "altx-single-line-noop-tty", "pane": "tty", "text": "abcdef\n", "keys": "lvll<A-x>"} +{"name": "mm-basic", "pane": "file", "text": "a(bc(d)e)f\n", "keys": "lmm"} +{"name": "mm-basic-tty", "pane": "tty", "text": "a(bc(d)e)f\n", "keys": "lmm"} +{"name": "mm-back", "pane": "file", "text": "a(bc(d)e)f\n", "keys": "8lmm"} +{"name": "mm-back-tty", "pane": "tty", "text": "a(bc(d)e)f\n", "keys": "8lmm"} +{"name": "mm-nonbracket-noop", "pane": "file", "text": "abc\n", "keys": "mm"} +{"name": "mm-nonbracket-noop-tty", "pane": "tty", "text": "abc\n", "keys": "mm"} +{"name": "mi-paren", "pane": "file", "text": "fn(a, b)\n", "keys": "fami("} +{"name": "mi-paren-tty", "pane": "tty", "text": "fn(a, b)\n", "keys": "fami("} +{"name": "ma-paren", "pane": "file", "text": "fn(a, b)\n", "keys": "fama("} +{"name": "ma-paren-tty", "pane": "tty", "text": "fn(a, b)\n", "keys": "fama("} +{"name": "mi-nested", "pane": "file", "text": "(a(b)c)\n", "keys": "3lmi("} +{"name": "mi-nested-tty", "pane": "tty", "text": "(a(b)c)\n", "keys": "3lmi("} +{"name": "mi-word", "pane": "file", "text": "alpha beta\n", "keys": "wwmiw"} +{"name": "mi-word-tty", "pane": "tty", "text": "alpha beta\n", "keys": "wwmiw"} +{"name": "mi-WORD", "pane": "file", "text": "a.b c.d\n", "keys": "miW"} +{"name": "mi-WORD-tty", "pane": "tty", "text": "a.b c.d\n", "keys": "miW"} +{"name": "ma-word", "pane": "file", "text": "alpha beta gamma\n", "keys": "wwmaw"} +{"name": "mi-quote", "pane": "file", "text": "say \"hi there\" ok\n", "keys": "6lmi\""} +{"name": "ma-quote", "pane": "file", "text": "say \"hi there\" ok\n", "keys": "6lma\""} +{"name": "mi-para", "pane": "file", "text": "aa\nbb\n\ncc\n", "keys": "mip"} +{"name": "mi-para-tty", "pane": "tty", "text": "aa\nbb\n\ncc\n", "keys": "mip"} +{"name": "ma-para", "pane": "file", "text": "aa\nbb\n\ncc\n", "keys": "map"} +{"name": "mi-para-blank", "pane": "file", "text": "aa\n\ncc\n", "keys": "jmip"} +{"name": "mi-empty-pair", "pane": "file", "text": "a()b\n", "keys": "lmi("} +{"name": "par-fwd", "pane": "file", "text": "aa\nbb\n\ncc\ndd\n\nee\n", "keys": "]p"} +{"name": "par-fwd-tty", "pane": "tty", "text": "aa\nbb\n\ncc\ndd\n\nee\n", "keys": "]p"} +{"name": "par-fwd-count", "pane": "file", "text": "aa\nbb\n\ncc\ndd\n\nee\n", "keys": "2]p"} +{"name": "par-fwd-count-tty", "pane": "tty", "text": "aa\nbb\n\ncc\ndd\n\nee\n", "keys": "2]p"} +{"name": "par-bwd", "pane": "file", "text": "aa\nbb\n\ncc\ndd\n\nee\n", "keys": "6j[p"} +{"name": "par-bwd-tty", "pane": "tty", "text": "aa\nbb\n\ncc\ndd\n\nee\n", "keys": "6j[p"} +{"name": "par-fwd-mid", "pane": "file", "text": "aa\nbb\n\ncc\ndd\n\nee\n", "keys": "j]p"} +{"name": "par-fwd-mid-tty", "pane": "tty", "text": "aa\nbb\n\ncc\ndd\n\nee\n", "keys": "j]p"} +{"name": "par-bwd-mid", "pane": "file", "text": "aa\nbb\n\ncc\ndd\n\nee\n", "keys": "4j[p"} +{"name": "par-bwd-mid-tty", "pane": "tty", "text": "aa\nbb\n\ncc\ndd\n\nee\n", "keys": "4j[p"} +{"name": "par-fwd-at-end", "pane": "file", "text": "aa\n\nbb\n", "keys": "2j]p"} +{"name": "add-nl-below", "pane": "file", "text": "aa\nbb\n", "keys": "]<space>"} +{"name": "add-nl-above", "pane": "file", "text": "aa\nbb\n", "keys": "j[<space>"} +{"name": "add-nl-count", "pane": "file", "text": "aa\nbb\n", "keys": "2]<space>"} +{"name": "d-word", "pane": "file", "text": "alpha beta\n", "keys": "wd"} +{"name": "d-bare-char", "pane": "file", "text": "abc\n", "keys": "d"} +{"name": "d-on-nl-joins", "pane": "file", "text": "ab\ncd\n", "keys": "lld"} +{"name": "d-x-lines", "pane": "file", "text": "aaa\nbbb\nccc\n", "keys": "xd"} +{"name": "d-percent-all", "pane": "file", "text": "one\ntwo\n", "keys": "%d"} +{"name": "alt-d-noyank", "pane": "file", "text": "alpha beta\n", "keys": "w<A-d>"} +{"name": "alt-c-window-op", "pane": "file", "text": "abc def\n", "keys": "<A-c>"} +{"name": "d-then-p", "pane": "file", "text": "alpha beta\n", "keys": "wdp"} +{"name": "c-word", "pane": "file", "text": "alpha beta gamma\n", "keys": "wcX<esc>"} +{"name": "c-bare", "pane": "file", "text": "abc\n", "keys": "cZ<esc>"} +{"name": "c-linewise", "pane": "file", "text": "aaa\nbbb\n", "keys": "xcX<esc>"} +{"name": "c-linewise-indent", "pane": "file", "text": " aa\nbb\n", "keys": "xcZ<esc>"} +{"name": "y-keeps-sel", "pane": "file", "text": "alpha beta\n", "keys": "wy"} +{"name": "y-keeps-sel-tty", "pane": "tty", "text": "alpha beta\n", "keys": "wy"} +{"name": "y-bare-char", "pane": "file", "text": "abc def\n", "keys": "yp"} +{"name": "y-bare-eol", "pane": "file", "text": "ab\ncd\n", "keys": "glyp"} +{"name": "yp-word", "pane": "file", "text": "alpha beta\n", "keys": "weyp"} +{"name": "xyp-linewise", "pane": "file", "text": "one\ntwo\n", "keys": "xyp"} +{"name": "xyp-below-end-line", "pane": "file", "text": "one\ntwo\n", "keys": "xyjp"} +{"name": "xyP-linewise", "pane": "file", "text": "one\ntwo\n", "keys": "xyP"} +{"name": "vlyp-inline", "pane": "file", "text": "abcd\n", "keys": "vlyp"} +{"name": "vlyP-inline", "pane": "file", "text": "abcd\n", "keys": "vlyP"} +{"name": "p-count", "pane": "file", "text": "ab\n", "keys": "vy2p"} +{"name": "p-after-sel-end", "pane": "file", "text": "abcd\n", "keys": "vlyllp"} +{"name": "wP-before", "pane": "file", "text": "one two\n", "keys": "wyggwP"} +{"name": "u-restores-sel", "pane": "file", "text": "alpha beta\n", "keys": "wdu"} +{"name": "u-insert-session", "pane": "file", "text": "abc\n", "keys": "ixyz<esc>u"} +{"name": "U-redo", "pane": "file", "text": "alpha beta\n", "keys": "wduU"} +{"name": "u-linewise", "pane": "file", "text": "aaa\nbbb\n", "keys": "xdu"} +{"name": "r-bare", "pane": "file", "text": "abc\n", "keys": "rz"} +{"name": "r-sel-keeps", "pane": "file", "text": "abcdef\n", "keys": "vllrz"} +{"name": "r-x-replaces-nl", "pane": "file", "text": "ab\ncd\n", "keys": "xrz"} +{"name": "r-cancel-esc", "pane": "file", "text": "abc\n", "keys": "r<esc>l"} +{"name": "R-inline", "pane": "file", "text": "alpha beta\n", "keys": "wyggR"} +{"name": "R-linewise", "pane": "file", "text": "one\ntwo\n", "keys": "xyjR"} +{"name": "tilde-sel-keeps", "pane": "file", "text": "abc\n", "keys": "vll~"} +{"name": "tilde-bare", "pane": "file", "text": "aBc\n", "keys": "~"} +{"name": "backtick-lower", "pane": "file", "text": "ABC\n", "keys": "vll`"} +{"name": "alt-backtick-upper", "pane": "file", "text": "abc\n", "keys": "vll<A-`>"} +{"name": "J-cursor-stays", "pane": "file", "text": "aa\nbb\ncc\n", "keys": "J"} +{"name": "J-sel-lines", "pane": "file", "text": "aa\nbb\ncc\ndd\n", "keys": "xxJ"} +{"name": "J-ws-collapse", "pane": "file", "text": "aa\n bb\n", "keys": "J"} +{"name": "J-empty-next-nospace", "pane": "file", "text": "aa\n\nbb\n", "keys": "J"} +{"name": "J-last-line-eats-nl", "pane": "file", "text": "aa\nbb\n", "keys": "jJ"} +{"name": "J-count-ignored", "pane": "file", "text": "a\nb\nc\nd\n", "keys": "3J"} +{"name": "indent-basic", "pane": "file", "text": "foo\nbar\n", "keys": "<gt>"} +{"name": "indent-realign", "pane": "file", "text": " x\n", "keys": "gs<gt>"} +{"name": "indent-cursor-maps", "pane": "file", "text": "foo\n", "keys": "ll<gt>"} +{"name": "indent-x-sel", "pane": "file", "text": "a\n\nb\n", "keys": "x2x<gt>"} +{"name": "indent-count", "pane": "file", "text": "x\n", "keys": "2<gt>"} +{"name": "unindent-basic", "pane": "file", "text": " x\n", "keys": "gs<lt>"} +{"name": "unindent-tab", "pane": "file", "text": "\tx\n", "keys": "<lt>"} +{"name": "unindent-partial", "pane": "file", "text": " x\n", "keys": "<lt>"} +{"name": "unindent-cursor", "pane": "file", "text": " ab\n", "keys": "gl<lt>"} +{"name": "ctrl-a-sel", "pane": "file", "text": "15 x\n", "keys": "vl<C-a>"} +{"name": "ctrl-a-bare-digit", "pane": "file", "text": "7\n", "keys": "<C-a>"} +{"name": "ctrl-a-noop-nonint", "pane": "file", "text": "a 15 b\n", "keys": "f1<C-a>"} +{"name": "ctrl-a-neg-sel", "pane": "file", "text": "-3\n", "keys": "vl<C-a>"} +{"name": "ctrl-a-pad", "pane": "file", "text": "007\n", "keys": "vll<C-a>"} +{"name": "ctrl-a-count", "pane": "file", "text": "5\n", "keys": "3<C-a>"} +{"name": "ctrl-x-basic", "pane": "file", "text": "9\n", "keys": "<C-x>"} +{"name": "ms-sel", "pane": "file", "text": "hello\n", "keys": "vllms("} +{"name": "ms-bare", "pane": "file", "text": "ab\n", "keys": "ms("} +{"name": "ms-quote-self", "pane": "file", "text": "ab cd\n", "keys": "wems'"} +{"name": "md-basic", "pane": "file", "text": "a(bcd)e\n", "keys": "3lmd("} +{"name": "md-quote", "pane": "file", "text": "a 'bc' d\n", "keys": "3lmd'"} +{"name": "mr-basic", "pane": "file", "text": "a(bcd)e\n", "keys": "3lmr(["} +{"name": "mr-to-quote", "pane": "file", "text": "a 'bc' d\n", "keys": "3lmr'\""} +{"name": "o-basic", "pane": "file", "text": "ab\n", "keys": "ox<esc>"} +{"name": "o-copies-indent-level", "pane": "file", "text": " foo\n", "keys": "o"} +{"name": "o-partial-indent-drops", "pane": "file", "text": " foo\n", "keys": "o"} +{"name": "o-count", "pane": "file", "text": "ab\n", "keys": "2o<esc>"} +{"name": "O-basic", "pane": "file", "text": "aa\nbb\n", "keys": "jOx<esc>"} +{"name": "O-copies-indent", "pane": "file", "text": " foo\n", "keys": "O"} +{"name": "i-type-esc", "pane": "file", "text": "alpha\n", "keys": "ihello <esc>"} +{"name": "i-keeps-sel-start", "pane": "file", "text": "alpha beta\n", "keys": "wi"} +{"name": "wa-sel-end", "pane": "file", "text": "alpha beta\n", "keys": "wa"} +{"name": "wiX-edit-drops-sel", "pane": "file", "text": "alpha beta\n", "keys": "wiX<esc>"} +{"name": "a-esc-restore", "pane": "file", "text": "abc\n", "keys": "a<esc>"} +{"name": "ax-restore", "pane": "file", "text": "abc\n", "keys": "ax<esc>"} +{"name": "lax-restore", "pane": "file", "text": "abc\n", "keys": "lax<esc>"} +{"name": "A-eol", "pane": "file", "text": "abc\ndef\n", "keys": "A<esc>"} +{"name": "A-type", "pane": "file", "text": "one two\n", "keys": "AX<esc>"} +{"name": "I-firstnonws", "pane": "file", "text": " abc\n", "keys": "llI"} +{"name": "esc-pending-cancel", "pane": "file", "text": "abc\n", "keys": "f<esc>l"} +{"name": "ins-enter-mid", "pane": "file", "text": "ab\n", "keys": "a<ret><esc>"} +{"name": "ins-enter-indent", "pane": "file", "text": " foo\n", "keys": "A<ret>x<esc>"} +{"name": "ins-backspace", "pane": "file", "text": "abc\n", "keys": "lli<backspace><esc>"} +{"name": "ins-backspace-join", "pane": "file", "text": "ab\ncd\n", "keys": "ji<backspace><esc>"} +{"name": "ins-ctrl-w", "pane": "file", "text": "one two\n", "keys": "A<C-w><esc>"} +{"name": "ins-ctrl-w-col0-join", "pane": "file", "text": "ab\ncd\n", "keys": "ji<C-w><esc>"} +{"name": "ins-alt-bs", "pane": "file", "text": "one two\n", "keys": "A<A-backspace><esc>"} +{"name": "ins-alt-d", "pane": "file", "text": "one two\n", "keys": "i<A-d><esc>"} +{"name": "ins-alt-del", "pane": "file", "text": "one two\n", "keys": "i<A-del><esc>"} +{"name": "ins-ctrl-u", "pane": "file", "text": "one two\n", "keys": "A<C-u><esc>"} +{"name": "ins-ctrl-k", "pane": "file", "text": "one two\n", "keys": "wi<C-k><esc>"} +{"name": "ins-ctrl-h", "pane": "file", "text": "abc\n", "keys": "lli<C-h><esc>"} +{"name": "ins-ctrl-d", "pane": "file", "text": "abc\n", "keys": "i<C-d><esc>"} +{"name": "ins-del-eol-join", "pane": "file", "text": "ab\ncd\n", "keys": "gla<del><esc>"} +{"name": "ins-ctrl-j", "pane": "file", "text": "ab\n", "keys": "a<C-j><esc>"} +{"name": "ins-home", "pane": "file", "text": " abc\n", "keys": "gli<home>x<esc>"} +{"name": "ins-end", "pane": "file", "text": " abc\n", "keys": "i<end>x<esc>"} +{"name": "ins-pgdn", "pane": "file", "text": "l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n", "keys": "i<pagedown><esc>"} +{"name": "ins-arrows", "pane": "file", "text": "abc\ndef\n", "keys": "i<down><right>x<esc>"} +{"name": "ins-tab-col0", "pane": "file", "text": "ab\n", "keys": "i<tab><esc>"} +{"name": "ins-tab-mid", "pane": "file", "text": "ab\n", "keys": "li<tab><esc>"} diff --git a/test/hxcases/goldens.jsonl b/test/hxcases/goldens.jsonl new file mode 100644 index 00000000..baa45d34 --- /dev/null +++ b/test/hxcases/goldens.jsonl @@ -0,0 +1,360 @@ +{"name":"h-basic","text":"abc def\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"h-basic-tty","text":"abc def\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"h-crosses-nl","text":"ab\ncd\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}} +{"name":"h-crosses-nl-tty","text":"ab\ncd\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}} +{"name":"l-basic","text":"abc\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"l-basic-tty","text":"abc\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"l-crosses-nl","text":"ab\ncd\n","mode":"normal","cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}} +{"name":"l-crosses-nl-tty","text":"ab\ncd\n","mode":"normal","cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}} +{"name":"l-count","text":"abcdef\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3}} +{"name":"l-count-tty","text":"abcdef\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3}} +{"name":"h-count","text":"abcdef\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}} +{"name":"h-count-tty","text":"abcdef\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}} +{"name":"l-clamp-eof","text":"ab\n","mode":"normal","cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}} +{"name":"j-basic","text":"aa\nbb\ncc\n","mode":"normal","cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}} +{"name":"j-basic-tty","text":"aa\nbb\ncc\n","mode":"normal","cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}} +{"name":"j-onto-nl-cell","text":"abcdef\nab\nabcdef\n","mode":"normal","cursor":{"row":1,"col":2},"anchor":{"row":1,"col":2}} +{"name":"j-onto-nl-cell-tty","text":"abcdef\nab\nabcdef\n","mode":"normal","cursor":{"row":1,"col":2},"anchor":{"row":1,"col":2}} +{"name":"j-sticky-col","text":"abcdef\nab\nabcdef\n","mode":"normal","cursor":{"row":2,"col":5},"anchor":{"row":2,"col":5}} +{"name":"j-sticky-col-tty","text":"abcdef\nab\nabcdef\n","mode":"normal","cursor":{"row":2,"col":5},"anchor":{"row":2,"col":5}} +{"name":"j-phantom","text":"one\ntwo\n","mode":"normal","cursor":{"row":2,"col":0},"anchor":{"row":2,"col":0}} +{"name":"k-basic","text":"aa\nbb\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"k-basic-tty","text":"aa\nbb\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"k-sticky-col","text":"abcdef\nab\nabcdef\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":5}} +{"name":"k-sticky-col-tty","text":"abcdef\nab\nabcdef\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":5}} +{"name":"j-count","text":"a\nb\nc\nd\n","mode":"normal","cursor":{"row":2,"col":0},"anchor":{"row":2,"col":0}} +{"name":"j-count-tty","text":"a\nb\nc\nd\n","mode":"normal","cursor":{"row":2,"col":0},"anchor":{"row":2,"col":0}} +{"name":"arrow-right-down","text":"abc\ndef\n","mode":"normal","cursor":{"row":1,"col":1},"anchor":{"row":1,"col":1}} +{"name":"arrow-right-down-tty","text":"abc\ndef\n","mode":"normal","cursor":{"row":1,"col":1},"anchor":{"row":1,"col":1}} +{"name":"arrow-left-up","text":"abc\ndef\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"arrow-left-up-tty","text":"abc\ndef\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"w-basic","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"w-basic-tty","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"w-punct","text":"foo.bar baz\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} +{"name":"w-punct-tty","text":"foo.bar baz\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} +{"name":"w-punct-run","text":"foo.bar baz\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3}} +{"name":"w-punct-run-tty","text":"foo.bar baz\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3}} +{"name":"w-count","text":"one two three four\n","mode":"normal","cursor":{"row":0,"col":7},"anchor":{"row":0,"col":4}} +{"name":"w-count-tty","text":"one two three four\n","mode":"normal","cursor":{"row":0,"col":7},"anchor":{"row":0,"col":4}} +{"name":"w-eol-cross","text":"ab cd\nef\n","mode":"normal","cursor":{"row":1,"col":1},"anchor":{"row":1,"col":0}} +{"name":"w-eol-cross-tty","text":"ab cd\nef\n","mode":"normal","cursor":{"row":1,"col":1},"anchor":{"row":1,"col":0}} +{"name":"w-from-empty-line","text":"\nabc\n","mode":"normal","cursor":{"row":1,"col":2},"anchor":{"row":1,"col":0}} +{"name":"w-skips-blank","text":"aa\n\nbb\n","mode":"normal","cursor":{"row":2,"col":1},"anchor":{"row":2,"col":0}} +{"name":"w-skips-blank-tty","text":"aa\n\nbb\n","mode":"normal","cursor":{"row":2,"col":1},"anchor":{"row":2,"col":0}} +{"name":"w-eof-collapse","text":"alpha\n","mode":"normal","cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}} +{"name":"b-basic","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":9}} +{"name":"b-basic-tty","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":9}} +{"name":"b-bof-noop","text":"alpha\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"b-bof-noop-tty","text":"alpha\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"b-from-nl-cell","text":"ab\ncd\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":1}} +{"name":"b-from-nl-cell-tty","text":"ab\ncd\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":1}} +{"name":"b-count","text":"a bb ccc dddd\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":8}} +{"name":"b-count-tty","text":"a bb ccc dddd\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":8}} +{"name":"e-basic","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":0}} +{"name":"e-basic-tty","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":0}} +{"name":"e-from-mid","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":1}} +{"name":"e-from-mid-tty","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":1}} +{"name":"e-count","text":"a bb ccc dddd\n","mode":"normal","cursor":{"row":0,"col":7},"anchor":{"row":0,"col":4}} +{"name":"e-count-tty","text":"a bb ccc dddd\n","mode":"normal","cursor":{"row":0,"col":7},"anchor":{"row":0,"col":4}} +{"name":"e-cross-blank","text":"aa\n\nbb\n","mode":"normal","cursor":{"row":2,"col":1},"anchor":{"row":2,"col":0}} +{"name":"e-cross-blank-tty","text":"aa\n\nbb\n","mode":"normal","cursor":{"row":2,"col":1},"anchor":{"row":2,"col":0}} +{"name":"W-basic","text":"foo.bar baz\n","mode":"normal","cursor":{"row":0,"col":7},"anchor":{"row":0,"col":0}} +{"name":"W-basic-tty","text":"foo.bar baz\n","mode":"normal","cursor":{"row":0,"col":7},"anchor":{"row":0,"col":0}} +{"name":"B-basic","text":"foo.bar baz\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":7}} +{"name":"B-basic-tty","text":"foo.bar baz\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":7}} +{"name":"E-basic","text":"foo.bar baz\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":0}} +{"name":"E-basic-tty","text":"foo.bar baz\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":0}} +{"name":"f-basic","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} +{"name":"f-basic-tty","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} +{"name":"f-count","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"f-count-tty","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"f-cross-line","text":"one\ntwo\n","mode":"normal","cursor":{"row":1,"col":1},"anchor":{"row":0,"col":0}} +{"name":"f-cross-line-tty","text":"one\ntwo\n","mode":"normal","cursor":{"row":1,"col":1},"anchor":{"row":0,"col":0}} +{"name":"f-notfound-noop","text":"abc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"f-notfound-noop-tty","text":"abc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"f-digit-arg","text":"a4b\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":0}} +{"name":"f-digit-arg-tty","text":"a4b\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":0}} +{"name":"f-repeat-same-target","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":0}} +{"name":"t-basic","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":0}} +{"name":"t-basic-tty","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":0}} +{"name":"t-twice-skips-edge","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":1}} +{"name":"t-twice-skips-edge-tty","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":1}} +{"name":"F-backward","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":5}} +{"name":"F-backward-tty","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":5}} +{"name":"T-backward","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":5}} +{"name":"T-backward-tty","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":5}} +{"name":"alt-dot-repeat-f","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":2}} +{"name":"alt-dot-repeat-f-tty","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":2}} +{"name":"alt-dot-repeat-t","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":1}} +{"name":"alt-dot-repeat-t-tty","text":"abcabc\n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":1}} +{"name":"alt-dot-count","text":"axbxcxd\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":3}} +{"name":"alt-dot-count-tty","text":"axbxcxd\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":3}} +{"name":"G-count","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":4,"col":0},"anchor":{"row":4,"col":0}} +{"name":"G-count-tty","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":4,"col":0},"anchor":{"row":4,"col":0}} +{"name":"G-count-clamp","text":"one\ntwo\n","mode":"normal","cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}} +{"name":"G-count-clamp-tty","text":"one\ntwo\n","mode":"normal","cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}} +{"name":"G-bare-noop","text":"aa\nbb\ncc\n","mode":"normal","cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}} +{"name":"G-bare-noop-tty","text":"aa\nbb\ncc\n","mode":"normal","cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}} +{"name":"count-multidigit","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":10,"col":0},"anchor":{"row":10,"col":0}} +{"name":"count-multidigit-tty","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":10,"col":0},"anchor":{"row":10,"col":0}} +{"name":"G-count-resets-col","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":4,"col":0},"anchor":{"row":4,"col":0}} +{"name":"G-count-resets-col-tty","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":4,"col":0},"anchor":{"row":4,"col":0}} +{"name":"gg-basic","text":"aa\nbb\ncc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"gg-basic-tty","text":"aa\nbb\ncc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"gg-count","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":2,"col":0},"anchor":{"row":2,"col":0}} +{"name":"gg-count-tty","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":2,"col":0},"anchor":{"row":2,"col":0}} +{"name":"ge-basic","text":"aa\nbb\ncc\n","mode":"normal","cursor":{"row":2,"col":0},"anchor":{"row":2,"col":0}} +{"name":"ge-basic-tty","text":"aa\nbb\ncc\n","mode":"normal","cursor":{"row":2,"col":0},"anchor":{"row":2,"col":0}} +{"name":"ge-col0","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"ge-col0-tty","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"gh-basic","text":"abc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"gh-basic-tty","text":"abc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"gl-basic","text":"abc def\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":6}} +{"name":"gl-basic-tty","text":"abc def\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":6}} +{"name":"gl-empty-line","text":"\nabc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"gl-empty-line-tty","text":"\nabc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"gs-basic","text":" abc\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}} +{"name":"gs-basic-tty","text":" abc\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}} +{"name":"gs-allws-noop","text":" \nx\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"gs-allws-noop-tty","text":" \nx\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"gbar-count","text":"abcdef\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3}} +{"name":"gbar-count-tty","text":"abcdef\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3}} +{"name":"gbar-clamp","text":"ab\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}} +{"name":"gbar-clamp-tty","text":"ab\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}} +{"name":"gbar-nocount","text":"abcdef\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"gbar-nocount-tty","text":"abcdef\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"gj-basic","text":"abcdef\nab\nabcdef\n","mode":"normal","cursor":{"row":2,"col":5},"anchor":{"row":2,"col":5}} +{"name":"gj-basic-tty","text":"abcdef\nab\nabcdef\n","mode":"normal","cursor":{"row":2,"col":5},"anchor":{"row":2,"col":5}} +{"name":"gk-basic","text":"aa\nbb\ncc\n","mode":"normal","cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}} +{"name":"gk-basic-tty","text":"aa\nbb\ncc\n","mode":"normal","cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}} +{"name":"home-basic","text":"abc def\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"home-basic-tty","text":"abc def\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"end-basic","text":"abc def\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":6}} +{"name":"end-basic-tty","text":"abc def\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":6}} +{"name":"end-empty-line","text":"\nabc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"end-empty-line-tty","text":"\nabc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"gt-noscroll","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":3,"col":0},"anchor":{"row":3,"col":0}} +{"name":"gt-noscroll-tty","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":3,"col":0},"anchor":{"row":3,"col":0}} +{"name":"gc-noscroll","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":6,"col":0},"anchor":{"row":6,"col":0}} +{"name":"gb-noscroll","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":9,"col":0},"anchor":{"row":9,"col":0}} +{"name":"gt-after-zz","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":8,"col":0},"anchor":{"row":8,"col":0}} +{"name":"gc-after-zz","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":15,"col":0},"anchor":{"row":15,"col":0}} +{"name":"gb-after-zz","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":23,"col":0},"anchor":{"row":23,"col":0}} +{"name":"gt-count","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":9,"col":0},"anchor":{"row":9,"col":0}} +{"name":"ctrl-d-basic","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":11,"col":0},"anchor":{"row":11,"col":0}} +{"name":"ctrl-d-small","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":11,"col":0},"anchor":{"row":11,"col":0}} +{"name":"ctrl-d-sticky","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":12,"col":1},"anchor":{"row":12,"col":1}} +{"name":"ctrl-u-back","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":9,"col":0},"anchor":{"row":9,"col":0}} +{"name":"ctrl-f-page","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":25,"col":0},"anchor":{"row":25,"col":0}} +{"name":"ctrl-f-small","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":12,"col":0},"anchor":{"row":12,"col":0}} +{"name":"ctrl-b-page","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":18,"col":0},"anchor":{"row":18,"col":0}} +{"name":"pgdn-basic","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":25,"col":0},"anchor":{"row":25,"col":0}} +{"name":"pgup-basic","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":18,"col":0},"anchor":{"row":18,"col":0}} +{"name":"pgup-noop-in-view","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":5,"col":0},"anchor":{"row":5,"col":0}} +{"name":"pgup-noop-in-view-tty","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\n","mode":"normal","cursor":{"row":5,"col":0},"anchor":{"row":5,"col":0}} +{"name":"v-ctrl-d-extends","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"select","cursor":{"row":11,"col":0},"anchor":{"row":0,"col":0}} +{"name":"zt-then-gt","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":12,"col":0},"anchor":{"row":12,"col":0}} +{"name":"zz-then-gt","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":8,"col":0},"anchor":{"row":8,"col":0}} +{"name":"zb-then-gt","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":3,"col":0},"anchor":{"row":3,"col":0}} +{"name":"zc-alias-zz","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":8,"col":0},"anchor":{"row":8,"col":0}} +{"name":"zj-snaps-cursor","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":4,"col":0},"anchor":{"row":4,"col":0}} +{"name":"zj-noop-in-band","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":10,"col":0},"anchor":{"row":10,"col":0}} +{"name":"zk-bottom-snap","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":19,"col":0},"anchor":{"row":19,"col":0}} +{"name":"z-ctrl-d-alias","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":11,"col":0},"anchor":{"row":11,"col":0}} +{"name":"z-pgdn-alias","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":25,"col":0},"anchor":{"row":25,"col":0}} +{"name":"v-reports-select","text":"alpha beta\n","mode":"select","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"v-reports-select-tty","text":"alpha beta\n","mode":"select","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"v-extend-w","text":"alpha beta gamma\n","mode":"select","cursor":{"row":0,"col":10},"anchor":{"row":0,"col":0}} +{"name":"v-extend-w-tty","text":"alpha beta gamma\n","mode":"select","cursor":{"row":0,"col":10},"anchor":{"row":0,"col":0}} +{"name":"v-anchor-fixed-crossing","text":"abcdef\n","mode":"select","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":2}} +{"name":"v-anchor-fixed-crossing-tty","text":"abcdef\n","mode":"select","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":2}} +{"name":"v-exit-keeps-sel","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"v-exit-keeps-sel-tty","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"v-esc-keeps-sel","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"v-esc-keeps-sel-tty","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"v-gl-extends","text":"abc def\n","mode":"select","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":0}} +{"name":"v-gl-extends-tty","text":"abc def\n","mode":"select","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":0}} +{"name":"v-gg-extends","text":"aa\nbb\ncc\n","mode":"select","cursor":{"row":0,"col":0},"anchor":{"row":2,"col":0}} +{"name":"v-gg-extends-tty","text":"aa\nbb\ncc\n","mode":"select","cursor":{"row":0,"col":0},"anchor":{"row":2,"col":0}} +{"name":"v-find-extends","text":"abcabc\n","mode":"select","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"v-find-extends-tty","text":"abcabc\n","mode":"select","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"v-x-extends-line","text":"ab\ncd\nef\n","mode":"select","cursor":{"row":1,"col":2},"anchor":{"row":0,"col":0}} +{"name":"v-x-extends-line-tty","text":"ab\ncd\nef\n","mode":"select","cursor":{"row":1,"col":2},"anchor":{"row":0,"col":0}} +{"name":"v-j-phantom-blocked","text":"one\ntwo\n","mode":"select","cursor":{"row":1,"col":0},"anchor":{"row":0,"col":0}} +{"name":"w-esc-keeps-sel","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"w-esc-keeps-sel-tty","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"semi-collapse","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":5}} +{"name":"semi-collapse-tty","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":5}} +{"name":"altsemi-flip","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":5}} +{"name":"altsemi-flip-tty","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":5}} +{"name":"altsemi-flip-x","text":"one\ntwo\ncc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":3}} +{"name":"altsemi-flip-x-tty","text":"one\ntwo\ncc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":3}} +{"name":"percent-select-all","text":"one\ntwo\n","mode":"normal","cursor":{"row":1,"col":3},"anchor":{"row":0,"col":0}} +{"name":"percent-then-d","text":"","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"x-selects-line","text":"one\ntwo\nthree\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":0}} +{"name":"x-selects-line-tty","text":"one\ntwo\nthree\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":0}} +{"name":"x-extends","text":"one\ntwo\nthree\n","mode":"normal","cursor":{"row":1,"col":3},"anchor":{"row":0,"col":0}} +{"name":"x-extends-tty","text":"one\ntwo\nthree\n","mode":"normal","cursor":{"row":1,"col":3},"anchor":{"row":0,"col":0}} +{"name":"x-count","text":"a\nb\nc\nd\n","mode":"normal","cursor":{"row":1,"col":1},"anchor":{"row":0,"col":0}} +{"name":"x-count-tty","text":"a\nb\nc\nd\n","mode":"normal","cursor":{"row":1,"col":1},"anchor":{"row":0,"col":0}} +{"name":"x-empty-line","text":"a\n\nb\nc\n","mode":"normal","cursor":{"row":2,"col":1},"anchor":{"row":1,"col":0}} +{"name":"x-empty-line-tty","text":"a\n\nb\nc\n","mode":"normal","cursor":{"row":2,"col":1},"anchor":{"row":1,"col":0}} +{"name":"x-last-line","text":"one\ntwo\n","mode":"normal","cursor":{"row":1,"col":3},"anchor":{"row":1,"col":0}} +{"name":"x-then-w-drops","text":"aa\nbb cc\n","mode":"normal","cursor":{"row":1,"col":2},"anchor":{"row":1,"col":0}} +{"name":"x-then-w-drops-tty","text":"aa\nbb cc\n","mode":"normal","cursor":{"row":1,"col":2},"anchor":{"row":1,"col":0}} +{"name":"x-then-d","text":"two\nthree\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"X-bare","text":"abc\ndef\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":0}} +{"name":"X-bare-tty","text":"abc\ndef\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":0}} +{"name":"X-from-v","text":"abc\ndef\nghi\n","mode":"select","cursor":{"row":1,"col":3},"anchor":{"row":0,"col":0}} +{"name":"X-from-v-tty","text":"abc\ndef\nghi\n","mode":"select","cursor":{"row":1,"col":3},"anchor":{"row":0,"col":0}} +{"name":"X-keeps-direction","text":"abc\ndef\nghi\n","mode":"select","cursor":{"row":0,"col":0},"anchor":{"row":1,"col":3}} +{"name":"X-keeps-direction-tty","text":"abc\ndef\nghi\n","mode":"select","cursor":{"row":0,"col":0},"anchor":{"row":1,"col":3}} +{"name":"X-noop-when-full","text":"abc\ndef\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":0}} +{"name":"altx-shrink","text":"abc\ndef\nghi\n","mode":"select","cursor":{"row":1,"col":3},"anchor":{"row":1,"col":0}} +{"name":"altx-shrink-tty","text":"abc\ndef\nghi\n","mode":"select","cursor":{"row":1,"col":3},"anchor":{"row":1,"col":0}} +{"name":"altx-single-line-noop","text":"abcdef\n","mode":"select","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":1}} +{"name":"altx-single-line-noop-tty","text":"abcdef\n","mode":"select","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":1}} +{"name":"mm-basic","text":"a(bc(d)e)f\n","mode":"normal","cursor":{"row":0,"col":8},"anchor":{"row":0,"col":8}} +{"name":"mm-basic-tty","text":"a(bc(d)e)f\n","mode":"normal","cursor":{"row":0,"col":8},"anchor":{"row":0,"col":8}} +{"name":"mm-back","text":"a(bc(d)e)f\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"mm-back-tty","text":"a(bc(d)e)f\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"mm-nonbracket-noop","text":"abc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"mm-nonbracket-noop-tty","text":"abc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"mi-paren","text":"fn(a, b)\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":3}} +{"name":"mi-paren-tty","text":"fn(a, b)\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":3}} +{"name":"ma-paren","text":"fn(a, b)\n","mode":"normal","cursor":{"row":0,"col":7},"anchor":{"row":0,"col":2}} +{"name":"ma-paren-tty","text":"fn(a, b)\n","mode":"normal","cursor":{"row":0,"col":7},"anchor":{"row":0,"col":2}} +{"name":"mi-nested","text":"(a(b)c)\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3}} +{"name":"mi-nested-tty","text":"(a(b)c)\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3}} +{"name":"mi-word","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":9},"anchor":{"row":0,"col":6}} +{"name":"mi-word-tty","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":9},"anchor":{"row":0,"col":6}} +{"name":"mi-WORD","text":"a.b c.d\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} +{"name":"mi-WORD-tty","text":"a.b c.d\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} +{"name":"ma-word","text":"alpha beta gamma\n","mode":"normal","cursor":{"row":0,"col":10},"anchor":{"row":0,"col":10}} +{"name":"mi-quote","text":"say \"hi there\" ok\n","mode":"normal","cursor":{"row":0,"col":12},"anchor":{"row":0,"col":5}} +{"name":"ma-quote","text":"say \"hi there\" ok\n","mode":"normal","cursor":{"row":0,"col":13},"anchor":{"row":0,"col":4}} +{"name":"mi-para","text":"aa\nbb\n\ncc\n","mode":"normal","cursor":{"row":1,"col":2},"anchor":{"row":0,"col":0}} +{"name":"mi-para-tty","text":"aa\nbb\n\ncc\n","mode":"normal","cursor":{"row":1,"col":2},"anchor":{"row":0,"col":0}} +{"name":"ma-para","text":"aa\nbb\n\ncc\n","mode":"normal","cursor":{"row":2,"col":0},"anchor":{"row":0,"col":0}} +{"name":"mi-para-blank","text":"aa\n\ncc\n","mode":"normal","cursor":{"row":2,"col":2},"anchor":{"row":2,"col":0}} +{"name":"mi-empty-pair","text":"a()b\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}} +{"name":"par-fwd","text":"aa\nbb\n\ncc\ndd\n\nee\n","mode":"normal","cursor":{"row":2,"col":0},"anchor":{"row":0,"col":0}} +{"name":"par-fwd-tty","text":"aa\nbb\n\ncc\ndd\n\nee\n","mode":"normal","cursor":{"row":2,"col":0},"anchor":{"row":0,"col":0}} +{"name":"par-fwd-count","text":"aa\nbb\n\ncc\ndd\n\nee\n","mode":"normal","cursor":{"row":5,"col":0},"anchor":{"row":0,"col":0}} +{"name":"par-fwd-count-tty","text":"aa\nbb\n\ncc\ndd\n\nee\n","mode":"normal","cursor":{"row":5,"col":0},"anchor":{"row":0,"col":0}} +{"name":"par-bwd","text":"aa\nbb\n\ncc\ndd\n\nee\n","mode":"normal","cursor":{"row":3,"col":0},"anchor":{"row":5,"col":0}} +{"name":"par-bwd-tty","text":"aa\nbb\n\ncc\ndd\n\nee\n","mode":"normal","cursor":{"row":3,"col":0},"anchor":{"row":5,"col":0}} +{"name":"par-fwd-mid","text":"aa\nbb\n\ncc\ndd\n\nee\n","mode":"normal","cursor":{"row":2,"col":0},"anchor":{"row":1,"col":0}} +{"name":"par-fwd-mid-tty","text":"aa\nbb\n\ncc\ndd\n\nee\n","mode":"normal","cursor":{"row":2,"col":0},"anchor":{"row":1,"col":0}} +{"name":"par-bwd-mid","text":"aa\nbb\n\ncc\ndd\n\nee\n","mode":"normal","cursor":{"row":3,"col":0},"anchor":{"row":4,"col":0}} +{"name":"par-bwd-mid-tty","text":"aa\nbb\n\ncc\ndd\n\nee\n","mode":"normal","cursor":{"row":3,"col":0},"anchor":{"row":4,"col":0}} +{"name":"par-fwd-at-end","text":"aa\n\nbb\n","mode":"normal","cursor":{"row":2,"col":2},"anchor":{"row":2,"col":0}} +{"name":"add-nl-below","text":"aa\n\nbb\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"add-nl-above","text":"aa\n\nbb\n","mode":"normal","cursor":{"row":2,"col":0},"anchor":{"row":2,"col":0}} +{"name":"add-nl-count","text":"aa\n\n\nbb\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"d-word","text":"beta\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"d-bare-char","text":"bc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"d-on-nl-joins","text":"abcd\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}} +{"name":"d-x-lines","text":"bbb\nccc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"d-percent-all","text":"","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"alt-d-noyank","text":"beta\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"alt-c-window-op","text":"bc def\n","mode":"insert","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"d-then-p","text":"balpha eta\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":1}} +{"name":"c-word","text":"Xbeta gamma\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"c-bare","text":"Zbc\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"c-linewise","text":"X\nbbb\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"c-linewise-indent","text":"Z\nbb\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"y-keeps-sel","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"y-keeps-sel-tty","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"y-bare-char","text":"aabc def\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"y-bare-eol","text":"abb\ncd\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}} +{"name":"yp-word","text":"alpha beta beta\n","mode":"normal","cursor":{"row":0,"col":14},"anchor":{"row":0,"col":10}} +{"name":"xyp-linewise","text":"one\none\ntwo\n","mode":"normal","cursor":{"row":1,"col":3},"anchor":{"row":1,"col":0}} +{"name":"xyp-below-end-line","text":"one\ntwo\none\n","mode":"normal","cursor":{"row":2,"col":3},"anchor":{"row":2,"col":0}} +{"name":"xyP-linewise","text":"one\none\ntwo\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":0}} +{"name":"vlyp-inline","text":"ababcd\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":2}} +{"name":"vlyP-inline","text":"ababcd\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":0}} +{"name":"p-count","text":"aaab\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":1}} +{"name":"p-after-sel-end","text":"abcdab\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":4}} +{"name":"wP-before","text":"one one two\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":0}} +{"name":"u-restores-sel","text":"alpha beta\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"u-insert-session","text":"abc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"U-redo","text":"beta\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"u-linewise","text":"aaa\nbbb\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":0}} +{"name":"r-bare","text":"zbc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"r-sel-keeps","text":"zzzdef\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} +{"name":"r-x-replaces-nl","text":"zzzcd\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} +{"name":"r-cancel-esc","text":"abc\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"R-inline","text":"alpha lpha beta\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"R-linewise","text":"one\ntwoone\n","mode":"normal","cursor":{"row":1,"col":6},"anchor":{"row":1,"col":3}} +{"name":"tilde-sel-keeps","text":"ABC\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} +{"name":"tilde-bare","text":"ABc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"backtick-lower","text":"abc\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} +{"name":"alt-backtick-upper","text":"ABC\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} +{"name":"J-cursor-stays","text":"aa bb\ncc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"J-sel-lines","text":"aa bb\ncc\ndd\n","mode":"normal","cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +{"name":"J-ws-collapse","text":"aa bb\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"J-empty-next-nospace","text":"aa\nbb\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"J-last-line-eats-nl","text":"aa\nbb","mode":"normal","cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}} +{"name":"J-count-ignored","text":"a b\nc\nd\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"indent-basic","text":" foo\nbar\n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":4}} +{"name":"indent-realign","text":" x\n","mode":"normal","cursor":{"row":0,"col":8},"anchor":{"row":0,"col":8}} +{"name":"indent-cursor-maps","text":" foo\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":6}} +{"name":"indent-x-sel","text":" a\n\n b\n","mode":"normal","cursor":{"row":2,"col":5},"anchor":{"row":0,"col":4}} +{"name":"indent-count","text":" x\n","mode":"normal","cursor":{"row":0,"col":8},"anchor":{"row":0,"col":8}} +{"name":"unindent-basic","text":" x\n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":4}} +{"name":"unindent-tab","text":"x\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"unindent-partial","text":"x\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"unindent-cursor","text":"ab\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"ctrl-a-sel","text":"16 x\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":0}} +{"name":"ctrl-a-bare-digit","text":"8\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"ctrl-a-noop-nonint","text":"a 15 b\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} +{"name":"ctrl-a-neg-sel","text":"-2\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":0}} +{"name":"ctrl-a-pad","text":"008\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} +{"name":"ctrl-a-count","text":"8\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"ctrl-x-basic","text":"8\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"ms-sel","text":"(hel)lo\n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":0}} +{"name":"ms-bare","text":"(a)b\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":0}} +{"name":"ms-quote-self","text":"ab' cd'\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":2}} +{"name":"md-basic","text":"abcde\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}} +{"name":"md-quote","text":"a bc d\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}} +{"name":"mr-basic","text":"a[bcd]e\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3}} +{"name":"mr-to-quote","text":"a \"bc\" d\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3}} +{"name":"o-basic","text":"ab\nx\n","mode":"normal","cursor":{"row":1,"col":1},"anchor":{"row":1,"col":1}} +{"name":"o-copies-indent-level","text":" foo\n \n","mode":"insert","cursor":{"row":1,"col":4},"anchor":{"row":1,"col":4}} +{"name":"o-partial-indent-drops","text":" foo\n\n","mode":"insert","cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}} +{"name":"o-count","text":"ab\n\n\n","mode":"normal","cursor":{"row":1,"col":0},"anchor":{"row":1,"col":0}} +{"name":"O-basic","text":"aa\nx\nbb\n","mode":"normal","cursor":{"row":1,"col":1},"anchor":{"row":1,"col":1}} +{"name":"O-copies-indent","text":" \n foo\n","mode":"insert","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":4}} +{"name":"i-type-esc","text":"hello alpha\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":6}} +{"name":"i-keeps-sel-start","text":"alpha beta\n","mode":"insert","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":5}} +{"name":"wa-sel-end","text":"alpha beta\n","mode":"insert","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":0}} +{"name":"wiX-edit-drops-sel","text":"Xalpha beta\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":6}} +{"name":"a-esc-restore","text":"abc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"ax-restore","text":"axbc\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":0}} +{"name":"lax-restore","text":"abxc\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":1}} +{"name":"A-eol","text":"abc\ndef\n","mode":"normal","cursor":{"row":0,"col":3},"anchor":{"row":0,"col":3}} +{"name":"A-type","text":"one twoX\n","mode":"normal","cursor":{"row":0,"col":8},"anchor":{"row":0,"col":8}} +{"name":"I-firstnonws","text":" abc\n","mode":"insert","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}} +{"name":"esc-pending-cancel","text":"abc\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"ins-enter-mid","text":"a\nb\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":0}} +{"name":"ins-enter-indent","text":" foo\n x\n","mode":"normal","cursor":{"row":1,"col":5},"anchor":{"row":1,"col":5}} +{"name":"ins-backspace","text":"ac\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"ins-backspace-join","text":"abcd\n","mode":"normal","cursor":{"row":0,"col":2},"anchor":{"row":0,"col":2}} +{"name":"ins-ctrl-w","text":"one \n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":4}} +{"name":"ins-ctrl-w-col0-join","text":"cd\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"ins-alt-bs","text":"one \n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":4}} +{"name":"ins-alt-d","text":" two\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"ins-alt-del","text":" two\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"ins-ctrl-u","text":"\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"ins-ctrl-k","text":"\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"ins-ctrl-h","text":"ac\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"ins-ctrl-d","text":"bc\n","mode":"normal","cursor":{"row":0,"col":0},"anchor":{"row":0,"col":0}} +{"name":"ins-del-eol-join","text":"abcd\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"ins-ctrl-j","text":"a\nb\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":0}} +{"name":"ins-home","text":"x abc\n","mode":"normal","cursor":{"row":0,"col":1},"anchor":{"row":0,"col":1}} +{"name":"ins-end","text":" abcx\n","mode":"normal","cursor":{"row":0,"col":6},"anchor":{"row":0,"col":6}} +{"name":"ins-pgdn","text":"l00\nl01\nl02\nl03\nl04\nl05\nl06\nl07\nl08\nl09\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\n","mode":"normal","cursor":{"row":25,"col":0},"anchor":{"row":25,"col":0}} +{"name":"ins-arrows","text":"abc\ndxef\n","mode":"normal","cursor":{"row":1,"col":2},"anchor":{"row":1,"col":2}} +{"name":"ins-tab-col0","text":" ab\n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":4}} +{"name":"ins-tab-mid","text":"a b\n","mode":"normal","cursor":{"row":0,"col":4},"anchor":{"row":0,"col":4}} diff --git a/test/hxcases/regen.sh b/test/hxcases/regen.sh new file mode 100755 index 00000000..308cc9d2 --- /dev/null +++ b/test/hxcases/regen.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# Regenerate test/hxcases/goldens.jsonl by running the helix reference harness +# over cases.jsonl. The harness is hx-harness on the pardes-harness branch of +# the genizah helix checkout (see docs/helix-keys.md, "Differential testing"): +# cd ~/05-genizah/helix && git switch pardes-harness && \ +# cargo build --release -p helix-term --features helix-term/integration --bin hx-harness +# Override the binary with $HX_HARNESS. helix ignores pane:"tty" — a tty +# twin's golden is helix on the same text, which IS the oracle for tty +# navigation parity. +set -eu +cd "$(dirname "$0")" +HX_HARNESS="${HX_HARNESS:-$HOME/05-genizah/helix/target/release/hx-harness}" +[ -x "$HX_HARNESS" ] || { echo "regen.sh: no hx-harness at $HX_HARNESS (set \$HX_HARNESS)" >&2; exit 1; } +"$HX_HARNESS" cases.jsonl > goldens.jsonl.tmp +mv goldens.jsonl.tmp goldens.jsonl +wc -l goldens.jsonl diff --git a/test/hxcases/smoke.jsonl b/test/hxcases/smoke.jsonl new file mode 100644 index 00000000..0c25adda --- /dev/null +++ b/test/hxcases/smoke.jsonl @@ -0,0 +1,20 @@ +{"name":"w-basic","pane":"file","text":"alpha beta\n","keys":"w"} +{"name":"w-then-b","pane":"file","text":"alpha beta\n","keys":"wb"} +{"name":"e-basic","pane":"file","text":"alpha beta\n","keys":"e"} +{"name":"x-line","pane":"file","text":"one\ntwo\nthree\n","keys":"x"} +{"name":"x-twice","pane":"file","text":"one\ntwo\nthree\n","keys":"xx"} +{"name":"d-char","pane":"file","text":"alpha beta\n","keys":"d"} +{"name":"x-then-d","pane":"file","text":"one\ntwo\nthree\n","keys":"xd"} +{"name":"i-type-esc","pane":"file","text":"alpha\n","keys":"ihello <esc>"} +{"name":"f-char","pane":"file","text":"alpha beta\n","keys":"ft"} +{"name":"f-cross-newline","pane":"file","text":"one\ntwo\n","keys":"fw"} +{"name":"r-char","pane":"file","text":"alpha\n","keys":"rX"} +{"name":"j-join","pane":"file","text":"one\ntwo\nthree\n","keys":"J"} +{"name":"semicolon-collapse","pane":"file","text":"alpha beta\n","keys":"w;"} +{"name":"percent-all","pane":"file","text":"one\ntwo\n","keys":"%"} +{"name":"mi-paren","pane":"file","text":"fn(a, b)\n","keys":"fami("} +{"name":"count-2w","pane":"file","text":"one two three four\n","keys":"2w"} +{"name":"ge-then-gt","pane":"file","text":"l1\nl2\nl3\nl4\nl5\nl6\nl7\nl8\nl9\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\nl30\n","keys":"gegt"} +{"name":"zt-then-gt","pane":"file","text":"l1\nl2\nl3\nl4\nl5\nl6\nl7\nl8\nl9\nl10\nl11\nl12\nl13\nl14\nl15\nl16\nl17\nl18\nl19\nl20\nl21\nl22\nl23\nl24\nl25\nl26\nl27\nl28\nl29\nl30\n","keys":"12jztgt"} +{"name":"v-select","pane":"file","text":"alpha beta\n","keys":"vw"} +{"name":"noop","pane":"file","text":"alpha\n","keys":""} diff --git a/test/hxcases/waivers.jsonl b/test/hxcases/waivers.jsonl new file mode 100644 index 00000000..8110a84c --- /dev/null +++ b/test/hxcases/waivers.jsonl @@ -0,0 +1,2 @@ +{"name":"wiX-edit-drops-sel","reason":"helix maps the selection through every insert-mode edit; pardes drops it on the first edit instead (anchor-only divergence, text+cursor+mode match). Re-judged phase 5 and kept: mapping the anchor through all ~23 mutation sites in handleInsert (multi-line inserts, EOL joins, kill runs) is genuinely invasive, and nothing in pardes consumes an implicit selection after insert-mode typing - the acme chords need explicit selections, which never enter insert."} +{"name":"alt-c-window-op","reason":"deliberate pardes binding: Alt-c is the move-pane-to-fresh-column window op in ANY mode (do-not-touch contract); helix Alt-c is change-noyank. Alt-d + i covers the helix behavior; the buffer is untouched on the pardes side."} diff --git a/test/hxdiff.zig b/test/hxdiff.zig new file mode 100644 index 00000000..62638e23 --- /dev/null +++ b/test/hxdiff.zig @@ -0,0 +1,355 @@ +// pardes-hxdiff: the pardes half of the helix differential harness. Drives +// the sans-IO core (src/pardes.zig) headlessly over JSON-Lines cases and +// prints one contract result line per case on stdout, input order — the same +// case/result contract helix's hx-harness speaks (pardes-harness branch in +// the genizah checkout), so the two editors diff key-for-key. +// +// case: {"name":"w-basic","pane":"file","text":"alpha beta\n","keys":"w"} +// result: {"name":"w-basic","text":"alpha beta\n","mode":"normal", +// "cursor":{"row":0,"col":5},"anchor":{"row":0,"col":0}} +// +// zig build hxdiff (diff the checked-in corpus) +// zig build hxdiff -- <cases.jsonl> (results to stdout, no diff) +// ./zig-out/bin/pardes-hxdiff <cases.jsonl> [goldens.jsonl [waivers.jsonl]] +// +// DIFF MODE (goldens given): every result is compared field-by-field +// (text/mode/cursor/anchor) against the same-named golden line. Waivers +// ({"name":...,"reason":...}) exempt named cases — each must carry a reason. +// Any unwaivered mismatch prints a per-case report and exits 1. +// +// Viewport is fixed at 80x24, matching the helix harness: one pane = 22 body +// rows (topbar + tag take two; helix: statusline + commandline take two). +// pane "file" swaps the boot pane for a file pane holding the case text +// (Pardes.hxOpenFileContent, the test-only entry). pane "tty" keeps the +// tty_only boot shell — no real pty, the spawn effect is ignored — feeds the +// text as pty output with \n cooked to \r\n (ONLCR), then leaves tty mode +// with Ctrl-<tty_toggle> exactly like a live session and parks the cursor at +// (0,0), mirroring the helix harness's initial Selection::single(0,1). The +// final tty text is the motion surface (paneCursorLines) re-joined, plus the +// trailing '\n' ghostty's dump trims off the cursor's empty row — the case +// text always ends in one, so this restores byte-for-byte comparability. +// Keys are helix notation: printables verbatim, <esc> <ret> <tab> <space> +// <backspace> <del> <up/down/left/right> <home/end> <pageup/pagedown> +// <C-x> <A-x> <lt> <gt>. The clipboard round-trips through a fake: +// set_clipboard stores the core's yank register, get_clipboard answers with +// Event.paste, so y-then-p behaves like a live session. +const std = @import("std"); +const libc = std.c; +const pardes = @import("pardes"); + +const gpa = std.heap.page_allocator; + +pub fn main(init: std.process.Init) !void { + var arena_state = std.heap.ArenaAllocator.init(gpa); + defer arena_state.deinit(); + const arena = arena_state.allocator(); + const args = try init.minimal.args.toSlice(init.arena.allocator()); + + var cases_path: ?[]const u8 = null; + var goldens_path: ?[]const u8 = null; + var waivers_path: ?[]const u8 = null; + for (args[1..]) |a| { + if (cases_path == null) { + cases_path = a; + } else if (goldens_path == null) { + goldens_path = a; + } else if (waivers_path == null) { + waivers_path = a; + } else fatal("usage: pardes-hxdiff <cases.jsonl> [goldens.jsonl [waivers.jsonl]]", .{}); + } + const path = cases_path orelse fatal("usage: pardes-hxdiff <cases.jsonl> [goldens.jsonl [waivers.jsonl]]", .{}); + + const src = readFileAlloc(arena, path) catch |e| fatal("read {s}: {s}", .{ path, @errorName(e) }); + + // goldens + waivers, keyed by name (diff mode) + var goldens: std.StringHashMap(Result) = .init(arena); + if (goldens_path) |gp| { + const gsrc = readFileAlloc(arena, gp) catch |e| fatal("read {s}: {s}", .{ gp, @errorName(e) }); + var glines = std.mem.splitScalar(u8, gsrc, '\n'); + var lno: usize = 0; + while (glines.next()) |raw| { + lno += 1; + const line = std.mem.trim(u8, raw, " \t\r"); + if (line.len == 0) continue; + const g = std.json.parseFromSliceLeaky(Result, arena, line, .{ .ignore_unknown_fields = true }) catch |e| + fatal("{s}:{d}: bad golden line: {s}", .{ gp, lno, @errorName(e) }); + goldens.put(g.name, g) catch fatal("oom", .{}); + } + } + var waivers: std.StringHashMap([]const u8) = .init(arena); + if (waivers_path) |wp| { + const wsrc = readFileAlloc(arena, wp) catch |e| fatal("read {s}: {s}", .{ wp, @errorName(e) }); + var wlines = std.mem.splitScalar(u8, wsrc, '\n'); + var lno: usize = 0; + while (wlines.next()) |raw| { + lno += 1; + const line = std.mem.trim(u8, raw, " \t\r"); + if (line.len == 0) continue; + const w = std.json.parseFromSliceLeaky(Waiver, arena, line, .{ .ignore_unknown_fields = true }) catch |e| + fatal("{s}:{d}: bad waiver line: {s}", .{ wp, lno, @errorName(e) }); + if (w.reason.len == 0) fatal("{s}:{d}: waiver {s} MUST carry a reason", .{ wp, lno, w.name }); + waivers.put(w.name, w.reason) catch fatal("oom", .{}); + } + } + + var out: std.ArrayList(u8) = .empty; + var n_cases: usize = 0; + var n_bad: usize = 0; + var n_waived: usize = 0; + var lines = std.mem.splitScalar(u8, src, '\n'); + var lineno: usize = 0; + while (lines.next()) |raw| { + lineno += 1; + const line = std.mem.trim(u8, raw, " \t\r"); + if (line.len == 0) continue; + const case = std.json.parseFromSliceLeaky(Case, arena, line, .{ .ignore_unknown_fields = true }) catch |e| + fatal("{s}:{d}: bad case line: {s}", .{ path, lineno, @errorName(e) }); + n_cases += 1; + const res = runCase(arena, case) catch |e| fatal("case {s}: {s}", .{ case.name, @errorName(e) }); + if (goldens_path == null) { + const jl = std.json.Stringify.valueAlloc(arena, res, .{}) catch fatal("oom", .{}); + out.appendSlice(arena, jl) catch fatal("oom", .{}); + out.append(arena, '\n') catch fatal("oom", .{}); + continue; + } + const g = goldens.get(case.name) orelse fatal("no golden for case {s} (regen goldens?)", .{case.name}); + const diff = diffResult(arena, g, res); + if (diff.len == 0) continue; + if (waivers.get(case.name)) |reason| { + n_waived += 1; + std.debug.print("WAIVED {s}: {s}\n", .{ case.name, reason }); + continue; + } + n_bad += 1; + std.debug.print("MISMATCH {s} (keys: {s})\n{s}", .{ case.name, case.keys, diff }); + } + if (goldens_path == null) { + try std.Io.File.stdout().writeStreamingAll(init.io, out.items); + return; + } + std.debug.print("hxdiff: {d} cases, {d} mismatches, {d} waived\n", .{ n_cases, n_bad, n_waived }); + if (n_bad > 0) std.process.exit(1); +} + +const Case = struct { + name: []const u8, + pane: []const u8 = "file", + text: []const u8, + keys: []const u8, +}; + +const Pos = struct { row: i32, col: i32 }; + +// field order is the contract's emit order (Stringify writes declaration order) +const Result = struct { + name: []const u8, + text: []const u8, + mode: []const u8, + cursor: Pos, + anchor: Pos, +}; + +const Waiver = struct { + name: []const u8, + reason: []const u8, +}; + +/// field-by-field compare; returns a human-readable report ("" = match) +fn diffResult(arena: std.mem.Allocator, want: Result, got: Result) []const u8 { + var buf: std.ArrayList(u8) = .empty; + if (!std.mem.eql(u8, want.text, got.text)) { + appendf(arena, &buf, " text: helix {f} != pardes {f}\n", .{ std.json.fmt(want.text, .{}), std.json.fmt(got.text, .{}) }); + } + if (!std.mem.eql(u8, want.mode, got.mode)) { + appendf(arena, &buf, " mode: helix {s} != pardes {s}\n", .{ want.mode, got.mode }); + } + if (want.cursor.row != got.cursor.row or want.cursor.col != got.cursor.col) { + appendf(arena, &buf, " cursor: helix ({d},{d}) != pardes ({d},{d})\n", .{ @as(i64, want.cursor.row), @as(i64, want.cursor.col), @as(i64, got.cursor.row), @as(i64, got.cursor.col) }); + } + if (want.anchor.row != got.anchor.row or want.anchor.col != got.anchor.col) { + appendf(arena, &buf, " anchor: helix ({d},{d}) != pardes ({d},{d})\n", .{ @as(i64, want.anchor.row), @as(i64, want.anchor.col), @as(i64, got.anchor.row), @as(i64, got.anchor.col) }); + } + return buf.items; +} + +fn appendf(arena: std.mem.Allocator, buf: *std.ArrayList(u8), comptime fmt: []const u8, fargs: anytype) void { + const s = std.fmt.allocPrint(arena, fmt, fargs) catch return; + buf.appendSlice(arena, s) catch {}; +} + +fn runCase(arena: std.mem.Allocator, case: Case) !Result { + // fresh core per case: the tty_only boot — one shell pane, tty mode, no + // greeting. Live-session contract: sizes arrive as the first resize event. + const core = try pardes.Pardes.init(gpa, .{ .tty_only = true }); + defer core.deinit(); + var clip: []const u8 = ""; + core.update(.{ .resize = .{ .cols = 80, .rows = 24 } }); + pump(core, arena, &clip); + + if (std.mem.eql(u8, case.pane, "file")) { + _ = try core.hxOpenFileContent(case.text); + } else if (std.mem.eql(u8, case.pane, "tty")) { + // the harness is the pty here: cook \n to \r\n the way ONLCR would + var cooked: std.ArrayList(u8) = .empty; + for (case.text) |ch| { + if (ch == '\n') try cooked.append(arena, '\r'); + try cooked.append(arena, ch); + } + core.update(.{ .output = .{ .pane = 0, .bytes = cooked.items } }); + pump(core, arena, &clip); + // leave tty mode the way a live session does: Ctrl-<tty_toggle>, + // then park the cursor at (0,0) — the helix harness's initial + // Selection::single(0,1) equivalent (a live exit would leave the + // modal cursor tracking the shell cursor below the output) + core.update(.{ .key = .{ .cp = core.opts.tty_toggle, .ctrl = true } }); + pump(core, arena, &clip); + if (core.panes[core.active]) |pane| { + pane.cur_row = 0; + pane.cur_col = 0; + pane.cur_pinned = true; + } + } else fatal("case {s}: unknown pane {s}", .{ case.name, case.pane }); + + // keys: helix notation — printables verbatim, <...> specials + var ki: usize = 0; + while (ki < case.keys.len) { + var key: pardes.Key = .{ .cp = 0 }; + if (case.keys[ki] == '<') { + const close = std.mem.indexOfScalarPos(u8, case.keys, ki, '>') orelse + fatal("case {s}: unterminated < in keys", .{case.name}); + var name = case.keys[ki + 1 .. close]; + ki = close + 1; + while (true) { + if (std.mem.startsWith(u8, name, "C-")) { + key.ctrl = true; + name = name[2..]; + } else if (std.mem.startsWith(u8, name, "A-")) { + key.alt = true; + name = name[2..]; + } else break; + } + if (name.len == 1) { + key.cp = name[0]; + if (!key.ctrl and !key.alt) key.text = name; + } else if (std.mem.eql(u8, name, "esc")) { + key.cp = pardes.Key.escape; + } else if (std.mem.eql(u8, name, "ret")) { + key.cp = pardes.Key.enter; + } else if (std.mem.eql(u8, name, "tab")) { + key.cp = pardes.Key.tab; + } else if (std.mem.eql(u8, name, "space")) { + key.cp = ' '; + if (!key.ctrl and !key.alt) key.text = " "; + } else if (std.mem.eql(u8, name, "backspace")) { + key.cp = pardes.Key.backspace; + } else if (std.mem.eql(u8, name, "del")) { + key.cp = pardes.Key.delete; + } else if (std.mem.eql(u8, name, "lt")) { + key.cp = '<'; + if (!key.ctrl and !key.alt) key.text = "<"; + } else if (std.mem.eql(u8, name, "gt")) { + key.cp = '>'; + if (!key.ctrl and !key.alt) key.text = ">"; + } else if (std.mem.eql(u8, name, "up")) { + key.cp = pardes.Key.up; + } else if (std.mem.eql(u8, name, "down")) { + key.cp = pardes.Key.down; + } else if (std.mem.eql(u8, name, "left")) { + key.cp = pardes.Key.left; + } else if (std.mem.eql(u8, name, "right")) { + key.cp = pardes.Key.right; + } else if (std.mem.eql(u8, name, "home")) { + key.cp = pardes.Key.home; + } else if (std.mem.eql(u8, name, "end")) { + key.cp = pardes.Key.end; + } else if (std.mem.eql(u8, name, "pageup")) { + key.cp = pardes.Key.page_up; + } else if (std.mem.eql(u8, name, "pagedown")) { + key.cp = pardes.Key.page_down; + } else fatal("case {s}: unknown key <{s}>", .{ case.name, name }); + } else { + key.cp = case.keys[ki]; + key.text = case.keys[ki .. ki + 1]; + ki += 1; + } + core.update(.{ .key = key }); + pump(core, arena, &clip); + } + + // one contract result line off the active pane's final state + const pane = core.panes[core.active] orelse return error.NoActivePane; + var text: []const u8 = undefined; + if (pane.file) |f| { + text = f.content; + } else { + // the tty motion surface, dumped honestly: whole scrollback+grid, + // prompt rows blanked, typed runs spliced — plus the trailing '\n' + // ghostty's dump trims off the cursor's empty final row + const pl = try core.paneCursorLines(pane); + var buf: std.ArrayList(u8) = .empty; + for (pl.lines, 0..) |ln, i| { + if (i > 0) try buf.append(arena, '\n'); + try buf.appendSlice(arena, ln); + } + if (buf.items.len > 0 and buf.items[buf.items.len - 1] != '\n') try buf.append(arena, '\n'); + text = buf.items; + } + var anchor: Pos = .{ .row = pane.cur_row, .col = pane.cur_col }; + if (pane.vsel.active) { + anchor = .{ .row = pane.vsel.row, .col = pane.vsel.col }; + } else if (pane.msel.active) { + // line selection: the far end (the r0/r1 not holding the cursor), col 0 + anchor = .{ .row = if (pane.cur_row == pane.msel.r1) pane.msel.r0 else pane.msel.r1, .col = 0 }; + } + // mode "select" ONLY while v-extend is on (helix keeps x/%/mi selections + // in normal mode); pane.mode itself never holds a select state + const mode = if (pane.mode == .normal and pane.select) "select" else @tagName(pane.mode); + return .{ + .name = case.name, + .text = try arena.dupe(u8, text), + .mode = mode, + .cursor = .{ .row = pane.cur_row, .col = pane.cur_col }, + .anchor = anchor, + }; +} + +/// Drain queued effects. The fake clipboard: set_clipboard snapshots the +/// core's yank register, get_clipboard answers with Event.paste — the async +/// OSC 52 round trip of a live shell, collapsed to a synchronous reply. +/// Everything else (spawn, write, resize_pty, ...) is ignored: no real pty. +fn pump(core: *pardes.Pardes, arena: std.mem.Allocator, clip: *[]const u8) void { + while (true) { + var want_paste = false; + while (core.nextEffect()) |eff| switch (eff) { + .set_clipboard => clip.* = if (core.yank) |y| (arena.dupe(u8, y) catch "") else "", + .get_clipboard => want_paste = true, + else => {}, + }; + if (!want_paste) return; + core.update(.{ .paste = clip.* }); + } +} + +fn readFileAlloc(arena: std.mem.Allocator, path: []const u8) ![]u8 { + const path_z = try arena.dupeZ(u8, path); + const fd = libc.open(path_z, .{ .ACCMODE = .RDONLY }); + if (fd < 0) return error.OpenFailed; + defer _ = libc.close(fd); + var buf: std.ArrayList(u8) = .empty; + var chunk: [16384]u8 = undefined; + while (true) { + const n = libc.read(fd, &chunk, chunk.len); + if (n < 0) { + if (libc.errno(n) == .INTR) continue; + return error.ReadFailed; + } + if (n == 0) break; + try buf.appendSlice(arena, chunk[0..@intCast(n)]); + } + return buf.items; +} + +fn fatal(comptime fmt: []const u8, args: anytype) noreturn { + std.debug.print("pardes-hxdiff: " ++ fmt ++ "\n", args); + std.process.exit(1); +} diff --git a/test/snapshots/fileedit.golden b/test/snapshots/fileedit.golden index 72950b96..13d6835a 100644 --- a/test/snapshots/fileedit.golden +++ b/test/snapshots/fileedit.golden @@ -60,7 +60,7 @@ | | | -== snap undone grid=100x30 cursor=7,3 +== snap undone grid=100x30 cursor=13,3 |Kill Newcol Tutor Debug Colors NextColor Dump | NOR /tmp/pardes-snap/fileedit/cwd/f.txt Save Del NOR /tmp/pardes-snap/fileedit/cwd Del | 1 liEDIT''MEne 1 diff --git a/test/snapshots/modal.golden b/test/snapshots/modal.golden index 668fd02c..dfe34130 100644 --- a/test/snapshots/modal.golden +++ b/test/snapshots/modal.golden @@ -29,7 +29,7 @@ | | | -== snap moved grid=100x30 cursor=2,6 +== snap moved grid=100x30 cursor=5,6 |Kill Newcol Tutor Debug Colors NextColor Dump | NOR /tmp/pardes-snap/modal/cwd Del NOR /tmp/pardes-snap/modal/cwd Del | @@ -60,7 +60,7 @@ | | | -== snap xsel grid=100x30 cursor=2,6 +== snap xsel grid=100x30 cursor=15,6 |Kill Newcol Tutor Debug Colors NextColor Dump | NOR /tmp/pardes-snap/modal/cwd Del NOR /tmp/pardes-snap/modal/cwd Del | @@ -98,7 +98,7 @@ |3: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, |4: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, |5: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, -|6: 0-1 d,#525252, 2-49 #d8c8a8,#4a3a1e, 50-51 d,#525252, 52-99 d,d, +|6: 0-1 d,#525252, 2-15 #d8c8a8,#4a3a1e, 16-49 d,d, 50-51 d,#525252, 52-99 d,d, |7: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, |8: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, |9: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, @@ -122,7 +122,7 @@ |27: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, |28: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, |29: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, -== snap xsel2 grid=100x30 cursor=2,7 +== snap xsel2 grid=100x30 cursor=15,7 |Kill Newcol Tutor Debug Colors NextColor Dump | NOR /tmp/pardes-snap/modal/cwd Del NOR /tmp/pardes-snap/modal/cwd Del | @@ -153,7 +153,7 @@ | | | -== snap yanked grid=100x30 cursor=2,6 +== snap yanked grid=100x30 cursor=15,7 |Kill Newcol Tutor Debug Colors NextColor Dump | NOR /tmp/pardes-snap/modal/cwd Del NOR /tmp/pardes-snap/modal/cwd Del | @@ -184,7 +184,7 @@ | | | -== snap vsel grid=100x30 cursor=3,7 +== snap vsel grid=100x30 cursor=16,8 |Kill Newcol Tutor Debug Colors NextColor Dump | NOR /tmp/pardes-snap/modal/cwd Del NOR /tmp/pardes-snap/modal/cwd Del | @@ -223,8 +223,8 @@ |4: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, |5: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, |6: 0-1 d,#525252, 2-49 #d8c8a8,#4a3a1e, 50-51 d,#525252, 52-99 d,d, -|7: 0-1 d,#525252, 2-3 #d8c8a8,#4a3a1e, 4-49 d,d, 50-51 d,#525252, 52-99 d,d, -|8: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, +|7: 0-1 d,#525252, 2-49 #d8c8a8,#4a3a1e, 50-51 d,#525252, 52-99 d,d, +|8: 0-1 d,#525252, 2-16 #d8c8a8,#4a3a1e, 17-49 d,d, 50-51 d,#525252, 52-99 d,d, |9: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, |10: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, |11: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, @@ -246,15 +246,15 @@ |27: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, |28: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, |29: 0-1 d,#525252, 2-49 d,d, 50-51 d,#525252, 52-99 d,d, -== snap typed grid=100x30 cursor=3,7 +== snap typed grid=100x30 cursor=2,6 |Kill Newcol Tutor Debug Colors NextColor Dump | NOR /tmp/pardes-snap/modal/cwd Del NOR /tmp/pardes-snap/modal/cwd Del | | words.txt words.txt | | -| one two three -| fTYPEDour five six +| TYPEDone two three +| four five six | seven eight nine | | @@ -277,7 +277,7 @@ | | | -== snap undone grid=100x30 cursor=3,7 +== snap undone grid=100x30 cursor=16,8 |Kill Newcol Tutor Debug Colors NextColor Dump | NOR /tmp/pardes-snap/modal/cwd Del NOR /tmp/pardes-snap/modal/cwd Del | @@ -308,15 +308,15 @@ | | | -== snap redone grid=100x30 cursor=3,7 +== snap redone grid=100x30 cursor=2,6 |Kill Newcol Tutor Debug Colors NextColor Dump | NOR /tmp/pardes-snap/modal/cwd Del NOR /tmp/pardes-snap/modal/cwd Del | | words.txt words.txt | | -| one two three -| fTYPEDour five six +| TYPEDone two three +| four five six | seven eight nine | | @@ -339,15 +339,15 @@ | | | -== snap bottom grid=100x30 cursor=2,9 +== snap bottom grid=100x30 cursor=2,8 |Kill Newcol Tutor Debug Colors NextColor Dump | NOR /tmp/pardes-snap/modal/cwd Del NOR /tmp/pardes-snap/modal/cwd Del | | words.txt words.txt | | -| one two three -| fTYPEDour five six +| TYPEDone two three +| four five six | seven eight nine | | diff --git a/test/snapshots/modal.snap b/test/snapshots/modal.snap index 73905175..68809e18 100644 --- a/test/snapshots/modal.snap +++ b/test/snapshots/modal.snap @@ -48,6 +48,6 @@ snap undone key U stable 400 5000 snap redone -key G +key g e stable 400 5000 snap bottom diff --git a/test/snapshots/scrolloff.golden b/test/snapshots/scrolloff.golden index 90e0e83f..f2165a10 100644 --- a/test/snapshots/scrolloff.golden +++ b/test/snapshots/scrolloff.golden @@ -122,7 +122,7 @@ | | | -== snap end grid=100x30 cursor=7,7 +== snap end grid=100x30 cursor=7,6 |Kill Newcol Tutor Debug Colors NextColor Dump | NOR /tmp/pardes-snap/scrolloff/cwd/g.txt Save De NOR /tmp/pardes-snap/scrolloff/cwd Del | 36 line 36 @@ -156,12 +156,12 @@ == snap kup grid=100x30 cursor=7,4 |Kill Newcol Tutor Debug Colors NextColor Dump | NOR /tmp/pardes-snap/scrolloff/cwd/g.txt Save De NOR /tmp/pardes-snap/scrolloff/cwd Del -| 31 line 31 -| 32 line 32 g.txt +| 30 line 30 +| 31 line 31 g.txt +| 32 line 32 | 33 line 33 | 34 line 34 | 35 line 35 -| 36 line 36 | NOR /tmp/pardes-snap/scrolloff/cwd Del | | g.txt diff --git a/test/snapshots/scrolloff.snap b/test/snapshots/scrolloff.snap index 067e851f..af64a3c7 100644 --- a/test/snapshots/scrolloff.snap +++ b/test/snapshots/scrolloff.snap @@ -27,8 +27,9 @@ snap scrolled1 key j j j j stable 400 5000 snap jdown -# (d) G: bottom clamp, view stops at EOF-at-bottom, cursor on the bottom row -key G +# (d) ge (goto last line; bare G is a helix no-op): bottom clamp, view stops +# at EOF-at-bottom, cursor on the bottom row +key g e stable 400 5000 snap end # (c) k-walk up: cursor climbs to the top margin, then the view scrolls |
