1use std::{
10 error::Error,
11 fs::{self},
12 process::Command,
13};
14
15use clap::Args;
16use strum::IntoEnumIterator;
17
18use crate::{config, template::Template};
19
20#[derive(Args, Debug)]
22pub struct InitOptions {
23 #[arg(long, required = false)]
25 sentation_only: bool,
26}
27
28const MD_VITE_CONFIG_JS: &str = include_str!("../static/md-templates/vite.config.js");
30const MD_INDEX_HTML: &str = include_str!("../static/md-templates/index.html");
31const MD_MAIN_JS: &str = include_str!("../static/md-templates/main.js");
32const MD_SLIDES: &str = include_str!("../static/md-templates/slides.md");
33const MD_CUSTOM_CSS: &str = include_str!("../static/md-templates/custom.css");
34const MD_FERRIS: &[u8] = include_bytes!("../static/md-templates/ferris.png");
35
36
37const HTML_VITE_CONFIG_JS: &str = include_str!("../static/html-templates/vite.config.js");
39const HTML_INDEX_HTML: &str = include_str!("../static/html-templates/index.html");
40const HTML_MAIN_JS: &str = include_str!("../static/html-templates/main.js");
41const HTML_SLIDES: &str = include_str!("../static/html-templates/slides.html");
42const HTML_CUSTOM_CSS: &str = include_str!("../static/html-templates/custom.css");
43const HTML_FERRIS: &[u8] = include_bytes!("../static/html-templates/ferris.png");
44
45
46pub fn init(_opts: InitOptions) -> Result<(), Box<dyn Error>> {
60 let conf = config::create_conf()?;
61
62
63 let template: Template = prompt_template()?;
64
65 std::fs::create_dir_all(&conf.title)?;
66
67 let output = Command::new("npm")
68 .args(["init", "-y", "--prefix", &conf.title])
69 .current_dir(&conf.title)
70 .output()?;
71
72 if !output.status.success() {
74 eprintln!(
75 "npm init failed: {}",
76 String::from_utf8_lossy(&output.stderr)
77 );
78 return Err("npm init failed".into());
79 }
80
81 let npm_commands = vec![
82 format!("install --save-dev vite http-server"),
83 format!("install reveal.js serve vite-plugin-singlefile"),
84 format!("install vite@5"),
85 format!("install patch-package"),
86 ];
87
88 for c in npm_commands {
89 let args: Vec<&str> = c.split(' ').collect();
90 let output = Command::new("npm")
91 .args(&args)
92 .current_dir(&conf.title)
93 .output()?;
94
95 if !output.status.success() {
96 eprintln!(
97 "npm {} failed: {}",
98 c,
99 String::from_utf8_lossy(&output.stderr)
100 );
101 return Err(format!("npm {} failed", c).into());
102 }
103 println!("Bootstrapped npm {}", c);
104
105 }
106
107 println!("Saving config file...");
108
109 config::write_config(&conf.title, &conf)?;
110
111 match template {
113 Template::Markdown => {
114 fs::write(format!("{}/vite.config.js", &conf.title), MD_VITE_CONFIG_JS)?;
116 fs::write(format!("{}/index.html", &conf.title), MD_INDEX_HTML)?;
117
118 std::fs::create_dir_all(format!("{}/src", &conf.title))?;
119 fs::write(format!("{}/src/main.js", &conf.title), MD_MAIN_JS)?;
120
121 std::fs::create_dir_all(format!("{}/slides", &conf.title))?;
122 fs::write(format!("{}/slides/slides.md", &conf.title), MD_SLIDES)?;
123
124 std::fs::create_dir_all(format!("{}/css", &conf.title))?;
125 fs::write(format!("{}/css/custom.css", &conf.title), MD_CUSTOM_CSS)?;
126
127 std::fs::create_dir_all(format!("{}/public", &conf.title))?;
128 fs::write(format!("{}/public/ferris.png", &conf.title), MD_FERRIS)?;
129 }
130 Template::HTML => {
131
132 fs::write(format!("{}/vite.config.js", &conf.title), HTML_VITE_CONFIG_JS)?;
134 fs::write(format!("{}/index.html", &conf.title), HTML_INDEX_HTML)?;
135
136 std::fs::create_dir_all(format!("{}/src", &conf.title))?;
137 fs::write(format!("{}/src/main.js", &conf.title), HTML_MAIN_JS)?;
138
139 std::fs::create_dir_all(format!("{}/slides", &conf.title))?;
140 fs::write(format!("{}/slides/slides.html", &conf.title), HTML_SLIDES)?;
141
142 std::fs::create_dir_all(format!("{}/css", &conf.title))?;
143 fs::write(format!("{}/css/custom.css", &conf.title), HTML_CUSTOM_CSS)?;
144
145 std::fs::create_dir_all(format!("{}/public", &conf.title))?;
146 fs::write(format!("{}/public/ferris.png", &conf.title), HTML_FERRIS)?
147 },
148 }
149
150 Ok(())
151}
152
153fn prompt_template() -> Result<Template, Box<dyn Error>> {
154 let template_opts: Vec<Template> = Template::iter().collect();
155
156 let chosen_template = inquire::Select::new("Select a template:", template_opts).prompt()?;
157
158 Ok(chosen_template)
159}