Skip to content

Instantly share code, notes, and snippets.

@mosmeh
Created June 27, 2020 09:27
Show Gist options
  • Save mosmeh/abb88a1ea1014d46844e980a30796221 to your computer and use it in GitHub Desktop.
Save mosmeh/abb88a1ea1014d46844e980a30796221 to your computer and use it in GitHub Desktop.
Spinner
use crossterm::{cursor, queue};
use std::io::{self, Write};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread::{self, JoinHandle};
use std::time::Duration;
const DEFAULT_FRAMES: &str = "⠙⠹⠸⠼⠴⠦⠧⠇⠏";
const DEFAULT_INTERVAL: Duration = Duration::from_millis(50);
struct Spinner {
message: String,
frames: Vec<String>,
interval: Duration,
}
impl Spinner {
fn new(message: &str) -> Self {
Self::with_frames(message, DEFAULT_FRAMES, DEFAULT_INTERVAL)
}
fn with_frames(message: &str, frames: &str, interval: Duration) -> Self {
Self {
message: message.to_string(),
frames: frames.chars().map(|c| c.to_string()).collect(),
interval,
}
}
fn start(self) -> SpinnerHandle {
let stopped = Arc::new(AtomicBool::new(false));
let stopped_clone = stopped.clone();
let mut stdout = io::stdout();
queue!(stdout, cursor::Hide).unwrap();
stdout.flush().unwrap();
let thread = std::thread::spawn(move || {
for f in self.frames.iter().cycle() {
let mut stdout = io::stdout();
queue!(stdout, cursor::MoveToColumn(0)).unwrap();
if stopped.load(Ordering::Relaxed) {
println!(" {}", self.message);
stdout.flush().unwrap();
break;
}
print!("{} {}", f, self.message);
stdout.flush().unwrap();
thread::sleep(self.interval);
}
});
SpinnerHandle {
thread: Some(thread),
stopped: stopped_clone,
}
}
}
struct SpinnerHandle {
thread: Option<JoinHandle<()>>,
stopped: Arc<AtomicBool>,
}
impl Drop for SpinnerHandle {
fn drop(&mut self) {
self.stop();
}
}
impl SpinnerHandle {
fn stop(&mut self) {
self.stopped.store(true, Ordering::Relaxed);
if let Some(thread) = self.thread.take() {
let _ = thread.join();
}
let mut stdout = io::stdout();
queue!(stdout, cursor::Show).unwrap();
stdout.flush().unwrap();
}
}
fn main() {
{
let _handle = Spinner::new("Updating").start();
std::thread::sleep(std::time::Duration::from_secs(3));
}
println!("Finished");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment