Skip to content

fix(cli): make Shift+letter actually type a capital under modifyOtherKeys - #94385

Open
MwC-Trexx wants to merge 3 commits into
NousResearch:mainfrom
MwC-Trexx:fix/cli-modify-other-keys-insert-text
Open

fix(cli): make Shift+letter actually type a capital under modifyOtherKeys#94385
MwC-Trexx wants to merge 3 commits into
NousResearch:mainfrom
MwC-Trexx:fix/cli-modify-other-keys-insert-text

Conversation

@MwC-Trexx

@MwC-Trexx MwC-Trexx commented Aug 25, 2026

Copy link
Copy Markdown

Summary

  • Patch prompt_toolkit's VT100 parser so character-valued ANSI_SEQUENCES entries insert the character, not the matched escape bytes
  • Preserve intentionally blanked insert_text on multi-key ANSI tails (Alt / Shift+Alt must not type the letter)
  • Add PromptSession-level regression tests for Shift+letter, Shift+Space, Alt, and Shift+Alt under modifyOtherKeys level 2 / CSI-u

Motivation

#87511 mapped ESC[27;2;<code>~ / ESC[<code>;2u to uppercase letters, but the classic CLI still leaks raw CSI into the buffer on Ghostty (and iTerm2 / WezTerm / kitty). prompt_toolkit builds KeyPress(key=<table value>, data=<matched bytes>) and the default Keys.Any binding inserts event.data — so mapping fixed what the key is, not what it types.

Verified on current main before this change: Shift+W then hat submits \x1b[27;2;87~hat. After: What.

Changes

  • hermes_cli/pt_input_extras.py_install_literal_key_data_patch() (defensive getattr, marker on wrapper, only rewrites non-empty insert_text != key, called at end of install_modify_other_keys_aliases())
  • tests/cli/test_modify_other_keys_insert_text.py — asserts submitted text via real PromptSession + pipe input; includes Alt/Shift+Alt non-insert guards

Related

Test plan

  • ./venv/bin/python -m pytest tests/cli/test_modify_other_keys_insert_text.py tests/cli/test_modify_other_keys_aliases.py -q233 passed
  • Pipe repro: \x1b[27;2;87~hat \x1b[27;2;72~appensWhat Happens
  • Alt+a / Shift+Alt+a do not insert into the buffer
  • Manual on Ghostty classic CLI: type capitals with Shift — no [27;2;…~ leak; Shift+Enter still newline; Alt chords unchanged

Notes for reviewers

  • No platform-specific code; pure prompt_toolkit layer
  • Keys is a str Enum — not isinstance(key, Keys) is load-bearing even though every current Keys value is multi-char
  • Ctrl/Alt Keys-valued entries, named keys, bracketed paste, and Shift+Enter aliases are intentionally unchanged
  • Private _call_handler is patched defensively (getattr + try); missing/renamed API degrades to no-op without breaking later installers

…Keys

NousResearch#87511 mapped ESC[27;2;<code>~ / CSI-u to the uppercase character, but
prompt_toolkit still inserts event.data (the raw escape bytes) for
character-valued ANSI_SEQUENCES entries. Shift+letter therefore leaks
[27;2;…~] into the classic CLI on Ghostty/iTerm/WezTerm/kitty (NousResearch#87390).

Narrow KeyPress.data to the character for single-char table entries via
a defensive Vt100Parser._call_handler wrap. Assert on submitted prompt
text (not parsed keys) so this class of bug cannot regress silently.

Refs NousResearch#87511, NousResearch#87390, NousResearch#86866, NousResearch#87785.
The literal-key data patch rewrote insert_text for every single-char
key. Stock Vt100Parser blanks insert_text on keys after the first in a
multi-key ANSI match (Alt+letter → (Escape, "a") with "" on the letter).
Reviving that blank made Shift+Alt+letter type the capital.

Only rewrite when insert_text is non-empty and differs from the key.
Pin with Alt / Shift+Alt regression tests.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cli CLI entry point, hermes_cli/, setup wizard labels Aug 25, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related to #87785: both repair the same prompt_toolkit self-insert path. This revision explicitly preserves blank insert_text on multi-key Alt and Shift+Alt tails; maintainers should choose or consolidate the two approaches.

Note that Keys is a str Enum so the isinstance(key, Keys) exclusion is
load-bearing, and soften the docstring so it no longer claims nothing
else changes shape (multi-key blanked tails are intentionally preserved).
@MwC-Trexx

Copy link
Copy Markdown
Author

Thanks for taking a look.

Pushed a small follow-up on this same PR (no new PR):

  • Keep multi-key ANSI tails blanked (insert_text only rewritten when non-empty and different from the key), so Alt / Shift+Alt do not type the letter
  • Soften the docstring around “what changes shape”
  • Note that Keys is a str Enum, so not isinstance(key, Keys) is intentional and load-bearing
  • Regression tests for Alt and Shift+Alt non-insert

tests/cli/test_modify_other_keys_insert_text.py + tests/cli/test_modify_other_keys_aliases.py: 233 passed.

Happy to coordinate with #87785 if that is preferred as the landing vehicle.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants