cargo_plugin_utils/
tty.rs

1//! TTY detection utilities for respecting cargo's progress settings.
2
3/// Check if progress should be shown based on cargo's term.progress.when
4/// setting (respects CARGO_TERM_PROGRESS_WHEN environment variable).
5///
6/// Returns `true` if progress should be shown, `false` otherwise.
7///
8/// # Values
9///
10/// - `"never"` - Never show progress
11/// - `"always"` - Always show progress
12/// - `"auto"` (default) - Show if stdout is a TTY (interactive terminal)
13///
14/// # Examples
15///
16/// ```no_run
17/// use cargo_plugin_utils::should_show_progress;
18///
19/// if should_show_progress() {
20///     // Show progress bar
21/// }
22/// ```
23#[allow(clippy::disallowed_methods)] // CLI tool needs direct env access
24pub fn should_show_progress() -> bool {
25    // Respect cargo's term.progress.when setting
26    // Values: "auto" (default), "always", "never"
27    match std::env::var("CARGO_TERM_PROGRESS_WHEN")
28        .as_deref()
29        .unwrap_or("auto")
30    {
31        "never" => false,
32        "always" => true,
33        "auto" => {
34            // Auto: show if stdout is a TTY (interactive terminal)
35            atty::is(atty::Stream::Stdout)
36        }
37        _ => {
38            // Default to auto behavior for unknown values
39            atty::is(atty::Stream::Stdout)
40        }
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use std::env;
47
48    use super::*;
49
50    /// Helper to run a test with a specific env var value, then restore
51    /// original
52    fn with_env_var<F, R>(key: &str, value: Option<&str>, test_fn: F) -> R
53    where
54        F: FnOnce() -> R,
55    {
56        let original = env::var(key).ok();
57        match value {
58            Some(val) => unsafe { env::set_var(key, val) },
59            None => unsafe { env::remove_var(key) },
60        }
61        let result = test_fn();
62        match original {
63            Some(val) => unsafe { env::set_var(key, &val) },
64            None => unsafe { env::remove_var(key) },
65        }
66        result
67    }
68
69    #[test]
70    fn test_should_show_progress_default() {
71        // Without env var set, should use "auto" behavior
72        with_env_var("CARGO_TERM_PROGRESS_WHEN", None, || {
73            // Result depends on whether we're in a TTY, but should not panic
74            let _ = should_show_progress();
75        });
76    }
77
78    #[test]
79    fn test_should_show_progress_never() {
80        with_env_var("CARGO_TERM_PROGRESS_WHEN", Some("never"), || {
81            assert!(
82                !should_show_progress(),
83                "should return false when set to 'never'"
84            );
85        });
86    }
87
88    #[test]
89    fn test_should_show_progress_always() {
90        with_env_var("CARGO_TERM_PROGRESS_WHEN", Some("always"), || {
91            assert!(
92                should_show_progress(),
93                "should return true when set to 'always'"
94            );
95        });
96    }
97
98    #[test]
99    fn test_should_show_progress_auto() {
100        with_env_var("CARGO_TERM_PROGRESS_WHEN", Some("auto"), || {
101            // Result depends on TTY, but should not panic
102            let _ = should_show_progress();
103        });
104    }
105
106    #[test]
107    fn test_should_show_progress_unknown_value() {
108        // Unknown values should fall back to auto behavior
109        with_env_var("CARGO_TERM_PROGRESS_WHEN", Some("unknown_value"), || {
110            // Result depends on TTY, but should not panic
111            let _ = should_show_progress();
112        });
113    }
114
115    #[test]
116    fn test_should_show_progress_empty_string() {
117        // Empty string is an unknown value, should fall back to auto
118        with_env_var("CARGO_TERM_PROGRESS_WHEN", Some(""), || {
119            let _ = should_show_progress();
120        });
121    }
122}