-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: implement spinner * fix: spinner - fix docs
- Loading branch information
Showing
6 changed files
with
292 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# VHS documentation | ||
# | ||
# Output: | ||
# Output <path>.gif Create a GIF output at the given <path> | ||
# Output <path>.mp4 Create an MP4 output at the given <path> | ||
# Output <path>.webm Create a WebM output at the given <path> | ||
# | ||
# Require: | ||
# Require <string> Ensure a program is on the $PATH to proceed | ||
# | ||
# Settings: | ||
# Set FontSize <number> Set the font size of the terminal | ||
# Set FontFamily <string> Set the font family of the terminal | ||
# Set Height <number> Set the height of the terminal | ||
# Set Width <number> Set the width of the terminal | ||
# Set LetterSpacing <float> Set the font letter spacing (tracking) | ||
# Set LineHeight <float> Set the font line height | ||
# Set LoopOffset <float>% Set the starting frame offset for the GIF loop | ||
# Set Theme <json|string> Set the theme of the terminal | ||
# Set Padding <number> Set the padding of the terminal | ||
# Set Framerate <number> Set the framerate of the recording | ||
# Set PlaybackSpeed <float> Set the playback speed of the recording | ||
# Set MarginFill <file|#000000> Set the file or color the margin will be filled with. | ||
# Set Margin <number> Set the size of the margin. Has no effect if MarginFill isn't set. | ||
# Set BorderRadius <number> Set terminal border radius, in pixels. | ||
# Set WindowBar <string> Set window bar type. (one of: Rings, RingsRight, Colorful, ColorfulRight) | ||
# Set WindowBarSize <number> Set window bar size, in pixels. Default is 40. | ||
# Set TypingSpeed <time> Set the typing speed of the terminal. Default is 50ms. | ||
# | ||
# Sleep: | ||
# Sleep <time> Sleep for a set amount of <time> in seconds | ||
# | ||
# Type: | ||
# Type[@<time>] "<characters>" Type <characters> into the terminal with a | ||
# <time> delay between each character | ||
# | ||
# Keys: | ||
# Escape[@<time>] [number] Press the Escape key | ||
# Backspace[@<time>] [number] Press the Backspace key | ||
# Delete[@<time>] [number] Press the Delete key | ||
# Insert[@<time>] [number] Press the Insert key | ||
# Down[@<time>] [number] Press the Down key | ||
# Enter[@<time>] [number] Press the Enter key | ||
# Space[@<time>] [number] Press the Space key | ||
# Tab[@<time>] [number] Press the Tab key | ||
# Left[@<time>] [number] Press the Left Arrow key | ||
# Right[@<time>] [number] Press the Right Arrow key | ||
# Up[@<time>] [number] Press the Up Arrow key | ||
# Down[@<time>] [number] Press the Down Arrow key | ||
# PageUp[@<time>] [number] Press the Page Up key | ||
# PageDown[@<time>] [number] Press the Page Down key | ||
# Ctrl+<key> Press the Control key + <key> (e.g. Ctrl+C) | ||
# | ||
# Display: | ||
# Hide Hide the subsequent commands from the output | ||
# Show Show the subsequent commands in the output | ||
|
||
Output assets/spinner.gif | ||
|
||
Set Shell "fish" | ||
Set Padding 10 | ||
Set FontSize 16 | ||
Set Width 600 | ||
Set Height 300 | ||
Set TypingSpeed 100ms | ||
|
||
Hide | ||
Type "cargo build --example spinner && clear" Enter | ||
Sleep 2s | ||
Show | ||
|
||
Type "target/debug/examples/spinner" Enter | ||
Sleep 5s |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
use std::{thread::sleep, time::Duration}; | ||
|
||
use demand::{Spinner, SpinnerStyle}; | ||
|
||
fn main() { | ||
Spinner::new("Loading Data...") | ||
.style(SpinnerStyle::line()) | ||
.run(|| { | ||
sleep(Duration::from_secs(2)); | ||
}) | ||
.expect("error running spinner"); | ||
println!("Done!"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
use std::{ | ||
io::{self, Write}, | ||
thread::sleep, | ||
time::Duration, | ||
}; | ||
|
||
use console::Term; | ||
use termcolor::{Buffer, WriteColor}; | ||
|
||
use crate::Theme; | ||
|
||
/// Show a spinner | ||
/// | ||
/// # Example | ||
/// ```rust | ||
/// use demand::{Spinner,SpinnerStyle}; | ||
/// use std::time::Duration; | ||
/// use std::thread::sleep; | ||
/// | ||
/// let spinner = Spinner::new("Loading data...") | ||
/// .style(SpinnerStyle::line()) | ||
/// .run(|| { | ||
/// sleep(Duration::from_secs(2)); | ||
/// }) | ||
/// .expect("error running spinner"); | ||
/// ``` | ||
pub struct Spinner { | ||
// The title of the spinner | ||
pub title: String, | ||
// The style of the spinner | ||
pub style: SpinnerStyle, | ||
/// The colors/style of the spinner | ||
pub theme: Theme, | ||
|
||
term: Term, | ||
frame: usize, | ||
height: usize, | ||
} | ||
|
||
impl Spinner { | ||
/// Create a new spinner with the given title | ||
pub fn new<S: Into<String>>(title: S) -> Self { | ||
Self { | ||
title: title.into(), | ||
style: SpinnerStyle::line(), | ||
theme: Theme::default(), | ||
term: Term::stderr(), | ||
frame: 0, | ||
height: 0, | ||
} | ||
} | ||
|
||
/// Set the style of the spinner | ||
pub fn style(mut self, style: SpinnerStyle) -> Self { | ||
self.style = style; | ||
self | ||
} | ||
|
||
/// Set the theme of the dialog | ||
pub fn theme(mut self, theme: Theme) -> Self { | ||
self.theme = theme; | ||
self | ||
} | ||
|
||
/// Displays the dialog to the user and returns their response | ||
pub fn run<F>(mut self, func: F) -> io::Result<()> | ||
where | ||
F: Fn() + Send + 'static, | ||
{ | ||
let handle = std::thread::spawn(move || { | ||
func(); | ||
}); | ||
|
||
self.term.hide_cursor()?; | ||
loop { | ||
self.clear()?; | ||
let output = self.render()?; | ||
self.height = output.lines().count() - 1; | ||
self.term.write_all(output.as_bytes())?; | ||
sleep(self.style.fps); | ||
if handle.is_finished() { | ||
self.clear()?; | ||
self.term.show_cursor()?; | ||
break; | ||
} | ||
} | ||
Ok(()) | ||
} | ||
|
||
/// Render the spinner and return the output | ||
fn render(&mut self) -> io::Result<String> { | ||
let mut out = Buffer::ansi(); | ||
|
||
if self.frame > self.style.chars.len() - 1 { | ||
self.frame = 0 | ||
} | ||
|
||
out.set_color(&self.theme.input_prompt)?; | ||
write!(out, "{} ", self.style.chars[self.frame])?; | ||
out.reset()?; | ||
|
||
write!(out, "{}", self.title)?; | ||
|
||
self.frame += 1; | ||
|
||
Ok(std::str::from_utf8(out.as_slice()).unwrap().to_string()) | ||
} | ||
|
||
fn clear(&mut self) -> io::Result<()> { | ||
self.term.clear_to_end_of_screen()?; | ||
self.term.clear_last_lines(self.height)?; | ||
self.height = 0; | ||
Ok(()) | ||
} | ||
} | ||
|
||
/// The style of the spinner | ||
/// | ||
/// # Example | ||
/// ```rust | ||
/// use demand::SpinnerStyle; | ||
/// | ||
/// let style = SpinnerStyle::dots(); | ||
/// ``` | ||
pub struct SpinnerStyle { | ||
chars: Vec<&'static str>, | ||
fps: Duration, | ||
} | ||
|
||
impl SpinnerStyle { | ||
// Create a new spinner type of dots | ||
pub fn dots() -> Self { | ||
Self { | ||
chars: vec!["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"], | ||
fps: Duration::from_millis(1000 / 10), | ||
} | ||
} | ||
// Create a new spinner type of jump | ||
pub fn jump() -> Self { | ||
Self { | ||
chars: vec!["⢄", "⢂", "⢁", "⡁", "⡈", "⡐", "⡠"], | ||
fps: Duration::from_millis(1000 / 10), | ||
} | ||
} | ||
// Create a new spinner type of line | ||
pub fn line() -> Self { | ||
Self { | ||
chars: vec!["-", "\\", "|", "/"], | ||
fps: Duration::from_millis(1000 / 10), | ||
} | ||
} | ||
// Create a new spinner type of points | ||
pub fn points() -> Self { | ||
Self { | ||
chars: vec!["∙∙∙", "●∙∙", "∙●∙", "∙∙●"], | ||
fps: Duration::from_millis(1000 / 7), | ||
} | ||
} | ||
// Create a new spinner type of meter | ||
pub fn meter() -> Self { | ||
Self { | ||
chars: vec!["▱▱▱", "▰▱▱", "▰▰▱", "▰▰▰", "▰▰▱", "▰▱▱", "▱▱▱"], | ||
fps: Duration::from_millis(1000 / 7), | ||
} | ||
} | ||
// Create a new spinner type of mini dots | ||
pub fn minidots() -> Self { | ||
Self { | ||
chars: vec!["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"], | ||
fps: Duration::from_millis(1000 / 12), | ||
} | ||
} | ||
// Create a new spinner type of ellipsis | ||
pub fn ellipsis() -> Self { | ||
Self { | ||
chars: vec![" ", ". ", ".. ", "..."], | ||
fps: Duration::from_millis(1000 / 3), | ||
} | ||
} | ||
} |