mod api;
mod app;
mod args;
mod cache;
mod export_types;
mod favorites;
mod fmt;
mod output;
mod storage;
mod storage_cmd;
mod types;
mod ui;
use anyhow::Result;
use crossterm::{
event::{self, Event, KeyEventKind},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::prelude::*;
use tokio::sync::mpsc;
use args::Args;
#[tokio::main]
async fn main() -> Result<()> {
let args = args::parse_args()?;
if let Some(cmd) = args.storage_cmd {
return storage_cmd::run(cmd);
}
if args.output.is_some() {
return output::run(&args).await;
}
run_tui(args).await
}
async fn run_tui(args: Args) -> Result<()> {
let (tx, mut rx) = mpsc::channel::<app::Msg>(64);
let mut application = app::App::new(tx, args.language);
application.load();
enable_raw_mode()?;
let mut stdout = std::io::stdout();
execute!(stdout, EnterAlternateScreen)?;
let mut terminal = Terminal::new(CrosstermBackend::new(stdout))?;
let result = event_loop(&mut terminal, &mut application, &mut rx).await;
let _ = disable_raw_mode();
let _ = execute!(terminal.backend_mut(), LeaveAlternateScreen);
let _ = terminal.show_cursor();
cache::save(&application.cache);
result
}
async fn event_loop(
terminal: &mut Terminal<CrosstermBackend<std::io::Stdout>>,
app: &mut app::App,
rx: &mut mpsc::Receiver<app::Msg>,
) -> Result<()> {
loop {
while let Ok(msg) = rx.try_recv() {
app.on_msg(msg);
}
terminal.draw(|f| ui::render(f, app))?;
if event::poll(std::time::Duration::from_millis(50))? {
match event::read()? {
Event::Key(key) => {
if key.kind == KeyEventKind::Press && app.on_key(key) {
break;
}
}
Event::Resize(_, _) => {} _ => {}
}
}
while let Ok(msg) = rx.try_recv() {
app.on_msg(msg);
}
}
Ok(())
}