orbiton/commands/
new.rs

1// Command for creating a new Orbit project
2
3use anyhow::{Context, Result};
4use clap::Args;
5use console::style;
6use dialoguer::{theme::ColorfulTheme, Select};
7use log::debug;
8use std::fs;
9use std::path::PathBuf;
10
11use crate::templates::project_templates::{TemplateManager, TemplateType};
12
13#[derive(Args)]
14pub struct NewArgs {
15    /// Name of the project
16    #[arg(required = true)]
17    name: String,
18
19    /// Template to use (basic, component-library, full-app)
20    #[arg(short, long)]
21    template: Option<String>,
22
23    /// Output directory
24    #[arg(short, long)]
25    output_dir: Option<PathBuf>,
26}
27
28pub fn execute(args: NewArgs) -> Result<()> {
29    println!(
30        "{} a new Orbit project: {}",
31        style("Creating").bold().green(),
32        style(&args.name).bold()
33    );
34
35    let template_manager =
36        TemplateManager::new().context("Failed to initialize template manager")?;
37
38    // Determine the template to use
39    let template_type = if let Some(template) = args.template {
40        TemplateType::from_str(&template)
41            .with_context(|| format!("Invalid template type: {template}"))?
42    } else {
43        // Prompt the user to select a template
44        let templates = template_manager.list_templates();
45        let template_names: Vec<String> = templates.iter().map(|t| t.to_string()).collect();
46        let selection = Select::with_theme(&ColorfulTheme::default())
47            .with_prompt("Select a project template")
48            .default(0)
49            .items(&template_names)
50            .interact()
51            .context("Failed to get user selection")?;
52
53        templates
54            .get(selection)
55            .ok_or_else(|| anyhow::anyhow!("Invalid template selection"))?
56            .clone()
57    };
58
59    // Determine the output directory
60    let output_dir = match args.output_dir {
61        Some(dir) => dir,
62        None => {
63            // Use the current directory + project name
64            let mut dir = std::env::current_dir()?;
65            dir.push(&args.name);
66            dir
67        }
68    };
69
70    // Create the output directory if it doesn't exist
71    if !output_dir.exists() {
72        debug!("Creating output directory: {output_dir:?}");
73        fs::create_dir_all(&output_dir)
74            .with_context(|| format!("Failed to create directory: {output_dir:?}"))?;
75    }
76
77    // Generate the project from the template
78    template_manager
79        .generate_project(&args.name, template_type, &output_dir)
80        .with_context(|| format!("Failed to generate project in {output_dir:?}"))?;
81
82    println!(
83        "\n{} project created at {output_dir:?}",
84        style("Successfully").bold().green()
85    );
86
87    // Print next steps
88    println!("\n{}", style("Next steps:").bold());
89    println!("  cd {}", args.name);
90    println!("  orbiton dev");
91
92    Ok(())
93}