cc_switch/cli/
completion.rs1use crate::config::ConfigStorage;
2use anyhow::Result;
3use clap::CommandFactory;
4use colored::*;
5use std::fs;
6use std::io::stdout;
7
8pub fn generate_aliases(shell: &str) -> Result<()> {
16 match shell {
17 "fish" => {
18 println!("alias cs='cc-switch'");
19 println!("alias ccd='claude --dangerously-skip-permissions'");
20 println!("alias cx='cc-switch codex'");
21 }
22 "zsh" => {
23 println!("alias cs='cc-switch'");
24 println!("alias ccd='claude --dangerously-skip-permissions'");
25 println!("alias cx='cc-switch codex'");
26 }
27 "bash" => {
28 println!("alias cs='cc-switch'");
29 println!("alias ccd='claude --dangerously-skip-permissions'");
30 println!("alias cx='cc-switch codex'");
31 }
32 _ => {
33 anyhow::bail!(
34 "Unsupported shell: {}. Supported shells: fish, zsh, bash",
35 shell
36 );
37 }
38 }
39
40 Ok(())
41}
42
43pub fn generate_completion(shell: &str) -> Result<()> {
51 use crate::cli::Cli;
52
53 let mut app = Cli::command();
54
55 match shell {
56 "fish" => {
57 generate_fish_completion(&mut app);
58 }
59 "zsh" => {
60 clap_complete::generate(
61 clap_complete::shells::Zsh,
62 &mut app,
63 "cc-switch",
64 &mut stdout(),
65 );
66
67 println!("\n# Useful aliases for cc-switch");
69 println!("# Add these aliases to your ~/.zshrc:");
70 println!("alias cs='cc-switch'");
71 println!("alias ccd='claude --dangerously-skip-permissions'");
72 println!("# Or run this command to add aliases temporarily:");
73 println!("alias cs='cc-switch'; alias ccd='claude --dangerously-skip-permissions'");
74
75 println!("\n# Zsh completion generated successfully");
76 println!("# Add this to your ~/.zsh/completions/_cc-switch");
77 println!("# Or add this line to your ~/.zshrc:");
78 println!("# fpath=(~/.zsh/completions $fpath)");
79 println!("# Then restart your shell or run 'source ~/.zshrc'");
80 println!(
81 "{}",
82 "# Aliases 'cs' and 'ccd' have been added for convenience".green()
83 );
84 }
85 "bash" => {
86 clap_complete::generate(
87 clap_complete::shells::Bash,
88 &mut app,
89 "cc-switch",
90 &mut stdout(),
91 );
92
93 println!("\n# Useful aliases for cc-switch");
95 println!("# Add these aliases to your ~/.bashrc or ~/.bash_profile:");
96 println!("alias cs='cc-switch'");
97 println!("alias ccd='claude --dangerously-skip-permissions'");
98 println!("# Or run this command to add aliases temporarily:");
99 println!("alias cs='cc-switch'; alias ccd='claude --dangerously-skip-permissions'");
100
101 println!("\n# Bash completion generated successfully");
102 println!("# Add this to your ~/.bash_completion or /etc/bash_completion.d/");
103 println!("# Then restart your shell or run 'source ~/.bashrc'");
104 println!(
105 "{}",
106 "# Aliases 'cs' and 'ccd' have been added for convenience".green()
107 );
108 }
109 "elvish" => {
110 clap_complete::generate(
111 clap_complete::shells::Elvish,
112 &mut app,
113 "cc-switch",
114 &mut stdout(),
115 );
116
117 println!("\n# Useful aliases for cc-switch");
119 println!("fn cs {{|@args| cc-switch $@args }}");
120 println!("fn ccd {{|@args| claude --dangerously-skip-permissions $@args }}");
121
122 println!("\n# Elvish completion generated successfully");
123 println!(
124 "{}",
125 "# Aliases 'cs' and 'ccd' have been added for convenience".green()
126 );
127 }
128 "powershell" => {
129 clap_complete::generate(
130 clap_complete::shells::PowerShell,
131 &mut app,
132 "cc-switch",
133 &mut stdout(),
134 );
135
136 println!("\n# Useful aliases for cc-switch");
138 println!("Set-Alias -Name cs -Value cc-switch");
139 println!("function ccd {{ claude --dangerously-skip-permissions @args }}");
140
141 println!("\n# PowerShell completion generated successfully");
142 println!(
143 "{}",
144 "# Aliases 'cs' and 'ccd' have been added for convenience".green()
145 );
146 }
147 _ => {
148 anyhow::bail!(
149 "Unsupported shell: {}. Supported shells: fish, zsh, bash, elvish, powershell",
150 shell
151 );
152 }
153 }
154
155 Ok(())
156}
157
158pub fn list_aliases_for_completion() -> Result<()> {
167 let storage = ConfigStorage::load()?;
168
169 println!("cc");
171 println!("official");
172
173 if storage.configurations.contains_key("current") {
176 println!("current");
177 }
178
179 let mut aliases: Vec<String> = storage.configurations.keys().cloned().collect();
181 aliases.sort();
182
183 for alias_name in aliases {
184 if alias_name != "current" {
185 println!("{alias_name}");
186 }
187 }
188
189 Ok(())
190}
191
192pub fn list_codex_aliases_for_completion() -> Result<()> {
199 let storage = ConfigStorage::load()?;
200
201 if let Some(ref configs) = storage.codex_configurations {
203 let mut aliases: Vec<String> = configs.keys().cloned().collect();
204 aliases.sort();
205
206 for alias_name in aliases {
207 println!("{alias_name}");
208 }
209 }
210
211 Ok(())
212}
213
214fn generate_fish_completion(app: &mut clap::Command) {
219 clap_complete::generate(
221 clap_complete::shells::Fish,
222 app,
223 "cc-switch",
224 &mut std::io::stdout(),
225 );
226
227 println!("\n# Custom completion for use subcommand with dynamic aliases");
229 println!(
230 "complete -c cc-switch -n '__fish_cc_switch_using_subcommand use' -f -a '(cc-switch --list-aliases)' -d 'Configuration alias name'"
231 );
232 println!("# Custom completion for switch subcommand (alias for use)");
234 println!(
235 "complete -c cc-switch -n '__fish_cc_switch_using_subcommand switch' -f -a '(cc-switch --list-aliases)' -d 'Configuration alias name'"
236 );
237 println!("# Custom completion for remove subcommand with dynamic aliases");
239 println!(
240 "complete -c cc-switch -n '__fish_cc_switch_using_subcommand remove' -f -a '(cc-switch --list-aliases)' -d 'Configuration alias name'"
241 );
242
243 println!("\n# Custom completion for codex subcommand with dynamic aliases");
245 println!(
246 "complete -c cc-switch -n '__fish_seen_subcommand_from codex' -n '__fish_seen_subcommand_from use' -f -a '(cc-switch --list-codex-aliases)' -d 'Codex configuration alias name'"
247 );
248 println!(
249 "complete -c cc-switch -n '__fish_seen_subcommand_from codex' -n '__fish_seen_subcommand_from remove' -f -a '(cc-switch --list-codex-aliases)' -d 'Codex configuration alias name'"
250 );
251
252 println!("\n# To use these aliases immediately, run:");
254 println!("# eval \"(cc-switch alias fish)\"");
255 println!("\n# Or add them permanently to your ~/.config/fish/config.fish:");
256 println!("# echo \"alias cs='cc-switch'\" >> ~/.config/fish/config.fish");
257 println!(
258 "# echo \"alias ccd='claude --dangerously-skip-permissions'\" >> ~/.config/fish/config.fish"
259 );
260 println!("\n# IMPORTANT: For cs alias completion to work, you must also:");
261 println!(
262 "# 1. Add the completion script: cc-switch completion fish > ~/.config/fish/completions/cc-switch.fish"
263 );
264 println!("# 2. OR run: eval \"(cc-switch completion fish)\" | source");
265
266 println!("\n# Completion for the 'cs' alias");
268 println!("complete -c cs -w cc-switch");
269
270 println!("\n# Completion for 'cs' alias subcommands");
272 println!(
273 "complete -c cs -n '__fish_use_subcommand' -f -a 'add remove list set-default-dir completion alias use switch current codex daemon statusline' -d 'Subcommand'"
274 );
275
276 println!("\n# Completion for 'daemon' subcommand");
278 println!(
279 "complete -c cc-switch -n '__fish_cc_switch_using_subcommand daemon; and not __fish_seen_subcommand_from start stop status restart' -f -a 'start stop status restart' -d 'Daemon action'"
280 );
281 println!(
282 "complete -c cc-switch -n '__fish_cc_switch_using_subcommand daemon; and __fish_seen_subcommand_from start' -l foreground -d 'Run in the foreground'"
283 );
284 println!(
285 "complete -c cc-switch -n '__fish_cc_switch_using_subcommand daemon; and __fish_seen_subcommand_from start' -l log-level -d 'Log level (error/warn/info/debug/trace)' -r -f -a 'error warn info debug trace'"
286 );
287 println!(
288 "complete -c cc-switch -n '__fish_cc_switch_using_subcommand daemon; and __fish_seen_subcommand_from start' -s v -l verbose -d 'Increase verbosity (-v/-vv/-vvv)'"
289 );
290 println!(
291 "complete -c cc-switch -n '__fish_cc_switch_using_subcommand daemon; and __fish_seen_subcommand_from restart' -l foreground -d 'Run in the foreground after restart'"
292 );
293 println!(
294 "complete -c cc-switch -n '__fish_cc_switch_using_subcommand daemon; and __fish_seen_subcommand_from restart' -l log-level -d 'Log level (error/warn/info/debug/trace)' -r -f -a 'error warn info debug trace'"
295 );
296 println!(
297 "complete -c cc-switch -n '__fish_cc_switch_using_subcommand daemon; and __fish_seen_subcommand_from restart' -s v -l verbose -d 'Increase verbosity (-v/-vv/-vvv)'"
298 );
299 println!(
300 "complete -c cc-switch -n '__fish_cc_switch_using_subcommand daemon; and __fish_seen_subcommand_from status' -l json -d 'Output as JSON'"
301 );
302
303 println!("\n# Completion for 'cs list' subcommand");
305 println!(
306 "complete -c cs -n '__fish_seen_subcommand_from list' -l plain -s p -d 'Plain text output'"
307 );
308 println!(
309 "complete -c cs -n '__fish_seen_subcommand_from list' -l name -s n -d 'Show only name and URL'"
310 );
311
312 println!("\n# Completion for 'cs daemon' subcommand");
314 println!(
315 "complete -c cs -n '__fish_seen_subcommand_from daemon; and not __fish_seen_subcommand_from start stop status restart' -f -a 'start stop status restart' -d 'Daemon action'"
316 );
317 println!(
318 "complete -c cs -n '__fish_seen_subcommand_from daemon; and __fish_seen_subcommand_from start' -l foreground -d 'Run in the foreground'"
319 );
320 println!(
321 "complete -c cs -n '__fish_seen_subcommand_from daemon; and __fish_seen_subcommand_from start' -l log-level -d 'Log level' -r -f -a 'error warn info debug trace'"
322 );
323 println!(
324 "complete -c cs -n '__fish_seen_subcommand_from daemon; and __fish_seen_subcommand_from start' -s v -l verbose -d 'Increase verbosity'"
325 );
326 println!(
327 "complete -c cs -n '__fish_seen_subcommand_from daemon; and __fish_seen_subcommand_from restart' -l foreground -d 'Run in the foreground after restart'"
328 );
329 println!(
330 "complete -c cs -n '__fish_seen_subcommand_from daemon; and __fish_seen_subcommand_from restart' -l log-level -d 'Log level' -r -f -a 'error warn info debug trace'"
331 );
332 println!(
333 "complete -c cs -n '__fish_seen_subcommand_from daemon; and __fish_seen_subcommand_from restart' -s v -l verbose -d 'Increase verbosity'"
334 );
335 println!(
336 "complete -c cs -n '__fish_seen_subcommand_from daemon; and __fish_seen_subcommand_from status' -l json -d 'Output as JSON'"
337 );
338
339 println!("\n# Completion for 'cs statusline' subcommand");
341 println!(
342 "complete -c cs -n '__fish_seen_subcommand_from statusline' -f -a 'install uninstall' -d 'Statusline action'"
343 );
344
345 println!("\n# Completion for the 'cx' alias (cc-switch codex)");
347 println!("complete -c cx -f");
348 println!(
349 "complete -c cx -n '__fish_use_subcommand' -f -a 'add use remove list' -d 'Codex subcommand'"
350 );
351 println!(
352 "complete -c cx -n '__fish_seen_subcommand_from use' -f -a '(cc-switch --list-codex-aliases)' -d 'Codex configuration alias name'"
353 );
354 println!(
355 "complete -c cx -n '__fish_seen_subcommand_from remove' -f -a '(cc-switch --list-codex-aliases)' -d 'Codex configuration alias name'"
356 );
357 println!(
358 "complete -c cx -n '__fish_seen_subcommand_from list' -f -l plain -s p -d 'Plain text output'"
359 );
360 println!(
361 "complete -c cx -n '__fish_seen_subcommand_from list' -f -l name -s n -d 'Show only name and auth mode'"
362 );
363 println!(
364 "complete -c cx -n '__fish_seen_subcommand_from add' -f -l interactive -s i -d 'Interactive mode'"
365 );
366 println!(
367 "complete -c cx -n '__fish_seen_subcommand_from add' -f -l from-file -d 'Import from auth.json (defaults to ~/.codex/auth.json if no path)' -r"
368 );
369
370 println!("\n# Fish completion generated successfully");
371 println!("# Add this to your ~/.config/fish/completions/cc-switch.fish");
372 println!("# Then restart your shell or run 'source ~/.config/fish/config.fish'");
373 println!(
374 "{}",
375 "# Aliases 'cs' and 'ccd' have been added for convenience".green()
376 );
377
378 generate_cx_completion_file();
381}
382
383fn generate_cx_completion_file() {
388 let home = dirs::home_dir().unwrap_or_else(|| std::path::PathBuf::from("~"));
390 let completions_dir = home.join(".config").join("fish").join("completions");
391
392 if !completions_dir.exists()
393 && let Err(e) = fs::create_dir_all(&completions_dir)
394 {
395 eprintln!("Warning: Could not create completions directory: {e}");
396 return;
397 }
398
399 let cx_content = r#"# Completion for 'cx' alias (cc-switch codex)
400# cx is a fish function; disable file completion by default
401complete -c cx -f
402complete -c cx -n '__fish_use_subcommand' -f -a 'add use remove list' -d 'Codex subcommand'
403complete -c cx -n '__fish_seen_subcommand_from use' -f -a '(cc-switch --list-codex-aliases)' -d 'Codex configuration alias name'
404complete -c cx -n '__fish_seen_subcommand_from remove' -f -a '(cc-switch --list-codex-aliases)' -d 'Codex configuration alias name'
405complete -c cx -n '__fish_seen_subcommand_from list' -f -l plain -s p -d 'Plain text output'
406complete -c cx -n '__fish_seen_subcommand_from list' -f -l name -s n -d 'Show only name and auth mode'
407complete -c cx -n '__fish_seen_subcommand_from add' -f -l interactive -s i -d 'Interactive mode'
408complete -c cx -n '__fish_seen_subcommand_from add' -f -l from-file -d 'Import from auth.json (defaults to ~/.codex/auth.json if no path)' -r
409"#;
410
411 let cx_path = completions_dir.join("cx.fish");
412
413 if let Err(e) = fs::write(&cx_path, cx_content) {
414 eprintln!("Warning: Could not write cx.fish: {e}");
415 }
416
417 eprintln!("\nCreated completion file: {}", cx_path.display());
418}