Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/palette.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 2024-07-04 - Terminal UI Keyboard Traps
**Learning:** In terminal raw mode (TTY), reading standard escape sequences natively intercepts `\x03` (Ctrl-C) as standard text, causing keyboard traps.
**Action:** When handling raw input, explicitly catch the `\x03` byte and raise `KeyboardInterrupt` to ensure users can exit the interface, and update prompt messages to explicitly inform the user of standard exit choices like "Ctrl-C to cancel" rather than "Esc" to prevent sequence hanging.
9 changes: 7 additions & 2 deletions libs/terminal_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ def _read_key(self):
return 'enter'
if key == '\x1b':
return 'escape'
if key == '\x03':
raise KeyboardInterrupt('Selection cancelled by user.')
return key

import termios
Expand All @@ -37,6 +39,8 @@ def _read_key(self):
try:
tty.setraw(fd)
key = sys.stdin.read(1)
if key == '\x03':
raise KeyboardInterrupt('Selection cancelled by user.')
if key == '\x1b':
next_chars = sys.stdin.read(2)
mapping = {'[A': 'up', '[B': 'down', '[D': 'left', '[C': 'right'}
Expand Down Expand Up @@ -67,7 +71,7 @@ def _render_selector(self, title, options, selected_index, help_text, default):
style = 'bold green' if index == selected_index else ''
table.add_row(marker, label, style=style)

footer = help_text or 'Use Up/Down arrows and Enter to select.'
footer = help_text or 'Use Up/Down arrows and Enter to select. Ctrl-C to cancel.'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚑ Quick win

Ctrl-C hint is lost whenever callers pass an explicit help_text.

The new "Ctrl-C to cancel" text is only used as a fallback when help_text is falsy. But _select_boolean (line 118) and select_model (line 129) always pass their own explicit help_text strings that don't mention Ctrl-C, so those screens β€” a large fraction of all prompts shown by interactive_settings/launch β€” never surface the cancellation hint this PR is meant to add. Only select_mode/select_language (which pass no help_text) benefit from the new default.

Consider always appending the Ctrl-C hint regardless of whether a custom help_text was supplied.

πŸ’‘ Proposed fix
-        footer = help_text or 'Use Up/Down arrows and Enter to select. Ctrl-C to cancel.'
+        base_footer = help_text or 'Use Up/Down arrows and Enter to select.'
+        footer = f'{base_footer} Ctrl-C to cancel.' if 'Ctrl-C' not in base_footer else base_footer
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
footer = help_text or 'Use Up/Down arrows and Enter to select. Ctrl-C to cancel.'
base_footer = help_text or 'Use Up/Down arrows and Enter to select.'
footer = f'{base_footer} Ctrl-C to cancel.' if 'Ctrl-C' not in base_footer else base_footer
πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/terminal_ui.py` at line 74, The footer in the terminal selection helper
currently drops the Ctrl-C cancel hint whenever `help_text` is provided. Update
the footer construction in `libs/terminal_ui.py` so the cancel hint is always
appended, and make sure the callers like `_select_boolean` and `select_model`
still show their custom help text plus the Ctrl-C guidance. Keep the change
centered around the footer logic used by the selection prompt functions.

self.console.print(Panel.fit(footer, title='Interpreter TUI', border_style='green'))
self.console.print(f"[bold cyan]{title}[/bold cyan]")
self.console.print(table)
Expand All @@ -76,7 +80,8 @@ def _render_selector(self, title, options, selected_index, help_text, default):
def _select_option(self, title, options, default, help_text=None):
if not sys.stdin.isatty():
default_choice = default if default in options else options[0]
answer = Prompt.ask(f"{title}", default=default_choice).strip()
options_str = '|'.join(str(opt) for opt in options)
answer = Prompt.ask(f"{title} \\[{options_str}]", default=default_choice).strip()
if answer in options:
return answer
for option in options:
Expand Down
Loading