theater_cli/commands/
dynamic_completion.rs1use clap::Parser;
2use tracing::debug;
3
4use crate::error::CliResult;
5use crate::CommandContext;
6
7#[derive(Debug, Parser)]
8pub struct DynamicCompletionArgs {
9 #[arg(required = true)]
11 pub line: String,
12
13 #[arg(required = true)]
15 pub current: String,
16}
17
18pub 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
32async 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"] => Ok(get_command_completions(&args.current)),
39
40 ["theater", "start"] => get_manifest_completions(&args.current).await,
42
43 ["theater", "create"] => Ok(get_template_completions(&args.current)),
45
46 ["theater", "completion"] => Ok(get_shell_completions(&args.current)),
48
49 _ => Ok(vec![]),
50 }
51}
52
53fn get_command_completions(current: &str) -> Vec<String> {
55 let commands = vec!["build", "completion", "create", "start"];
56
57 commands
58 .into_iter()
59 .filter(|cmd| cmd.starts_with(current))
60 .map(|s| s.to_string())
61 .collect()
62}
63
64fn get_template_completions(current: &str) -> Vec<String> {
66 let templates = vec!["basic", "message-server", "supervisor"];
67
68 templates
69 .into_iter()
70 .filter(|tmpl| tmpl.starts_with(current))
71 .map(|s| s.to_string())
72 .collect()
73}
74
75fn get_shell_completions(current: &str) -> Vec<String> {
77 let shells = vec!["bash", "zsh", "fish", "powershell", "elvish"];
78
79 shells
80 .into_iter()
81 .filter(|shell| shell.starts_with(current))
82 .map(|s| s.to_string())
83 .collect()
84}
85
86async fn get_manifest_completions(current: &str) -> CliResult<Vec<String>> {
88 let mut completions = Vec::new();
89
90 if let Ok(entries) = std::fs::read_dir(".") {
91 for entry in entries.flatten() {
92 if let Some(name) = entry.file_name().to_str() {
93 if (name == "manifest.toml" || name.ends_with(".toml")) && name.starts_with(current)
94 {
95 completions.push(name.to_string());
96 }
97 }
98 }
99 }
100
101 Ok(completions)
102}