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
36const HTML_VITE_CONFIG_JS: &str = include_str!("../static/html-templates/vite.config.js");
38const HTML_INDEX_HTML: &str = include_str!("../static/html-templates/index.html");
39const HTML_MAIN_JS: &str = include_str!("../static/html-templates/main.js");
40const HTML_SLIDES: &str = include_str!("../static/html-templates/slides.html");
41const HTML_CUSTOM_CSS: &str = include_str!("../static/html-templates/custom.css");
42const HTML_FERRIS: &[u8] = include_bytes!("../static/html-templates/ferris.png");
43
44pub fn init(_opts: InitOptions) -> Result<(), Box<dyn Error>> {
58 let conf = config::create_conf()?;
59
60 let template: Template = prompt_template()?;
61
62 std::fs::create_dir_all(&conf.title)?;
63
64 let output = Command::new("npm")
65 .args(["init", "-y", "--prefix", &conf.title])
66 .current_dir(&conf.title)
67 .output()?;
68
69 if !output.status.success() {
71 eprintln!(
72 "npm init failed: {}",
73 String::from_utf8_lossy(&output.stderr)
74 );
75 return Err("npm init failed".into());
76 }
77
78 let npm_commands = vec![
79 format!("install --save-dev vite http-server"),
80 format!("install reveal.js serve vite-plugin-singlefile"),
81 format!("install vite@5"),
82 format!("install patch-package"),
83 ];
84
85 for c in npm_commands {
86 let args: Vec<&str> = c.split(' ').collect();
87 let output = Command::new("npm")
88 .args(&args)
89 .current_dir(&conf.title)
90 .output()?;
91
92 if !output.status.success() {
93 eprintln!(
94 "npm {} failed: {}",
95 c,
96 String::from_utf8_lossy(&output.stderr)
97 );
98 return Err(format!("npm {} failed", c).into());
99 }
100 println!("Bootstrapped npm {}", c);
101 }
102
103 println!("Saving config file...");
104
105 config::write_config(&conf.title, &conf)?;
106
107 match template {
109 Template::Markdown => {
110 fs::write(format!("{}/vite.config.js", &conf.title), MD_VITE_CONFIG_JS)?;
112 fs::write(format!("{}/index.html", &conf.title), MD_INDEX_HTML)?;
113
114 std::fs::create_dir_all(format!("{}/src", &conf.title))?;
115 fs::write(format!("{}/src/main.js", &conf.title), MD_MAIN_JS)?;
116
117 std::fs::create_dir_all(format!("{}/slides", &conf.title))?;
118 fs::write(format!("{}/slides/slides.md", &conf.title), MD_SLIDES)?;
119
120 std::fs::create_dir_all(format!("{}/css", &conf.title))?;
121 fs::write(format!("{}/css/custom.css", &conf.title), MD_CUSTOM_CSS)?;
122
123 std::fs::create_dir_all(format!("{}/public", &conf.title))?;
124 fs::write(format!("{}/public/ferris.png", &conf.title), MD_FERRIS)?;
125 }
126 Template::HTML => {
127 fs::write(
129 format!("{}/vite.config.js", &conf.title),
130 HTML_VITE_CONFIG_JS,
131 )?;
132 fs::write(format!("{}/index.html", &conf.title), HTML_INDEX_HTML)?;
133
134 std::fs::create_dir_all(format!("{}/src", &conf.title))?;
135 fs::write(format!("{}/src/main.js", &conf.title), HTML_MAIN_JS)?;
136
137 std::fs::create_dir_all(format!("{}/slides", &conf.title))?;
138 fs::write(format!("{}/slides/slides.html", &conf.title), HTML_SLIDES)?;
139
140 std::fs::create_dir_all(format!("{}/css", &conf.title))?;
141 fs::write(format!("{}/css/custom.css", &conf.title), HTML_CUSTOM_CSS)?;
142
143 std::fs::create_dir_all(format!("{}/public", &conf.title))?;
144 fs::write(format!("{}/public/ferris.png", &conf.title), HTML_FERRIS)?
145 }
146 }
147
148 Ok(())
149}
150
151fn prompt_template() -> Result<Template, Box<dyn Error>> {
152 let template_opts: Vec<Template> = Template::iter().collect();
153
154 let chosen_template = inquire::Select::new("Select a template:", template_opts).prompt()?;
155
156 Ok(chosen_template)
157}