feat(claudbg-wfoe): Ctrl+C quits TUI immediately without confirmation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main
Elijah Voigt 2 months ago
parent 8a0ddf8ccd
commit 02e86e5062

@ -1,10 +1,11 @@
--- ---
# claudbg-wfoe # claudbg-wfoe
title: 'TUI: Ctrl+C immediately quits without confirmation' title: 'TUI: Ctrl+C immediately quits without confirmation'
status: todo status: in-progress
type: feature type: feature
priority: normal
created_at: 2026-04-01T16:47:04Z created_at: 2026-04-01T16:47:04Z
updated_at: 2026-04-01T16:47:04Z updated_at: 2026-04-01T16:57:38Z
--- ---
Support Ctrl+C to immediately quit without confirmation. Currently quit requires a confirmation dialog; Ctrl+C should bypass this and exit immediately. Support Ctrl+C to immediately quit without confirmation. Currently quit requires a confirmation dialog; Ctrl+C should bypass this and exit immediately.

@ -16,7 +16,7 @@ use crate::tui::state::AppState;
/// Dialog dimensions. /// Dialog dimensions.
const DIALOG_WIDTH: u16 = 36; const DIALOG_WIDTH: u16 = 36;
const DIALOG_HEIGHT: u16 = 37; const DIALOG_HEIGHT: u16 = 38;
/// Compute a centered [`Rect`] of the given size within `area`. /// Compute a centered [`Rect`] of the given size within `area`.
fn centered_rect(width: u16, height: u16, area: Rect) -> Rect { fn centered_rect(width: u16, height: u16, area: Rect) -> Rect {
@ -69,7 +69,8 @@ const HELP_TEXT: &str = "\
Esc clear & close\n\ Esc clear & close\n\
\n\ \n\
Global\n\ Global\n\
q/Q quit\n\ q/Q quit (confirm)\n\
Ctrl+C quit immediately\n\
? this help\n\ ? this help\n\
c toggle color\n\ c toggle color\n\
Ctrl+L redraw screen"; Ctrl+L redraw screen";

@ -119,6 +119,16 @@ fn render(frame: &mut ratatui::Frame, state: &AppState) {
/// then falls back to global keybindings for any event not consumed by /// then falls back to global keybindings for any event not consumed by
/// the screen. /// the screen.
fn handle_event(event: Event, state: &mut AppState) { fn handle_event(event: Event, state: &mut AppState) {
// Ctrl+C quits immediately, bypassing any modal dialogs.
if let Event::Key(key) = &event
&& key.kind == KeyEventKind::Press
&& key.code == KeyCode::Char('c')
&& key.modifiers.contains(KeyModifiers::CONTROL)
{
state.should_quit = true;
return;
}
// Modal dialogs intercept all input while visible. // Modal dialogs intercept all input while visible.
if state.show_quit_dialog { if state.show_quit_dialog {
handle_quit_dialog_event(event, state); handle_quit_dialog_event(event, state);
@ -405,4 +415,40 @@ mod tests {
handle_event(key_press(KeyCode::Char('c')), &mut state); handle_event(key_press(KeyCode::Char('c')), &mut state);
assert!(state.color_enabled, "color toggled back on"); assert!(state.color_enabled, "color toggled back on");
} }
fn ctrl_key_press(code: KeyCode) -> Event {
Event::Key(KeyEvent {
code,
modifiers: KeyModifiers::CONTROL,
kind: KeyEventKind::Press,
state: KeyEventState::NONE,
})
}
/// Ctrl+C quits immediately without showing the quit dialog.
#[test]
fn ctrl_c_quits_immediately() {
let mut state = AppState::new();
handle_event(ctrl_key_press(KeyCode::Char('c')), &mut state);
assert!(state.should_quit);
assert!(!state.show_quit_dialog);
}
/// Ctrl+C quits immediately even when the quit dialog is already open.
#[test]
fn ctrl_c_quits_through_quit_dialog() {
let mut state = AppState::new();
state.show_quit_dialog = true;
handle_event(ctrl_key_press(KeyCode::Char('c')), &mut state);
assert!(state.should_quit);
}
/// Ctrl+C quits immediately even when the help modal is open.
#[test]
fn ctrl_c_quits_through_help_modal() {
let mut state = AppState::new();
state.show_help = true;
handle_event(ctrl_key_press(KeyCode::Char('c')), &mut state);
assert!(state.should_quit);
}
} }

Loading…
Cancel
Save