fix(cli): map Shift+<symbol> under xterm modifyOtherKeys=2 - #91224
Open
sanastasiou wants to merge 1 commit into
Open
fix(cli): map Shift+<symbol> under xterm modifyOtherKeys=2#91224sanastasiou wants to merge 1 commit into
sanastasiou wants to merge 1 commit into
Conversation
_enable_extended_enter_keys() pushes modifyOtherKeys level 2 to Ghostty, iTerm2, WezTerm, VS Code, tmux and Windows Terminal. Those terminals then re-encode modified keys as ESC[27;<mod>;<codepoint>~. install_modify_other_keys_aliases() mapped Shift+letter but deliberately skipped Shift+symbol, so on Ghostty 1.3.x every shifted punctuation key leaked into the prompt buffer as literal "^[[27;2;NN~" text -- '?', '!', ':', '"', '_', '+', '<' and friends were untypeable in the interactive CLI while the mode was active. This is the same class of bug as NousResearch#87711, which fixed it for letters only. The symbols were skipped on the grounds that they are layout-specific (US Shift+1 = '!', AZERTY = 'A~'). That holds when deriving the shifted character from an UNSHIFTED codepoint, but the modifyOtherKeys encoding reports the codepoint ALREADY SHIFTED by the terminal, which has applied the user's real keymap. Echoing chr(codepoint) is therefore not a layout guess -- it is what the terminal says was typed, and is correct on every layout. Only the modifyOtherKeys (tilde) spelling is registered, NOT the CSI-u one: the Kitty protocol reports the UNSHIFTED codepoint plus a shift bit, so mapping ESC[47;2u to chr(47) would type '/' for Shift+/. Kitty-protocol terminals deliver printable keys as plain text anyway. Letters and Space are already registered and are skipped by the membership check, so this only fills genuinely unmapped codepoints. Tests: tests/cli/test_cli_shift_symbol_keys.py -- 6 tests covering the shifted-symbol table, an exhaustive no-leak sweep over printable ASCII, Shift+letter non-regression, Space/Tab/Backspace not being clobbered, CSI-u spellings left alone, and installer idempotency.
Contributor
The reasoning flip ("layout-specific" only applies when deriving the shifted char from an unshifted codepoint — modifyOtherKeys reports the already-shifted one) is correct per the xterm spec, the decision to exclude the CSI-u/Kitty spelling is right, and the test suite is exemplary: exhaustive leak check, regression guard on letters, dedicated-key preservation, Kitty non-mapping, and idempotency. Minor notes:
No blocking issues found. |
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.
What does this PR do?
Fixes shifted punctuation being untypeable in the interactive CLI on terminals
that speak xterm
modifyOtherKeys._enable_extended_enter_keys()pushes modifyOtherKeys level 2 (CSI >4;2m) toGhostty, iTerm2, WezTerm, VS Code, tmux and Windows Terminal. Those terminals
then re-encode modified keys as
ESC[27;<mod>;<codepoint>~.install_modify_other_keys_aliases()maps Shift+letter but not Shift+symbol, soon Ghostty 1.3.x pressing Shift+/ inserts the literal text
^[[27;2;63~into the prompt instead of?. Same for!:"_+<>()~— i.e. most punctuation is unusable while the mode is active.This is the same class of bug as #87711, which fixed it for letters only.
The symbols were skipped deliberately, with this comment:
That reasoning holds when deriving a shifted character from an unshifted
codepoint. But the modifyOtherKeys encoding reports the codepoint already
shifted by the terminal, which has applied the user's real keymap — Shift+/
on a US layout arrives as
63(?), not47(/). So echoingchr(codepoint)is not a layout guess; it is exactly what the terminal says wastyped, and is correct on every layout. There is no "wrong input" risk to trade
against here.
Related Issue
Related to #87711 (same leak, letters only). No separate issue filed.
Type of Change
Changes Made
hermes_cli/pt_input_extras.py— ininstall_modify_other_keys_aliases(),register
ESC[27;2;<cp>~→chr(cp)for every printable ASCII codepoint(0x20–0x7E) that is not already mapped. Removed the now-obsolete "symbols are
layout-specific" note and documented why the shifted-codepoint encoding makes
this layout-safe.
tests/cli/test_cli_shift_symbol_keys.py— new, 6 tests.Deliberately scoped to the modifyOtherKeys (tilde) spelling only — not
CSI-u. The Kitty protocol reports the unshifted codepoint plus a shift bit,
so registering
ESC[47;2u→chr(47)would type/for Shift+/. Kitty-protocolterminals deliver printable keys as plain text anyway, so there is nothing to map.
A test pins this so a later "make it symmetric" refactor cannot silently break it.
Letters and Space are registered earlier in the same function and are skipped by
the
if seq not in ANSI_SEQUENCESmembership check, so this only fills genuinelyunmapped codepoints. Codepoints 9/32/127 keep their dedicated
BackTab/" "/ControlHmeanings.How to Test
Reproduce (before this patch), in Ghostty:
hermes^[[27;2;63~instead of?.With the patch, each inserts the expected character.
Headless equivalent:
Test suite:
The new suite covers: the shifted-symbol table; an exhaustive no-leak sweep over
all printable ASCII; Shift+letter non-regression; Space/Tab/Backspace not being
clobbered; CSI-u spellings left untouched; and installer idempotency.
Verified end-to-end on Ghostty 1.3.1 / macOS with prompt_toolkit 3.0.52.