1 use std::io::{self, Write};
2 use std::sync::{Arc, LazyLock, Mutex};
3 use std::thread;
4 use std::time::{Duration, Instant};
5
6 static PROGRESS: LazyLock<Progress> = LazyLock::new(|| Progress {
7 message: Arc::new(Mutex::new("".to_string())),
8 is_complete: Arc::new(Mutex::new(false)),
9 });
10
11 pub struct Progress {
12 message: Arc<Mutex<String>>,
13 is_complete: Arc<Mutex<bool>>,
14 }
15
16 impl Progress {
start(&self)17 fn start(&self) {
18 let is_complete = self.is_complete.clone();
19 let message_ref = self.message.clone();
20 thread::spawn(move || {
21 let start = Instant::now();
22 while !*is_complete.lock().unwrap() {
23 let minutes = start.elapsed().as_secs() / 60;
24 let seconds = start.elapsed().as_secs() % 60;
25 let mut message =
26 format!(" {:01}:{:02} {}", minutes, seconds, message_ref.lock().unwrap());
27 if message.len() > 80 {
28 message.truncate(77);
29 message.push('…');
30 }
31 print!("\x1B[2K"); // clear the line
32 print!("\r{} ", message);
33 io::stdout().flush().unwrap();
34 thread::sleep(Duration::from_millis(100));
35 }
36 let mut complete = PROGRESS.is_complete.lock().unwrap();
37 *complete = false;
38 });
39 }
40
stop(&self)41 fn stop(&self) {
42 let mut is_complete = self.is_complete.lock().unwrap();
43 *is_complete = true;
44 print!("\x1B[2K"); // clear the line
45 print!("\r");
46 io::stdout().flush().unwrap();
47 }
48 }
49
update(message: &str)50 pub fn update(message: &str) {
51 let mut new_message = PROGRESS.message.lock().unwrap();
52 *new_message = message.to_string();
53 }
54
start(message: &str)55 pub fn start(message: &str) {
56 update(message);
57 PROGRESS.start();
58 }
59
stop()60 pub fn stop() {
61 PROGRESS.stop();
62 }
63