pub struct Spinner {
pub tick_delay: Duration,
pub message: String,
pub style: SpinnerStyle,
pub safe_output_terminal: SafeRawTerminal,
pub shared_writer: SharedWriter,
pub shutdown_sender: Sender<()>,
/* private fields */
}
Fields§
§tick_delay: Duration
§message: String
§style: SpinnerStyle
§safe_output_terminal: SafeRawTerminal
§shutdown_sender: Sender<()>
Implementations§
Source§impl Spinner
impl Spinner
Sourcepub async fn try_start(
spinner_message: String,
tick_delay: Duration,
style: SpinnerStyle,
safe_output_terminal: SafeRawTerminal,
shared_writer: SharedWriter,
) -> Result<Option<Spinner>>
pub async fn try_start( spinner_message: String, tick_delay: Duration, style: SpinnerStyle, safe_output_terminal: SafeRawTerminal, shared_writer: SharedWriter, ) -> Result<Option<Spinner>>
Create a new instance of Spinner.
§Returns
- This will return an error if the task is already running.
- If the terminal is not fully interactive then it will return None, and won’t
start the task. This is when the terminal is not considered fully interactive:
stdout
is piped, eg:echo "foo" | cargo run --example spinner
.- or all three
stdin
,stdout
,stderr
are notis_tty
, eg when running incargo test
.
- Otherwise, it will start the task and return a Spinner instance.
More info on terminal piping:
Examples found in repository?
examples/spinner.rs (lines 73-79)
61async fn example_with_concurrent_output(style: SpinnerStyle) -> miette::Result<()> {
62 let terminal_async = TerminalAsync::try_new("$ ").await?;
63 let terminal_async = terminal_async.expect("terminal is not fully interactive");
64 let address = "127.0.0.1:8000";
65 let message_trying_to_connect = format!(
66 "This is a sample indeterminate progress message: trying to connect to server on {}",
67 &address
68 );
69
70 let mut shared_writer = terminal_async.clone_shared_writer();
71
72 // Start spinner. Automatically pauses the terminal.
73 let mut maybe_spinner = Spinner::try_start(
74 message_trying_to_connect.clone(),
75 DELAY_UNIT,
76 style,
77 Arc::new(StdMutex::new(stderr())),
78 shared_writer.clone(),
79 )
80 .await?;
81
82 // Start another task, to simulate some async work, that uses a interval to display
83 // output, for a fixed amount of time, using `terminal_async.println_prefixed()`.
84 let _ = try_join!(tokio::spawn(async move {
85 // To calculate the delay.
86 let duration = ARTIFICIAL_UI_DELAY;
87 let start = Instant::now();
88
89 // Dropping the interval cancels it.
90 let mut interval = tokio::time::interval(Duration::from_millis(DELAY_MS * 5));
91
92 loop {
93 interval.tick().await;
94 let elapsed = start.elapsed();
95 if elapsed >= duration {
96 break;
97 }
98 let _ = writeln!(shared_writer, "⏳foo");
99 }
100 }));
101
102 // Stop spinner. Automatically resumes the terminal.
103 if let Some(spinner) = maybe_spinner.as_mut() {
104 spinner
105 .stop("This is a sample final message for the spinner component: Connected to server")
106 .await?;
107 }
108
109 tokio::time::sleep(Duration::from_millis(500)).await;
110
111 Ok(())
112}
More examples
examples/terminal_async.rs (lines 386-395)
362 pub fn spawn_task_that_shows_spinner(
363 shared_writer: &mut SharedWriter,
364 readline: &mut Readline,
365 task_name: &str,
366 delay: Duration,
367 ) {
368 let mut interval = interval(delay);
369 let mut tick_counter = 0;
370 let max_tick_count = 30;
371
372 let task_name = task_name.to_string();
373
374 let shared_writer_clone_1 = shared_writer.clone();
375 let mut shared_writer_clone_2 = shared_writer.clone();
376
377 if readline.safe_spinner_is_active.lock().unwrap().is_some() {
378 _ = writeln!(
379 shared_writer,
380 "Spinner is already active, can't start another one"
381 );
382 }
383
384 tokio::spawn(async move {
385 // Try to create and start a spinner.
386 let maybe_spinner = Spinner::try_start(
387 format!(
388 "{} - This is a sample indeterminate progress message",
389 task_name
390 ),
391 Duration::from_millis(100),
392 SpinnerStyle::default(),
393 Arc::new(StdMutex::new(stderr())),
394 shared_writer_clone_1,
395 )
396 .await;
397
398 loop {
399 // Check for spinner shutdown (via interruption).
400 if let Ok(Some(ref spinner)) = maybe_spinner {
401 if spinner.is_shutdown() {
402 break;
403 }
404 }
405
406 // Wait for the interval duration (one tick).
407 interval.tick().await;
408
409 // Don't print more than `max_tick_count` times.
410 tick_counter += 1;
411 if tick_counter >= max_tick_count {
412 break;
413 }
414
415 // Display a message at every tick.
416 let _ = writeln!(
417 shared_writer_clone_2,
418 "[{task_name}] - [{tick_counter}] interval went off while spinner was spinning!"
419 );
420 }
421
422 // Don't forget to stop the spinner.
423 if let Ok(Some(mut spinner)) = maybe_spinner {
424 let msg = format!("{} - Task ended. Resuming terminal and showing any output that was generated while spinner was active.", task_name);
425 let _ = spinner.stop(msg.as_str()).await;
426 }
427 });
428 }
Sourcepub fn is_shutdown(&self) -> bool
pub fn is_shutdown(&self) -> bool
This is meant for the task that spawned this Spinner to check if it should shutdown, due to:
- The user pressing
Ctrl-C
orCtrl-D
. - Or the Spinner::stop got called.
Examples found in repository?
examples/terminal_async.rs (line 401)
362 pub fn spawn_task_that_shows_spinner(
363 shared_writer: &mut SharedWriter,
364 readline: &mut Readline,
365 task_name: &str,
366 delay: Duration,
367 ) {
368 let mut interval = interval(delay);
369 let mut tick_counter = 0;
370 let max_tick_count = 30;
371
372 let task_name = task_name.to_string();
373
374 let shared_writer_clone_1 = shared_writer.clone();
375 let mut shared_writer_clone_2 = shared_writer.clone();
376
377 if readline.safe_spinner_is_active.lock().unwrap().is_some() {
378 _ = writeln!(
379 shared_writer,
380 "Spinner is already active, can't start another one"
381 );
382 }
383
384 tokio::spawn(async move {
385 // Try to create and start a spinner.
386 let maybe_spinner = Spinner::try_start(
387 format!(
388 "{} - This is a sample indeterminate progress message",
389 task_name
390 ),
391 Duration::from_millis(100),
392 SpinnerStyle::default(),
393 Arc::new(StdMutex::new(stderr())),
394 shared_writer_clone_1,
395 )
396 .await;
397
398 loop {
399 // Check for spinner shutdown (via interruption).
400 if let Ok(Some(ref spinner)) = maybe_spinner {
401 if spinner.is_shutdown() {
402 break;
403 }
404 }
405
406 // Wait for the interval duration (one tick).
407 interval.tick().await;
408
409 // Don't print more than `max_tick_count` times.
410 tick_counter += 1;
411 if tick_counter >= max_tick_count {
412 break;
413 }
414
415 // Display a message at every tick.
416 let _ = writeln!(
417 shared_writer_clone_2,
418 "[{task_name}] - [{tick_counter}] interval went off while spinner was spinning!"
419 );
420 }
421
422 // Don't forget to stop the spinner.
423 if let Ok(Some(mut spinner)) = maybe_spinner {
424 let msg = format!("{} - Task ended. Resuming terminal and showing any output that was generated while spinner was active.", task_name);
425 let _ = spinner.stop(msg.as_str()).await;
426 }
427 });
428 }
Sourcepub async fn stop(&mut self, final_message: &str) -> Result<()>
pub async fn stop(&mut self, final_message: &str) -> Result<()>
Examples found in repository?
examples/spinner.rs (line 105)
61async fn example_with_concurrent_output(style: SpinnerStyle) -> miette::Result<()> {
62 let terminal_async = TerminalAsync::try_new("$ ").await?;
63 let terminal_async = terminal_async.expect("terminal is not fully interactive");
64 let address = "127.0.0.1:8000";
65 let message_trying_to_connect = format!(
66 "This is a sample indeterminate progress message: trying to connect to server on {}",
67 &address
68 );
69
70 let mut shared_writer = terminal_async.clone_shared_writer();
71
72 // Start spinner. Automatically pauses the terminal.
73 let mut maybe_spinner = Spinner::try_start(
74 message_trying_to_connect.clone(),
75 DELAY_UNIT,
76 style,
77 Arc::new(StdMutex::new(stderr())),
78 shared_writer.clone(),
79 )
80 .await?;
81
82 // Start another task, to simulate some async work, that uses a interval to display
83 // output, for a fixed amount of time, using `terminal_async.println_prefixed()`.
84 let _ = try_join!(tokio::spawn(async move {
85 // To calculate the delay.
86 let duration = ARTIFICIAL_UI_DELAY;
87 let start = Instant::now();
88
89 // Dropping the interval cancels it.
90 let mut interval = tokio::time::interval(Duration::from_millis(DELAY_MS * 5));
91
92 loop {
93 interval.tick().await;
94 let elapsed = start.elapsed();
95 if elapsed >= duration {
96 break;
97 }
98 let _ = writeln!(shared_writer, "⏳foo");
99 }
100 }));
101
102 // Stop spinner. Automatically resumes the terminal.
103 if let Some(spinner) = maybe_spinner.as_mut() {
104 spinner
105 .stop("This is a sample final message for the spinner component: Connected to server")
106 .await?;
107 }
108
109 tokio::time::sleep(Duration::from_millis(500)).await;
110
111 Ok(())
112}
More examples
examples/terminal_async.rs (line 425)
362 pub fn spawn_task_that_shows_spinner(
363 shared_writer: &mut SharedWriter,
364 readline: &mut Readline,
365 task_name: &str,
366 delay: Duration,
367 ) {
368 let mut interval = interval(delay);
369 let mut tick_counter = 0;
370 let max_tick_count = 30;
371
372 let task_name = task_name.to_string();
373
374 let shared_writer_clone_1 = shared_writer.clone();
375 let mut shared_writer_clone_2 = shared_writer.clone();
376
377 if readline.safe_spinner_is_active.lock().unwrap().is_some() {
378 _ = writeln!(
379 shared_writer,
380 "Spinner is already active, can't start another one"
381 );
382 }
383
384 tokio::spawn(async move {
385 // Try to create and start a spinner.
386 let maybe_spinner = Spinner::try_start(
387 format!(
388 "{} - This is a sample indeterminate progress message",
389 task_name
390 ),
391 Duration::from_millis(100),
392 SpinnerStyle::default(),
393 Arc::new(StdMutex::new(stderr())),
394 shared_writer_clone_1,
395 )
396 .await;
397
398 loop {
399 // Check for spinner shutdown (via interruption).
400 if let Ok(Some(ref spinner)) = maybe_spinner {
401 if spinner.is_shutdown() {
402 break;
403 }
404 }
405
406 // Wait for the interval duration (one tick).
407 interval.tick().await;
408
409 // Don't print more than `max_tick_count` times.
410 tick_counter += 1;
411 if tick_counter >= max_tick_count {
412 break;
413 }
414
415 // Display a message at every tick.
416 let _ = writeln!(
417 shared_writer_clone_2,
418 "[{task_name}] - [{tick_counter}] interval went off while spinner was spinning!"
419 );
420 }
421
422 // Don't forget to stop the spinner.
423 if let Ok(Some(mut spinner)) = maybe_spinner {
424 let msg = format!("{} - Task ended. Resuming terminal and showing any output that was generated while spinner was active.", task_name);
425 let _ = spinner.stop(msg.as_str()).await;
426 }
427 });
428 }
Auto Trait Implementations§
impl Freeze for Spinner
impl !RefUnwindSafe for Spinner
impl Send for Spinner
impl Sync for Spinner
impl Unpin for Spinner
impl !UnwindSafe for Spinner
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
Converts
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
Converts
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§impl<D> OwoColorize for D
impl<D> OwoColorize for D
Source§fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>where
C: Color,
fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>where
C: Color,
Set the foreground color generically Read more
Source§fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>where
C: Color,
fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>where
C: Color,
Set the background color generically. Read more
Source§fn black(&self) -> FgColorDisplay<'_, Black, Self>
fn black(&self) -> FgColorDisplay<'_, Black, Self>
Change the foreground color to black
Source§fn on_black(&self) -> BgColorDisplay<'_, Black, Self>
fn on_black(&self) -> BgColorDisplay<'_, Black, Self>
Change the background color to black
Source§fn red(&self) -> FgColorDisplay<'_, Red, Self>
fn red(&self) -> FgColorDisplay<'_, Red, Self>
Change the foreground color to red
Source§fn on_red(&self) -> BgColorDisplay<'_, Red, Self>
fn on_red(&self) -> BgColorDisplay<'_, Red, Self>
Change the background color to red
Source§fn green(&self) -> FgColorDisplay<'_, Green, Self>
fn green(&self) -> FgColorDisplay<'_, Green, Self>
Change the foreground color to green
Source§fn on_green(&self) -> BgColorDisplay<'_, Green, Self>
fn on_green(&self) -> BgColorDisplay<'_, Green, Self>
Change the background color to green
Source§fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>
fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>
Change the foreground color to yellow
Source§fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>
fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>
Change the background color to yellow
Source§fn blue(&self) -> FgColorDisplay<'_, Blue, Self>
fn blue(&self) -> FgColorDisplay<'_, Blue, Self>
Change the foreground color to blue
Source§fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>
fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>
Change the background color to blue
Source§fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>
fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>
Change the foreground color to magenta
Source§fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>
fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>
Change the background color to magenta
Source§fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>
fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>
Change the foreground color to purple
Source§fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>
fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>
Change the background color to purple
Source§fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>
fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>
Change the foreground color to cyan
Source§fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>
fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>
Change the background color to cyan
Source§fn white(&self) -> FgColorDisplay<'_, White, Self>
fn white(&self) -> FgColorDisplay<'_, White, Self>
Change the foreground color to white
Source§fn on_white(&self) -> BgColorDisplay<'_, White, Self>
fn on_white(&self) -> BgColorDisplay<'_, White, Self>
Change the background color to white
Source§fn default_color(&self) -> FgColorDisplay<'_, Default, Self>
fn default_color(&self) -> FgColorDisplay<'_, Default, Self>
Change the foreground color to the terminal default
Source§fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>
fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>
Change the background color to the terminal default
Source§fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>
fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>
Change the foreground color to bright black
Source§fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>
fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>
Change the background color to bright black
Source§fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>
fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>
Change the foreground color to bright red
Source§fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>
fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>
Change the background color to bright red
Source§fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>
fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>
Change the foreground color to bright green
Source§fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>
fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>
Change the background color to bright green
Source§fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>
fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>
Change the foreground color to bright yellow
Source§fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>
fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>
Change the background color to bright yellow
Source§fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>
fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>
Change the foreground color to bright blue
Source§fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>
fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>
Change the background color to bright blue
Source§fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
Change the foreground color to bright magenta
Source§fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
Change the background color to bright magenta
Source§fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>
Change the foreground color to bright purple
Source§fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>
Change the background color to bright purple
Source§fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>
fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>
Change the foreground color to bright cyan
Source§fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>
fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>
Change the background color to bright cyan
Source§fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>
fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>
Change the foreground color to bright white
Source§fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>
fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>
Change the background color to bright white
Source§fn bold(&self) -> BoldDisplay<'_, Self>
fn bold(&self) -> BoldDisplay<'_, Self>
Make the text bold
Source§fn dimmed(&self) -> DimDisplay<'_, Self>
fn dimmed(&self) -> DimDisplay<'_, Self>
Make the text dim
Source§fn italic(&self) -> ItalicDisplay<'_, Self>
fn italic(&self) -> ItalicDisplay<'_, Self>
Make the text italicized
Source§fn underline(&self) -> UnderlineDisplay<'_, Self>
fn underline(&self) -> UnderlineDisplay<'_, Self>
Make the text underlined
Source§fn blink(&self) -> BlinkDisplay<'_, Self>
fn blink(&self) -> BlinkDisplay<'_, Self>
Make the text blink
Source§fn blink_fast(&self) -> BlinkFastDisplay<'_, Self>
fn blink_fast(&self) -> BlinkFastDisplay<'_, Self>
Make the text blink (but fast!)
Source§fn reversed(&self) -> ReversedDisplay<'_, Self>
fn reversed(&self) -> ReversedDisplay<'_, Self>
Swap the foreground and background colors
Hide the text
Source§fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>
fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>
Cross out the text
Source§fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
Set the foreground color at runtime. Only use if you do not know which color will be used at
compile-time. If the color is constant, use either
OwoColorize::fg
or
a color-specific method, such as OwoColorize::green
, Read moreSource§fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>where
Color: DynColor,
Set the background color at runtime. Only use if you do not know what color to use at
compile-time. If the color is constant, use either
OwoColorize::bg
or
a color-specific method, such as OwoColorize::on_yellow
, Read moreSource§fn fg_rgb<const R: u8, const G: u8, const B: u8>(
&self,
) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>
fn fg_rgb<const R: u8, const G: u8, const B: u8>( &self, ) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>
Set the foreground color to a specific RGB value.
Source§fn bg_rgb<const R: u8, const G: u8, const B: u8>(
&self,
) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>
fn bg_rgb<const R: u8, const G: u8, const B: u8>( &self, ) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>
Set the background color to a specific RGB value.
Source§fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>
fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>
Sets the foreground color to an RGB value.
Source§fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>
fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>
Sets the background color to an RGB value.