Skip to content

Commit da7b1c4

Browse files
committed
🎨 Palette: [UX improvement] Clarify TUI choices and prevent keyboard traps
1 parent 2a47494 commit da7b1c4

2 files changed

Lines changed: 11 additions & 5 deletions

File tree

‎.Jules/palette.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
## 2025-01-23 - Prevent keyboard traps and clarify choices in TUI
3+
**Learning:** In terminal UI environments, web-specific UX concepts translate to explicit prompt choices, clear shortcut hints ('Esc/Ctrl-C to cancel'), and avoiding keyboard traps by mapping standard interrupt bytes (`\x03`) to exit actions.
4+
**Action:** Always map `\x03` to an exit action in raw mode, explicitly list valid input choices in prompt strings, and clearly communicate cancellation shortcuts to users.

‎libs/terminal_ui.py‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def _read_key(self):
2525
return mapping.get(extended, extended)
2626
if key == '\r':
2727
return 'enter'
28-
if key == '\x1b':
28+
if key in ('\x1b', '\x03'):
2929
return 'escape'
3030
return key
3131

@@ -37,6 +37,8 @@ def _read_key(self):
3737
try:
3838
tty.setraw(fd)
3939
key = sys.stdin.read(1)
40+
if key == '\x03':
41+
return 'escape'
4042
if key == '\x1b':
4143
next_chars = sys.stdin.read(2)
4244
mapping = {'[A': 'up', '[B': 'down', '[D': 'left', '[C': 'right'}
@@ -67,7 +69,7 @@ def _render_selector(self, title, options, selected_index, help_text, default):
6769
style = 'bold green' if index == selected_index else ''
6870
table.add_row(marker, label, style=style)
6971

70-
footer = help_text or 'Use Up/Down arrows and Enter to select.'
72+
footer = help_text or 'Use Up/Down arrows and Enter to select. Esc/Ctrl-C to cancel.'
7173
self.console.print(Panel.fit(footer, title='Interpreter TUI', border_style='green'))
7274
self.console.print(f"[bold cyan]{title}[/bold cyan]")
7375
self.console.print(table)
@@ -76,7 +78,7 @@ def _render_selector(self, title, options, selected_index, help_text, default):
7678
def _select_option(self, title, options, default, help_text=None):
7779
if not sys.stdin.isatty():
7880
default_choice = default if default in options else options[0]
79-
answer = Prompt.ask(f"{title}", default=default_choice).strip()
81+
answer = Prompt.ask(f"{title} [{'|'.join(options)}]", default=default_choice).strip()
8082
if answer in options:
8183
return answer
8284
for option in options:
@@ -110,7 +112,7 @@ def _select_option(self, title, options, default, help_text=None):
110112

111113
def _select_boolean(self, title, default=False):
112114
default_choice = 'yes' if default else 'no'
113-
choice = self._select_option(title, ['yes', 'no'], default_choice, 'Use Up/Down arrows and Enter to choose.')
115+
choice = self._select_option(title, ['yes', 'no'], default_choice, 'Use Up/Down arrows and Enter to choose. Esc/Ctrl-C to cancel.')
114116
return choice == 'yes'
115117

116118
def select_mode(self, default_mode='code'):
@@ -121,7 +123,7 @@ def select_model(self, default_model=None):
121123
default_model = default_model or self.utility_manager.get_default_model_name()
122124
if default_model not in models:
123125
default_model = models[0]
124-
return self._select_option('Model', models, default_model, 'Use Up/Down arrows, Enter, or type the first letter to jump.')
126+
return self._select_option('Model', models, default_model, 'Use Up/Down arrows, Enter, or type the first letter to jump. Esc/Ctrl-C to cancel.')
125127

126128
def select_language(self, default_lang='python'):
127129
return self._select_option('Language', ['python', 'javascript'], default_lang)

0 commit comments

Comments
 (0)