mod app;
mod input;
mod ui;
use std::io;
use std::time::{Duration, Instant};
use crossterm::event::{self, Event};
use crossterm::execute;
use crossterm::terminal::{
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
};
use ratatui::backend::CrosstermBackend;
use ratatui::Terminal;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = std::env::args().collect();
if args.len() < 2 {
eprintln!("Usage: dbiewlite <path-to-sqlite-file>");
eprintln!("Example: dbiewlite mydata.db");
std::process::exit(1);
}
let db_path = &args[1];
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let mut app = match app::App::new(db_path) {
Ok(a) => a,
Err(e) => {
disable_raw_mode()?;
execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
terminal.show_cursor()?;
eprintln!("Failed to open database: {}", e);
std::process::exit(1);
}
};
let tick_rate = Duration::from_millis(100);
let mut last_tick = Instant::now();
loop {
terminal.draw(|f| ui::draw(f, &mut app))?;
let timeout = tick_rate.saturating_sub(last_tick.elapsed());
if event::poll(timeout)? {
if let Event::Key(key) = event::read()? {
input::handle_key(&mut app, key);
}
}
if last_tick.elapsed() >= tick_rate {
last_tick = Instant::now();
}
if let Some(at) = app.status_message_at {
if at.elapsed() >= Duration::from_secs(3) {
app.status_message = None;
app.status_message_at = None;
}
}
if app.should_quit {
break;
}
}
disable_raw_mode()?;
execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
terminal.show_cursor()?;
Ok(())
}