1use crate::{carousel::TaskResult, Options};
2use std::fmt;
3use std::io::{self, Write};
4use std::sync::atomic;
5use std::sync::Mutex;
6use std::thread;
7
8lazy_static::lazy_static! {
9 static ref TASK: Mutex<Option<thread::JoinHandle<TaskResult>>> = <_>::default();
10}
11
12static ACTIVE: atomic::AtomicBool = atomic::AtomicBool::new(false);
13
14#[inline]
15fn print_flush(buf: &[u8]) {
16 let mut stdout = io::stdout();
17 let _r = stdout.write_all(buf);
18 let _r = stdout.flush();
19}
20
21#[inline]
22pub fn spawn0(prompt: impl fmt::Display) {
23 spawn(prompt, Options::default());
24}
25
26pub fn spawn(prompt: impl fmt::Display, opts: Options) {
30 if ACTIVE.load(atomic::Ordering::SeqCst) {
31 stop();
32 }
33 ACTIVE.store(true, atomic::Ordering::SeqCst);
34 if atty::is(atty::Stream::Stdout) {
35 print_flush(format!("{} ", prompt).as_bytes());
36 let task = thread::spawn(move || rotate(opts));
37 TASK.lock().unwrap().replace(task);
38 } else {
39 print_flush(format!("{}... ", prompt).as_bytes());
40 let _r = io::stdout().flush();
41 }
42}
43
44#[inline]
45pub fn stop() {
46 stop_carousel(Some(""));
47}
48
49#[inline]
50pub fn stop_with(res: impl fmt::Display) {
51 stop_carousel(Some(res));
52}
53
54#[inline]
55pub fn stop_clear() {
56 stop_carousel(None::<&str>);
57}
58
59pub fn stop_carousel(res: Option<impl fmt::Display>) {
63 ACTIVE.store(false, atomic::Ordering::SeqCst);
64 if let Some(task) = TASK.lock().unwrap().take() {
65 let _r = task.join();
66 }
67 if let Some(s) = res {
68 crate::carousel::cleanup(s);
69 } else {
70 print_flush(crate::carousel::CLREOL);
71 }
72}
73
74fn rotate(opts: Options) -> TaskResult {
75 let mut c = crate::carousel::Carousel::new(opts);
76 let mut stdout = io::stdout();
77 while ACTIVE.load(atomic::Ordering::Relaxed) {
78 stdout.write_all(c.rotate())?;
79 stdout.flush()?;
80 thread::sleep(opts.delay);
81 }
82 Ok(())
83}