split out input code

This commit is contained in:
Robin Appelman 2024-12-18 17:21:56 +01:00
commit 589f695497
3 changed files with 92 additions and 88 deletions

86
src/ui/input.rs Normal file
View file

@ -0,0 +1,86 @@
use crate::ui::find_hit_row;
use crate::ui::state::{Mode, UiPage, UiState};
use ratatui::crossterm::event;
use ratatui::crossterm::event::{Event, KeyCode, KeyModifiers, MouseButton, MouseEventKind};
use std::io;
use std::time::Duration;
pub enum UiEvent {
Quit,
Back,
Up(usize, bool),
Down(usize, bool),
Scroll(isize),
Errors,
Select,
#[allow(dead_code)]
SelectAt(usize),
Enter(usize),
Copy,
EnterFilterMode,
ClearFilter,
Text(char),
PopText(PopMode),
}
pub enum PopMode {
Character,
Word,
}
pub fn handle_events(page: UiPage, ui_state: &UiState) -> io::Result<Option<UiEvent>> {
if event::poll(Duration::from_millis(50))? {
match event::read()? {
Event::Key(key) if key.kind == event::KeyEventKind::Press => {
return Ok(match (ui_state.mode(), key.code) {
(_, KeyCode::Char('c')) if key.modifiers == KeyModifiers::CONTROL => {
Some(UiEvent::Quit)
}
(Mode::Normal, KeyCode::Esc) => Some(UiEvent::Back),
(Mode::Normal, KeyCode::Char('q')) => Some(UiEvent::Quit),
(Mode::Normal, KeyCode::Char('e')) if page == UiPage::MatchList => {
Some(UiEvent::Errors)
}
(_, KeyCode::Left) if page != UiPage::MatchList => Some(UiEvent::Back),
(_, KeyCode::Down) => Some(UiEvent::Down(1, true)),
(_, KeyCode::Up) => Some(UiEvent::Up(1, true)),
(_, KeyCode::PageDown) => Some(UiEvent::Down(10, false)),
(_, KeyCode::PageUp) => Some(UiEvent::Up(10, false)),
(_, KeyCode::End) => Some(UiEvent::Down(usize::MAX, false)),
(_, KeyCode::Home) => Some(UiEvent::Up(usize::MAX, false)),
(_, KeyCode::Enter | KeyCode::Right) => Some(UiEvent::Select),
(Mode::Normal, KeyCode::Char('c')) => Some(UiEvent::Copy),
(Mode::Normal, KeyCode::F(4) | KeyCode::Char('f')) => {
Some(UiEvent::EnterFilterMode)
}
(Mode::FilterInput, KeyCode::Esc) => Some(UiEvent::ClearFilter),
(Mode::FilterInput, KeyCode::F(4)) => Some(UiEvent::Back),
(Mode::FilterInput, KeyCode::Backspace) => {
Some(UiEvent::PopText(PopMode::Character))
}
(Mode::FilterInput, KeyCode::Char('w'))
if key.modifiers == KeyModifiers::CONTROL =>
{
Some(UiEvent::PopText(PopMode::Word))
}
(Mode::FilterInput, KeyCode::Char(c)) => Some(UiEvent::Text(c)),
_ => None,
});
}
Event::Mouse(mouse) => {
return Ok(match mouse.kind {
MouseEventKind::ScrollUp => Some(UiEvent::Scroll(-1)),
MouseEventKind::ScrollDown => Some(UiEvent::Scroll(1)),
MouseEventKind::Down(MouseButton::Left) => {
find_hit_row(mouse.row, ui_state).map(UiEvent::Enter)
}
_ => None,
})
}
_ => {}
}
}
Ok(None)
}

View file

