Skip to main content

driven/cli/
template.rs

1//! Template command - manage rule templates
2
3use crate::{Result, templates::TemplateRegistry};
4use dialoguer::{Select, theme::ColorfulTheme};
5use std::path::Path;
6
7/// Template command handler
8#[derive(Debug)]
9pub struct TemplateCommand;
10
11impl TemplateCommand {
12    /// List available templates
13    pub fn list() -> Result<()> {
14        let registry = TemplateRegistry::new();
15        let templates = registry.list();
16
17        println!("📦 Available Templates:");
18        println!();
19
20        for template in templates {
21            println!("  {} - {}", template.name, template.description);
22        }
23
24        println!();
25        super::print_info("Use 'driven template apply <name>' to apply a template");
26
27        Ok(())
28    }
29
30    /// Search templates
31    pub fn search(query: &str) -> Result<()> {
32        let registry = TemplateRegistry::new();
33        let results = registry.search(query);
34
35        if results.is_empty() {
36            super::print_warning(&format!("No templates matching '{}'", query));
37        } else {
38            println!("🔍 Templates matching '{}':", query);
39            println!();
40
41            for template in results {
42                println!("  {} - {}", template.name, template.description);
43            }
44        }
45
46        Ok(())
47    }
48
49    /// Apply a template
50    pub fn apply(project_root: &Path, template_name: &str) -> Result<()> {
51        let registry = TemplateRegistry::new();
52
53        let template = registry.get(template_name).ok_or_else(|| {
54            crate::DrivenError::Template(format!("Template not found: {}", template_name))
55        })?;
56
57        let spinner = super::create_spinner(&format!("Applying template '{}'...", template_name));
58
59        // Get the content by rendering the template
60        let content = template.render(&Default::default())?;
61
62        // Write to rules file
63        let rules_path = project_root.join(".driven/rules.md");
64        if let Some(parent) = rules_path.parent() {
65            std::fs::create_dir_all(parent).map_err(|e| {
66                crate::DrivenError::Template(format!("Failed to create directory: {}", e))
67            })?;
68        }
69
70        std::fs::write(&rules_path, content).map_err(|e| {
71            crate::DrivenError::Template(format!("Failed to write template: {}", e))
72        })?;
73
74        spinner.finish_and_clear();
75        super::print_success(&format!(
76            "Applied template '{}' to {}",
77            template_name,
78            rules_path.display()
79        ));
80
81        Ok(())
82    }
83
84    /// Interactive template selection
85    pub fn interactive(project_root: &Path) -> Result<()> {
86        let registry = TemplateRegistry::new();
87        let templates = registry.list();
88        let theme = ColorfulTheme::default();
89
90        let items: Vec<_> = templates
91            .iter()
92            .map(|t| format!("{} - {}", t.name, t.description))
93            .collect();
94
95        let selection = Select::with_theme(&theme)
96            .with_prompt("Select a template")
97            .items(&items)
98            .default(0)
99            .interact()
100            .map_err(|e| crate::DrivenError::Cli(e.to_string()))?;
101
102        Self::apply(project_root, &templates[selection].name)
103    }
104}