Skip to content

Commit

Permalink
Merge pull request #4 from alt-art/load-spinner
Browse files Browse the repository at this point in the history
Spinner to give feedback on load
  • Loading branch information
newtoallofthis123 authored Oct 8, 2023
2 parents 8af13ea + c9dad26 commit 98f1c55
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 4 deletions.
70 changes: 69 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ reqwest = {version = "0.11"}
serde = {version = "1", features = ["derive"]}
serde_json = {version = "1"}
tokio = {version = "1", features = ["full"]}
human-panic = {version = "1.0"}
human-panic = {version = "1.0"}
crossterm = "0.27.0"
futures = "0.3.28"
7 changes: 5 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
#![allow(clippy::multiple_crate_versions)]
#![allow(clippy::multiple_crate_versions, clippy::module_name_repetitions)]

use human_panic::setup_panic;

mod cli;
mod web;
mod spinner;

use spinner::wrap_spinner;

#[tokio::main]
async fn main() {
Expand All @@ -16,7 +19,7 @@ async fn main() {
} else if cmd == "-v" || cmd == "--version" {
cli::print_version();
} else {
let (url, lyrics) = web::get_lyrics(input.as_str()).await;
let (url, lyrics) = wrap_spinner(web::get_lyrics(input.as_str())).await.unwrap();
bunt::println!("\n--------------------------");
bunt::println!("{$yellow}{}{/$}", input);
bunt::println!("--------------------------");
Expand Down
77 changes: 77 additions & 0 deletions src/spinner.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use crossterm::style::Print;
use crossterm::terminal::ClearType;
use crossterm::{cursor, execute, terminal};
use futures::Future;
use std::io::stderr;
use tokio::sync::oneshot::{self, error::TryRecvError, Receiver, Sender};
use tokio::task::JoinHandle;
use tokio::time;

const LOADING_SPINNER_DELAY: u64 = 40;
const LOADING_SPINNER_DOTS: [&str; 56] = [
"⢀⠀", "⡀⠀", "⠄⠀", "⢂⠀", "⡂⠀", "⠅⠀", "⢃⠀", "⡃⠀", "⠍⠀", "⢋⠀", "⡋⠀", "⠍⠁", "⢋⠁", "⡋⠁", "⠍⠉", "⠋⠉",
"⠋⠉", "⠉⠙", "⠉⠙", "⠉⠩", "⠈⢙", "⠈⡙", "⢈⠩", "⡀⢙", "⠄⡙", "⢂⠩", "⡂⢘", "⠅⡘", "⢃⠨", "⡃⢐", "⠍⡐", "⢋⠠",
"⡋⢀", "⠍⡁", "⢋⠁", "⡋⠁", "⠍⠉", "⠋⠉", "⠋⠉", "⠉⠙", "⠉⠙", "⠉⠩", "⠈⢙", "⠈⡙", "⠈⠩", "⠀⢙", "⠀⡙", "⠀⠩",
"⠀⢘", "⠀⡘", "⠀⠨", "⠀⢐", "⠀⡐", "⠀⠠", "⠀⢀", "⠀⡀",
];

type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;

pub struct Spinner {
tx: Sender<()>,
handle: JoinHandle<Result<()>>,
}

impl Spinner {
pub fn new() -> Self {
let (tx, rx) = oneshot::channel();
let handle = tokio::spawn(Self::spin(rx));
Self { tx, handle }
}

pub async fn stop(self) -> Result<()> {
self.tx.send(()).ok();
self.handle.await??;
Ok(())
}

async fn spin(mut rx: Receiver<()>) -> Result<()> {
let mut dots = LOADING_SPINNER_DOTS.iter().cycle();
terminal::enable_raw_mode()?;
execute!(
stderr(),
cursor::SavePosition,
cursor::Hide,
terminal::Clear(ClearType::CurrentLine),
)?;
let mut interval = time::interval(time::Duration::from_millis(LOADING_SPINNER_DELAY));
while rx.try_recv() == Err(TryRecvError::Empty) {
execute!(
stderr(),
cursor::MoveToColumn(1),
terminal::Clear(ClearType::CurrentLine),
Print(dots.next().unwrap())
)?;
interval.tick().await;
}
execute!(
stderr(),
terminal::Clear(ClearType::CurrentLine),
cursor::RestorePosition,
cursor::Show,
)?;
terminal::disable_raw_mode()?;
Ok(())
}
}

pub async fn wrap_spinner<F>(future: F) -> Result<F::Output>
where
F: Future + Send,
F::Output: Send,
{
let spinner = Spinner::new();
let result = future.await;
spinner.stop().await?;
Ok(result)
}

0 comments on commit 98f1c55

Please sign in to comment.