1use crate::element::{Element, UDTuple};
2use crate::Convert;
3use async_std::fs::File;
4use async_std::io::WriteExt;
5use std::io::Write;
6use std::path::PathBuf;
7
8type Doc = (Class, Option<u8>, Option<String>);
9
10#[derive(Debug, Clone)]
12pub struct Latex {
13 pub document_class: Doc,
18 pub metadata: Metadata,
20 pub packages: Vec<Package>,
22 pub document_elements: Vec<Element>,
24 pub maketitle: bool,
25}
26
27#[derive(Debug, Clone)]
29pub enum Class {
30 Article,
32 Book,
34 Report,
36 Beamer,
38}
39#[derive(Debug, Clone)]
41pub struct Metadata {
42 pub author: String,
44 pub title: String,
46 pub date: String,
48}
49#[derive(Debug, Clone)]
51pub struct Package(pub String);
52
53impl Package {
55 pub fn new(pkg: &str) -> Self {
56 Package(pkg.to_string())
57 }
58}
59
60impl Class {
61 pub fn as_class_str(&self) -> String {
62 match self {
63 Class::Article => "article".to_string(),
64 Class::Book => "book".to_string(),
65 Class::Report => "report".to_string(),
66 Class::Beamer => "beamer".to_string(),
67 }
68 }
69}
70
71impl Metadata {
72 pub fn new(title: &str, author: &str, date: &str) -> Self {
73 Self {
74 title: title.to_string(),
75 author: author.to_string(),
76 date: date.to_string(),
77 }
78 }
79}
80
81impl Default for Metadata {
82 fn default() -> Self {
83 Self {
84 author: "default author".to_string(),
85 title: "default title".to_string(),
86 date: "what day is it?".to_string(),
87 }
88 }
89}
90
91impl Latex {
92 pub fn new() -> Self {
93 Self {
94 document_class: (Class::Article, Some(11), Some("letterpaper".to_string())),
95 metadata: Metadata::default(),
96 packages: Vec::new(),
97 document_elements: Vec::new(),
98 maketitle: true,
99 }
100 }
101 pub fn set_class(&mut self, class: Class) {
103 self.document_class.0 = class;
104 }
105 pub fn set_class_options(&mut self, font_size: u8, paper_size: &str) {
107 self.document_class.1 = Some(font_size);
108 self.document_class.2 = Some(paper_size.to_string());
109 }
110 pub fn set_metadata(&mut self, meta: Metadata) {
112 self.metadata = meta;
113 }
114 pub fn set_packages(&mut self, packages: &Vec<Package>) {
116 self.packages = packages.to_owned();
117 }
118 pub fn add_package(&mut self, package: String) {
120 self.packages.push(Package(package));
121 }
122 pub fn set_elements(&mut self, elements: Vec<Element>) {
124 self.document_elements = elements;
125 }
126 pub fn get_ud(&self) -> Vec<UDTuple> {
129 let mut v: Vec<UDTuple> = Vec::new();
130
131 for i in &self.document_elements {
132 match i {
133 Element::UserDefined(u) => v.push(u.evaluate()),
134 _ => v.push(("".to_owned(), "".to_owned(), "".to_owned())),
135 }
136 }
137 v
138 }
139 pub fn no_maketitle(&mut self){
140 self.maketitle = false
141 }
142 pub fn write(&self, path: PathBuf) -> Result<(), std::io::Error> {
144 let ud_vec = &self.get_ud();
145 let path = path.as_path();
146 let mut file = std::fs::File::create(path)?;
147 let mut s: Vec<String> = Vec::new();
148 s.push(self.document_class.to_latex_string());
149 for i in ud_vec {
150 s.push(i.1.to_owned())
151 }
152 s.push(self.metadata.to_latex_string());
153 for i in &self.packages {
154 s.push(i.to_latex_string())
155 }
156 for i in ud_vec {
157 s.push(i.2.to_owned())
158 }
159 s.push(String::from("\\begin{document}"));
160 if self.maketitle{
161 s.push(String::from(
162 "\\maketitle\n\\pagenumbering{arabic}\n\\newpage",
163 ));
164 }
165 for i in &self.document_elements {
167 match i {
168 Element::Part(e) => {
169 s.push(e.to_latex_string());
170 for j in &e.1 {
171 s.push(j.to_latex_string());
172 s.push(j.loop_through())
173 }
174 }
175 Element::Chapter(e) => {
176 s.push(e.to_latex_string());
177 for j in &e.1 {
178 s.push(j.to_latex_string());
179 s.push(j.loop_through())
180 }
181 }
182 Element::Section(e) => {
183 s.push(e.to_latex_string());
184 for j in &e.1 {
185 s.push(j.to_latex_string());
186 s.push(j.loop_through())
187 }
188 }
189 Element::Paragraph(e) => {
190 s.push(e.to_latex_string());
191 for j in e.1.as_ref().unwrap() {
192 s.push(j.to_latex_string());
193 s.push(j.loop_through())
194 }
195 }
196 Element::Environment(e) => {
197 s.push(e.to_latex_string());
198 }
199 Element::List(e) => s.push(e.to_latex_string()),
200 Element::UserDefined(e) => {
201 let ud = e.evaluate();
202 s.push(ud.0)
203 }
204 Element::Text(e) => s.push(e.to_latex_string()),
205 Element::Input(e) => s.push(e.to_latex_string()),
206 }
207 }
208 s.push(String::from("\\end{document}"));
209 let content = s.join("\n");
210 file.write_all(&content.as_bytes())?;
211 Ok(())
212 }
213 pub async fn async_write(&self, path: PathBuf) -> Result<(), async_std::io::Error> {
215 let ud_vec = &self.get_ud();
216 let pool = rayon::ThreadPoolBuilder::new()
217 .num_threads(4)
218 .build()
219 .unwrap();
220 let path = path.as_path();
221 let mut file = File::create(path).await?;
222 let mut s: Vec<String> = Vec::new();
223 s.push(self.document_class.to_latex_string());
224 for i in ud_vec {
225 s.push(i.1.to_owned())
226 }
227 s.push(self.metadata.to_latex_string());
228 for i in &self.packages {
229 s.push(i.to_latex_string())
230 }
231 for i in ud_vec {
232 s.push(i.2.to_owned())
233 }
234 s.push(String::from("\\begin{document}"));
235 if self.maketitle{
236 s.push(String::from(
237 "\\maketitle\n\\pagenumbering{arabic}\n\\newpage",
238 ));
239 }
240 for i in &self.document_elements {
242 match i {
243 Element::Part(e) => {
244 s.push(e.to_latex_string());
245 for j in &e.1 {
246 s.push(j.to_latex_string());
247 s.push(pool.install(|| j.clone().loop_through_parallel()))
248 }
249 }
250 Element::Chapter(e) => {
251 s.push(e.to_latex_string());
252 for j in &e.1 {
253 s.push(j.to_latex_string());
254 s.push(pool.install(|| j.clone().loop_through_parallel()))
255 }
256 }
257 Element::Section(e) => {
258 s.push(e.to_latex_string());
259 for j in &e.1 {
260 s.push(j.to_latex_string());
261 s.push(pool.install(|| j.clone().loop_through_parallel()))
262 }
263 }
264 Element::Paragraph(e) => {
265 s.push(e.to_latex_string());
266 for j in e.1.as_ref().unwrap() {
267 s.push(j.to_latex_string());
268 s.push(pool.install(|| j.clone().loop_through_parallel()))
269 }
270 }
271 Element::Environment(e) => {
272 s.push(e.to_latex_string());
273 }
274 Element::List(e) => s.push(e.to_latex_string()),
275 Element::UserDefined(e) => {
276 let ud = e.evaluate();
277 s.push(ud.0)
278 }
279 Element::Text(e) => s.push(e.to_latex_string()),
280 Element::Input(e) => s.push(e.to_latex_string()),
281 }
282 }
283 s.push(String::from("\\end{document}"));
284 let content = s.join("\n");
285 file.write_all(&content.as_bytes()).await?;
286 Ok(())
287 }
288 pub async fn split_write(
291 &self,
292 main: PathBuf,
293 structure: PathBuf,
294 ) -> Result<(), async_std::io::Error> {
295 let ud_vec = &self.get_ud();
296 let main = main.as_path();
297 let structure = structure.as_path();
298
299 let mut s: Vec<String> = Vec::new();
300 let mut struct_s: Vec<String> = Vec::new();
301
302 s.push(self.document_class.to_latex_string());
303 for i in ud_vec {
304 s.push(i.1.to_owned())
305 }
306 s.push(self.metadata.to_latex_string());
307 for i in &self.packages {
308 struct_s.push(i.to_latex_string())
309 }
310 for i in ud_vec {
311 struct_s.push(i.2.to_owned())
312 }
313 s.push(String::from("\\begin{document}"));
314 if self.maketitle{
315 s.push(String::from(
316 "\\maketitle\n\\pagenumbering{arabic}\n\\newpage",
317 ));
318 }
319 for i in &self.document_elements {
321 match i {
322 Element::Part(e) => {
323 s.push(e.to_latex_string());
324 for j in &e.1 {
325 s.push(j.to_latex_string());
326 s.push(j.loop_through())
327 }
328 }
329 Element::Chapter(e) => {
330 s.push(e.to_latex_string());
331 for j in &e.1 {
332 s.push(j.to_latex_string());
333 s.push(j.loop_through())
334 }
335 }
336 Element::Section(e) => {
337 s.push(e.to_latex_string());
338 for j in &e.1 {
339 s.push(j.to_latex_string());
340 s.push(j.loop_through())
341 }
342 }
343 Element::Paragraph(e) => {
344 s.push(e.to_latex_string());
345 for j in e.1.as_ref().unwrap() {
346 s.push(j.to_latex_string());
347 s.push(j.loop_through())
348 }
349 }
350 Element::Environment(e) => {
351 s.push(e.to_latex_string());
352 }
353 Element::List(e) => s.push(e.to_latex_string()),
354 Element::UserDefined(e) => {
355 let ud = e.evaluate();
356 s.push(ud.0)
357 }
358 Element::Text(e) => s.push(e.to_latex_string()),
359 Element::Input(e) => s.push(e.to_latex_string()),
360 }
361 }
362 s.push(String::from("\\end{document}"));
363 let content = s.join("\n");
364 let mut main_file = File::create(main).await?;
365 main_file.write_all(&content.as_bytes()).await?;
366
367 let structure_cont = struct_s.join("\n");
368 let mut struct_file = File::create(structure).await?;
369 struct_file.write_all(&structure_cont.as_bytes()).await?;
370 Ok(())
371 }
372 pub fn split_string(&self) -> (String, String) {
373 let ud_vec = &self.get_ud();
374 let mut s: Vec<String> = Vec::new();
375 let mut struct_s: Vec<String> = Vec::new();
376
377 s.push(self.document_class.to_latex_string());
378 for i in ud_vec {
379 s.push(i.1.to_owned())
380 }
381 s.push(self.metadata.to_latex_string());
382 for i in &self.packages {
383 struct_s.push(i.to_latex_string())
384 }
385 for i in ud_vec {
386 struct_s.push(i.2.to_owned())
387 }
388 s.push(String::from("\\begin{document}"));
389 s.push(String::from(
390 "\\maketitle\n\\pagenumbering{arabic}\n\\newpage",
391 ));
392 for i in &self.document_elements {
394 match i {
395 Element::Part(e) => {
396 s.push(e.to_latex_string());
397 for j in &e.1 {
398 s.push(j.to_latex_string());
399 s.push(j.loop_through())
400 }
401 }
402 Element::Chapter(e) => {
403 s.push(e.to_latex_string());
404 for j in &e.1 {
405 s.push(j.to_latex_string());
406 s.push(j.loop_through())
407 }
408 }
409 Element::Section(e) => {
410 s.push(e.to_latex_string());
411 for j in &e.1 {
412 s.push(j.to_latex_string());
413 s.push(j.loop_through())
414 }
415 }
416 Element::Paragraph(e) => {
417 s.push(e.to_latex_string());
418 for j in e.1.as_ref().unwrap() {
419 s.push(j.to_latex_string());
420 s.push(j.loop_through())
421 }
422 }
423 Element::Environment(e) => {
424 s.push(e.to_latex_string());
425 }
426 Element::List(e) => s.push(e.to_latex_string()),
427 Element::UserDefined(e) => {
428 let ud = e.evaluate();
429 s.push(ud.0)
430 }
431 Element::Text(e) => s.push(e.to_latex_string()),
432 Element::Input(e) => s.push(e.to_latex_string()),
433 }
434 }
435 s.push(String::from("\\end{document}"));
436 let content = s.join("\n");
437 let structure_cont = struct_s.join("\n");
438 (content, structure_cont)
439 }
440}
441
442impl Convert for Doc {
444 fn to_latex_string(&self) -> String {
445 let fs = match self.1.clone() {
446 Some(f) => f.to_string(),
447 None => "11".to_owned(),
448 };
449 let paper = match self.2.clone() {
450 Some(a) => a,
451 None => "letterpaper".to_owned(),
452 };
453 format!(
454 "\\documentclass[{}pt, {}]{{{}}}",
455 &fs,
456 &paper,
457 &self.0.as_class_str()
458 )
459 }
460}
461
462impl Convert for Metadata {
463 fn to_latex_string(&self) -> String {
464 let v = vec![
465 format!("\\author{{{}}}", &self.author),
466 format!("\\title{{{}}}", &self.title),
467 format!("\\date{{{}}}", &self.date),
468 ];
469 v.join("\n")
470 }
471}
472
473impl Convert for Package {
474 fn to_latex_string(&self) -> String {
475 format!("\\usepackage{{{}}}", &self.0)
476 }
477}