use crate::args::UninstallArgs;
use crate::installer;
use crate::style::Palette;
use anyhow::{anyhow, Result};
use std::path::Path;
use std::process::ExitCode;
pub fn run(args: UninstallArgs) -> Result<ExitCode> {
let palette = Palette::for_stdout();
let Palette {
green,
yellow,
bold,
reset,
..
} = palette;
let exe = installer::current_binary()?;
println!("{bold}keyhog uninstall{reset}");
println!(" binary {}", exe.display());
if !args.yes {
println!(
"\n{yellow}{bold}dry run{reset} - nothing removed. Re-run with {bold}--yes{reset} to delete the binary above."
);
print_integration_hints(&exe, &palette);
return Ok(ExitCode::SUCCESS);
}
remove_binary(&exe)?;
println!("\n{green}{bold}✓ removed {}{reset}", exe.display());
print_integration_hints(&exe, &palette);
Ok(ExitCode::SUCCESS)
}
fn print_integration_hints(exe: &Path, palette: &Palette) {
let Palette {
dim, bold, reset, ..
} = *palette;
let dir = exe
.parent()
.map(|d| d.display().to_string())
.unwrap_or_else(|| "the install dir".into());
println!("\n{bold}manual cleanup (keyhog never edits your shell config):{reset}");
println!(
" {dim}- PATH export for {dir} in your shell rc (~/.bashrc, ~/.zshrc, ~/.config/fish/config.fish){reset}"
);
println!(" {dim}- shell completions you installed via `keyhog completion`{reset}");
println!(" {dim}- the pre-commit hook in any repo where you ran `keyhog hook install`{reset}");
}
#[cfg(unix)]
fn remove_binary(exe: &Path) -> Result<()> {
std::fs::remove_file(exe).map_err(|e| {
anyhow!(
"could not remove {} ({e}); if keyhog lives in a system path, re-run with sudo",
exe.display()
)
})
}
#[cfg(windows)]
fn remove_binary(exe: &Path) -> Result<()> {
Err(anyhow!(
"Windows can't delete a running .exe. After this process exits, remove: {}",
exe.display()
))
}