Skip to main content

gemini_cli/
config.rs

1use std::io::Write;
2
3use nils_common::shell::{SingleQuoteEscapeStyle, quote_posix_single_with_style};
4
5pub fn show() -> i32 {
6    let stdout = std::io::stdout();
7    let mut stdout = stdout.lock();
8    show_with_io(&mut stdout)
9}
10
11pub fn show_with_io(stdout: &mut impl Write) -> i32 {
12    let snapshot = crate::runtime::config_snapshot();
13
14    let _ = writeln!(stdout, "GEMINI_CLI_MODEL={}", snapshot.model);
15    let _ = writeln!(stdout, "GEMINI_CLI_REASONING={}", snapshot.reasoning);
16    let _ = writeln!(
17        stdout,
18        "GEMINI_ALLOW_DANGEROUS_ENABLED={}",
19        snapshot.allow_dangerous_enabled_raw
20    );
21
22    if let Some(path) = snapshot.secret_dir {
23        let _ = writeln!(stdout, "GEMINI_SECRET_DIR={}", path.to_string_lossy());
24    } else {
25        let _ = writeln!(stdout, "GEMINI_SECRET_DIR=");
26    }
27
28    if let Some(path) = snapshot.auth_file {
29        let _ = writeln!(stdout, "GEMINI_AUTH_FILE={}", path.to_string_lossy());
30    } else {
31        let _ = writeln!(stdout, "GEMINI_AUTH_FILE=");
32    }
33
34    if let Some(path) = snapshot.secret_cache_dir {
35        let _ = writeln!(stdout, "GEMINI_SECRET_CACHE_DIR={}", path.to_string_lossy());
36    } else {
37        let _ = writeln!(stdout, "GEMINI_SECRET_CACHE_DIR=");
38    }
39
40    let _ = writeln!(
41        stdout,
42        "GEMINI_STARSHIP_ENABLED={}",
43        snapshot.starship_enabled
44    );
45    let _ = writeln!(
46        stdout,
47        "GEMINI_AUTO_REFRESH_ENABLED={}",
48        snapshot.auto_refresh_enabled
49    );
50    let _ = writeln!(
51        stdout,
52        "GEMINI_AUTO_REFRESH_MIN_DAYS={}",
53        snapshot.auto_refresh_min_days
54    );
55
56    0
57}
58
59pub fn set(key: &str, value: &str) -> i32 {
60    let stdout = std::io::stdout();
61    let mut stdout = stdout.lock();
62    let stderr = std::io::stderr();
63    let mut stderr = stderr.lock();
64    set_with_io(key, value, &mut stdout, &mut stderr)
65}
66
67pub fn set_with_io(
68    key: &str,
69    value: &str,
70    stdout: &mut impl Write,
71    stderr: &mut impl Write,
72) -> i32 {
73    match key {
74        "model" | "GEMINI_CLI_MODEL" => {
75            let _ = writeln!(
76                stdout,
77                "export GEMINI_CLI_MODEL={}",
78                quote_posix_single(value)
79            );
80            0
81        }
82        "reasoning" | "reason" | "GEMINI_CLI_REASONING" => {
83            let _ = writeln!(
84                stdout,
85                "export GEMINI_CLI_REASONING={}",
86                quote_posix_single(value)
87            );
88            0
89        }
90        "dangerous" | "allow-dangerous" | "GEMINI_ALLOW_DANGEROUS_ENABLED" => {
91            let lowered = value.trim().to_ascii_lowercase();
92            if lowered != "true" && lowered != "false" {
93                let _ = writeln!(
94                    stderr,
95                    "gemini-cli config: dangerous must be true|false (got: {})",
96                    value
97                );
98                return 64;
99            }
100            let _ = writeln!(stdout, "export GEMINI_ALLOW_DANGEROUS_ENABLED={}", lowered);
101            0
102        }
103        _ => {
104            let _ = writeln!(stderr, "gemini-cli config: unknown key: {key}");
105            let _ = writeln!(stderr, "gemini-cli config: keys: model|reasoning|dangerous");
106            64
107        }
108    }
109}
110
111fn quote_posix_single(raw: &str) -> String {
112    quote_posix_single_with_style(raw, SingleQuoteEscapeStyle::DoubleQuoteBoundary)
113}
114
115#[cfg(test)]
116mod tests {
117    use super::quote_posix_single;
118
119    #[test]
120    fn quote_posix_single_handles_single_quotes_and_empty() {
121        assert_eq!(quote_posix_single(""), "''");
122        assert_eq!(quote_posix_single("abc"), "'abc'");
123        assert_eq!(quote_posix_single("a'b"), "'a'\"'\"'b'");
124    }
125}