@ -4,32 +4,29 @@ use crate::ui::error_list::error_list;
use crate::ui::footer::footer; use crate::ui::footer::footer;
use crate::ui::grouped_logs::grouped_logs; use crate::ui::grouped_logs::grouped_logs;
use crate::ui::histogram::UiHistogram; use crate::ui::histogram::UiHistogram;
use crate::ui::input::handle_events;
use crate::ui::match_list::match_list; use crate::ui::match_list::match_list;
use crate::ui::single_log::single_log; use crate::ui::single_log::single_log;
use crate::ui::single_match::grouped_lines; use crate::ui::single_match::grouped_lines;
use crate::ui::state::{ use crate::ui::state::{
ErrorState, GroupedLogsState, LogState, MatchListState, MatchState, Mode, PopMode, UiEvent, ErrorState, GroupedLogsState, LogState, MatchListState, MatchState, UiState,
UiPage, UiState,
};
use ratatui::crossterm::event::{
DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyModifiers, MouseButton,
MouseEventKind,
}; };
use ratatui::crossterm::event::{DisableMouseCapture, EnableMouseCapture};
use ratatui::crossterm::terminal::{ use ratatui::crossterm::terminal::{
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
}; };
use ratatui::crossterm::{event, ExecutableCommand}; use ratatui::crossterm::ExecutableCommand;
use ratatui::prelude::*; use ratatui::prelude::*;
use ratatui::Terminal; use ratatui::Terminal;
use std::io; use std::io;
use std::io::stdout; use std::io::stdout;
use std::panic::{set_hook, take_hook}; use std::panic::{set_hook, take_hook};
use std::time::Duration;
mod error_list; mod error_list;
mod footer; mod footer;
mod grouped_logs; mod grouped_logs;
mod histogram; mod histogram;
mod input;
mod match_list; mod match_list;
mod single_log; mod single_log;
mod single_match; mod single_match;
@ -81,63 +78,6 @@ pub fn restore_tui() -> io::Result<()> {
Ok(()) Ok(())
} }
fn handle_events(page: UiPage, ui_state: &UiState) -> io::Result<Option<UiEvent>> {
if event::poll(Duration::from_millis(50))? {
match event::read()? {
Event::Key(key) if key.kind == event::KeyEventKind::Press => {
return Ok(match (ui_state.mode(), key.code) {
(_, KeyCode::Char('c')) if key.modifiers == KeyModifiers::CONTROL => {
Some(UiEvent::Quit)
}
(Mode::Normal, KeyCode::Esc) => Some(UiEvent::Back),
(Mode::Normal, KeyCode::Char('q')) => Some(UiEvent::Quit),
(Mode::Normal, KeyCode::Char('e')) if page == UiPage::MatchList => {
Some(UiEvent::Errors)
}
(_, KeyCode::Left) if page != UiPage::MatchList => Some(UiEvent::Back),
(_, KeyCode::Down) => Some(UiEvent::Down(1, true)),
(_, KeyCode::Up) => Some(UiEvent::Up(1, true)),
(_, KeyCode::PageDown) => Some(UiEvent::Down(10, false)),
(_, KeyCode::PageUp) => Some(UiEvent::Up(10, false)),
(_, KeyCode::End) => Some(UiEvent::Down(usize::MAX, false)),
(_, KeyCode::Home) => Some(UiEvent::Up(usize::MAX, false)),
(_, KeyCode::Enter | KeyCode::Right) => Some(UiEvent::Select),
(Mode::Normal, KeyCode::Char('c')) => Some(UiEvent::Copy),
(Mode::Normal, KeyCode::F(4) | KeyCode::Char('f')) => {
Some(UiEvent::EnterFilterMode)
}
(Mode::FilterInput, KeyCode::Esc) => Some(UiEvent::ClearFilter),
(Mode::FilterInput, KeyCode::F(4)) => Some(UiEvent::Back),
(Mode::FilterInput, KeyCode::Backspace) => {
Some(UiEvent::PopText(PopMode::Character))
}
(Mode::FilterInput, KeyCode::Char('w'))
if key.modifiers == KeyModifiers::CONTROL =>
{
Some(UiEvent::PopText(PopMode::Word))
}
(Mode::FilterInput, KeyCode::Char(c)) => Some(UiEvent::Text(c)),
_ => None,
});
}
Event::Mouse(mouse) => {
return Ok(match mouse.kind {
MouseEventKind::ScrollUp => Some(UiEvent::Scroll(-1)),
MouseEventKind::ScrollDown => Some(UiEvent::Scroll(1)),
MouseEventKind::Down(MouseButton::Left) => {
find_hit_row(mouse.row, ui_state).map(UiEvent::Enter)
}
_ => None,
})
}
_ => {}
}
}
Ok(None)
}
fn find_hit_row(row: u16, ui_state: &UiState) -> Option<usize> { fn find_hit_row(row: u16, ui_state: &UiState) -> Option<usize> {
if let Some(table_row) = row.checked_sub(ui_state.content_offset()) { if let Some(table_row) = row.checked_sub(ui_state.content_offset()) {
let selected = ui_state.index_for_row(table_row as usize); let selected = ui_state.index_for_row(table_row as usize);

View file

@ -1,6 +1,7 @@
use crate::app::{App, Filter, LogMatch, EMPTY_FILTER}; use crate::app::{App, Filter, LogMatch, EMPTY_FILTER};
use crate::logline::{FullLogLine, LogLine}; use crate::logline::{FullLogLine, LogLine};
use crate::ui::footer::FooterParams; use crate::ui::footer::FooterParams;
use crate::ui::input::{PopMode, UiEvent};
use crate::ui::table::ScrollbarTableState; use crate::ui::table::ScrollbarTableState;
use crate::ui::UI_HEADER_SIZE; use crate::ui::UI_HEADER_SIZE;
use crate::{copy_osc, parse_line_full}; use crate::{copy_osc, parse_line_full};
@ -481,29 +482,6 @@ impl<'a> UiState<'a> {
} }
} }
pub enum UiEvent {
Quit,
Back,
Up(usize, bool),
Down(usize, bool),
Scroll(isize),
Errors,
Select,
#[allow(dead_code)]
SelectAt(usize),
Enter(usize),
Copy,
EnterFilterMode,
ClearFilter,
Text(char),
PopText(PopMode),
}
pub enum PopMode {
Character,
Word,
}
#[derive(PartialEq)] #[derive(PartialEq)]
pub enum UiPage { pub enum UiPage {
MatchList, MatchList,