1use std::fs;
4use std::io::IsTerminal;
5use std::path::Path;
6
7use anyhow::{Result, anyhow};
8use colored::Colorize;
9use dialoguer::{Input, Select};
10
11fn sanitize_project_name(raw: &str) -> String {
16 let cleaned: String = raw
17 .chars()
18 .map(|c| {
19 if c.is_ascii_alphanumeric() || matches!(c, '-' | '_' | '.') {
20 c
21 } else {
22 '-'
23 }
24 })
25 .collect();
26
27 let trimmed = cleaned.trim_matches(|c| c == '-' || c == '.').to_string();
31 if trimmed.is_empty() {
32 "my-project".to_string()
33 } else {
34 trimmed
35 }
36}
37
38fn current_dir_name() -> Option<String> {
40 std::env::current_dir()
41 .ok()
42 .and_then(|d| d.file_name().map(|n| n.to_string_lossy().to_string()))
43 .filter(|n| !n.is_empty())
44}
45
46fn template(project_name: &str) -> String {
51 format!(
52 "project({{\n name = \"{project_name}\"\n}})\n\npackages({{\n \
53 -- Record project dependencies here, or add them with:\n -- zoi \
54 install --save <package>\n}})\n"
55 )
56}
57
58pub fn run(yes: bool, force: bool) -> Result<()> {
70 let config_path = Path::new("zoi.lua");
71
72 if config_path.exists() && !force {
73 return Err(anyhow!(
74 "A 'zoi.lua' already exists in this directory. Run 'zoi init \
75 --force' to overwrite it."
76 ));
77 }
78
79 let default_name = current_dir_name().map_or_else(
82 || "my-project".to_string(),
83 |n| sanitize_project_name(&n)
84 );
85
86 let project_name = if yes {
87 default_name
88 } else if std::io::stdin().is_terminal() {
89 let input = Input::<String>::new()
90 .with_prompt("Project name")
91 .default(default_name)
92 .allow_empty(false)
93 .interact_text()?;
94 sanitize_project_name(input.trim())
95 } else {
96 default_name
99 };
100
101 let contents = template(&project_name);
102
103 if config_path.exists() {
104 println!(
105 "{} Overwriting existing 'zoi.lua'...",
106 "Warning:".yellow().bold()
107 );
108 }
109
110 if !yes && std::io::stdout().is_terminal() {
113 println!("\n{}", contents.dimmed());
114 let choice = Select::new()
115 .with_prompt("Write this zoi.lua?")
116 .items(["Yes", "No, cancel"])
117 .default(0)
118 .interact()?;
119 if choice == 1 {
120 println!("{}", "Aborted.".yellow());
121 return Ok(());
122 }
123 }
124
125 fs::write(config_path, &contents)?;
126
127 println!(
128 "{} Created {} for project '{}'",
129 "Success:".green().bold(),
130 "zoi.lua".cyan(),
131 project_name
132 );
133 println!(
134 "\nAdd a dependency with:\n {}",
135 "zoi install --save <package>".dimmed()
136 );
137
138 Ok(())
139}