use super::types::App;
use ratatui::crossterm::event::{KeyCode, KeyModifiers};
pub(crate) fn handle_key(app: &mut App, code: KeyCode, mods: KeyModifiers) {
if app.overlays.show_help {
app.overlays.show_help = false;
return;
}
if code == KeyCode::F(1) || (code == KeyCode::Char('?') && app.input.is_empty()) {
app.overlays.show_help = true;
return;
}
let ctrl_mod = mods.contains(KeyModifiers::CONTROL);
match code {
KeyCode::Char('o') if ctrl_mod => return app.toggle_selection_mode(),
KeyCode::Char('y') if ctrl_mod => return app.copy_last_answer(),
KeyCode::Char('b') if ctrl_mod => return app.copy_transcript(),
KeyCode::F(2) => return app.toggle_selection_mode(),
KeyCode::F(3) => return app.copy_last_answer(),
KeyCode::F(4) => return app.copy_transcript(),
_ => {}
}
if app.overlays.picker.is_some() {
match code {
KeyCode::Up => app.picker_move(-1),
KeyCode::Down => app.picker_move(1),
KeyCode::Enter => app.picker_confirm(),
KeyCode::Esc => app.overlays.picker = None,
_ => {}
}
return;
}
if app.request.pending_approval.is_some() {
match code {
KeyCode::Char('y') | KeyCode::Char('Y') | KeyCode::Enter => app.answer_approval(true),
KeyCode::Char('n') | KeyCode::Char('N') | KeyCode::Esc => app.answer_approval(false),
_ => {}
}
return;
}
if app.overlays.menu.is_some() {
match code {
KeyCode::Up => return app.menu_move(-1),
KeyCode::Down => return app.menu_move(1),
KeyCode::Tab | KeyCode::Enter => return app.accept_selected(),
KeyCode::Esc => {
app.overlays.menu = None;
return;
}
_ => {}
}
}
if code == KeyCode::Esc && app.is_busy() {
if let Some(stream) = &app.request.stream {
stream.cancel.cancel();
}
app.transcript
.push(super::transcript::BlockKind::System, "Cancelling…");
return;
}
let ctrl = mods.contains(KeyModifiers::CONTROL);
let alt = mods.contains(KeyModifiers::ALT);
let word = ctrl || alt;
let was_armed = app.ctrl_c_armed;
app.ctrl_c_armed = false;
match code {
KeyCode::Char('c') if ctrl => {
if app.is_busy() {
if let Some(stream) = &app.request.stream {
stream.cancel.cancel();
}
app.transcript
.push(super::transcript::BlockKind::System, "Cancelling…");
} else if !app.input.is_empty() {
app.input.clear();
app.overlays.menu = None;
} else if was_armed {
app.should_quit = true;
} else {
app.ctrl_c_armed = true;
app.transcript.push(
super::transcript::BlockKind::System,
"Press Ctrl+C again to exit.",
);
}
return;
}
KeyCode::Char('d') if ctrl && app.input.is_empty() => return app.should_quit = true,
KeyCode::Char('a') if ctrl => app.input.move_home(),
KeyCode::Char('e') if ctrl => app.input.move_end(),
KeyCode::Char('k') if ctrl => app.input.kill_to_line_end(),
KeyCode::Char('u') if ctrl => app.input.kill_to_line_start(),
KeyCode::Char('w') if ctrl => app.input.delete_word_left(),
KeyCode::Char(c) if !ctrl => app.input.insert_char(c),
KeyCode::Enter if alt || mods.contains(KeyModifiers::SHIFT) => app.input.insert_newline(),
KeyCode::Enter => return app.submit(),
KeyCode::Backspace => app.input.backspace(),
KeyCode::Delete => app.input.delete(),
KeyCode::Left if word => app.input.move_word_left(),
KeyCode::Right if word => app.input.move_word_right(),
KeyCode::Left => app.input.move_left(),
KeyCode::Right => app.input.move_right(),
KeyCode::Home => app.input.move_home(),
KeyCode::End => app.input.move_end(),
KeyCode::Up => return app.history_prev(),
KeyCode::Down => return app.history_next(),
KeyCode::PageUp => return app.scroll_pages(true),
KeyCode::PageDown => return app.scroll_pages(false),
_ => return,
}
app.history.reset();
app.refresh_menu();
}