duplicate_finder/
progress_line.rs

1use crate::tty::{terminal_size, Width};
2use std::iter::repeat;
3
4macro_rules! repeat {
5    ($s: expr, $n: expr) => {{
6        &repeat($s).take($n).collect::<String>()
7    }};
8}
9
10pub struct ProgressLine {
11    pub total: u64,
12    pub current: u64,
13    pub width: Option<usize>,
14    pub message: String,
15    pub show_counters: bool,
16    pub show_message: bool,
17}
18
19impl ProgressLine {
20    pub fn to_string(&self) -> String {
21        let width = self.width();
22
23        let mut base = String::new();
24        let mut prefix = String::new();
25        let mut out;
26
27        if self.show_message {
28            prefix = prefix + &format!("{}", self.message)
29        }
30
31        if self.show_counters {
32            let (c, t) = (self.current as f64, self.total as f64);
33            let percent = self.current as f64 / (self.total as f64 / 100f64);
34
35            prefix = prefix
36                + &format!(
37                    "{}/{}, {:.*}%",
38                    c,
39                    t,
40                    2,
41                    if percent.is_nan() { 0.0 } else { percent }
42                );
43        }
44
45        let p = prefix.len() + 3;
46        if p < width {
47            let size = width - p;
48            let curr_count =
49                ((self.current as f64 / self.total as f64) * size as f64).ceil() as usize;
50            if size >= curr_count {
51                let rema_count = size - curr_count;
52                if rema_count > 0 && curr_count > 0 {
53                    base = "[".to_string() + repeat!("=", curr_count - 1) + ">";
54                } else {
55                    base = "[".to_string() + repeat!("=", curr_count);
56                }
57                base = base + repeat!("-", rema_count) + "] ";
58            }
59        }
60
61        out = base + &prefix;
62
63        if out.len() < width {
64            let gap = width - out.len();
65            out = out + repeat!(" ", gap);
66        }
67
68        out
69    }
70
71    pub fn to_empty_string(&self) -> String {
72        repeat!(" ", self.width()).to_string()
73    }
74
75    fn width(&self) -> usize {
76        if let Some(w) = self.width {
77            w
78        } else if let Some((Width(w), _)) = terminal_size() {
79            w as usize
80        } else {
81            80
82        }
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    const MESSAGE: &str = "some. ";
91
92    #[test]
93    fn converts_self_to_string_full_1() {
94        let line = create_progress_line(100, 0, Some(80), MESSAGE.to_string(), true, true);
95
96        assert_eq!(
97            "[-----------------------------------------------------------] some. 0/100, 0.00%",
98            line.to_string()
99        );
100    }
101
102    #[test]
103    fn converts_self_to_string_full_2() {
104        let line = create_progress_line(100, 10, Some(80), MESSAGE.to_string(), true, true);
105
106        assert_eq!(
107            "[=====>---------------------------------------------------] some. 10/100, 10.00%",
108            line.to_string()
109        );
110    }
111
112    #[test]
113    fn converts_self_to_string_full_3() {
114        let line = create_progress_line(100, 90, Some(80), MESSAGE.to_string(), true, true);
115
116        assert_eq!(
117            "[===================================================>-----] some. 90/100, 90.00%",
118            line.to_string()
119        );
120    }
121
122    #[test]
123    fn converts_self_to_string_full_4() {
124        let line = create_progress_line(100, 50, Some(80), MESSAGE.to_string(), true, true);
125
126        assert_eq!(
127            "[============================>----------------------------] some. 50/100, 50.00%",
128            line.to_string()
129        );
130    }
131
132    #[test]
133    fn converts_self_to_string_full_5() {
134        let line = create_progress_line(100, 100, Some(80), MESSAGE.to_string(), true, true);
135
136        assert_eq!(
137            "[=======================================================] some. 100/100, 100.00%",
138            line.to_string()
139        );
140    }
141
142    #[test]
143    fn converts_self_to_string_file() {
144        let line = create_progress_line(100, 34, Some(100), MESSAGE.to_string(), false, true);
145
146        assert_eq!(
147            "[==============================>------------------------------------------------------------] some. ",
148            line.to_string()
149        );
150    }
151
152    #[test]
153    fn converts_self_to_string_summary() {
154        let line = create_progress_line(41200, 6333, Some(60), String::new(), true, false);
155
156        assert_eq!(
157            "[=====>---------------------------------] 6333/41200, 15.37%",
158            line.to_string()
159        );
160    }
161
162    fn create_progress_line(
163        total: u64,
164        current: u64,
165        width: Option<usize>,
166        message: String,
167        show_counters: bool,
168        show_message: bool,
169    ) -> super::ProgressLine {
170        ProgressLine {
171            total,
172            current,
173            width,
174            message,
175            show_counters,
176            show_message,
177        }
178    }
179}