Skip to main content

theater_cli/commands/
dynamic_completion.rs

1use clap::Parser;
2use tracing::debug;
3
4use crate::error::CliResult;
5use crate::CommandContext;
6
7#[derive(Debug, Parser)]
8pub struct DynamicCompletionArgs {
9    /// The command line being completed
10    #[arg(required = true)]
11    pub line: String,
12
13    /// The current word being completed
14    #[arg(required = true)]
15    pub current: String,
16}
17
18/// Generate dynamic completions based on current theater state
19pub async fn execute_async(args: &DynamicCompletionArgs, _ctx: &CommandContext) -> CliResult<()> {
20    debug!("Generating dynamic completion for: '{}'", args.line);
21    debug!("Current word: '{}'", args.current);
22
23    let completions = generate_dynamic_completions(args).await?;
24
25    for completion in completions {
26        println!("{}", completion);
27    }
28
29    Ok(())
30}
31
32/// Generate completions based on context
33async fn generate_dynamic_completions(args: &DynamicCompletionArgs) -> CliResult<Vec<String>> {
34    let words: Vec<&str> = args.line.split_whitespace().collect();
35
36    match words.as_slice() {
37        // theater <command>
38        ["theater"] => Ok(get_command_completions(&args.current)),
39
40        // theater spawn|setup <manifest>
41        ["theater", "spawn"] | ["theater", "setup"] => {
42            get_manifest_completions(&args.current).await
43        }
44
45        // theater create <template>
46        ["theater", "create"] => Ok(get_template_completions(&args.current)),
47
48        // theater completion <shell>
49        ["theater", "completion"] => Ok(get_shell_completions(&args.current)),
50
51        _ => Ok(vec![]),
52    }
53}
54
55/// Get available command completions
56fn get_command_completions(current: &str) -> Vec<String> {
57    let commands = vec!["build", "completion", "create", "setup", "spawn"];
58
59    commands
60        .into_iter()
61        .filter(|cmd| cmd.starts_with(current))
62        .map(|s| s.to_string())
63        .collect()
64}
65
66/// Get template completions
67fn get_template_completions(current: &str) -> Vec<String> {
68    let templates = vec!["basic", "message-server", "supervisor"];
69
70    templates
71        .into_iter()
72        .filter(|tmpl| tmpl.starts_with(current))
73        .map(|s| s.to_string())
74        .collect()
75}
76
77/// Get shell completions
78fn get_shell_completions(current: &str) -> Vec<String> {
79    let shells = vec!["bash", "zsh", "fish", "powershell", "elvish"];
80
81    shells
82        .into_iter()
83        .filter(|shell| shell.starts_with(current))
84        .map(|s| s.to_string())
85        .collect()
86}
87
88/// Get manifest file completions
89async fn get_manifest_completions(current: &str) -> CliResult<Vec<String>> {
90    let mut completions = Vec::new();
91
92    if let Ok(entries) = std::fs::read_dir(".") {
93        for entry in entries.flatten() {
94            if let Some(name) = entry.file_name().to_str() {
95                if (name == "manifest.toml" || name.ends_with(".toml")) && name.starts_with(current)
96                {
97                    completions.push(name.to_string());
98                }
99            }
100        }
101    }
102
103    Ok(completions)
104}