Skip to main content

tidepool_gvm/
progress_flat.rs

1//! Basic progress display system
2//!
3//! Inspired by the simple progress display style of tools like Scoop.
4
5use std::io::{self, Write};
6
7/// Basic progress indicator
8#[derive(Clone)]
9pub struct BasicProgress {
10    label: String,
11    use_colors: bool,
12}
13
14impl BasicProgress {
15    /// Creates a new progress indicator
16    pub fn new(label: String) -> Self {
17        let use_colors = Self::should_use_colors();
18        Self { label, use_colors }
19    }
20
21    /// Detects if colors should be used
22    fn should_use_colors() -> bool {
23        std::env::var("NO_COLOR").is_err() && std::env::var("TERM").unwrap_or_default() != "dumb"
24    }
25
26    /// Displays progress (Scoop style)
27    pub fn show(&self, percent: f64, info: Option<&str>) {
28        let bar_width = 50;
29        let filled = (percent * bar_width as f64) as usize;
30        let empty = bar_width - filled;
31
32        // Build progress bar with simple characters
33        let bar = format!("{}{}", "=".repeat(filled), " ".repeat(empty));
34
35        let info_text = info.unwrap_or("");
36
37        // Both branches are the same, merged into one
38        print!("\r{} [{}] {:.0}% {}", self.label, bar, percent * 100.0, info_text);
39
40        io::stdout().flush().ok();
41    }
42
43    /// Displays download progress
44    pub fn show_download(&self, downloaded: u64, total: u64) {
45        let percent = if total > 0 { downloaded as f64 / total as f64 } else { 0.0 };
46        let info = if total > 0 {
47            format!("{}/{}", format_size(downloaded), format_size(total))
48        } else {
49            format_size(downloaded)
50        };
51        self.show(percent, Some(&info));
52    }
53
54    /// Finalizes the progress display as done
55    pub fn done(&self, message: &str) {
56        println!();
57        if self.use_colors {
58            println!("{message} ... \x1b[32mdone\x1b[0m.");
59        } else {
60            println!("{message} ... done.");
61        }
62    }
63
64    /// Finalizes the progress display as failed
65    pub fn failed(&self, message: &str) {
66        println!();
67        if self.use_colors {
68            println!("{message} ... \x1b[31mfailed\x1b[0m.");
69        } else {
70            println!("{message} ... failed.");
71        }
72    }
73}
74
75/// Installation steps manager
76pub struct InstallSteps {
77    use_colors: bool,
78}
79
80impl Default for InstallSteps {
81    fn default() -> Self {
82        Self::new()
83    }
84}
85
86impl InstallSteps {
87    pub fn new() -> Self {
88        let use_colors = std::env::var("NO_COLOR").is_err()
89            && std::env::var("TERM").unwrap_or_default() != "dumb";
90        Self { use_colors }
91    }
92
93    /// Displays the start of the installation
94    pub fn start(&self, version: &str) {
95        if self.use_colors {
96            println!("\x1b[36mInstalling 'go' ({version}) [64bit] from 'workspace'\x1b[0m");
97        } else {
98            println!("Installing 'go' ({version}) [64bit] from 'workspace'");
99        }
100    }
101
102    /// Displays step information
103    pub fn info(&self, message: &str) {
104        if self.use_colors {
105            println!("\x1b[90m{message}\x1b[0m");
106        } else {
107            println!("{message}");
108        }
109    }
110
111    /// Displays a warning message
112    pub fn warn(&self, message: &str) {
113        if self.use_colors {
114            println!("\x1b[33mWARN\x1b[0m {message}");
115        } else {
116            println!("WARN {message}");
117        }
118    }
119
120    /// Displays the completion message
121    pub fn complete(&self, version: &str) {
122        if self.use_colors {
123            println!("\x1b[32m'go' ({version}) was installed successfully!\x1b[0m");
124        } else {
125            println!("'go' ({version}) was installed successfully!");
126        }
127    }
128}
129
130/// Formats a file size (simplified version)
131fn format_size(bytes: u64) -> String {
132    const UNITS: &[&str] = &["B", "KB", "MB", "GB"];
133    let mut size = bytes as f64;
134    let mut unit_index = 0;
135
136    while size >= 1024.0 && unit_index < UNITS.len() - 1 {
137        size /= 1024.0;
138        unit_index += 1;
139    }
140
141    if unit_index == 0 {
142        format!("{bytes} {}", UNITS[unit_index])
143    } else {
144        format!("{size:.1}{}", UNITS[unit_index])
145    }
146}
147
148#[cfg(test)]
149mod tests {
150    use super::*;
151
152    #[test]
153    fn test_format_size() {
154        assert_eq!(format_size(1024), "1.0KB");
155        assert_eq!(format_size(1048576), "1.0MB");
156        assert_eq!(format_size(500), "500 B");
157    }
158
159    #[test]
160    fn test_basic_progress_creation() {
161        let progress = BasicProgress::new("Testing".to_string());
162        assert_eq!(progress.label, "Testing");
163    }
164}