multi_progressbar/bar/
block.rs

1use crate::{ProgressBar, TaskProgress};
2
3/// BlockProgressBar is a progress bar using block characters to show progress.
4pub struct BlockProgressBar<T: TaskProgress> {
5    _phantom: std::marker::PhantomData<T>,
6}
7
8impl<T> BlockProgressBar<T>
9where
10    T: TaskProgress,
11{
12    /// creates a new BlockProgressBar.
13    pub fn new() -> Self {
14        BlockProgressBar {
15            _phantom: std::marker::PhantomData,
16        }
17    }
18}
19
20impl<T> BlockProgressBar<T>
21where
22    T: TaskProgress,
23{
24    fn block_char(width: usize, progress: f64) -> String {
25        let block_chars = [' ', '▏', '▎', '▍', '▌', '▋', '▊', '▉', '█'];
26        let progress_in_block = progress * width as f64;
27        let complete_blocks = progress_in_block.floor() as usize;
28        let remainder = progress_in_block - complete_blocks as f64;
29        let mut bar = String::new();
30        bar.push_str(&"█".repeat(complete_blocks));
31        if remainder > 0.0 {
32            let remainder_index = (remainder * 8.0).floor() as usize;
33            bar.push(block_chars[remainder_index]);
34        }
35        bar.push_str(&" ".repeat(width - complete_blocks));
36        bar
37    }
38}
39
40impl<T> ProgressBar for BlockProgressBar<T>
41where
42    T: TaskProgress,
43{
44    type Task = T;
45    fn format_line(&self, progress: &Self::Task, width: usize) -> String {
46        let (before, after) = (progress.before(), progress.after());
47        let (current, total) = progress.progress();
48
49        if total == 0 {
50            return " ".repeat(width);
51        }
52
53        let before_len = before.as_ref().map(|s| s.len()).unwrap_or(0);
54        let after_len = after.as_ref().map(|s| s.len()).unwrap_or(0);
55
56        // check if we have enough space to show progress bar
57        if before_len + after_len + 2 > width {
58            return " ".repeat(width);
59        }
60
61        let bar_width = width - before_len - after_len - 2;
62        let bar_progress = current as f64 / total as f64;
63
64        let mut bar = String::new();
65        bar.push_str(&before.unwrap_or_default());
66        bar.push('[');
67        bar.push_str(&Self::block_char(bar_width, bar_progress));
68        bar.push(']');
69        bar.push_str(&after.unwrap_or_default());
70        bar
71    }
72}