Skip to main content

anstyle_progress/
progress.rs

1/// Terminal progress formatter
2///
3/// # Example
4///
5/// ```rust
6/// # use anstyle_progress::TermProgress;
7/// # use anstyle_progress::TermProgressStatus;
8/// let mut progress = anstyle_progress::TermProgress::none()
9///   .status(TermProgressStatus::Normal);
10///
11/// let progress = progress.percent(Some(0));
12/// println!("{progress}");
13///
14/// let progress = progress.percent(Some(50));
15/// println!("{progress}");
16///
17/// let progress = progress.percent(Some(100));
18/// println!("{progress}");
19///
20/// println!("{progress:#}");
21/// ```
22#[derive(Copy, Clone)]
23pub struct TermProgress {
24    status: Option<TermProgressStatus>,
25    percent: Option<u8>,
26}
27
28impl TermProgress {
29    /// No progress to display
30    pub fn none() -> Self {
31        Self {
32            status: None,
33            percent: None,
34        }
35    }
36
37    /// Change the reported status
38    pub fn status(mut self, status: TermProgressStatus) -> Self {
39        self.status = Some(status);
40        self
41    }
42
43    /// Between `0..=100`
44    pub fn percent(mut self, percent: Option<u8>) -> Self {
45        assert!(matches!(percent, Some(0..=100) | None));
46        self.percent = percent;
47        self
48    }
49}
50
51impl Default for TermProgress {
52    fn default() -> Self {
53        Self::none()
54    }
55}
56
57/// Reported status along with progress
58#[allow(missing_docs)]
59#[derive(Copy, Clone)]
60pub enum TermProgressStatus {
61    Normal,
62    Paused,
63    Error,
64}
65
66impl core::fmt::Display for TermProgress {
67    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
68        let Some(status) = self.status else {
69            return Ok(());
70        };
71        let st = match (f.alternate(), status, self.percent) {
72            (true, _, _) => 0,
73            (false, TermProgressStatus::Normal, Some(_)) => 1,
74            (false, TermProgressStatus::Error, _) => 2,
75            (false, TermProgressStatus::Normal, None) => 3,
76            (false, TermProgressStatus::Paused, _) => 4,
77        };
78        let pr = self.percent.unwrap_or(0);
79        write!(f, "\x1b]9;4;{st};{pr}\x1b\\")
80    }
81}