Skip to main content

systemprompt_cli/
cli_settings.rs

1use std::env;
2use std::io::IsTerminal;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum OutputFormat {
6    Table,
7    Json,
8    Yaml,
9}
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
12pub enum VerbosityLevel {
13    Quiet,
14    Normal,
15    Verbose,
16    Debug,
17}
18
19impl VerbosityLevel {
20    pub const fn as_tracing_filter(&self) -> Option<&'static str> {
21        match self {
22            Self::Quiet => Some("error"),
23            Self::Normal => None,
24            Self::Verbose => Some("debug"),
25            Self::Debug => Some("trace"),
26        }
27    }
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum ColorMode {
32    Auto,
33    Always,
34    Never,
35}
36
37#[derive(Debug, Clone)]
38pub struct CliConfig {
39    pub output_format: OutputFormat,
40    pub verbosity: VerbosityLevel,
41    pub color_mode: ColorMode,
42    pub interactive: bool,
43    pub profile_override: Option<String>,
44}
45
46impl Default for CliConfig {
47    fn default() -> Self {
48        Self {
49            output_format: OutputFormat::Table,
50            verbosity: VerbosityLevel::Normal,
51            color_mode: ColorMode::Auto,
52            interactive: true,
53            profile_override: None,
54        }
55    }
56}
57
58impl CliConfig {
59    pub fn new() -> Self {
60        let mut config = Self::default();
61        config.apply_environment_variables();
62        config
63    }
64
65    pub const fn with_output_format(mut self, format: OutputFormat) -> Self {
66        self.output_format = format;
67        self
68    }
69
70    pub const fn with_verbosity(mut self, level: VerbosityLevel) -> Self {
71        self.verbosity = level;
72        self
73    }
74
75    pub const fn with_color_mode(mut self, mode: ColorMode) -> Self {
76        self.color_mode = mode;
77        self
78    }
79
80    pub const fn with_interactive(mut self, interactive: bool) -> Self {
81        self.interactive = interactive;
82        self
83    }
84
85    pub fn with_profile_override(mut self, profile: Option<String>) -> Self {
86        self.profile_override = profile;
87        self
88    }
89
90    fn apply_environment_variables(&mut self) {
91        if let Ok(format) = env::var("SYSTEMPROMPT_OUTPUT_FORMAT") {
92            self.output_format = match format.to_lowercase().as_str() {
93                "json" => OutputFormat::Json,
94                "yaml" => OutputFormat::Yaml,
95                "table" => OutputFormat::Table,
96                _ => self.output_format,
97            };
98        }
99
100        if let Ok(level) = env::var("SYSTEMPROMPT_LOG_LEVEL") {
101            self.verbosity = match level.to_lowercase().as_str() {
102                "quiet" => VerbosityLevel::Quiet,
103                "normal" => VerbosityLevel::Normal,
104                "verbose" => VerbosityLevel::Verbose,
105                "debug" => VerbosityLevel::Debug,
106                _ => self.verbosity,
107            };
108        }
109
110        if env::var("SYSTEMPROMPT_NO_COLOR").is_ok() || env::var("NO_COLOR").is_ok() {
111            self.color_mode = ColorMode::Never;
112        }
113
114        if env::var("SYSTEMPROMPT_NON_INTERACTIVE").is_ok() {
115            self.interactive = false;
116        }
117    }
118
119    pub fn should_use_color(&self) -> bool {
120        match self.color_mode {
121            ColorMode::Always => true,
122            ColorMode::Never => false,
123            ColorMode::Auto => std::io::stdout().is_terminal(),
124        }
125    }
126
127    pub fn is_json_output(&self) -> bool {
128        self.output_format == OutputFormat::Json
129    }
130
131    pub fn should_show_verbose(&self) -> bool {
132        self.verbosity >= VerbosityLevel::Verbose
133    }
134
135    pub fn is_interactive(&self) -> bool {
136        self.interactive && std::io::stdin().is_terminal() && std::io::stdout().is_terminal()
137    }
138
139    pub const fn output_format(&self) -> OutputFormat {
140        self.output_format
141    }
142}
143
144thread_local! {
145    static CLI_CONFIG: std::cell::RefCell<CliConfig> = std::cell::RefCell::new(CliConfig::new());
146}
147
148pub fn set_global_config(config: CliConfig) {
149    CLI_CONFIG.with(|c| {
150        *c.borrow_mut() = config;
151    });
152}
153
154pub fn get_global_config() -> CliConfig {
155    CLI_CONFIG.with(|c| c.borrow().clone())
156}