Skip to main content

tftio_lib/
progress.rs

1//! Shared progress indicator helpers.
2
3use std::time::Duration;
4
5use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
6
7use crate::output::stderr_is_tty;
8
9/// Build a stderr spinner when interactive progress is enabled.
10#[must_use]
11pub fn make_spinner(enabled: bool, message: &str) -> Option<ProgressBar> {
12    if !enabled || !stderr_is_tty() {
13        return None;
14    }
15
16    let progress_bar = ProgressBar::with_draw_target(None, ProgressDrawTarget::stderr());
17    let style = ProgressStyle::default_spinner()
18        .template("{spinner:.green} {msg}")
19        .unwrap_or_else(|_| ProgressStyle::default_spinner());
20    progress_bar.set_style(style);
21    progress_bar.set_message(message.to_owned());
22    progress_bar.enable_steady_tick(Duration::from_millis(120));
23
24    Some(progress_bar)
25}
26
27#[cfg(test)]
28mod tests {
29    use super::*;
30
31    #[test]
32    fn make_spinner_returns_none_when_disabled() {
33        assert!(make_spinner(false, "x").is_none());
34    }
35
36    #[test]
37    fn make_spinner_returns_none_without_a_tty() {
38        // Under the test harness stderr is not a terminal, so an enabled
39        // spinner is still suppressed. The interactive construction body
40        // (lines that build and tick the ProgressBar) requires a real TTY
41        // and is left to the accepted TTY-gated coverage residual.
42        assert!(make_spinner(true, "working").is_none());
43    }
44}