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