1use std::io::{BufReader, Read, Write};
2
3pub struct Builder {
4 name: String,
5 source: String,
6 logo_url: String,
7 as_comment: bool,
8}
9
10impl Builder {
11 pub fn new() -> Builder {
12 Builder {
13 name: "book".to_string(),
14 source: "book".to_string(),
15 logo_url: "".to_string(),
16 as_comment: false,
17 }
18 }
19
20 pub fn set_name(mut self, name: &str) -> Self {
21 self.name = name.to_string();
22 self
23 }
24 pub fn set_source(mut self, source: &str) -> Self {
25 self.source = source.to_string();
26 self
27 }
28 pub fn set_logo_url(mut self, logo_url: &str) -> Self {
29 self.logo_url = logo_url.to_string();
30 self
31 }
32 pub fn include_as_comment(mut self, as_comment: bool) -> Self {
33 self.as_comment = as_comment;
34 self
35 }
36
37 pub fn run(self) -> Result<(), std::io::Error> {
38 std::fs::create_dir_all(format!("examples/{}", self.name))?;
39 let mut main_rs = std::fs::File::create(format!("examples/{}/main.rs", self.name))?;
40 let readme_md = std::fs::File::open("README.md")?;
41 let mut reader = BufReader::new(readme_md);
42 let mut contents = "".to_string();
43 let _ = reader.read_to_string(&mut contents);
44
45 let mut lines: Vec<String> = vec![];
46
47 if self.logo_url != "" {
48 lines.push(format!("#![doc(html_logo_url = \"{}\")]", self.logo_url));
49 }
50
51 let mut readme_lines: Vec<String> = contents.split("\n").map(|n| format!("//! {}", n)).collect();
52 lines.append(&mut readme_lines);
53 lines.push("\nfn main () {}\n".to_string());
54
55 let summary_md = std::fs::File::open(format!("{}/src/SUMMARY.md", self.source))?;
56 let mut reader = BufReader::new(summary_md);
57 let mut summary_contents = "".to_string();
58 let _ = reader.read_to_string(&mut summary_contents);
59 let mut summary_lines: Vec<String> = summary_contents.split("\n")
60 .filter(|n| n.contains("(") && n.contains("["))
61 .map(|n| n.to_string())
62 .collect();
63
64 #[derive(Debug)]
65 enum StringOrVec {
66 String(String),
67 Vec(Vec<StringOrVec>),
68 }
69
70 fn create_branch(lines: &mut Vec<String>, current_level: i32) -> Vec<StringOrVec> {
71 let mut branch: Vec<StringOrVec> = vec![];
72 while lines.len() > 0 {
73 let value = lines.remove(0);
74
75 let mut x: Vec<String> = value.split("").map(|n| n.to_string()).collect();
76 let mut spaces: Vec<String> = vec![];
77 if x[0] == "" {
78 x.remove(0);
79 }
80 while x[0] == " " {
81 spaces.push(x.remove(0));
82 }
83
84 let new_level = (spaces.len() / 2) as i32;
85
86 if current_level == new_level {
87 branch.push(StringOrVec::String(value));
88 } else if current_level < new_level {
89 lines.insert(0, value);
90 branch.push(StringOrVec::Vec(create_branch(lines, new_level)));
91 } else if current_level > new_level {
92 lines.insert(0, value);
93 return branch;
94 }
95 }
96 branch
97 }
98 let tree = create_branch(&mut summary_lines, 0);
99
100
101 fn add_lines(lines: &mut Vec<String>, tree: Vec<StringOrVec>, source: String, as_comment: bool) -> Result<(), std::io::Error> {
102 let mut level = 0;
103 for entry in tree {
104 match entry {
105 StringOrVec::String(s) => {
106 level += 1;
107 let m_header: Vec<String> = s.trim().split("[").map(|n| n.to_string()).collect();
108 let n_header: Vec<String> = m_header[1].split("]").map(|n| n.to_string()).collect();
109 let header = n_header[0].to_lowercase().replace(" ", "_");
110
111 let m_link: Vec<String> = s.trim().split("(").map(|n| n.to_string()).collect();
112 let link: Vec<String> = m_link[1].split(")").map(|n| n.to_string()).collect();
113
114
115 if as_comment {
116 println!("{}/src/{}", source, link[0]);
117 let source_file = std::fs::File::open(format!("{}/src/{}", source, link[0]))?;
118 let mut reader = BufReader::new(source_file);
119 let mut contents = "".to_string();
120 let _ = reader.read_to_string(&mut contents);
121 let mut source_lines: Vec<String> = contents.split("\n").map(|n| format!("/// {}", n)).collect();
122 lines.append(&mut source_lines);
123 } else {
124 lines.push(format!("#[doc = include_str!(\"../../{}/src/{}\")]", source.to_string(), link[0]));
125 }
126 lines.push(format!("pub mod s{}_{} {{}}", level, header));
127 }
128 StringOrVec::Vec(v) => {
129 let old = lines.remove(lines.len() - 1);
130 lines.push(format!("{}", old.strip_suffix("}").unwrap()));
131 let _ = add_lines(lines, v, source.to_string(), as_comment);
132 lines.push(format!("}}\n"));
133 }
134 }
135 }
136 Ok(())
137 }
138 let _ = add_lines(&mut lines, tree, self.source, self.as_comment);
139
140
141 lines.push("".to_string());
142 contents = lines.join("\n");
143
144
145 main_rs.write_all(contents.as_bytes())?;
146 Ok(())
147 }
148}