#![forbid(unsafe_code)]
mod about;
mod app_runner;
mod background;
mod cli;
mod doctor;
mod pipeline;
use clap::{CommandFactory, Parser};
use cli::Cli;
fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_env("MANDIBLE_LOG"))
.with_writer(std::io::stderr)
.try_init()
.ok();
let cli = Cli::parse();
if let Some(shell) = cli.completions {
let mut cmd = Cli::command();
let bin_name = cmd.get_name().to_string();
clap_complete::generate(shell, &mut cmd, bin_name, &mut std::io::stdout());
return Ok(());
}
let Some(tool) = cli.target_tool() else {
anyhow::bail!("usage: mandible <tool> (or: mandible --doctor <tool>)");
};
let tool = tool.to_string();
if cli.doctor.is_none() && tool == env!("CARGO_PKG_NAME") {
about::print();
return Ok(());
}
if let Some(doctor_tool) = &cli.doctor {
let loaded = pipeline::load(doctor_tool);
let ok = loaded.root.is_some();
doctor::print_report(&loaded);
if !ok {
anyhow::bail!("doctor: no extraction tier produced a result for {doctor_tool:?}");
}
return Ok(());
}
if !mandible_tui::terminal::stdout_is_tty() {
anyhow::bail!(
"mandible requires an interactive terminal (stdout is not a tty). \
Try running it directly in a terminal, or use `mandible --doctor {tool}` \
for a non-interactive report."
);
}
if mandible_extract::resolve_tool(&tool).path.is_none() {
anyhow::bail!(
"{tool:?} was not found on PATH. Run `mandible --doctor {tool}` for details on \
what was tried."
);
}
let stub = mandible_core::CommandNode::new(tool.clone(), mandible_core::Provenance::default());
let app = mandible_tui::App::new(tool, stub);
app_runner::run(app)
}