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' -d 'Subcommand'"
274 );
275
276 println!("\n# Completion for 'cs list' subcommand");
278 println!(
279 "complete -c cs -n '__fish_seen_subcommand_from list' -l plain -s p -d 'Plain text output'"
280 );
281 println!(
282 "complete -c cs -n '__fish_seen_subcommand_from list' -l name -s n -d 'Show only name and URL'"
283 );
284
285 println!("\n# Completion for the 'cx' alias (cc-switch codex)");
287 println!("complete -c cx -f");
288 println!(
289 "complete -c cx -n '__fish_use_subcommand' -f -a 'add use remove list' -d 'Codex subcommand'"
290 );
291 println!(
292 "complete -c cx -n '__fish_seen_subcommand_from use' -f -a '(cc-switch --list-codex-aliases)' -d 'Codex configuration alias name'"
293 );
294 println!(
295 "complete -c cx -n '__fish_seen_subcommand_from remove' -f -a '(cc-switch --list-codex-aliases)' -d 'Codex configuration alias name'"
296 );
297 println!(
298 "complete -c cx -n '__fish_seen_subcommand_from list' -f -l plain -s p -d 'Plain text output'"
299 );
300 println!(
301 "complete -c cx -n '__fish_seen_subcommand_from list' -f -l name -s n -d 'Show only name and auth mode'"
302 );
303 println!(
304 "complete -c cx -n '__fish_seen_subcommand_from add' -f -l interactive -s i -d 'Interactive mode'"
305 );
306 println!(
307 "complete -c cx -n '__fish_seen_subcommand_from add' -f -l from-file -d 'Import from JSON file' -r"
308 );
309
310 println!("\n# Fish completion generated successfully");
311 println!("# Add this to your ~/.config/fish/completions/cc-switch.fish");
312 println!("# Then restart your shell or run 'source ~/.config/fish/config.fish'");
313 println!(
314 "{}",
315 "# Aliases 'cs' and 'ccd' have been added for convenience".green()
316 );
317
318 generate_cx_completion_file();
321}
322
323fn generate_cx_completion_file() {
328 let home = dirs::home_dir().unwrap_or_else(|| std::path::PathBuf::from("~"));
330 let completions_dir = home.join(".config").join("fish").join("completions");
331
332 if !completions_dir.exists()
333 && let Err(e) = fs::create_dir_all(&completions_dir)
334 {
335 eprintln!("Warning: Could not create completions directory: {e}");
336 return;
337 }
338
339 let cx_content = r#"# Completion for 'cx' alias (cc-switch codex)
340# cx is a fish function; disable file completion by default
341complete -c cx -f
342complete -c cx -n '__fish_use_subcommand' -f -a 'add use remove list' -d 'Codex subcommand'
343complete -c cx -n '__fish_seen_subcommand_from use' -f -a '(cc-switch --list-codex-aliases)' -d 'Codex configuration alias name'
344complete -c cx -n '__fish_seen_subcommand_from remove' -f -a '(cc-switch --list-codex-aliases)' -d 'Codex configuration alias name'
345complete -c cx -n '__fish_seen_subcommand_from list' -f -l plain -s p -d 'Plain text output'
346complete -c cx -n '__fish_seen_subcommand_from list' -f -l name -s n -d 'Show only name and auth mode'
347complete -c cx -n '__fish_seen_subcommand_from add' -f -l interactive -s i -d 'Interactive mode'
348complete -c cx -n '__fish_seen_subcommand_from add' -f -l from-file -d 'Import from JSON file' -r
349"#;
350
351 let cx_path = completions_dir.join("cx.fish");
352
353 if let Err(e) = fs::write(&cx_path, cx_content) {
354 eprintln!("Warning: Could not write cx.fish: {e}");
355 }
356
357 eprintln!("\nCreated completion file: {}", cx_path.display());
358}