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}