test(input): hold the shared key encoder against ghostty's - #183
Draft
Ayman Bagabas (aymanbagabas) wants to merge 6 commits into
Draft
test(input): hold the shared key encoder against ghostty's#183Ayman Bagabas (aymanbagabas) wants to merge 6 commits into
Ayman Bagabas (aymanbagabas) wants to merge 6 commits into
Conversation
…ey-encoder-oracle # Conflicts: # README.md # SKILL.md # crates/tui-test/src/terminal/ghostty/core.rs # crates/tui-test/src/terminal/ghostty/mod.rs
Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
…r-oracle # Conflicts: # crates/tui-test/src/terminal/ghostty/core.rs
Three of the four backends have no key encoder of their own and always use `keys.rs`, so a bug there is a bug on three backends at once, and nothing was checking it against anything. Ghostty ships an encoder maintained by people who work on nothing else, which makes it a reference implementation worth comparing to. The comparison runs 495 events: every token whose encoding both encoders claim to define, across legacy, application cursor keys, and three Kitty mode combinations. It has already paid for itself. It found `key press A` sending `a`, `Space` encoding to nothing, `Alt+a` losing its modifier, and `Shift+a` reporting a modifier that had been consumed producing the text. All four are fixed in the commits this one sits on. Two spellings are normalized before comparing, because they are spellings rather than meanings. Under event reporting ghostty writes the press event type out as `:1` and the default parameters as `1;1`, where kitty and xterm omit both; the spec makes both legal and every consumer accepts either. Normalizing keeps those modes in the matrix instead of excluding them. Combinations legacy cannot express are excluded rather than asserted and then explained away. Ghostty upgrades `Ctrl+Tab` to `CSI 27;5;9~` where legacy has a bare `\t` with the Ctrl lost, and `Ctrl+Shift+0` to `CSI 41;5u`. That is a richer answer to a different question. What is left over is one real disagreement, named in `ORACLE_KNOWN_DIVERGENCES` with its reasoning rather than dropped: under report-all-keys ghostty sends Space as text where the shared encoder sends `CSI 32u`. The Kitty spec appears to be on the shared encoder's side. The test asserts a known divergence still diverges, so the list cannot go stale. Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
…r-oracle # Conflicts: # crates/tui-test/src/terminal/ghostty/core.rs # crates/tui-test/src/terminal/ghostty/mod.rs
…r-oracle # Conflicts: # crates/tui-test/src/terminal/ghostty/core.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Differential-tests tui-test's shared key encoder against ghostty's, which is a reference implementation maintained by people who work on nothing else.
Why
Three of the four backends have no key encoder of their own and always fall back to
keys.rs. A bug there is a bug on alacritty, rio, and xterm.js at once — and nothing was checkingkeys.rsagainst anything but its own expectations. Ghostty ships an encoder, so it can be held up as an oracle.It has already paid for itself
Four real bugs, all in the PRs beneath this one, all found by this test and none by the hand-written cases:
key press Asentakey press Spacesent nothingutf8as empty, and only single-character tokens set itkey press Alt+asentaset_options_from_terminalresetsmacos_option_as_alttoFalse, so Alt composed instead of prefixing ESCShift+asentCSI 97;2uinstead ofAconsumed_modswas never set, so ghostty reported a Shift that had been spent producing the textkitty_keyboard = falsestill encoded Kittyset_options_from_terminalreads flags off the live terminal, going around the profileAll five would have shipped. That is the argument for the test.
The last one is the interesting one: it only exists when #180 and #182 are both present, so neither branch could surface it on its own, and it is why #182 is now stacked on #180 rather than parallel to it.
What it compares
495 events: every token whose encoding both encoders claim to define, across five terminal states — legacy, application cursor keys (
CSI ?1h), and three Kitty mode combinations (>1u,>3u,>15u).Two spellings normalized
Both are spellings, not meanings, and the spec makes both legal:
REPORT_EVENT_TYPESon, ghostty writes the press event as:1; kitty and xterm omit it because press is the default.CSI 1;5:1AandCSI 1;5Adecode identically.CSI 1;1Awhere kitty and xterm writeCSI A.Normalizing keeps those modes in the matrix rather than excluding them. Both normalizers are deliberately narrow — the event-type one only strips a
:1immediately before the final byte, so the:65alternate-key sub-parameter inCSI 97:65;6uis untouched.What is excluded, and why
Combinations the legacy scheme cannot express. Ghostty upgrades them to
CSI-uor xterm'smodifyOtherKeysform:Ctrl+TabbecomesCSI 27;5;9~where legacy has a bare\twith the Ctrl silently lost, andCtrl+Shift+0becomesCSI 41;5u. That is a richer answer to a different question, not a different answer to this one, so asserting it and then explaining it away would only teach readers to ignore the test. F3 is excluded too: ghostty and kitty spell itCSI 13~, xterm spells itSS3 R, and that split predates both.The one real disagreement
Named in
ORACLE_KNOWN_DIVERGENCESwith its reasoning rather than deleted:The test asserts that a listed divergence still diverges, so the list cannot silently go stale: if ghostty changes, the entry fails as loudly as a new disagreement would.
Result
495 compared, 0 unexplained disagreements, 1 documented.
cargo test --workspace --features tui-test-rs/ghostty,tui-test-rs/rio,tui-test-rs/xtermjsgives 533 passed, 0 failed.