Skip to main content

pito_tui/
progress.rs

1use std::time::Duration;
2
3pub const SPIN: Duration = Duration::from_millis(80);
4pub const SPINNER: [&str; 10] = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
5pub const ABOUT: &str = "≈";
6
7const LADDER: [char; 8] = ['⡀', '⡄', '⡆', '⡇', '⣇', '⣧', '⣷', '⣿'];
8const TRACK: char = '⣀';
9
10fn clean(fraction: f64) -> f64 {
11    if fraction.is_nan() {
12        0.0
13    } else {
14        fraction.clamp(0.0, 1.0)
15    }
16}
17
18pub fn bar(fraction: f64, cells: usize) -> String {
19    let total = cells * 8;
20    let steps = ((clean(fraction) * total as f64).floor() as usize).min(total);
21    let (full, part) = (steps / 8, steps % 8);
22    let mut text: String = std::iter::repeat_n(LADDER[7], full).collect();
23    if part > 0 {
24        text.push(LADDER[part - 1]);
25    }
26    let used = full + usize::from(part > 0);
27    text.extend(std::iter::repeat_n(TRACK, cells.saturating_sub(used)));
28    text
29}
30
31pub fn percent(fraction: f64) -> u32 {
32    (clean(fraction) * 100.0).floor() as u32
33}
34
35pub fn share(fraction: f64, estimate: bool) -> String {
36    let about = if estimate { ABOUT } else { "" };
37    format!("{about}{}%", percent(fraction))
38}
39
40pub fn spinner(gone: Duration) -> &'static str {
41    let frame = gone.as_nanos() / SPIN.as_nanos();
42    SPINNER[(frame % SPINNER.len() as u128) as usize]
43}