use ratatui::{Terminal, backend::CrosstermBackend};
use crate::logic::send_query;
use crate::state::AppState;
use super::terminal::{restore_terminal, setup_terminal};
mod background;
mod channels;
mod cleanup;
mod event_loop;
mod handlers;
pub mod init;
mod tick_handler;
mod workers;
use background::{Channels, spawn_auxiliary_workers, spawn_event_thread};
use cleanup::cleanup_on_exit;
use event_loop::run_event_loop;
use init::{initialize_app_state, run_startup_config_preflight, trigger_initial_resolutions};
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
struct TerminalRestoreGuard {
active: bool,
}
impl TerminalRestoreGuard {
const fn new(active: bool) -> Self {
Self { active }
}
const fn disarm(&mut self) {
self.active = false;
}
}
impl Drop for TerminalRestoreGuard {
fn drop(&mut self) {
if self.active
&& let Err(err) = restore_terminal()
{
tracing::warn!(error = %err, "failed to restore terminal from drop guard");
}
}
}
pub async fn run(dry_run_flag: bool) -> Result<()> {
let headless = std::env::var("PACSEA_TEST_HEADLESS").ok().as_deref() == Some("1");
let prefs = run_startup_config_preflight();
let _ = crate::theme::theme();
if !headless {
setup_terminal()?;
}
let mut terminal_restore_guard = TerminalRestoreGuard::new(!headless);
let mut terminal = if headless {
None
} else {
Some(Terminal::new(CrosstermBackend::new(std::io::stdout()))?)
};
let mut app = AppState::default();
let init_flags = initialize_app_state(&mut app, dry_run_flag, headless, &prefs);
let mut channels = Channels::new(app.official_index_path.clone());
let updates_refresh_interval = crate::theme::settings().updates_refresh_interval.max(60);
spawn_auxiliary_workers(
headless,
&channels.status_tx,
&channels.news_tx,
&channels.news_feed_tx,
&channels.news_incremental_tx,
&channels.announcement_tx,
&channels.tick_tx,
&app.news_read_ids,
&app.news_read_urls,
&app.news_seen_pkg_versions,
&app.news_seen_aur_comments,
&app.official_index_path,
&channels.net_err_tx,
&channels.index_notify_tx,
&channels.updates_tx,
updates_refresh_interval,
app.installed_packages_mode,
crate::theme::settings().get_announcement,
app.last_startup_timestamp.as_deref(),
);
spawn_event_thread(
headless,
channels.event_tx.clone(),
channels.event_thread_cancelled.clone(),
);
trigger_initial_resolutions(
&mut app,
&init_flags,
&channels.deps_req_tx,
&channels.files_req_tx,
&channels.services_req_tx,
&channels.sandbox_req_tx,
);
send_query(&mut app, &channels.query_tx);
run_event_loop(&mut terminal, &mut app, &mut channels).await;
cleanup_on_exit(&mut app, &channels);
drop(channels);
if !headless {
restore_terminal()?;
terminal_restore_guard.disarm();
}
std::process::exit(0);
}