Skip to main content

cargo_plugin_utils/
tty.rs

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