mirror of https://github.com/aliasrobotics/cai.git
Fix REPL y/N prompts showing ^M after Enter
Restore cooked TTY state after prompt_toolkit exits so Rich console.input and other follow-up prompts (e.g. /compact confirmation) accept Enter normally.
This commit is contained in:
parent
1c79507140
commit
fda018a324
|
|
@ -216,6 +216,7 @@ def get_user_input(command_completer, key_bindings, history_file, toolbar_func,
|
||||||
return [sep_line]
|
return [sep_line]
|
||||||
|
|
||||||
# Get user input with all features
|
# Get user input with all features
|
||||||
|
result = ""
|
||||||
try:
|
try:
|
||||||
result = prompt(
|
result = prompt(
|
||||||
[("class:prompt", "CAI> ")],
|
[("class:prompt", "CAI> ")],
|
||||||
|
|
@ -244,6 +245,15 @@ def get_user_input(command_completer, key_bindings, history_file, toolbar_func,
|
||||||
except (AttributeError, OSError):
|
except (AttributeError, OSError):
|
||||||
_REPL_STDIN_EXHAUSTED_PENDING = True
|
_REPL_STDIN_EXHAUSTED_PENDING = True
|
||||||
return ""
|
return ""
|
||||||
|
finally:
|
||||||
|
# prompt_toolkit restores termios from the snapshot taken after we cleared
|
||||||
|
# ICRNL above; Rich console.input and plain input() then echo Enter as ^M.
|
||||||
|
try:
|
||||||
|
from cai.util.streaming import restore_terminal_state
|
||||||
|
|
||||||
|
restore_terminal_state(emit_trailing_newline=False)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
# Print bottom separator only when user submitted non-empty input,
|
# Print bottom separator only when user submitted non-empty input,
|
||||||
# so that empty Enter produces a single separator between prompts.
|
# so that empty Enter produces a single separator between prompts.
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,29 @@ class TestMultilinePromptConfig:
|
||||||
'Without this, Enter may only insert newlines after long agent turns.'
|
'Without this, Enter may only insert newlines after long agent turns.'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_tty_restored_after_prompt(self):
|
||||||
|
"""Cooked TTY must be restored after prompt() for follow-up console.input prompts.
|
||||||
|
|
||||||
|
We clear ICRNL before prompt_toolkit starts; on exit it restores that snapshot,
|
||||||
|
so /compact and other y/N confirmations see Enter as ^M unless we run
|
||||||
|
restore_terminal_state again in a finally block.
|
||||||
|
"""
|
||||||
|
from cai.repl.ui.prompt import get_user_input
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
source = inspect.getsource(get_user_input)
|
||||||
|
|
||||||
|
assert 'finally:' in source, (
|
||||||
|
'REGRESSION: get_user_input must use finally to restore the TTY after '
|
||||||
|
'prompt_toolkit exits. Without this, Rich console.input shows ^M on Enter.'
|
||||||
|
)
|
||||||
|
assert source.index('finally:') > source.index('prompt('), (
|
||||||
|
'REGRESSION: TTY restore must run after prompt(), not only before it.'
|
||||||
|
)
|
||||||
|
assert 'restore_terminal_state' in source[source.index('finally:'):], (
|
||||||
|
'REGRESSION: finally block must call restore_terminal_state after prompt().'
|
||||||
|
)
|
||||||
|
|
||||||
def test_icrnl_cleared_before_prompt(self):
|
def test_icrnl_cleared_before_prompt(self):
|
||||||
"""ICRNL/INLCR/IGNCR must be cleared before prompt() to keep Enter as submit.
|
"""ICRNL/INLCR/IGNCR must be cleared before prompt() to keep Enter as submit.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue