fix(cli): make the xterm modifyOtherKeys Shift+Enter encoding insert a newline

"\x1b[27;2;13~" (the older xterm modifyOtherKeys / rxvt encoding of
Shift+Enter) is already registered by prompt_toolkit by default -- as
Keys.ControlM, i.e. plain Enter/submit. The previous `setdefault()` call was
therefore a silent no-op against it: this Shift+Enter variant kept behaving
like a submit instead of inserting a newline, even after the ControlJ/WSL
fix, since setdefault only sets missing keys.

Assign directly to override that default for both known Shift+Enter
sequences, since inserting a newline is the whole point of the binding.
Add a regression test driving a real PromptSession/parser with this exact
sequence, since a mocked-buffer test can't observe prompt_toolkit's default
ANSI_SEQUENCES entries taking priority.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjunwei
2026-07-07 15:41:08 +08:00
committed by Xubin Ren
co-authored by Claude Opus 4.8
parent ea0516e655
commit 25a477050d
2 changed files with 31 additions and 1 deletions
+22
View File
@@ -118,6 +118,28 @@ async def test_raw_lf_enter_still_submits_like_wsl_terminals():
assert result == "hello"
@pytest.mark.asyncio
async def test_xterm_modifyotherkeys_shift_enter_inserts_newline():
""""\\x1b[27;2;13~" (the older xterm modifyOtherKeys/rxvt encoding of
Shift+Enter) is registered by prompt_toolkit *by default* as plain
Enter/submit, so a `setdefault()`-based override would silently no-op
against it. This must actually insert a newline like the kitty CSI-u
encoding does, which only a real PromptSession/parser can confirm.
"""
from prompt_toolkit.application import create_app_session
from prompt_toolkit.input import create_pipe_input
from prompt_toolkit.output import DummyOutput
with create_pipe_input() as pipe_input:
with create_app_session(input=pipe_input, output=DummyOutput()):
commands._init_prompt_session()
session = commands._PROMPT_SESSION
pipe_input.send_text("foo\x1b[27;2;13~bar\r")
result = await session.prompt_async("> ")
assert result == "foo\nbar"
def test_thinking_spinner_pause_stops_and_restarts():
"""Pause should stop the active spinner and restart it afterward."""
spinner = MagicMock()