use std::io;
use crossterm::event::{self, DisableMouseCapture, EnableMouseCapture, Event};
use crossterm::execute;
use crossterm::terminal::{
EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode,
};
use ratatui::Terminal;
use ratatui::backend::CrosstermBackend;
use crate::error::Result;
use super::app::App;
use super::ui;
pub fn init_terminal() -> Result<Terminal<CrosstermBackend<io::Stdout>>> {
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
let backend = CrosstermBackend::new(stdout);
let terminal = Terminal::new(backend)?;
Ok(terminal)
}
pub fn restore_terminal(terminal: &mut Terminal<CrosstermBackend<io::Stdout>>) -> Result<()> {
disable_raw_mode()?;
execute!(
terminal.backend_mut(),
DisableMouseCapture,
LeaveAlternateScreen
)?;
terminal.show_cursor()?;
Ok(())
}
pub fn run_event_loop(
terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
mut app: App,
) -> Result<()> {
event_loop(terminal, &mut app)
}
fn event_loop(terminal: &mut Terminal<CrosstermBackend<io::Stdout>>, app: &mut App) -> Result<()> {
use super::state::LiveMode;
let mut last_render = std::time::Instant::now();
loop {
let indexing_active = app.index_progress.is_some() || app.bg_indexer.is_some();
let should_render =
!indexing_active || last_render.elapsed() >= std::time::Duration::from_millis(16);
if should_render {
terminal.draw(|f| ui::render(f, app))?;
last_render = std::time::Instant::now();
}
let was_indexing = indexing_active;
if was_indexing {
app.index_tick();
}
let indexing_now = app.index_progress.is_some() || app.bg_indexer.is_some();
if was_indexing && !indexing_now {
continue;
}
if app.filter_progress.is_some() {
if event::poll(std::time::Duration::from_millis(0))?
&& let Event::Key(key) = event::read()?
&& key.code == crossterm::event::KeyCode::Esc
{
app.filter_progress = None;
continue;
}
app.filter_tick();
continue;
}
if app.stats_progress.is_some() {
if event::poll(std::time::Duration::from_millis(0))?
&& let Event::Key(key) = event::read()?
&& key.code == crossterm::event::KeyCode::Esc
{
app.stats_progress = None;
continue;
}
app.stats_tick();
continue;
}
if app.stream_build_progress.is_some() {
if event::poll(std::time::Duration::from_millis(0))?
&& let Event::Key(key) = event::read()?
&& key.code == crossterm::event::KeyCode::Esc
{
app.stream_build_progress = None;
continue;
}
app.stream_tick();
continue;
}
if app.live_mode.is_some() {
if matches!(app.live_mode, Some(LiveMode::Live)) {
app.live_tick();
} else if matches!(app.live_mode, Some(LiveMode::Paused)) {
app.check_eof();
}
let timeout = match app.live_mode {
Some(LiveMode::Live) => std::time::Duration::from_millis(200),
Some(LiveMode::Paused) => std::time::Duration::from_millis(500),
_ => std::time::Duration::from_secs(60),
};
if event::poll(timeout)? {
match event::read()? {
Event::Key(key) => app.handle_key(key),
Event::Mouse(mouse) => app.handle_mouse(mouse),
Event::Resize(_, _) => app.on_resize(),
_ => {}
}
}
} else if indexing_now {
if event::poll(std::time::Duration::from_millis(1))? {
match event::read()? {
Event::Key(key) => app.handle_key(key),
Event::Mouse(mouse) => app.handle_mouse(mouse),
Event::Resize(_, _) => app.on_resize(),
_ => {}
}
}
} else {
match event::read()? {
Event::Key(key) => app.handle_key(key),
Event::Mouse(mouse) => app.handle_mouse(mouse),
Event::Resize(_, _) => app.on_resize(),
_ => {}
}
}
if !app.running {
break;
}
}
super::state::save_history(&app.filter.history);
Ok(())
}