fix(cli): type the mapped key, not the raw sequence, for printable aliases - #94932
fix(cli): type the mapped key, not the raw sequence, for printable aliases#94932liuhao1024 wants to merge 1 commit into
Conversation
…iases Vt100Parser always attaches the raw matched bytes as KeyPress.data and TextArea's self-insert catch-all types event.data, so an ANSI_SEQUENCES value that is a plain printable string can never work: under modifyOtherKeys=2 (pushed for Ghostty), Shift+letter arrived as ESC[27;2;70~ and the alias installed by install_modify_other_keys_aliases in NousResearch#87630 keyed it to 'F' — but the buffer received the raw sequence '[27;2;70~' instead of the letter. Stock prompt_toolkit values are Keys enums whose bindings ignore data; only our aliases use plain strings, so every Shift+letter, Shift+Space, and lock-bit plain-key twin was broken by construction (NousResearch#94921). Rewrite the data to the key for exactly that shape — plain-str key + escape-prefixed raw data + printable key — in a Vt100Parser._call_handler wrapper installed alongside the alias table (same monkey-patch pattern the module already uses for ANSI_SEQUENCES). Normal typing (key == data), Keys-enum matches, and Alt-style tuple recursion (whose second element carries "" data) pass through untouched. Fixes NousResearch#94921
|
Confirmed duplicate — closing in favor of #88097. The triage is right that this is the earlier, broader repair. I independently reviewed @webtecnica's PR: opened 8 days earlier (Aug 17 vs Aug 25) and it patches the exact same mechanism — For whoever lands #88097, two cases from my parameterized coverage are worth absorbing: a full a–z Shift+letter matrix (both The underlying issues (#88071 here, #94921 on my side) look like the same report family; maintainer judgment on which issue stays canonical. |
What does this PR do?
Under
modifyOtherKeys=2(pushed for Ghostty since #87630), Shift+letter arrives asESC[27;2;<cp>~. The alias table installed byinstall_modify_other_keys_aliases()maps it to a plain string ('F') inANSI_SEQUENCES— but prompt_toolkit'sVt100Parseralways attaches the raw matched bytes asKeyPress.data, and TextArea's self-insert catch-all typesevent.data. So the input buffer received the literal sequence[27;2;70~instead ofF. As the reporter proved programmatically, anyANSI_SEQUENCESvalue that is a plain printable string is broken by construction: stock prompt_toolkit values areKeysenums whose bindings ignore data — only our aliases use plain strings (#94921).Affected surfaces (all plain-string alias values): Shift+letter A–Z (both codepoint spellings), Shift+Space, and the kitty lock-bit plain-key twins (e.g. Space with NumLock on,
ESC[32;129u).The fix installs a narrow
Vt100Parser._call_handlerwrapper alongside the alias table (the same monkey-patch pattern the module already uses forANSI_SEQUENCES, including idempotency and cache hygiene): when the matched key is a plainstr, the raw data is escape-prefixed, and the key is printable, theKeyPresscarries the key itself as data — which is exactly what ordinary typing already produces (key == data). Everything else passes through untouched:key == dataalready) — unchangedKeys-enum aliases (Ctrl+letter etc.) — data stays the raw sequence, their bindings ignore data""data) — unchanged (pinned by a test)Related Issue
Fixs #94921
Type of Change
Changes Made
hermes_cli/pt_input_extras.py— new_install_printable_alias_data_fix()(idempotent_call_handlerwrapper rewriting data→key for the plain-string alias shape), invoked frominstall_modify_other_keys_aliases()so every installer of the broken table gets the fix.tests/cli/test_modify_other_keys_aliases.py— new_parse_presseshelper returning fullKeyPressobjects (the existing_parseonly checked.key, which is why this slipped through); 26-z parametrized data pin, Shift+Space and lock-bit-space data pins, plain-typing/Ctrl-enum/Alt-tuple passthrough pins, and the reporter's end-to-end pipe-input TextArea repro (Shift+F typesF, plainqstill typesq).How to Test
pytest tests/cli/test_modify_other_keys_aliases.py tests/cli/test_cli_terminal_shortcuts.py tests/cli/test_cli_shift_enter_newline.py tests/cli/test_cli_cmd_backspace.py -q— should pass (244 + 20).[27;2;70~; with the change, the letter is typed.Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AScreenshots / Logs
From the issue (before): pressing Shift+F at the
hermesprompt in Ghostty inserted[27;2;70~. The reporter's programmatic repro (feeding\x1b[27;2;70~into a pipe-input TextArea) assertedarea.text == '\x1b[27;2;70~'— now it yields'F', verified end-to-end in the new test.