1use std::io::{self, Write};
4use std::time::Instant;
5
6use crate::spinner::Spinner;
7
8pub struct Status {
20 pub spinner: Spinner,
21 pub status: String,
22 pub started: Option<Instant>,
23}
24
25impl std::fmt::Debug for Status {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 f.debug_struct("Status")
28 .field("status", &self.status)
29 .field("started", &self.started)
30 .finish()
31 }
32}
33
34impl Status {
35 pub fn new(status: impl Into<String>) -> Self {
37 Self {
38 spinner: Spinner::default(),
39 status: status.into(),
40 started: None,
41 }
42 }
43
44 pub fn spinner(mut self, spinner: Spinner) -> Self {
46 self.spinner = spinner;
47 self
48 }
49
50 pub fn start(&mut self) -> io::Result<()> {
52 self.started = Some(Instant::now());
53 self.write_status()
54 }
55
56 pub fn update(&mut self, status: impl Into<String>) -> io::Result<()> {
58 self.status = status.into();
59 self.write_status()
60 }
61
62 pub fn stop(&mut self) -> io::Result<()> {
64 let _ = write!(io::stdout(), "\r\x1b[K");
66 let _ = io::stdout().flush();
67 self.started = None;
68 Ok(())
69 }
70
71 pub fn refresh(&mut self) -> io::Result<()> {
73 self.write_status()
74 }
75
76 fn write_status(&mut self) -> io::Result<()> {
77 let elapsed = self.started.map(|s| s.elapsed()).unwrap_or_default();
78 let spinner_str = self.spinner.render(elapsed);
79 write!(io::stdout(), "\r{spinner_str} {}", self.status)?;
80 io::stdout().flush()
81 }
82}