#![allow(dead_code)]
use std::io::{self, Write};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
const SPINNER: &[&str] = &[
"\u{2807}", "\u{280b}", "\u{2819}", "\u{2838}", "\u{2834}",
"\u{2826}", "\u{2847}", "\u{280f}",
];
const CHECK: &str = "\u{2713}";
const CROSS: &str = "\u{2717}";
pub(crate) fn header(title: &str) {
println!();
println!(" \x1b[1m{title}\x1b[0m");
println!();
}
pub(crate) fn footer() {
println!();
}
fn spin(label: &str, done: &Arc<AtomicBool>) {
let mut i = 0;
while !done.load(Ordering::Relaxed) {
let frame = SPINNER[i % SPINNER.len()];
print!(
"\r \x1b[36m{frame}\x1b[0m \x1b[90m{label}\x1b[0m\x1b[K"
);
let _ = io::stdout().flush();
thread::sleep(Duration::from_millis(80));
i += 1;
}
}
pub(crate) fn task<F, R>(label: &str, f: F) -> R
where
F: FnOnce() -> R,
{
let done = Arc::new(AtomicBool::new(false));
let done_clone = done.clone();
let label_owned = label.to_string();
let handle = thread::spawn(move || spin(&label_owned, &done_clone));
let result = f();
done.store(true, Ordering::Relaxed);
let _ = handle.join();
print!("\r \x1b[32m{CHECK}\x1b[0m {label}\x1b[K\n");
let _ = io::stdout().flush();
result
}
pub(crate) fn task_with_output<F>(label: &str, f: F)
where
F: FnOnce() -> Vec<String>,
{
let done = Arc::new(AtomicBool::new(false));
let done_clone = done.clone();
let label_owned = label.to_string();
let handle = thread::spawn(move || spin(&label_owned, &done_clone));
let lines = f();
done.store(true, Ordering::Relaxed);
let _ = handle.join();
print!("\r \x1b[32m{CHECK}\x1b[0m {label}\x1b[K\n");
for line in &lines {
println!(" \x1b[90m{line}\x1b[0m");
}
let _ = io::stdout().flush();
}
pub(crate) fn task_result<F, T, E>(label: &str, f: F) -> Result<T, E>
where
F: FnOnce() -> Result<T, E>,
E: std::fmt::Display,
{
let done = Arc::new(AtomicBool::new(false));
let done_clone = done.clone();
let label_owned = label.to_string();
let handle = thread::spawn(move || spin(&label_owned, &done_clone));
let result = f();
done.store(true, Ordering::Relaxed);
let _ = handle.join();
match &result {
Ok(_) => {
print!("\r \x1b[32m{CHECK}\x1b[0m {label}\x1b[K\n")
}
Err(e) => print!(
"\r \x1b[31m{CROSS}\x1b[0m {label} \x1b[90m({e})\x1b[0m\x1b[K\n"
),
}
let _ = io::stdout().flush();
result
}
pub(crate) fn summary(count: usize) {
println!();
println!(
" \x1b[1;32m{CHECK} {count} operations completed.\x1b[0m"
);
println!();
}