#![cfg(feature = "tui")]
mod types;
mod state;
mod utils;
mod editor;
mod render;
mod input;
pub use types::*;
pub use state::*;
pub use utils::{format_interval, parse_duration_str, build_notify_target, parse_extraction_string, centered_rect};
pub use editor::open_in_editor;
use std::io;
use std::time::{Duration, Instant};
use crossterm::{
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyEventKind},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::{
backend::CrosstermBackend,
Terminal,
};
use crate::error::Result;
pub fn run() -> Result<()> {
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let mut app = App::new()?;
let mut last_refresh = Instant::now();
let mut last_interaction = Instant::now();
loop {
if app.needs_full_redraw {
terminal.autoresize()?;
terminal.clear()?;
app.needs_full_redraw = false;
}
terminal.draw(|f| render::ui(f, &mut app))?;
let interaction_debounce = last_interaction.elapsed() > Duration::from_secs(2);
if last_refresh.elapsed() > Duration::from_secs(1) && interaction_debounce {
let _ = app.refresh();
last_refresh = Instant::now();
}
if event::poll(Duration::from_millis(100))? {
let event = event::read()?;
last_interaction = Instant::now();
match event {
Event::Key(key) if key.kind == KeyEventKind::Press => {
input::handle_key_event(&mut app, key.code, key.modifiers)?;
}
Event::Mouse(mouse) => {
input::handle_mouse_event(&mut app, mouse)?;
}
_ => {}
}
}
if app.should_quit {
break;
}
}
disable_raw_mode()?;
execute!(
terminal.backend_mut(),
LeaveAlternateScreen,
DisableMouseCapture
)?;
terminal.show_cursor()?;
Ok(())
}