pub mod app;
pub mod events;
pub mod ui;
use anyhow::Result;
use app::App;
use crossterm::{
event::{DisableMouseCapture, EnableMouseCapture},
execute,
terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
};
use ratatui::prelude::*;
use std::io;
use std::process::Command;
#[allow(dead_code)]
pub async fn run(config: crate::config::Config) -> 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(config).await?;
let res = run_app(&mut terminal, &mut app).await;
disable_raw_mode()?;
execute!(terminal.backend_mut(), LeaveAlternateScreen, DisableMouseCapture)?;
terminal.show_cursor()?;
res
}
async fn run_app<B: Backend>(terminal: &mut Terminal<B>, app: &mut App) -> Result<()> {
loop {
app.poll_thumbnail();
terminal.draw(|f| ui::draw(f, app))?;
if events::handle_events(app).await? {
break;
}
if app.open_editor {
break;
}
}
Ok(())
}
pub async fn run_with_default_terminal(config: crate::config::Config) -> Result<()> {
let mut terminal = ratatui::init();
let mut app = App::new(config).await?;
loop {
let result = run_app(&mut terminal, &mut app).await;
if app.open_editor {
app.open_editor = false;
ratatui::restore();
let config_path = app.config_path();
let editor = std::env::var("EDITOR").unwrap_or_else(|_| "vi".to_string());
app.status_message = Some(format!("Opening {} in {}...", config_path.display(), editor));
let status = Command::new(&editor).arg(&config_path).status();
match status {
Ok(s) if s.success() => {
if let Ok(new_config) = crate::config::Config::load(&config_path) {
app.config = new_config;
app.status_message = Some("Config reloaded".to_string());
}
}
Ok(_) => {
app.status_message = Some("Editor exited with error".to_string());
}
Err(e) => {
app.error_message = Some(format!("Failed to open editor: {}", e));
}
}
terminal = ratatui::init();
} else {
ratatui::restore();
return result;
}
}
}