lview/src/events.rs
2026-06-17 21:33:03 +02:00

121 lines
3.8 KiB
Rust

use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
use crate::app::{App, Screen};
/// Returns true if the app should keep running.
pub fn handle_event(app: &mut App, event: Event) -> bool {
match event {
Event::Key(key) if key.kind == KeyEventKind::Press => handle_key(app, key),
_ => true,
}
}
fn handle_key(app: &mut App, key: KeyEvent) -> bool {
// Global quit
if key.code == KeyCode::Char('q')
&& !matches!(app.screen, Screen::Search | Screen::PickerSearch)
{
return false;
}
match app.screen {
Screen::Picker => handle_picker(app, key),
Screen::Viewer => handle_viewer(app, key),
Screen::Search => handle_search(app, key),
Screen::PickerSearch => handle_picker_search(app, key),
}
}
fn handle_picker(app: &mut App, key: KeyEvent) -> bool {
match key.code {
KeyCode::Char('q') | KeyCode::Char('Q') => return false,
KeyCode::Char('j') | KeyCode::Down => app.next_log(),
KeyCode::Char('k') | KeyCode::Up => app.previous_log(),
KeyCode::Enter => {
if let Err(e) = app.open_selected_log() {
app.message = Some(format!("Failed to open log: {}", e));
}
}
KeyCode::Char('/') => app.enter_search(),
KeyCode::Char('r') => {
// Async discovery is triggered from main loop
app.loading = true;
}
_ => {}
}
true
}
fn handle_viewer(app: &mut App, key: KeyEvent) -> bool {
let Some(viewer) = app.viewer.as_mut() else {
app.screen = Screen::Picker;
return true;
};
match key.code {
KeyCode::Char('q') | KeyCode::Char('Q') | KeyCode::Esc => app.close_viewer(),
KeyCode::Char('j') | KeyCode::Down => viewer.scroll_down(1),
KeyCode::Char('k') | KeyCode::Up => viewer.scroll_up(1),
KeyCode::Char('d') if key.modifiers.contains(KeyModifiers::CONTROL) => viewer.scroll_down(10),
KeyCode::Char('u') if key.modifiers.contains(KeyModifiers::CONTROL) => viewer.scroll_up(10),
KeyCode::Char('g') => viewer.scroll_to_top(),
KeyCode::Char('G') => viewer.scroll_to_bottom(),
KeyCode::Char('l') | KeyCode::Char(' ') => viewer.toggle_live(),
KeyCode::Char('/') => app.enter_search(),
KeyCode::Char('n') => {
viewer.next_search_result();
}
KeyCode::Char('N') => {
viewer.prev_search_result();
}
KeyCode::Char('s') => {
if let Some(path) = app.save_viewer_buffer() {
app.message = Some(format!("Saved to {}", path));
}
}
_ => {}
}
true
}
fn handle_search(app: &mut App, key: KeyEvent) -> bool {
match key.code {
KeyCode::Esc => app.exit_search(),
KeyCode::Enter => app.confirm_search(),
KeyCode::Backspace => {
if let Some(query) = app.current_filter_query_mut() {
query.pop();
app.apply_current_filter();
}
}
KeyCode::Char(c) => {
if let Some(query) = app.current_filter_query_mut() {
query.push(c);
app.apply_current_filter();
}
}
_ => {}
}
true
}
fn handle_picker_search(app: &mut App, key: KeyEvent) -> bool {
match key.code {
KeyCode::Esc => app.exit_search(),
KeyCode::Enter => app.confirm_search(),
KeyCode::Backspace => {
if let Some(query) = app.current_filter_query_mut() {
query.pop();
app.apply_current_filter();
}
}
KeyCode::Char(c) => {
if let Some(query) = app.current_filter_query_mut() {
query.push(c);
app.apply_current_filter();
}
}
_ => {}
}
true
}