use ctrlc::set_handler;
use std::thread::sleep;
use std::time::{Duration, SystemTime};
use tty_overwriter::prelude::*;
const AWAIT_TIME: Duration = Duration::from_millis(5);
fn do_print(spinner: &Spinner) {
let char = spinner.current();
println!("fmt cargo fmt {char}");
println!("clippy cargo clippy {char}");
println!("node modules npm install {char}");
println!("analyse long process {char}");
}
fn redraw(spinner: &Spinner) {
let looper = spinner.current();
let first = Movement::new().up(4).right(26);
let second = Movement::new().down(1).right(2);
let third = Movement::new().down(1).left(2);
let fourth = Movement::new().down(1);
let last = AnsiSeq::MoveLines { up: 0, down: 1 };
print!("{first}{looper}{second}{looper}{third}{looper}{fourth}{looper}{last}");
}
fn main() {
let mut last_occurence = SystemTime::now();
let mut spinner = Spinner::default();
do_print(&spinner);
let hide = AnsiSeq::ShowAndHideCursor { show: false };
print!("{hide}");
let _ = set_handler(|| {
let show = AnsiSeq::ShowAndHideCursor { show: true };
print!("{show}");
std::process::exit(0);
});
loop {
redraw(&spinner);
let should_sleep_duration = AWAIT_TIME
.checked_sub(last_occurence.elapsed().unwrap())
.unwrap_or_default();
let elapsed = should_sleep_duration.as_millis() as usize;
if elapsed != 0 {
sleep(should_sleep_duration);
}
last_occurence = SystemTime::now();
spinner.tick(elapsed)
}
}
const FRAMES: [&str; 8] = ["⡏", "⠟", "⠻", "⢹", "⣸", "⣴", "⣦", "⣇"];
#[derive(Clone, Default)]
pub struct Spinner {
ticks: usize,
current_frame: usize,
}
impl Spinner {
pub fn current(&self) -> &'static str {
&FRAMES[self.ticks]
}
pub fn tick(&mut self, millis: usize) {
let up = self.current_frame + millis >= 40;
self.ticks = if up {
(self.ticks + 1) % FRAMES.len()
} else {
self.ticks
};
self.current_frame = if up { 0 } else { self.current_frame + millis };
}
}