Skip to main content

cc_switch/cli/
completion.rs

1use crate::config::ConfigStorage;
2use anyhow::Result;
3use clap::CommandFactory;
4use colored::*;
5use std::io::stdout;
6
7/// Generate shell aliases for eval
8///
9/// # Arguments
10/// * `shell` - Shell type (fish, zsh, bash)
11///
12/// # Errors
13/// Returns error if shell is not supported
14pub fn generate_aliases(shell: &str) -> Result<()> {
15    match shell {
16        "fish" => {
17            println!("alias cs='cc-switch'");
18            println!("alias ccd='claude --dangerously-skip-permissions'");
19            println!("alias cx='cc-switch codex'");
20        }
21        "zsh" => {
22            println!("alias cs='cc-switch'");
23            println!("alias ccd='claude --dangerously-skip-permissions'");
24            println!("alias cx='cc-switch codex'");
25        }
26        "bash" => {
27            println!("alias cs='cc-switch'");
28            println!("alias ccd='claude --dangerously-skip-permissions'");
29            println!("alias cx='cc-switch codex'");
30        }
31        _ => {
32            anyhow::bail!(
33                "Unsupported shell: {}. Supported shells: fish, zsh, bash",
34                shell
35            );
36        }
37    }
38
39    Ok(())
40}
41
42/// Generate shell completion script
43///
44/// # Arguments
45/// * `shell` - Shell type (fish, zsh, bash, elvish, powershell, nushell)
46///
47/// # Errors
48/// Returns error if shell is not supported or generation fails
49pub fn generate_completion(shell: &str) -> Result<()> {
50    use crate::cli::Cli;
51
52    let mut app = Cli::command();
53
54    match shell {
55        "fish" => {
56            generate_fish_completion(&mut app);
57        }
58        "zsh" => {
59            clap_complete::generate(
60                clap_complete::shells::Zsh,
61                &mut app,
62                "cc-switch",
63                &mut stdout(),
64            );
65
66            // Add aliases for zsh
67            println!("\n# Useful aliases for cc-switch");
68            println!("# Add these aliases to your ~/.zshrc:");
69            println!("alias cs='cc-switch'");
70            println!("alias ccd='claude --dangerously-skip-permissions'");
71            println!("# Or run this command to add aliases temporarily:");
72            println!("alias cs='cc-switch'; alias ccd='claude --dangerously-skip-permissions'");
73
74            println!("\n# Zsh completion generated successfully");
75            println!("# Add this to your ~/.zsh/completions/_cc-switch");
76            println!("# Or add this line to your ~/.zshrc:");
77            println!("# fpath=(~/.zsh/completions $fpath)");
78            println!("# Then restart your shell or run 'source ~/.zshrc'");
79            println!(
80                "{}",
81                "# Aliases 'cs' and 'ccd' have been added for convenience".green()
82            );
83        }
84        "bash" => {
85            clap_complete::generate(
86                clap_complete::shells::Bash,
87                &mut app,
88                "cc-switch",
89                &mut stdout(),
90            );
91
92            // Add aliases for bash
93            println!("\n# Useful aliases for cc-switch");
94            println!("# Add these aliases to your ~/.bashrc or ~/.bash_profile:");
95            println!("alias cs='cc-switch'");
96            println!("alias ccd='claude --dangerously-skip-permissions'");
97            println!("# Or run this command to add aliases temporarily:");
98            println!("alias cs='cc-switch'; alias ccd='claude --dangerously-skip-permissions'");
99
100            println!("\n# Bash completion generated successfully");
101            println!("# Add this to your ~/.bash_completion or /etc/bash_completion.d/");
102            println!("# Then restart your shell or run 'source ~/.bashrc'");
103            println!(
104                "{}",
105                "# Aliases 'cs' and 'ccd' have been added for convenience".green()
106            );
107        }
108        "elvish" => {
109            clap_complete::generate(
110                clap_complete::shells::Elvish,
111                &mut app,
112                "cc-switch",
113                &mut stdout(),
114            );
115
116            // Add aliases for elvish
117            println!("\n# Useful aliases for cc-switch");
118            println!("fn cs {{|@args| cc-switch $@args }}");
119            println!("fn ccd {{|@args| claude --dangerously-skip-permissions $@args }}");
120
121            println!("\n# Elvish completion generated successfully");
122            println!(
123                "{}",
124                "# Aliases 'cs' and 'ccd' have been added for convenience".green()
125            );
126        }
127        "powershell" => {
128            clap_complete::generate(
129                clap_complete::shells::PowerShell,
130                &mut app,
131                "cc-switch",
132                &mut stdout(),
133            );
134
135            // Add aliases for PowerShell
136            println!("\n# Useful aliases for cc-switch");
137            println!("Set-Alias -Name cs -Value cc-switch");
138            println!("function ccd {{ claude --dangerously-skip-permissions @args }}");
139
140            println!("\n# PowerShell completion generated successfully");
141            println!(
142                "{}",
143                "# Aliases 'cs' and 'ccd' have been added for convenience".green()
144            );
145        }
146        _ => {
147            anyhow::bail!(
148                "Unsupported shell: {}. Supported shells: fish, zsh, bash, elvish, powershell",
149                shell
150            );
151        }
152    }
153
154    Ok(())
155}
156
157/// List available configuration aliases for shell completion
158///
159/// Outputs all stored configuration aliases, one per line
160/// Also includes 'cc' and 'official' as special aliases for resetting to default Claude
161/// For contexts where user types 'cc-switch use c' or similar, 'current' is prioritized first
162///
163/// # Errors
164/// Returns error if loading configurations fails
165pub fn list_aliases_for_completion() -> Result<()> {
166    let storage = ConfigStorage::load()?;
167
168    // Always include 'cc' and 'official' for reset functionality
169    println!("cc");
170    println!("official");
171
172    // Prioritize 'current' first if it exists - this ensures when user types 'cc-switch use c'
173    // or 'cs use c', the 'current' configuration appears first in completion
174    if storage.configurations.contains_key("current") {
175        println!("current");
176    }
177
178    // Output all other stored aliases in alphabetical order
179    let mut aliases: Vec<String> = storage.configurations.keys().cloned().collect();
180    aliases.sort();
181
182    for alias_name in aliases {
183        if alias_name != "current" {
184            println!("{alias_name}");
185        }
186    }
187
188    Ok(())
189}
190
191/// List available Codex configuration aliases for shell completion
192///
193/// Outputs all stored Codex configuration aliases, one per line
194///
195/// # Errors
196/// Returns error if loading configurations fails
197pub fn list_codex_aliases_for_completion() -> Result<()> {
198    let storage = ConfigStorage::load()?;
199
200    // Output all stored Codex aliases in alphabetical order
201    if let Some(ref configs) = storage.codex_configurations {
202        let mut aliases: Vec<String> = configs.keys().cloned().collect();
203        aliases.sort();
204
205        for alias_name in aliases {
206            println!("{alias_name}");
207        }
208    }
209
210    Ok(())
211}
212
213/// Generate custom fish completion with dynamic alias completion
214///
215/// # Arguments
216/// * `app` - The CLI application struct
217fn generate_fish_completion(app: &mut clap::Command) {
218    // Generate basic completion
219    clap_complete::generate(
220        clap_complete::shells::Fish,
221        app,
222        "cc-switch",
223        &mut std::io::stdout(),
224    );
225
226    // Add custom completion for use subcommand with dynamic aliases
227    println!("\n# Custom completion for use subcommand with dynamic aliases");
228    println!(
229        "complete -c cc-switch -n '__fish_cc_switch_using_subcommand use' -f -a '(cc-switch --list-aliases)' -d 'Configuration alias name'"
230    );
231    // Also support 'switch' as alias for 'use'
232    println!("# Custom completion for switch subcommand (alias for use)");
233    println!(
234        "complete -c cc-switch -n '__fish_cc_switch_using_subcommand switch' -f -a '(cc-switch --list-aliases)' -d 'Configuration alias name'"
235    );
236    // Custom completion for remove subcommand with dynamic aliases
237    println!("# Custom completion for remove subcommand with dynamic aliases");
238    println!(
239        "complete -c cc-switch -n '__fish_cc_switch_using_subcommand remove' -f -a '(cc-switch --list-aliases)' -d 'Configuration alias name'"
240    );
241
242    // Add custom completion for codex subcommand
243    println!("\n# Custom completion for codex subcommand with dynamic aliases");
244    println!(
245        "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'"
246    );
247    println!(
248        "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'"
249    );
250
251    // Add useful aliases that can be eval'd
252    println!("\n# To use these aliases immediately, run:");
253    println!("# eval \"(cc-switch alias fish)\"");
254    println!("\n# Or add them permanently to your ~/.config/fish/config.fish:");
255    println!("# echo \"alias cs='cc-switch'\" >> ~/.config/fish/config.fish");
256    println!(
257        "# echo \"alias ccd='claude --dangerously-skip-permissions'\" >> ~/.config/fish/config.fish"
258    );
259    println!("\n# IMPORTANT: For cs alias completion to work, you must also:");
260    println!(
261        "# 1. Add the completion script: cc-switch completion fish > ~/.config/fish/completions/cc-switch.fish"
262    );
263    println!("# 2. OR run: eval \"(cc-switch completion fish)\" | source");
264
265    // Add completion for the 'cs' alias
266    println!("\n# Completion for the 'cs' alias");
267    println!("complete -c cs -w cc-switch");
268
269    // Add completion for cs alias subcommands (but NOT configuration aliases at top level)
270    println!("\n# Completion for 'cs' alias subcommands");
271    println!(
272        "complete -c cs -n '__fish_use_subcommand' -f -a 'add remove list set-default-dir completion alias use switch current' -d 'Subcommand'"
273    );
274
275    // Add completion for the 'cx' alias (cc-switch codex)
276    println!("\n# Completion for the 'cx' alias (cc-switch codex)");
277    println!(
278        "complete -c cx -n '__fish_use_subcommand' -f -a 'add use remove list' -d 'Codex subcommand'"
279    );
280    println!(
281        "complete -c cx -n '__fish_seen_subcommand_from use' -f -a '(cc-switch --list-codex-aliases)' -d 'Codex configuration alias name'"
282    );
283    println!(
284        "complete -c cx -n '__fish_seen_subcommand_from remove' -f -a '(cc-switch --list-codex-aliases)' -d 'Codex configuration alias name'"
285    );
286
287    // Add completion for the 'csd' alias (also cc-switch codex)
288    println!("\n# Completion for the 'csd' alias (cc-switch codex)");
289    println!(
290        "complete -c csd -n '__fish_use_subcommand' -f -a 'add use remove list' -d 'Codex subcommand'"
291    );
292    println!(
293        "complete -c csd -n '__fish_seen_subcommand_from use' -f -a '(cc-switch --list-codex-aliases)' -d 'Codex configuration alias name'"
294    );
295    println!(
296        "complete -c csd -n '__fish_seen_subcommand_from remove' -f -a '(cc-switch --list-codex-aliases)' -d 'Codex configuration alias name'"
297    );
298
299    println!("\n# Fish completion generated successfully");
300    println!("# Add this to your ~/.config/fish/completions/cc-switch.fish");
301    println!("# Then restart your shell or run 'source ~/.config/fish/config.fish'");
302    println!(
303        "{}",
304        "# Aliases 'cs' and 'ccd' have been added for convenience".green()
305    );
306}