Skip to content

Commit f8f055c

Browse files
tjazerzenclaude
andcommitted
Refactor TUI exit keybinding: use Ctrl+D instead of double Ctrl+C
- Changed Ctrl+C to only copy selected text (does nothing if no selection) - Added Ctrl+D for immediate exit without confirmation - Removed double Ctrl+C to quit logic and quit-pending state - Removed ESC to cancel quit logic - Updated footer and success messages to reflect new keybindings - Cleaned up unused CSS class for quit-pending state Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 9d4ec60 commit f8f055c

File tree

4 files changed

+8
-61
lines changed

4 files changed

+8
-61
lines changed

tui/components.py

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,33 +13,17 @@
1313
class CustomFooter(Horizontal):
1414
"""A custom footer with keyboard shortcuts and render ID."""
1515

16-
NORMAL_TEXT = "ctrl+c: quit/copy/ * ctrl+l: toggle logs"
17-
QUIT_PENDING_TEXT = "press ctrl+c again to quit * esc: cancel"
16+
FOOTER_TEXT = "ctrl+c: copy * ctrl+d: quit * ctrl+l: toggle logs"
1817

1918
def __init__(self, render_id: str = "", **kwargs):
2019
super().__init__(**kwargs)
2120
self.render_id = render_id
22-
self._footer_text_widget: Optional[Static] = None
2321

2422
def compose(self):
25-
self._footer_text_widget = Static(self.NORMAL_TEXT, classes="custom-footer-text")
26-
yield self._footer_text_widget
23+
yield Static(self.FOOTER_TEXT, classes="custom-footer-text")
2724
if self.render_id:
2825
yield Static(f"render id: {self.render_id}", classes="custom-footer-render-id")
2926

30-
def update_quit_state(self, quit_pending: bool) -> None:
31-
"""Update footer text based on quit-pending state."""
32-
if self._footer_text_widget is None:
33-
return
34-
if quit_pending:
35-
self._footer_text_widget.update(self.QUIT_PENDING_TEXT)
36-
self._footer_text_widget.remove_class("custom-footer-text")
37-
self._footer_text_widget.add_class("custom-footer-quit-pending")
38-
else:
39-
self._footer_text_widget.update(self.NORMAL_TEXT)
40-
self._footer_text_widget.remove_class("custom-footer-quit-pending")
41-
self._footer_text_widget.add_class("custom-footer-text")
42-
4327

4428
class ScriptOutputType(str, Enum):
4529
UNIT_TEST_OUTPUT_TEXT = "Unit tests output: "

tui/plain2code_tui.py

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from textual.app import App, ComposeResult
77
from textual.binding import Binding
88
from textual.containers import Vertical, VerticalScroll
9-
from textual.css.query import NoMatches
109
from textual.widgets import ContentSwitcher, Static
1110
from textual.worker import Worker, WorkerFailed, WorkerState
1211

@@ -55,8 +54,8 @@ class Plain2CodeTUI(App):
5554
"""A Textual TUI for plain2code."""
5655

5756
BINDINGS = [
58-
Binding("ctrl+c", "smart_quit", "Copy/Quit", show=False),
59-
Binding("escape", "cancel_quit", "Cancel Quit", show=False),
57+
Binding("ctrl+c", "copy_selection", "Copy", show=False),
58+
Binding("ctrl+d", "quit", "Quit", show=False),
6059
("ctrl+l", "toggle_logs", "Toggle Logs"),
6160
]
6261

@@ -80,7 +79,6 @@ def __init__(
8079
self.conformance_tests_script: Optional[str] = conformance_tests_script
8180
self.prepare_environment_script: Optional[str] = prepare_environment_script
8281
self.state_machine_version = state_machine_version
83-
self._quit_pending = False
8482

8583
# Initialize state handlers
8684
self._state_handlers: dict[str, StateHandler] = {
@@ -302,47 +300,17 @@ def ensure_exit():
302300
# daemon=True ensures this thread dies with the process if it exits before the timer fires
303301
threading.Thread(target=ensure_exit, daemon=True).start()
304302

305-
@property
306-
def quit_pending(self) -> bool:
307-
"""Whether a quit confirmation is pending."""
308-
return self._quit_pending
303+
async def action_copy_selection(self) -> None:
304+
"""Handle ctrl+c: copy selected text if any.
309305
310-
async def action_smart_quit(self) -> None:
311-
"""Handle ctrl+c: copy selected text if any, otherwise quit.
312-
313-
Copy-first, quit-second design:
314306
- If text is selected -> copy it to clipboard
315-
- If no text is selected -> enter quit-pending state
316-
- If already in quit-pending state -> actually quit
317-
- ESC cancels the quit confirmation
307+
- If no text is selected -> do nothing
318308
"""
319309
selected_text = self.screen.get_selected_text()
320310
if selected_text:
321311
self.copy_to_clipboard(selected_text)
322312
self.screen.clear_selection()
323313
self.notify("Copied to clipboard", timeout=2)
324-
return
325-
326-
if self._quit_pending:
327-
self.action_quit()
328-
return
329-
330-
self._quit_pending = True
331-
self._refresh_footer()
332-
333-
def action_cancel_quit(self) -> None:
334-
"""Cancel the quit confirmation when ESC is pressed."""
335-
if self._quit_pending:
336-
self._quit_pending = False
337-
self._refresh_footer()
338-
339-
def _refresh_footer(self) -> None:
340-
"""Refresh the CustomFooter widget to reflect current quit-pending state."""
341-
try:
342-
footer = self.screen.query_one(CustomFooter)
343-
footer.update_quit_state(self._quit_pending)
344-
except NoMatches:
345-
pass
346314

347315
def action_quit(self) -> None:
348316
"""Quit the application immediately.

tui/styles.css

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -399,11 +399,6 @@ CustomFooter {
399399
color: #888;
400400
}
401401

402-
.custom-footer-quit-pending {
403-
width: 1fr;
404-
color: #E0FF6E;
405-
}
406-
407402
.custom-footer-render-id {
408403
width: auto;
409404
color: #888;

tui/widget_helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def display_success_message(tui, rendered_code_path: str):
105105
rendered_code_path: The path to the rendered code
106106
"""
107107

108-
message = f"[#79FC96]✓ Rendering finished![/#79FC96] [#888888](ctrl+c to exit)[/#888888]\n[#888888]Generated code: {rendered_code_path}[/#888888] "
108+
message = f"[#79FC96]✓ Rendering finished![/#79FC96] [#888888](ctrl+d to exit)[/#888888]\n[#888888]Generated code: {rendered_code_path}[/#888888] "
109109

110110
widget: Static = tui.query_one(f"#{TUIComponents.RENDER_STATUS_WIDGET.value}", Static)
111111
widget.update(message)

0 commit comments

Comments
 (0)