pub mod app;
pub mod data;
pub mod diff;
pub mod events;
pub mod render;
use std::io;
use std::time::Duration;
use anyhow::Result;
use crossterm::event::{self, DisableMouseCapture, Event};
use crossterm::execute;
use crossterm::terminal::{
EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode,
};
use ratatui::Terminal;
use ratatui::backend::CrosstermBackend;
use crate::db::{MasterDb, SafetyOpts};
use app::App;
pub fn run(db: MasterDb, safety: SafetyOpts) -> Result<()> {
let mut app = App::new(db, safety)?;
let mut terminal = setup_terminal()?;
install_panic_hook();
let result = event_loop(&mut terminal, &mut app);
let restore = restore_terminal(&mut terminal);
result.and(restore)
}
type Term = Terminal<CrosstermBackend<io::Stdout>>;
fn event_loop(terminal: &mut Term, app: &mut App) -> Result<()> {
while !app.should_quit {
terminal.draw(|f| render::draw(f, app))?;
if event::poll(Duration::from_millis(300))? {
if let Event::Key(key) = event::read()? {
events::handle_key(app, key);
}
}
app.poll_rekordbox_if_due();
}
Ok(())
}
fn setup_terminal() -> Result<Term> {
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(stdout);
Ok(Terminal::new(backend)?)
}
fn restore_terminal(terminal: &mut Term) -> Result<()> {
disable_raw_mode()?;
execute!(terminal.backend_mut(), LeaveAlternateScreen, DisableMouseCapture)?;
terminal.show_cursor()?;
Ok(())
}
fn install_panic_hook() {
let original = std::panic::take_hook();
std::panic::set_hook(Box::new(move |info| {
let _ = disable_raw_mode();
let _ = execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture);
original(info);
}));
}