Skip to main content

ralph/cli/
color.rs

1//! Color option handling for CLI.
2//!
3//! Responsibilities:
4//! - Define the ColorArg type for CLI argument parsing.
5//! - Provide color initialization and global state management.
6//!
7//! Not handled here:
8//! - App-specific color handling (handled outside the CLI).
9//! - Direct color output (see outpututil.rs and output/theme.rs).
10//!
11//! Invariants/Assumptions:
12//! - NO_COLOR environment variable takes precedence over CLI flags.
13//! - Color initialization happens early in main() before any colored output.
14
15use clap::ValueEnum;
16
17/// Color output control options for CLI arguments.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, ValueEnum)]
19pub enum ColorArg {
20    /// Auto-detect based on terminal capabilities.
21    #[default]
22    Auto,
23    /// Always use colors.
24    Always,
25    /// Never use colors.
26    Never,
27}
28
29impl ColorArg {
30    /// Initialize the colored crate based on the color argument.
31    ///
32    /// This respects the NO_COLOR environment variable if set.
33    pub fn init(self) {
34        let use_color = match self {
35            ColorArg::Auto => {
36                // NO_COLOR takes precedence
37                if std::env::var("NO_COLOR").is_ok() {
38                    false
39                } else {
40                    // Auto-detect: use color if stdout is a tty
41                    atty::is(atty::Stream::Stdout)
42                }
43            }
44            ColorArg::Always => true,
45            ColorArg::Never => false,
46        };
47
48        colored::control::set_override(use_color);
49    }
50}
51
52/// Initialize colors from CLI arguments.
53///
54/// Call this early in main() before any colored output.
55///
56/// # Arguments
57/// * `color` - The color option from CLI arguments
58/// * `no_color` - Whether --no-color was specified
59///
60/// # Behavior
61/// - If `--no-color` is set, colors are disabled
62/// - If `NO_COLOR` env var is set, colors are disabled
63/// - Otherwise, the `--color` option is respected
64pub fn init_color(color: ColorArg, no_color: bool) {
65    if no_color || std::env::var("NO_COLOR").is_ok() {
66        colored::control::set_override(false);
67    } else {
68        color.init();
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn color_arg_variants_exist() {
78        // Just verify the variants are accessible
79        let _ = ColorArg::Auto;
80        let _ = ColorArg::Always;
81        let _ = ColorArg::Never;
82    }
83}