mod cli;
mod db;
mod shell;
mod tui;
use clap::Parser;
use crate::cli::{Cli, Commands};
use crate::tui::Action;
use std::process::{self, Command};
fn main() {
let cli = Cli::parse();
match &cli.command {
Some(Commands::Add {
command,
cwd,
exit_code,
hostname,
shell,
session_id,
}) => {
run_add(command, cwd, *exit_code, hostname.as_deref(), shell.as_deref(), session_id.as_deref());
}
Some(Commands::Init { shell }) => {
let script = shell::init_script(shell);
println!("{}", script);
}
None => {
run_tui(&cli);
}
}
}
fn run_add(
command: &[String],
cwd: &str,
exit_code: Option<i32>,
hostname: Option<&str>,
shell: Option<&str>,
session_id: Option<&str>,
) {
let cmd_str = command.join(" ").trim().to_string();
if cmd_str.is_empty() {
return;
}
let path = db::db_path();
let conn = match db::open(&path) {
Ok(c) => c,
Err(e) => {
eprintln!("re: failed to open database: {}", e);
process::exit(1);
}
};
let mut fallback_host = String::new();
let host = hostname.unwrap_or_else(|| {
fallback_host = whoami::fallible::hostname().unwrap_or_else(|_| "unknown".to_string());
&fallback_host
});
let sh = shell.unwrap_or("bash");
let cwd_opt = if cwd.is_empty() { None } else { Some(cwd) };
if let Err(e) = db::insert_command(&conn, &cmd_str, host, sh, cwd_opt, exit_code, session_id)
{
eprintln!("re: failed to insert command: {}", e);
}
let max_entries = std::env::var("MIGU_MAX_ENTRIES")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(100_000);
let _ = db::maybe_purge(&conn, max_entries);
}
fn run_tui(cli: &Cli) {
let path = cli.database.as_ref().map(|p| p.into()).unwrap_or_else(|| db::db_path());
let conn = match db::open(&path) {
Ok(c) => c,
Err(e) => {
eprintln!("re: failed to open database: {}", e);
process::exit(1);
}
};
let cwd = std::env::current_dir()
.ok()
.and_then(|p| p.to_str().map(|s| s.to_string()))
.unwrap_or_default();
let dedup = !cli.no_dedup;
match tui::run(&conn, &cwd, cli.limit as usize, dedup) {
Ok(Action::Insert(cmd)) => {
if std::env::var("MIGU_WIDGET").is_ok() {
let _ = std::fs::write("/tmp/migu-cmd", &cmd);
} else {
println!("{}", cmd);
}
}
Ok(Action::Execute(cmd)) => {
let status = Command::new("sh")
.arg("-c")
.arg(&cmd)
.spawn()
.and_then(|mut child| child.wait());
match status {
Ok(s) if !s.success() => {
std::process::exit(s.code().unwrap_or(1));
}
Err(e) => {
eprintln!("re: failed to execute command: {}", e);
process::exit(1);
}
_ => {}
}
}
Ok(Action::Quit) => {
}
Err(e) => {
eprintln!("re: TUI error: {}", e);
process::exit(1);
}
}
}