mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-18 04:41:56 +00:00
fix(cli): make Ctrl+Enter insert newline on WSL/SSH/Windows Terminal (#22777)
Native Windows, WSL, SSH sessions, and Windows Terminal all send Ctrl+Enter as bare LF (c-j). Hermes was binding c-j as submit on every POSIX platform, so Ctrl+Enter submitted instead of inserting a newline on those terminals. Reported in #22379. Add _preserve_ctrl_enter_newline() predicate that detects the environments where Ctrl+Enter must produce a newline (sys.platform == 'win32', SSH_CONNECTION/SSH_CLIENT/SSH_TTY env, WT_SESSION, WSL_DISTRO_NAME, /proc/version 'microsoft' marker). Gate the c-j-as-submit binding off in those environments and gate the c-j-as-newline handler on. Local POSIX TTYs without those markers (docker exec, plain ssh from a Mac) keep c-j as submit so plain Enter still works on thin PTYs. Add install_ctrl_enter_alias() in hermes_cli/pt_input_extras.py mapping the three CSI-u / modifyOtherKeys variants of Ctrl+Enter ('\x1b[13;5u', '\x1b[27;5;13~', '\x1b[27;5;13u') to the (Escape, ControlM) tuple Alt+Enter produces. This lets Kitty / mintty / xterm-with-modifyOtherKeys users over SSH get a Ctrl+Enter newline through the existing Alt+Enter handler. 9 new tests + extended existing test_lf_enter_binds_to_submit_handler_posix to cover bare-local vs SSH branches. Closes #22379.
This commit is contained in:
parent
2124ad72a2
commit
70bc52e408
4 changed files with 210 additions and 24 deletions
69
cli.py
69
cli.py
|
|
@ -72,9 +72,10 @@ except (ImportError, AttributeError):
|
|||
_STEADY_CURSOR = None
|
||||
|
||||
try:
|
||||
from hermes_cli.pt_input_extras import install_shift_enter_alias
|
||||
from hermes_cli.pt_input_extras import install_shift_enter_alias, install_ctrl_enter_alias
|
||||
install_shift_enter_alias()
|
||||
del install_shift_enter_alias
|
||||
install_ctrl_enter_alias()
|
||||
del install_shift_enter_alias, install_ctrl_enter_alias
|
||||
except Exception:
|
||||
pass
|
||||
import threading
|
||||
|
|
@ -1862,6 +1863,37 @@ _TERMINAL_INPUT_MODE_RESET_SEQ = (
|
|||
)
|
||||
|
||||
|
||||
def _preserve_ctrl_enter_newline() -> bool:
|
||||
"""Detect environments where Ctrl+Enter must produce a newline, not submit.
|
||||
|
||||
Native Windows, WSL, SSH sessions, and Windows Terminal all send Ctrl+Enter
|
||||
as bare LF (c-j). On those terminals c-j must NOT be bound to submit;
|
||||
binding it to submit makes Ctrl+Enter (intended as 'newline like Alt+Enter')
|
||||
submit instead. Local POSIX TTYs that deliver Enter as LF (docker exec,
|
||||
some thin PTYs without SSH) still need c-j bound to submit, so we keep
|
||||
that binding for those.
|
||||
|
||||
See issue #22379.
|
||||
"""
|
||||
if sys.platform == "win32":
|
||||
return True
|
||||
if any(os.environ.get(v) for v in ("SSH_CONNECTION", "SSH_CLIENT", "SSH_TTY")):
|
||||
return True
|
||||
if os.environ.get("WT_SESSION"):
|
||||
return True
|
||||
if "microsoft" in os.environ.get("WSL_DISTRO_NAME", "").lower():
|
||||
return True
|
||||
# WSL detection — env vars can be scrubbed under sudo, also peek /proc.
|
||||
for p in ("/proc/version", "/proc/sys/kernel/osrelease"):
|
||||
try:
|
||||
with open(p, "r", encoding="utf-8", errors="ignore") as f:
|
||||
if "microsoft" in f.read().lower():
|
||||
return True
|
||||
except OSError:
|
||||
continue
|
||||
return False
|
||||
|
||||
|
||||
def _bind_prompt_submit_keys(kb, handler) -> None:
|
||||
"""Bind terminal Enter forms to the submit handler.
|
||||
|
||||
|
|
@ -1869,13 +1901,15 @@ def _bind_prompt_submit_keys(kb, handler) -> None:
|
|||
some thin PTYs (docker exec, certain SSH flavors) deliver Enter as LF
|
||||
instead of CR — without this, Enter appears dead on those terminals.
|
||||
|
||||
On Windows, Windows Terminal delivers Ctrl+Enter as a distinct c-j key
|
||||
while plain Enter is c-m, so we leave c-j unbound here — it becomes the
|
||||
multi-line newline keystroke, giving Windows users an Enter-involving
|
||||
newline without any terminal settings changes.
|
||||
Exception: on Windows, WSL, SSH sessions, and Windows Terminal,
|
||||
c-j is the wire encoding of Ctrl+Enter (a distinct keystroke from
|
||||
plain Enter / c-m). We leave c-j unbound there so the c-j newline
|
||||
handler registered separately can fire — giving the user an
|
||||
Enter-involving newline keystroke without terminal settings changes.
|
||||
See _preserve_ctrl_enter_newline() and issue #22379.
|
||||
"""
|
||||
kb.add("enter")(handler)
|
||||
if sys.platform != "win32":
|
||||
if sys.platform != "win32" and not _preserve_ctrl_enter_newline():
|
||||
kb.add("c-j")(handler)
|
||||
|
||||
|
||||
|
|
@ -10855,18 +10889,19 @@ class HermesCLI:
|
|||
"""
|
||||
event.current_buffer.insert_text('\n')
|
||||
|
||||
if sys.platform == "win32":
|
||||
if _preserve_ctrl_enter_newline():
|
||||
@kb.add('c-j')
|
||||
def handle_ctrl_enter_newline_windows(event):
|
||||
"""Ctrl+Enter inserts a newline on Windows.
|
||||
def handle_ctrl_enter_newline(event):
|
||||
"""Ctrl+Enter inserts a newline on Windows, WSL, SSH, and WT.
|
||||
|
||||
Windows Terminal delivers Ctrl+Enter as LF (c-j), distinct
|
||||
from plain Enter (c-m). This binding makes Ctrl+Enter the
|
||||
Windows equivalent of Alt+Enter, giving an Enter-involving
|
||||
newline keystroke without requiring terminal settings changes.
|
||||
Ctrl+J (the raw LF keystroke) also triggers this by virtue
|
||||
of being the same key code — a harmless side effect since
|
||||
Ctrl+J has no conflicting Hermes binding.
|
||||
Windows Terminal (incl. WSL/SSH sessions through it) delivers
|
||||
Ctrl+Enter as LF (c-j), distinct from plain Enter (c-m). This
|
||||
binding makes Ctrl+Enter the equivalent of Alt+Enter on those
|
||||
terminals, giving an Enter-involving newline keystroke
|
||||
without requiring terminal settings changes. Ctrl+J (the raw
|
||||
LF keystroke) also triggers this by virtue of being the same
|
||||
key code — a harmless side effect since Ctrl+J has no
|
||||
conflicting Hermes binding. See issue #22379.
|
||||
"""
|
||||
event.current_buffer.insert_text('\n')
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue