1use std::io::{self, Write};
4use std::time::Instant;
5
6use crate::spinner::Spinner;
7
8pub 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 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 pub fn spinner(mut self, spinner: Spinner) -> Self { self.spinner = spinner; self }
45
46 pub fn start(&mut self) -> io::Result<()> {
48 self.started = Some(Instant::now());
49 self.write_status()
50 }
51
52 pub fn update(&mut self, status: impl Into<String>) -> io::Result<()> {
54 self.status = status.into();
55 self.write_status()
56 }
57
58 pub fn stop(&mut self) -> io::Result<()> {
60 let _ = write!(io::stdout(), "\r\x1b[K");
62 let _ = io::stdout().flush();
63 self.started = None;
64 Ok(())
65 }
66
67 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}