Skip to main content

rusty_rich/
status.rs

1//! Status — status message with spinner. Equivalent to Rich's `status.py`.
2
3use std::io::{self, Write};
4use std::time::Instant;
5
6use crate::spinner::Spinner;
7
8/// A status message rendered with an animated spinner.
9///
10/// Usage:
11/// ```ignore
12/// let status = Status::new("Working...");
13/// status.start();
14/// // do work...
15/// status.update("Still working...");
16/// status.stop();
17/// ```
18pub struct Status {
19    pub spinner: Spinner,
20    pub status: String,
21    pub started: Option<Instant>,
22}
23
24impl std::fmt::Debug for Status {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        f.debug_struct("Status")
27            .field("status", &self.status)
28            .field("started", &self.started)
29            .finish()
30    }
31}
32
33impl Status {
34    /// Create a new Status with the given message.
35    pub fn new(status: impl Into<String>) -> Self {
36        Self {
37            spinner: Spinner::default(),
38            status: status.into(),
39            started: None,
40        }
41    }
42
43    /// Builder: replace the default spinner with a custom [`Spinner`].
44    pub fn spinner(mut self, spinner: Spinner) -> Self { self.spinner = spinner; self }
45
46    /// Start displaying the status.
47    pub fn start(&mut self) -> io::Result<()> {
48        self.started = Some(Instant::now());
49        self.write_status()
50    }
51
52    /// Update the status message.
53    pub fn update(&mut self, status: impl Into<String>) -> io::Result<()> {
54        self.status = status.into();
55        self.write_status()
56    }
57
58    /// Stop the status display (clears the line).
59    pub fn stop(&mut self) -> io::Result<()> {
60        // Carriage return + clear line
61        let _ = write!(io::stdout(), "\r\x1b[K");
62        let _ = io::stdout().flush();
63        self.started = None;
64        Ok(())
65    }
66
67    /// Refresh the display.
68    pub fn refresh(&mut self) -> io::Result<()> {
69        self.write_status()
70    }
71
72    fn write_status(&mut self) -> io::Result<()> {
73        let elapsed = self.started.map(|s| s.elapsed()).unwrap_or_default();
74        let spinner_str = self.spinner.render(elapsed);
75        write!(io::stdout(), "\r{spinner_str} {}", self.status)?;
76        io::stdout().flush()
77    }
78}