workhelix_cli_common/
completions.rs

1//! Shell completion generation module.
2//!
3//! This module provides generic shell completion generation for CLI tools using clap.
4//! It works with any clap `CommandFactory` and generates completions for all major shells.
5
6use clap::CommandFactory;
7use clap_complete::Shell;
8use std::io;
9
10/// Generate shell completion scripts for a clap-based CLI.
11///
12/// This function generates shell completions and prints both installation instructions
13/// and the completion script to stdout. It supports bash, zsh, fish, elvish, and `PowerShell`.
14///
15/// # Type Parameters
16/// * `T` - A type that implements `CommandFactory` (typically your clap `Cli` struct)
17///
18/// # Arguments
19/// * `shell` - The shell type to generate completions for
20///
21/// # Examples
22/// ```no_run
23/// use clap::Parser;
24/// use workhelix_cli_common::completions::generate_completions;
25///
26/// #[derive(Parser)]
27/// struct Cli {
28///     // your CLI definition
29/// }
30///
31/// generate_completions::<Cli>(clap_complete::Shell::Bash);
32/// ```
33pub fn generate_completions<T: CommandFactory>(shell: Shell) {
34    let mut cmd = T::command();
35    let bin_name = cmd.get_name().to_string();
36
37    // Print instructions
38    println!("# Shell completion for {bin_name}");
39    println!("#");
40    println!("# To enable completions, add this to your shell config:");
41    println!("#");
42
43    match shell {
44        Shell::Bash => {
45            println!("# For bash (~/.bashrc):");
46            println!("#   source <({bin_name} completions bash)");
47        }
48        Shell::Zsh => {
49            println!("# For zsh (~/.zshrc):");
50            println!("#   {bin_name} completions zsh > ~/.zsh/completions/_{bin_name}");
51            println!("#   # Ensure fpath includes ~/.zsh/completions");
52        }
53        Shell::Fish => {
54            println!("# For fish (~/.config/fish/config.fish):");
55            println!("#   {bin_name} completions fish | source");
56        }
57        _ => {
58            println!("# For {shell}:");
59            println!("#   {bin_name} completions {shell} > /path/to/completions/_{bin_name}");
60        }
61    }
62
63    println!();
64
65    // Generate completions
66    clap_complete::generate(shell, &mut cmd, bin_name, &mut io::stdout());
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72    use clap::{Parser, Subcommand};
73
74    #[derive(Parser)]
75    #[command(name = "test-cli")]
76    struct TestCli {
77        #[command(subcommand)]
78        command: TestCommands,
79    }
80
81    #[derive(Subcommand)]
82    enum TestCommands {
83        Version,
84        Test { arg: String },
85    }
86
87    #[test]
88    fn test_generate_completions_bash() {
89        // Just verify it doesn't panic
90        generate_completions::<TestCli>(Shell::Bash);
91    }
92
93    #[test]
94    fn test_generate_completions_zsh() {
95        generate_completions::<TestCli>(Shell::Zsh);
96    }
97
98    #[test]
99    fn test_generate_completions_fish() {
100        generate_completions::<TestCli>(Shell::Fish);
101    }
102
103    #[test]
104    fn test_generate_completions_elvish() {
105        generate_completions::<TestCli>(Shell::Elvish);
106    }
107
108    #[test]
109    fn test_generate_completions_powershell() {
110        generate_completions::<TestCli>(Shell::PowerShell);
111    }
112
113    #[test]
114    fn test_all_shells_generate_without_panic() {
115        let shells = vec![
116            Shell::Bash,
117            Shell::Zsh,
118            Shell::Fish,
119            Shell::Elvish,
120            Shell::PowerShell,
121        ];
122
123        for shell in shells {
124            generate_completions::<TestCli>(shell);
125        }
126    }
127}