1use mech_core::*;
2use mech_core::nodes::{Kind, Matrix};
3use std::collections::{HashMap, HashSet};
4use colored::Colorize;
5use std::io::{Read, Write, Cursor};
6use crate::*;
7
8#[derive(Debug, Clone, PartialEq)]
9pub struct Formatter{
10 identifiers: HashMap<u64, String>,
11 rows: usize,
12 cols: usize,
13 indent: usize,
14 pub html: bool,
15 nested: bool,
16 toc: bool,
17 figure_num: usize,
18 h2_num: usize,
19 h3_num: usize,
20 h4_num: usize,
21 h5_num: usize,
22 h6_num: usize,
23 citation_num: usize,
24 citation_map: HashMap<u64, usize>,
25 citations: Vec<String>,
26 interpreter_id: u64,
27}
28
29
30impl Formatter {
31
32 pub fn new() -> Formatter {
33 Formatter {
34 identifiers: HashMap::new(),
35 rows: 0,
36 cols: 0,
37 indent: 0,
38 h2_num: 0,
39 h3_num: 0,
40 h4_num: 0,
41 h5_num: 0,
42 h6_num: 0,
43 citation_num: 0,
44 citation_map: HashMap::new(),
45 citations: Vec::new(),
46 figure_num: 0,
47 html: false,
48 nested: false,
49 toc: false,
50 interpreter_id: 0,
51 }
52 }
53
54 pub fn format(&mut self, tree: &Program) -> String {
55 self.html = false;
56 self.program(tree)
57 }
58
59 pub fn reset_numbering(&mut self) {
65 self.h2_num = 0;
66 self.h3_num = 0;
67 self.h4_num = 0;
68 self.h5_num = 0;
69 self.h6_num = 0;
70 self.figure_num = 0;
71 }
72
73 pub fn works_cited(&mut self) -> String {
74 if self.citations.is_empty() {
75 return "".to_string();
76 }
77 let id = hash_str("works-cited");
78
79 let gs = graphemes::init_source("Works Cited");
80 let (_,text) = paragraph(ParseString::new(&gs)).unwrap();
81 let h2 = self.subtitle(&Subtitle { level: 2, text });
82
83 let mut src = format!(r#"<section id="67320967384727436" class="mech-works-cited">"#);
84 src.push_str(&h2);
85 for citation in &self.citations {
86 src.push_str(citation);
87 }
88 src.push_str("</section>\n");
89 src
90 }
91
92 pub fn format_html(&mut self, tree: &Program, style: String, shim: String) -> String {
93 self.html = true;
94
95 let toc = tree.table_of_contents();
96 let formatted_src = self.program(tree);
97 self.reset_numbering();
98 let formatted_toc = self.table_of_contents(&toc);
99
100 let title = match toc.title {
101 Some(title) => title.to_string(),
102 None => "Mech Program".to_string(),
103 };
104
105 #[cfg(feature = "serde")]
106 let encoded_tree = match compress_and_encode(&tree) {
107 Ok(encoded) => encoded,
108 Err(e) => todo!(),
109 };
110 #[cfg(not(feature = "serde"))]
111 let encoded_tree = String::new();
112
113 shim.replace("{{STYLESHEET}}", &style)
114 .replace("{{TOC}}", &formatted_toc)
115 .replace("{{CONTENT}}", &formatted_src)
116 .replace("{{CODE}}", &encoded_tree)
117 .replace("{{TITLE}}", &title)
118 }
119
120 pub fn table_of_contents(&mut self, toc: &TableOfContents) -> String {
121 self.toc = true;
122 let sections = self.sections(&toc.sections);
123 self.toc = false;
124 let section_id = hash_str(&format!("section-{}", self.h2_num + 1));
125 let formatted_works_cited = if self.html && self.citation_num > 0 && !self.citations.is_empty() {
126 format!(
127 "<section id=\"\" section=\"{}\" class=\"mech-program-section toc\">
128 <h2 id=\"\" section=\"{}\" class=\"mech-program-subtitle toc active\">
129 <a class=\"mech-program-subtitle-link toc\" href=\"#67320967384727436\">Works Cited</a>
130 </h2>
131</section>",
132 section_id,
133 self.h2_num + 1
134 )
135 } else {
136 "".to_string()
137 };
138 format!("<div class=\"mech-toc\">{}{}</div>", sections, formatted_works_cited)
139 }
140
141 pub fn sections(&mut self, sections: &Vec<Section>) -> String {
142 let mut src = "".to_string();
143 let section_count = sections.len();
144 for (i, section) in sections.iter().enumerate() {
145 let s = self.section(section);
146 src = format!("{}{}", src, s);
147 }
148 format!("<section class=\"mech-toc-sections\">{}</section>",src)
149 }
150
151 pub fn program(&mut self, node: &Program) -> String {
152 let title = match &node.title {
153 Some(title) => self.title(&title),
154 None => "".to_string(),
155 };
156 let body = self.body(&node.body);
157 let formatted_works_cited = self.works_cited();
158 if self.html {
159 format!("<div class=\"mech-content\"><div class=\"mech-program\">{}{}{}</div></div>",title,body,formatted_works_cited)
160 } else {
161 format!("{}{}{}",title,body,formatted_works_cited)
162 }
163 }
164
165 pub fn title(&mut self, node: &Title) -> String {
166 if self.html {
167 format!("<h1 class=\"mech-program-title\">{}</h1>",node.to_string())
168 } else {
169 format!("{}\n===============================================================================\n",node.to_string())
170 }
171 }
172
173 pub fn subtitle(&mut self, node: &Subtitle) -> String {
174 let level = node.level;
175 if level == 2 {
176 self.h2_num += 1;
177 self.h3_num = 0;
178 self.h4_num = 0;
179 self.h5_num = 0;
180 self.h6_num = 0;
181 self.figure_num = 0;
182 } else if level == 3 {
183 self.h3_num += 1;
184 } else if level == 4 {
185 self.h4_num += 1;
186 } else if level == 5 {
187 self.h5_num += 1;
188 } else if level == 6 {
189 self.h6_num += 1;
190 }
191
192 let toc = if self.toc { "toc" } else { "" };
193 let title_id = hash_str(&format!("{}.{}.{}.{}.{}{}",self.h2_num,self.h3_num,self.h4_num,self.h5_num,self.h6_num,toc));
194
195 let link_str = format!("{}.{}.{}.{}.{}",self.h2_num,self.h3_num,self.h4_num,self.h5_num,self.h6_num);
196 let link_id = hash_str(&link_str);
197
198 let section = if level == 2 { format!("section=\"{}.{}\"", self.h2_num, self.h3_num) }
199 else if level == 3 { format!("section=\"{}.{}\"", self.h2_num, self.h3_num) }
200 else if level == 4 { format!("section=\"{}.{}.{}\"", self.h2_num, self.h3_num, self.h4_num) }
201 else if level == 5 { format!("section=\"{}.{}.{}.{}\"", self.h2_num, self.h3_num, self.h4_num, self.h5_num) }
202 else if level == 6 { format!("section=\"{}.{}.{}.{}.{}\"", self.h2_num, self.h3_num, self.h4_num, self.h5_num, self.h6_num) }
203 else { "".to_string() };
204
205 if self.html {
206 format!("<h{} id=\"{}\" {} class=\"mech-program-subtitle {}\"><a class=\"mech-program-subtitle-link {}\" href=\"#{}\">{}</a></h{}>", level, title_id, section, toc, toc, link_id, node.to_string(), level)
207 } else {
208 format!("{}\n-------------------------------------------------------------------------------\n",node.to_string())
209 }
210 }
211
212 pub fn body(&mut self, node: &Body) -> String {
213 let mut src = "".to_string();
214 let section_count = node.sections.len();
215 for (i, section) in node.sections.iter().enumerate() {
216 let s = self.section(section);
217 src = format!("{}{}", src, s);
218 }
219 if self.html {
220 format!("<div class=\"mech-program-body\">{}</div>",src)
221 } else {
222 src
223 }
224 }
225
226 pub fn section(&mut self, node: &Section) -> String {
227 let mut src = match &node.subtitle {
228 Some(title) => self.subtitle(title),
229 None => "".to_string(),
230 };
231 for el in node.elements.iter() {
232 let el_str = self.section_element(el);
233 src = format!("{}{}", src, el_str);
234 }
235 let toc = if self.toc { "toc" } else { "" };
236 let section_id = hash_str(&format!("section-{}",self.h2_num + 1));
237 let id = hash_str(&format!("section-{}{}",self.h2_num + 1, toc));
238 if self.html {
239 format!("<section id=\"{}\" section=\"{}\" class=\"mech-program-section {}\">{}</section>",id,section_id,toc,src)
240 } else {
241 src
242 }
243 }
244
245 pub fn paragraph(&mut self, node: &Paragraph) -> String {
246 let mut src = "".to_string();
247 for el in node.elements.iter() {
248 let el_str = self.paragraph_element(el);
249 src = format!("{}{}", src, el_str);
250 }
251 let result = if self.html {
252 format!("<p class=\"mech-paragraph\">{}</p>",src)
253 } else {
254 format!("{}\n",src)
255 };
256 result
257 }
258
259 pub fn inline_paragraph(&mut self, node: &Paragraph) -> String {
260 let mut src = "".to_string();
261 for el in node.elements.iter() {
262 let el_str = self.paragraph_element(el);
263 src = format!("{}{}", src, el_str);
264 }
265 let result = if self.html {
266 format!("<span class=\"mech-inline-paragraph\">{}</span>",src)
267 } else {
268 format!("{}",src)
269 };
270 result
271 }
272
273 fn footnote_reference(&mut self, node: &Token) -> String {
274 let id_string = node.to_string();
275 let id_hash = hash_str(&format!("footnote-{}",id_string));
276 if self.html {
277 format!("<a href=\"#{}\" class=\"mech-footnote-reference\">{}</a>",id_hash, id_string)
278 } else {
279 format!("[^{}]",id_string)
280 }
281 }
282
283 fn inline_equation(&mut self, node: &Token) -> String {
284 let id = hash_str(&format!("inline-equation-{}",node.to_string()));
285 if self.html {
286 format!("<span id=\"{}\" equation=\"{}\" class=\"mech-inline-equation\"></span>",id, node.to_string())
287 } else {
288 format!("$${}$$", node.to_string())
289 }
290 }
291
292 fn highlight(&mut self, node: &Token) -> String {
293 if self.html {
294 format!("<mark class=\"mech-highlight\">{}</mark>", node.to_string())
295 } else {
296 format!("!!{}!!", node.to_string())
297 }
298 }
299
300 fn reference(&mut self, node: &Token) -> String {
301 self.citation_num += 1;
302 let id = hash_str(&format!("reference-{}",node.to_string()));
303 let ref_id = hash_str(&format!("{}",node.to_string()));
304 self.citation_map.insert(ref_id, self.citation_num);
305 if self.html {
306 format!("<span id=\"{}\" class=\"mech-reference\">[<a href=\"#{}\" class=\"mech-reference-link\">{}</a>]</span>",id, ref_id, self.citation_num)
307 } else {
308 format!("[{}]",node.to_string())
309 }
310 }
311
312 pub fn paragraph_element(&mut self, node: &ParagraphElement) -> String {
313 match node {
314 ParagraphElement::Error(t, s) => {
315 if self.html {
316 format!("<span class=\"mech-error\" title=\"Error at {:?}\">{}</span>", s, t.to_string())
317 } else {
318 format!("{{ERROR: {} at {:?}}}", t.to_string(), s)
319 }
320 },
321 ParagraphElement::Highlight(n) => {
322 if self.html {
323 format!("<mark class=\"mech-highlight\">{}</mark>", n.to_string())
324 } else {
325 format!("!!{}!!", n.to_string())
326 }
327 },
328 ParagraphElement::SectionReference(n) => {
329 let section_id_str = n.to_string();
330 let parts: Vec<&str> = section_id_str.split('.').collect();
331 let mut nums = vec!["0"; 5]; for (i, part) in parts.iter().enumerate() {
333 nums[i] = part;
334 }
335 let id_str = format!("{}.{}.{}.{}.{}",nums[0], nums[1], nums[2], nums[3], nums[4]);
336 let id = hash_str(&id_str);
337
338 if self.html {
339 format!(
340 "<span class=\"mech-section-reference\">
341 <a href=\"#{}\" class=\"mech-section-reference-link\">§{}</a>
342 </span>",
343 id, n.to_string()
344 )
345 } else {
346 format!("§{}", n.to_string())
347 }
348 }
349 ParagraphElement::Reference(n) => self.reference(n),
350 ParagraphElement::InlineEquation(exq) => self.inline_equation(exq),
351 ParagraphElement::Text(n) => {
352 if self.html {
353 format!("<span class=\"mech-text\">{}</span>", n.to_string())
354 } else {
355 n.to_string()
356 }
357 }
358 ParagraphElement::FootnoteReference(n) => self.footnote_reference(n),
359 ParagraphElement::Strong(n) => {
360 let p = self.paragraph_element(n);
361 if self.html {
362 format!("<strong class=\"mech-strong\">{}</strong>", p)
363 } else {
364 format!("**{}**", p)
365 }
366 },
367 ParagraphElement::Hyperlink((text, url)) => {
368 let url_str = url.to_string();
369 let text_str = self.inline_paragraph(text);
370 if self.html {
371 format!("<a href=\"{}\" class=\"mech-hyperlink\">{}</a>",url_str,text_str)
372 } else {
373 format!("[{}]({})",text_str,url_str)
374 }
375 },
376 ParagraphElement::Emphasis(n) => {
377 if self.html {
378 format!("<em class=\"mech-em\">{}</em>", n.to_string())
379 } else {
380 format!("*{}*", n.to_string())
381 }
382 },
383 ParagraphElement::Underline(n) => {
384 if self.html {
385 format!("<u class=\"mech-u\">{}</u>", n.to_string())
386 } else {
387 format!("_{}_", n.to_string())
388 }
389 },
390 ParagraphElement::Strikethrough(n) => {
391 if self.html {
392 format!("<del class=\"mech-del\">{}</del>", n.to_string())
393 } else {
394 format!("~{}~", n.to_string())
395 }
396 },
397 ParagraphElement::InlineCode(n) => {
398 if self.html {
399 format!("<code class=\"mech-inline-code\">{}</code>", n.to_string().trim())
400 } else {
401 format!("`{}`", n.to_string())
402 }
403 },
404 ParagraphElement::InlineMechCode(code) => {
405 let result = self.mech_code(&vec![(code.clone(),None)]);
406 if self.html {
407 format!("<span class=\"mech-inline-mech-code-formatted\">{}</span>", result)
408 } else {
409 format!("{{{}}}", result)
410 }
411 },
412 ParagraphElement::EvalInlineMechCode(expr) => {
413 let code_id = hash_str(&format!("{:?}", expr));
414 let result = self.expression(expr);
415 if self.html {
416 format!("<code id=\"{}\" class=\"mech-inline-mech-code\">{}</code>", code_id, result)
417 } else {
418 format!("{{{}}}", result)
419 }
420 },
421 }
422 }
423
424 pub fn fenced_mech_code(&mut self, block: &FencedMechCode) -> String {
425 self.interpreter_id = block.config.namespace;
426 let block_id = hash_str(&format!("{:?}",block));
427 let namespace_str = &block.config.namespace_str;
428 let mut src = String::new();
429 for (code,cmmnt) in &block.code {
430 let c = match code {
431 MechCode::Comment(cmnt) => self.comment(cmnt),
432 MechCode::Expression(expr) => self.expression(expr),
433 MechCode::Statement(stmt) => self.statement(stmt),
437 _ => todo!(),
438 };
439 let formatted_comment = match cmmnt {
440 Some(cmmt) => self.comment(cmmt),
441 None => String::new(),
442 };
443 if self.html {
444 src.push_str(&format!("<span class=\"mech-code\">{}{}</span>", c, formatted_comment));
445 } else {
446 src.push_str(&format!("{}{}\n", c, formatted_comment));
447 }
448 }
449 let intrp_id = self.interpreter_id;
450 self.interpreter_id = 0;
451 let disabled_tag = match block.config.disabled {
452 true => "disabled".to_string(),
453 false => "".to_string(),
454 };
455 if self.html {
456 let (out_node,_) = block.code.last().unwrap();
457 let output_id = hash_str(&format!("{:?}", out_node));
458 let style_attr = match &block.options {
459 Some(option_map) if !option_map.elements.is_empty() => {
460 let style_str = option_map
461 .elements
462 .iter()
463 .map(|(k, v)| {
464 let clean_value = v.to_string().trim_matches('"').to_string();
465 format!("{}: {}", k.to_string(), clean_value)
466 })
467 .collect::<Vec<_>>()
468 .join("; ");
469 format!(" style=\"{}\"", style_str)
470 }
471 _ => "".to_string(),
472 };
473 if block.config.disabled {
474 format!("<pre class=\"mech-code-block disabled\"{}>{}</pre>", style_attr, src)
475 } else if block.config.hidden {
476 format!("<pre class=\"mech-code-block hidden\"{}>{}</pre>", style_attr, src)
478 } else {
479 let namespace_str = if namespace_str.is_empty() {
480 "".to_string()
481 } else {
482 format!("<div class=\"mech-code-block-namespace\"><a href=\"#{}\">{}</a></div>", block_id, namespace_str)
483 };
484 format!("<div id=\"{}\" class=\"mech-fenced-mech-block\"{}>
485 {}
486 <div class=\"mech-code-block\">{}</div>
487 <div class=\"mech-block-output\" id=\"{}:{}\"></div>
488 </div>", block_id, style_attr, namespace_str, src, output_id, intrp_id)
489 }
490 } else {
491 format!("```mech{}\n{}\n```", src, format!(":{}", disabled_tag))
492 }
493 }
494
495 pub fn image(&mut self, node: &Image) -> String {
496 self.figure_num += 1;
497
498 let src = node.src.to_string();
499 let caption_p = match &node.caption {
500 Some(caption) => self.paragraph(caption),
501 None => "".to_string(),
502 };
503
504 let figure_label = format!("Fig {}.{}", self.h2_num, self.figure_num);
505 let image_id = hash_str(&src);
506 let figure_id = hash_str(&figure_label);
507
508 if self.html {
509 let style_attr = match &node.style {
510 Some(option_map) if !option_map.elements.is_empty() => {
511 let style_str = option_map
512 .elements
513 .iter()
514 .map(|(k, v)| {
515 let clean_value = v.to_string().trim_matches('"').to_string();
516 format!("{}: {}", k.to_string(), clean_value)
517 })
518 .collect::<Vec<_>>()
519 .join("; ");
520 format!(" style=\"{}\"", style_str)
521 }
522 _ => "".to_string(),
523 };
524 format!(
525"<figure id=\"{}\" class=\"mech-figure\">
526 <img id=\"{}\" class=\"mech-image\" src=\"{}\"{} />
527 <figcaption class=\"mech-figure-caption\">
528 <strong class=\"mech-figure-label\">{}</strong> {}
529 </figcaption>
530</figure>",figure_id, image_id, src, style_attr, figure_label, caption_p)
531 } else {
532 let style_str = match &node.style {
533 Some(option_map) if !option_map.elements.is_empty() => {
534 let inner = option_map
535 .elements
536 .iter()
537 .map(|(k, v)| {
538 let clean_value = v.to_string().trim_matches('"').to_string();
539 format!("{}: \"{}\"", k.to_string(), clean_value)
540 })
541 .collect::<Vec<_>>()
542 .join(", ");
543 format!("{{{}}}", inner)
544 }
545 _ => "".to_string(),
546 };
547
548 format!("{}", caption_p, src, style_str)
549 }
550 }
551
552
553 pub fn abstract_el(&mut self, node: &Vec<Paragraph>) -> String {
554 let abstract_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
555 if self.html {
556 format!("<div id=\"abstract\" class=\"mech-abstract\">{}</div>", abstract_paragraph)
557 } else {
558 format!("{}\n", abstract_paragraph)
559 }
560 }
561
562 pub fn equation(&mut self, node: &Token) -> String {
563 let id = hash_str(&format!("equation-{}",node.to_string()));
564 if self.html {
565 format!("<div id=\"{}\" equation=\"{}\" class=\"mech-equation\"></div>",id, node.to_string())
566 } else {
567 format!("$$ {}\n", node.to_string())
568 }
569 }
570
571 pub fn diagram(&mut self, node: &Token) -> String {
572 let id = hash_str(&format!("diagram-{}",node.to_string()));
573 if self.html {
574 format!("<div id=\"{}\" class=\"mech-diagram mermaid\">{}</div>",id, node.to_string())
575 } else {
576 format!("```{{diagram}}\n{}\n```", node.to_string())
577 }
578 }
579
580 pub fn citation(&mut self, node: &Citation) -> String {
581 let id = hash_str(&format!("{}",node.id.to_string()));
582 self.citations.resize(self.citation_num, String::new());
583 let citation_text = self.paragraph(&node.text);
584 let citation_num = match self.citation_map.get(&id) {
585 Some(&num) => num,
586 None => {
587 return format!("Citation {} not found in citation map.", node.id.to_string());
588 }
589 };
590 let formatted_citation = if self.html {
591 format!("<div id=\"{}\" class=\"mech-citation\">
592 <div class=\"mech-citation-id\">[{}]:</div>
593 {}
594 </div>",id, citation_num, citation_text)
595 } else {
596 format!("[{}]: {}",node.id.to_string(), citation_text)
597 };
598 self.citations[citation_num - 1] = formatted_citation;
599 String::new()
600 }
601
602 pub fn float(&mut self, node: &Box<SectionElement>, float_dir: &FloatDirection) -> String {
603 let mut src = "".to_string();
604 let id = hash_str(&format!("float-{:?}",*node));
605 let (float_class,float_sigil) = match float_dir {
606 FloatDirection::Left => ("mech-float left","<<"),
607 FloatDirection::Right => ("mech-float right",">>"),
608 };
609 let el = self.section_element(node);
610 if self.html {
611 format!("<div id=\"{}\" class=\"{}\">{}</div>",id,float_class,el)
612 } else {
613 format!("{}{}\n",float_sigil, el)
614 }
615 }
616
617 pub fn info_block(&mut self, node: &Vec<Paragraph>) -> String {
618 let info_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
619 if self.html {
620 format!("<div class=\"mech-info-block\">{}</div>",info_paragraph)
621 } else {
622 format!("(i)> {}\n",info_paragraph)
623 }
624 }
625
626 pub fn question_block(&mut self, node: &Vec<Paragraph>) -> String {
627 let question_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
628 if self.html {
629 format!("<div class=\"mech-question-block\">{}</div>",question_paragraph)
630 } else {
631 format!("(?)> {}\n",question_paragraph)
632 }
633 }
634
635 pub fn success_block(&mut self, node: &Vec<Paragraph>) -> String {
636 let success_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
637 if self.html {
638 format!("<div class=\"mech-success-block\">{}</div>",success_paragraph)
639 } else {
640 format!("(✓)>> {}\n",success_paragraph)
641 }
642 }
643
644 pub fn warning_block(&mut self, node: &Vec<Paragraph>) -> String {
645 let warning_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
646 if self.html {
647 format!("<div class=\"mech-warning-block\">{}</div>",warning_paragraph)
648 } else {
649 format!("(!)>> {}\n",warning_paragraph)
650 }
651 }
652
653 pub fn idea_block(&mut self, node: &Vec<Paragraph>) -> String {
654 let idea_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
655 if self.html {
656 format!("<div class=\"mech-idea-block\">{}</div>",idea_paragraph)
657 } else {
658 format!("(*)> {}\n",idea_paragraph)
659 }
660 }
661
662 pub fn error_block(&mut self, node: &Vec<Paragraph>) -> String {
663 let error_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
664 if self.html {
665 format!("<div class=\"mech-error-block\">{}</div>",error_paragraph)
666 } else {
667 format!("(✗)>> {}\n",error_paragraph)
668 }
669 }
670
671 pub fn mika(&mut self, node: &(Mika, Option<MikaSection>)) -> String {
672 let (mika, section) = node;
673 let mika_str = format!("<div class=\"mech-mika\">{}</div>", mika.to_string());
674 if self.html {
675 match section {
676 Some(sec) => {
677 let mut sec_str = "".to_string();
678 for el in &sec.elements.elements {
679 let section_element = self.section_element(el);
680 sec_str.push_str(§ion_element);
681 }
682 format!("<div class=\"mech-mika-section\">{} {}</div>", mika_str, sec_str)
683 },
684 None => mika_str,
685 }
686 } else {
687 mika_str
688 }
689 }
690
691 pub fn section_element(&mut self, node: &SectionElement) -> String {
692 match node {
693 SectionElement::Abstract(n) => self.abstract_el(n),
694 SectionElement::QuoteBlock(n) => self.quote_block(n),
695 SectionElement::SuccessBlock(n) => self.success_block(n),
696 SectionElement::IdeaBlock(n) => self.idea_block(n),
697 SectionElement::InfoBlock(n) => self.info_block(n),
698 SectionElement::WarningBlock(n) => self.warning_block(n),
699 SectionElement::ErrorBlock(n) => self.error_block(n),
700 SectionElement::QuestionBlock(n) => self.question_block(n),
701 SectionElement::Citation(n) => self.citation(n),
702 SectionElement::CodeBlock(n) => self.code_block(n),
703 SectionElement::Comment(n) => self.comment(n),
704 SectionElement::Diagram(n) => self.diagram(n),
705 SectionElement::Equation(n) => self.equation(n),
706 SectionElement::FencedMechCode(n) => self.fenced_mech_code(n),
707 SectionElement::Float((n,f)) => self.float(n,f),
708 SectionElement::Footnote(n) => self.footnote(n),
709 SectionElement::Grammar(n) => self.grammar(n),
710 SectionElement::Image(n) => self.image(n),
711 SectionElement::List(n) => self.list(n),
712 SectionElement::MechCode(n) => self.mech_code(n),
713 SectionElement::Mika(n) => self.mika(n),
714 SectionElement::Paragraph(n) => self.paragraph(n),
715 SectionElement::Subtitle(n) => self.subtitle(n),
716 SectionElement::Table(n) => self.mechdown_table(n),
717 SectionElement::ThematicBreak => self.thematic_break(),
718 SectionElement::Error(src, range) => self.section_error(src.clone(), range),
719 }
720 }
721
722 pub fn section_error(&mut self, src: Token, range: &SourceRange) -> String {
723 if self.html {
724 let mut error_str = String::new();
725 error_str.push_str(&format!("<div class=\"mech-section-error\">\n"));
726 error_str.push_str(&format!("<strong>Error in section at range {:?}-{:?}:</strong>\n", range.start, range.end));
727 error_str.push_str(&format!("<pre class=\"mech-error-source\">{}</pre>\n", src.to_string()));
728 error_str.push_str("</div>\n");
729 error_str
730 } else {
731 let mut error_str = String::new();
732 error_str.push_str(&format!("Error in section at range {:?}-{:?}:\n", range.start, range.end));
733 error_str.push_str(&format!("{} ", src.to_string()));
734 error_str.push_str("\n");
735 error_str
736 }
737 }
738
739 pub fn footnote(&mut self, node: &Footnote) -> String {
740 let (id_name, paragraphs) = node;
741 let note_paragraph = paragraphs.iter().map(|p| self.paragraph(p)).collect::<String>();
742 let id: u64 = hash_str(&format!("footnote-{}",id_name.to_string()));
743 if self.html {
744 format!("<div class=\"mech-footnote\" id=\"{}\">
745 <div class=\"mech-footnote-id\">{}:</div>
746 {}
747 </div>",id, id_name.to_string(), note_paragraph)
748 } else {
749 format!("[^{}]: {}\n",id_name.to_string(), note_paragraph)
750 }
751 }
752
753 pub fn quote_block(&mut self, node: &Vec<Paragraph>) -> String {
754 let quote_paragraph = node.iter().map(|p| self.paragraph(p)).collect::<String>();
755 if self.html {
756 format!("<blockquote class=\"mech-block-quote\">{}</blockquote>",quote_paragraph)
757 } else {
758 format!("> {}\n",quote_paragraph)
759 }
760 }
761
762 pub fn thematic_break(&mut self) -> String {
763 if self.html {
764 format!("<hr class=\"mech-thematic-break\"/>")
765 } else {
766 format!("***\n")
767 }
768 }
769
770 pub fn mechdown_table(&mut self, node: &MarkdownTable) -> String {
771 if self.html {
772 self.mechdown_table_html(node)
773 } else {
774 self.mechdown_table_string(node)
775 }
776 }
777
778
779 pub fn mechdown_table_string(&mut self, node: &MarkdownTable) -> String {
780 fn render_row(cells: &[Paragraph], f: &mut impl FnMut(&Paragraph) -> String) -> String {
782 let mut row = String::from("|");
783 for cell in cells {
784 row.push_str(" ");
785 row.push_str(&f(cell));
786 row.push_str(" |");
787 }
788 row
789 }
790
791 let header_line = render_row(&node.header, &mut |p| self.paragraph(p));
793
794 let mut align_line = String::from("|");
796 for align in &node.alignment {
797 let spec = match align {
798 ColumnAlignment::Left => ":---",
799 ColumnAlignment::Center => ":---:",
800 ColumnAlignment::Right => "---:",
801 };
802 align_line.push_str(&format!(" {} |", spec));
803 }
804
805 let mut body_lines = vec![];
807 for row in &node.rows {
808 body_lines.push(render_row(row, &mut |p| self.paragraph(p)));
809 }
810
811 let mut markdown = String::new();
813 markdown.push_str(&header_line);
814 markdown.push('\n');
815 markdown.push_str(&align_line);
816 markdown.push('\n');
817 for line in body_lines {
818 markdown.push_str(&line);
819 markdown.push('\n');
820 }
821
822 markdown
823}
824
825
826 pub fn mechdown_table_html(&mut self, node: &MarkdownTable) -> String {
827 let mut html = String::new();
828 html.push_str("<table class=\"mech-table\">");
829
830 if !node.header.is_empty() {
832 html.push_str("<thead><tr class=\"mech-table-header\">");
833 for (i, cell) in node.header.iter().enumerate() {
834 let align = match node.alignment.get(i) {
835 Some(ColumnAlignment::Left) => "left",
836 Some(ColumnAlignment::Center) => "center",
837 Some(ColumnAlignment::Right) => "right",
838 None => "left", };
840 let cell_html = self.paragraph(cell);
841 html.push_str(&format!(
842 "<th class=\"mech-table-header-cell {}\">{}</th>",
843 align, cell_html
844 ));
845 }
846 html.push_str("</tr></thead>");
847 }
848
849 html.push_str("<tbody>");
851 for (row_index, row) in node.rows.iter().enumerate() {
852 let row_class = if row_index % 2 == 0 { "mech-table-row-even" } else { "mech-table-row-odd" };
853 html.push_str(&format!("<tr class=\"mech-table-row {}\">", row_class));
854 for (i, cell) in row.iter().enumerate() {
855 let align = match node.alignment.get(i) {
856 Some(ColumnAlignment::Left) => "left",
857 Some(ColumnAlignment::Center) => "center",
858 Some(ColumnAlignment::Right) => "right",
859 None => "left", };
861 let cell_html = self.paragraph(cell);
862 html.push_str(&format!(
863 "<td class=\"mech-table-cell {}\">{}</td>",
864 align, cell_html
865 ));
866 }
867 html.push_str("</tr>");
868 }
869 html.push_str("</tbody>");
870 html.push_str("</table>");
871 html
872 }
873
874 pub fn grammar(&mut self, node: &Grammar) -> String {
875 let mut src = "".to_string();
876 for rule in node.rules.iter() {
877 let id = self.grammar_identifier(&rule.name);
878 let rule_str = format!("{} <span class=\"mech-grammar-define-op\">:=</span>{}", id, self.grammar_expression(&rule.expr));
879 if self.html {
880 src = format!("{}<div class=\"mech-grammar-rule\">{} ;</div>",src,rule_str);
881 } else {
882 src = format!("{}{};\n",src,rule_str);
883 }
884 }
885 if self.html {
886 format!("<div class=\"mech-grammar\">{}</div>",src)
887 } else {
888 src
889 }
890 }
891
892 fn grammar_identifier(&mut self, node: &GrammarIdentifier) -> String {
893 let name = node.name.to_string();
894 if self.html {
895 format!("<span id=\"{}\" class=\"mech-grammar-identifier\">{}</span>",hash_str(&name), name)
896 } else {
897 name
898 }
899 }
900
901 fn grammar_expression(&mut self, node: &GrammarExpression) -> String {
902 let expr = match node {
903 GrammarExpression::List(element,deliniator) => {
904 let el = self.grammar_expression(element);
905 let del = self.grammar_expression(deliniator);
906 if self.html {
907 format!("<span class=\"mech-grammar-list\">[<span class=\"mech-grammar-list-element\">{}</span>,<span class=\"mech-grammar-list-deliniator\">{}</span>]</span>",el,del)
908 } else {
909 format!("[{},{}]",el,del)
910 }
911 },
912 GrammarExpression::Range(start,end) => {
913 if self.html {
914 format!("<span class=\"mech-grammar-range\"><span class=\"mech-grammar-terminal\">\"{}\"</span><span class=\"mech-grammar-range-op\">..</span><span class=\"mech-grammar-terminal\">\"{}\"</span></span>", start.to_string(), end.to_string())
915 } else {
916 format!("{}..{}", start.to_string(), end.to_string())
917 }
918 }
919 GrammarExpression::Choice(choices) => {
920 let mut src = "".to_string();
921 let inline = choices.len() <= 3;
922 for (i, choice) in choices.iter().enumerate() {
923 let choice_str = self.grammar_expression(choice);
924 if i == 0 {
925 src = format!("{}", choice_str);
926 } else {
927 if self.html {
928 src = if inline {
929 format!("{} <span class=\"mech-grammar-choice-op\">|</span> {}", src, choice_str)
930 } else {
931 format!("{}<div class=\"mech-grammar-choice\"><span class=\"mech-grammar-choice-op\">|</span> {}</div>", src, choice_str)
932 };
933 } else {
934 src = format!("{} | {}", src, choice_str);
935 }
936 }
937 }
938 src
939 },
940 GrammarExpression::Sequence(seq) => {
941 let mut src = "".to_string();
942 let inline = seq.len() <= 3;
943 for (i, factor) in seq.iter().enumerate() {
944 let factor_str = self.grammar_expression(factor);
945 if i == 0 {
946 src = format!("{}", factor_str);
947 } else {
948 if self.html {
949 src = if inline {
950 format!("{}, {}", src, factor_str)
951 } else {
952 format!("{}<div class=\"mech-grammar-sequence\"><span class=\"mech-grammar-sequence-op\">,</span> {}</div>", src, factor_str)
953 };
954 } else {
955 src = format!("{}, {}", src, factor_str);
956 }
957 }
958 }
959 src
960 },
961 GrammarExpression::Repeat0(expr) => {
962 let inner_expr = self.grammar_expression(expr);
963 if self.html {
964 format!("<span class=\"mech-grammar-repeat0-op\">*</span>{}", inner_expr)
965 } else {
966 format!("*{}", inner_expr)
967 }
968 },
969 GrammarExpression::Repeat1(expr) => {
970 let inner_expr = self.grammar_expression(expr);
971 if self.html {
972 format!("<span class=\"mech-grammar-repeat1-op\">+</span>{}", inner_expr)
973 } else {
974 format!("+{}", inner_expr)
975 }
976 },
977 GrammarExpression::Optional(expr) => {
978 let inner_expr = self.grammar_expression(expr);
979 if self.html {
980 format!("<span class=\"mech-grammar-optional-op\">?</span>{}", inner_expr)
981 } else {
982 format!("?{}", inner_expr)
983 }
984 },
985 GrammarExpression::Peek(expr) => {
986 let inner_expr = self.grammar_expression(expr);
987 if self.html {
988 format!("<span class=\"mech-grammar-peek-op\">></span>{}", inner_expr)
989 } else {
990 format!(">{}", inner_expr)
991 }
992 },
993 GrammarExpression::Not(expr) => {
994 let inner_expr = self.grammar_expression(expr);
995 if self.html {
996 format!("<span class=\"mech-grammar-not-op\">¬</span>{}", inner_expr)
997 } else {
998 format!("¬{}", inner_expr)
999 }
1000 },
1001 GrammarExpression::Terminal(token) => {
1002 if self.html {
1003 format!("<span class=\"mech-grammar-terminal\">\"{}\"</span>", token.to_string())
1004 } else {
1005 format!("\"{}\"", token.to_string())
1006 }
1007 },
1008 GrammarExpression::Group(expr) => {
1009 let inner_expr = self.grammar_expression(expr);
1010 if self.html {
1011 format!("<span class=\"mech-grammar-group\">(<span class=\"mech-grammar-group-content\">{}</span>)</span>", inner_expr)
1012 } else {
1013 format!("({})", inner_expr)
1014 }
1015 },
1016 GrammarExpression::Definition(id) => {
1017 let name = id.name.to_string();
1018 if self.html {
1019 format!("<span class=\"mech-grammar-definition\"><a href=\"#{}\">{}</a></span>",hash_str(&name), name)
1020 } else {
1021 name
1022 }
1023 },
1024 };
1025
1026 if self.html {
1027 format!("<span class=\"mech-grammar-expression\">{}</span>", expr)
1028 } else {
1029 expr
1030 }
1031 }
1032
1033 pub fn code_block(&mut self, node: &Token) -> String {
1034 let code = node.to_string();
1035 if self.html {
1036 format!("<pre class=\"mech-code-block\">{}</pre>",code)
1037 } else {
1038 format!("{}\n",code)
1039 }
1040 }
1041
1042 pub fn comment(&mut self, node: &Comment) -> String {
1043 let comment_text = self.paragraph(&node.paragraph);
1044 if self.html {
1045 format!("<span class=\"mech-comment\"><span class=\"mech-comment-sigil\">--</span>{}</span>", comment_text)
1046 } else {
1047 format!("{}\n",comment_text)
1048 }
1049 }
1050
1051 pub fn list(&mut self, node: &MDList) -> String {
1052 match node {
1053 MDList::Ordered(ordered_list) => self.ordered_list(ordered_list),
1054 MDList::Unordered(unordered_list) => self.unordered_list(unordered_list),
1055 MDList::Check(check_list) => self.check_list(check_list),
1056 }
1057 }
1058
1059 pub fn check_list(&mut self, node: &CheckList) -> String {
1060 let mut lis = "".to_string();
1061 for (i, ((checked, item), sublist)) in node.iter().enumerate() {
1062 let it = self.paragraph(item);
1063 if self.html {
1064 lis = format!("{}<li class=\"mech-check-list-item\"><input type=\"checkbox\" {}>{}</li>", lis, if *checked { "checked" } else { "" }, it);
1065 } else {
1066 lis = format!("{}* [{}] {}\n", lis, if *checked { "x" } else { " " }, it);
1067 }
1068 match sublist {
1069 Some(sublist) => {
1070 let sublist_str = self.list(sublist);
1071 lis = format!("{}{}", lis, sublist_str);
1072 },
1073 None => {},
1074 }
1075 }
1076 if self.html {
1077 format!("<ul class=\"mech-check-list\">{}</ul>", lis)
1078 } else {
1079 lis
1080 }
1081 }
1082
1083 pub fn ordered_list(&mut self, node: &OrderedList) -> String {
1084 let mut lis = "".to_string();
1085 for (i, ((num,item),sublist)) in node.items.iter().enumerate() {
1086 let it = self.paragraph(item);
1087 if self.html {
1088 lis = format!("{}<li class=\"mech-ol-list-item\">{}</li>",lis,it);
1089 } else {
1090 lis = format!("{}{}. {}\n",lis,i+1,it);
1091 }
1092 match sublist {
1093 Some(sublist) => {
1094 let sublist_str = self.list(sublist);
1095 lis = format!("{}{}",lis,sublist_str);
1096 },
1097 None => {},
1098 }
1099 }
1100 if self.html {
1101 format!("<ol start=\"{}\" class=\"mech-ordered-list\">{}</ol>",node.start.to_string(),lis)
1102 } else {
1103 lis
1104 }
1105 }
1106
1107 pub fn unordered_list(&mut self, node: &UnorderedList) -> String {
1108 let mut lis = "".to_string();
1109 for (i, ((bullet, item),sublist)) in node.iter().enumerate() {
1110 let it = self.paragraph(item);
1111 match (bullet, self.html) {
1112 (Some(bullet_tok),true) => lis = format!("{}<li data-bullet=\"{}\" class=\"mech-list-item-emoji\">{}</li>",lis,bullet_tok.to_string(),it),
1113 (None,true) => lis = format!("{}<li class=\"mech-ul-list-item\">{}</li>",lis,it),
1114 (_,false) => lis = format!("{}* {}\n",lis,it),
1115 }
1116 match sublist {
1117 Some(sublist) => {
1118 let sublist_str = self.list(sublist);
1119 lis = format!("{}{}",lis,sublist_str);
1120 },
1121 None => {},
1122 }
1123 }
1124 if self.html {
1125 format!("<ul class=\"mech-unordered-list\">{}</ul>",lis)
1126 } else {
1127 lis
1128 }
1129 }
1130
1131 pub fn mech_code(&mut self, node: &Vec<(MechCode,Option<Comment>)>) -> String {
1132 let mut src = String::new();
1133 for (code,cmmnt) in node {
1134 let c = match code {
1135 MechCode::Comment(cmnt) => self.comment(cmnt),
1136 MechCode::Expression(expr) => self.expression(expr),
1137 MechCode::Statement(stmt) => self.statement(stmt),
1141 _ => todo!(),
1142 };
1143 let formatted_comment = match cmmnt {
1144 Some(cmmt) => self.comment(cmmt),
1145 None => String::new(),
1146 };
1147 if self.html {
1148 src.push_str(&format!("<span class=\"mech-code\">{}{}</span>", c, formatted_comment));
1149 } else {
1150 src.push_str(&format!("{}{}\n", c, formatted_comment));
1151 }
1152 }
1153 if self.html {
1154 format!("<span class=\"mech-code-block\">{}</span>",src)
1155 } else {
1156 src
1157 }
1158 }
1159
1160 pub fn fsm_implementation(&mut self, node: &FsmImplementation) -> String {
1161 let name = node.name.to_string();
1162 let mut input = "".to_string();
1163 for (i, ident) in node.input.iter().enumerate() {
1164 let v = ident.to_string();
1165 if i == 0 {
1166 input = format!("{}", v);
1167 } else {
1168 input = format!("{}, {}", input, v);
1169 }
1170 }
1171 let start = self.pattern(&node.start);
1172 let mut arms = "".to_string();
1173 for (i, arm) in node.arms.iter().enumerate() {
1174 let a = self.fsm_arm(arm, i == node.arms.len() - 1);
1175 if i == 0 {
1176 arms = format!("{}", a);
1177 } else {
1178 arms = format!("{}{}", arms, a);
1179 }
1180 }
1181 if self.html {
1182 format!("<div class=\"mech-fsm-implementation\">
1183 <div class=\"mech-fsm-implementation-header\">
1184 <span class=\"mech-fsm-sigil\">#</span>
1185 <span class=\"mech-fsm-name\">{}</span>
1186 <span class=\"mech-left-paren\">(</span>
1187 <span class=\"mech-fsm-input\">{}</span>
1188 <span class=\"mech-right-paren\">)</span>
1189 <span class=\"mech-fsm-define-op\">→</span>
1190 <span class=\"mech-fsm-start\">{}</span>
1191 </div>
1192 <div class=\"mech-fsm-arms\">
1193 {}
1194 </div>
1195 </div>",name,input,start,arms)
1196 } else {
1197 format!("#{}({}) {} {}\n{}", name, input, "->" , start, arms)
1198 }
1199 }
1200
1201 pub fn fsm_arm(&mut self, node: &FsmArm, last: bool) -> String {
1202 let arm = match node {
1203 FsmArm::Guard(pattern, guards) => {
1204 let p = self.pattern(pattern);
1205 let mut gs = "".to_string();
1206 for (i, guard) in guards.iter().enumerate() {
1207 let g = self.guard(guard);
1208 if i == 0 {
1209 if self.html {
1210 gs = format!("<div class=\"mech-fsm-guard-arm\">├ {}</div>", g);
1211 } else {
1212 gs = format!(" ├ {}\n", g);
1213 }
1214 } else if i == guards.len() - 1 {
1215 if self.html {
1216 gs = format!("{}<div class=\"mech-fsm-guard-arm\">└ {}</div>", gs, g);
1217 } else {
1218 gs = format!("{} └ {}", gs, g);
1219 }
1220 } else {
1221 if self.html {
1222 gs = format!("{}<div class=\"mech-fsm-guard-arm\">├ {}</div>", gs, g);
1223 } else {
1224 gs = format!("{} ├ {}\n", gs, g);
1225 }
1226 }
1227 }
1228 if self.html {
1229 format!("<div class=\"mech-fsm-arm-guard\">
1230 <span class=\"mech-fsm-start\">{}</span>
1231 <span class=\"mech-fsm-guards\">{}</span>
1232 </div>",p,gs)
1233 } else {
1234 format!(" {}\n{}", p, gs)
1235 }
1236 },
1237 FsmArm::Transition(pattern, transitions) => {
1238 let p = self.pattern(pattern);
1239 let mut ts = "".to_string();
1240 for (i, transition) in transitions.iter().enumerate() {
1241 let t = self.transition(transition);
1242 if i == 0 {
1243 ts = format!("{}", t);
1244 } else {
1245 ts = format!("{}{}", ts, t);
1246 }
1247 }
1248 if self.html {
1249 format!("<div class=\"mech-fsm-arm\">
1250 <span class=\"mech-fsm-arm-pattern\">{}</span>
1251 <span class=\"mech-fsm-arm-transitions\">{}</span>
1252 </div>",p,ts)
1253 } else {
1254 format!(" {}{}", p, ts)
1255 }
1256 },
1257 };
1258 if self.html {
1259 if last {
1260 format!("<div class=\"mech-fsm-arm-last\">{}.</div>",arm)
1261 } else {
1262 format!("<div class=\"mech-fsm-arm\">{}</div>",arm)
1263 }
1264 } else {
1265 if last {
1266 format!("{}.", arm)
1267 } else {
1268 format!("{}\n", arm)
1269 }
1270 }
1271 }
1272
1273 pub fn guard(&mut self, node: &Guard) -> String {
1274 let condition = self.pattern(&node.condition);
1275 let mut transitions = "".to_string();
1276 for (i, transition) in node.transitions.iter().enumerate() {
1277 let t = self.transition(transition);
1278 if i == 0 {
1279 transitions = format!("{}", t);
1280 } else {
1281 transitions = format!("{}{}", transitions, t);
1282 }
1283 }
1284 if self.html {
1285 format!("<div class=\"mech-guard\">
1286 <span class=\"mech-guard-condition\">{}</span>
1287 <span class=\"mech-guard-transitions\">{}</span>
1288 </div>",condition,transitions)
1289 } else {
1290 format!("{}{}", condition, transitions)
1291 }
1292 }
1293
1294
1295 pub fn pattern(&mut self, node: &Pattern) -> String {
1296 let p = match node {
1297 Pattern::Wildcard => {
1298 if self.html {
1299 format!("<span class=\"mech-pattern-wildcard\">*</span>")
1300 } else {
1301 format!("*")
1302 }
1303 },
1304 Pattern::Tuple(tpl) => self.pattern_tuple(tpl),
1305 Pattern::Expression(expr) => self.expression(expr),
1306 Pattern::TupleStruct(tuple_struct) => self.pattern_tuple_struct(tuple_struct),
1307 };
1308 if self.html {
1309 format!("<span class=\"mech-pattern\">{}</span>",p)
1310 } else {
1311 p
1312 }
1313 }
1314
1315 pub fn pattern_tuple_struct(&mut self, node: &PatternTupleStruct) -> String {
1316 let name = node.name.to_string();
1317 let mut patterns = "".to_string();
1318 for (i, pattern) in node.patterns.iter().enumerate() {
1319 let p = self.pattern(pattern);
1320 if i == 0 {
1321 patterns = format!("{}", p);
1322 } else {
1323 patterns = format!("{}, {}", patterns, p);
1324 }
1325 }
1326 if self.html {
1327 format!("<span class=\"mech-tuple-struct\">
1328 <span class=\"mech-tuple-struct-sigil\">:</span>
1329 <span class=\"mech-tuple-struct-name\">{}</span>
1330 <span class=\"mech-left-paren\">(</span>
1331 <span class=\"mech-tuple-struct-patterns\">{}</span>
1332 <span class=\"mech-right-paren\">)</span>
1333 </span>",name,patterns)
1334 } else {
1335 format!(":{}({})", name, patterns)
1336 }
1337 }
1338
1339 pub fn pattern_tuple(&mut self, node: &PatternTuple) -> String {
1340 let mut patterns = "".to_string();
1341 for (i, pattern) in node.0.iter().enumerate() {
1342 let p = self.pattern(pattern);
1343 if i == 0 {
1344 patterns = format!("{}", p);
1345 } else {
1346 patterns = format!("{}, {}", patterns, p);
1347 }
1348 }
1349 if self.html {
1350 format!("<span class=\"mech-pattern-tuple\">
1351 <span class=\"mech-left-paren\">(</span>
1352 <span class=\"mech-patterns\">{}</span>
1353 <span class=\"mech-right-paren\">)</span>
1354 </span>",patterns)
1355 } else {
1356 format!("({})", patterns)
1357 }
1358 }
1359
1360 pub fn transition(&mut self, node: &Transition) -> String {
1361 match node {
1362 Transition::Next(pattern) => {
1363 if self.html {
1364 format!("<span class=\"mech-transition-next\">→ {}</span>",self.pattern(pattern))
1365 } else {
1366 format!(" {} {}", "->", self.pattern(pattern))
1367 }
1368 }
1369 Transition::Output(pattern) => {
1370 if self.html {
1371 format!("<span class=\"mech-transition-output\">⇒ {}</span>",self.pattern(pattern))
1372 } else {
1373 format!(" {} {}", "=>", self.pattern(pattern))
1374 }
1375 }
1376 Transition::Async(pattern) => {
1377 if self.html {
1378 format!("<span class=\"mech-transition-async\">↝ {}</span>",self.pattern(pattern))
1379 } else {
1380 format!(" {} {}", "~>", self.pattern(pattern))
1381
1382 }
1383 }
1384 Transition::Statement(stmt) => {
1385 if self.html {
1386 format!("<span class=\"mech-transition-statement\">→ {}</span>",self.statement(stmt))
1387 } else {
1388 format!(" {} {}", "->", self.statement(stmt))
1389 }
1390 }
1391 Transition::CodeBlock(code) => {
1392 let mut code_str = "".to_string();
1393 let formatted = self.mech_code(code);
1394 if self.html {
1395 code_str.push_str(&format!("<span class=\"mech-transition-code\">→ {}</span>", formatted));
1396 } else {
1397 code_str.push_str(&format!(" {} {}", "->", formatted));
1398 }
1399 code_str
1400 }
1401 }
1402 }
1403
1404 pub fn fsm_specification(&mut self, node: &FsmSpecification) -> String {
1405 let name = node.name.to_string();
1406 let mut input = "".to_string();
1407 for (i, var) in node.input.iter().enumerate() {
1408 let v = self.var(var);
1409 if i == 0 {
1410 input = format!("{}", v);
1411 } else {
1412 input = format!("{}, {}", input, v);
1413 }
1414 }
1415 let output = match &node.output {
1416 Some(kind) => format!(" {} {}", "⇒", self.kind_annotation(&kind.kind)),
1417 None => "".to_string(),
1418 };
1419 let mut states = "".to_string();
1420 for (i, state) in node.states.iter().enumerate() {
1421 let v = self.state_definition(state);
1422 let state_arm = if node.states.len() == 1 {
1423 format!("{} {}", "└", v)
1424 } else if i == 0 {
1425 format!("{} {}", "├", v)
1426 } else if i == node.states.len() - 1 {
1427 format!("{} {}{}", "└", v, ".")
1428 } else {
1429 format!("{} {}", "├", v)
1430 };
1431 if self.html {
1432 states = format!("{}<span class=\"mech-fsm-state\">{}</span>",states,state_arm);
1433 } else {
1434 states = format!("{} {}\n",states,state_arm);
1435 }
1436 }
1437 if self.html {
1438 format!("<div class=\"mech-fsm-specification\">
1439 <div class=\"mech-fsm-specification-header\">
1440 <span class=\"mech-fsm-sigil\">#</span>
1441 <span class=\"mech-fsm-name\">{}</span>
1442 <span class=\"mech-left-paren\">(</span>
1443 <span class=\"mech-fsm-input\">{}</span>
1444 <span class=\"mech-right-paren\">)</span>
1445 <span class=\"mech-fsm-output\">{}</span>
1446 <span class=\"mech-fsm-define-op\">:=</span>
1447 </div>
1448 <div class=\"mech-fsm-states\">{}</div>
1449 </div>",name,input,output,states)
1450 } else {
1451 format!("#{}({}){} {}\n{}", name, input, output, ":=", states)
1452 }
1453 }
1454
1455 pub fn state_definition(&mut self, node: &StateDefinition) -> String {
1456 let name = node.name.to_string();
1457 let mut state_variables = "".to_string();
1458 match &node.state_variables {
1459 Some(vars) => {
1460 for (i, var) in vars.iter().enumerate() {
1461 let v = self.var(var);
1462 if i == 0 {
1463 state_variables = format!("{}", v);
1464 } else {
1465 state_variables = format!("{}, {}", state_variables, v);
1466 }
1467 }
1468 },
1469 None => {}
1470 }
1471 if self.html {
1472 format!("<div class=\"mech-state-definition\">
1473 <span class=\"mech-state-name\"><span class=\"mech-state-name-sigil\">:</span>{}</span>
1474 <span class=\"mech-left-paren\">(</span>
1475 <span class=\"mech-state-variables\">{}</span>
1476 <span class=\"mech-right-paren\">)</span>
1477 </div>",name,state_variables)
1478 } else {
1479 format!("{}({})", name, state_variables)
1480 }
1481 }
1482
1483 pub fn variable_define(&mut self, node: &VariableDefine) -> String {
1484 let mut mutable = if node.mutable {
1485 "~".to_string()
1486 } else {
1487 "".to_string()
1488 };
1489 let var = self.var(&node.var);
1490 let expression = self.expression(&node.expression);
1491 if self.html {
1492 format!("<span class=\"mech-variable-define\"><span class=\"mech-variable-mutable\">{}</span>{}<span class=\"mech-variable-assign-op\">:=</span>{}</span>",mutable, var, expression)
1493 } else {
1494 format!("{}{} {} {}", mutable, var, ":=", expression)
1495 }
1496 }
1497
1498 pub fn statement(&mut self, node: &Statement) -> String {
1499 let s = match node {
1500 Statement::VariableDefine(var_def) => self.variable_define(var_def),
1501 Statement::OpAssign(op_asgn) => self.op_assign(op_asgn),
1502 Statement::VariableAssign(var_asgn) => self.variable_assign(var_asgn),
1503 Statement::TupleDestructure(tpl_dstrct) => self.tuple_destructure(tpl_dstrct),
1504 Statement::KindDefine(kind_def) => self.kind_define(kind_def),
1505 Statement::EnumDefine(enum_def) => self.enum_define(enum_def),
1506 _ => todo!(),
1507 };
1509 if self.html {
1510 format!("<span class=\"mech-statement\">{}</span>",s)
1511 } else {
1512 format!("{}", s)
1513 }
1514 }
1515
1516 pub fn enum_define(&mut self, node: &EnumDefine) -> String {
1517 let name = node.name.to_string();
1518 let mut variants = "".to_string();
1519 for (i, variant) in node.variants.iter().enumerate() {
1520 if i == 0 {
1521 if self.html {
1522 variants = format!("<span class=\"mech-enum-variant\">{}</span>", self.enum_variant(variant));
1523 } else {
1524 variants = format!("{}", self.enum_variant(variant));
1525 }
1526 } else {
1527 if self.html {
1528 variants = format!("{}<span class=\"mech-enum-variant-sep\">|</span><span class=\"mech-enum-variant\">{}</span>", variants, self.enum_variant(variant));
1529 } else {
1530 variants = format!("{} | {}", variants, self.enum_variant(variant));
1531 }
1532 }
1533 }
1534 if self.html {
1535 format!("<span class=\"mech-enum-define\"><span class=\"mech-kind-annotation\"><<span class=\"mech-enum-name\">{}</span>></span><span class=\"mech-enum-define-op\">:=</span><span class=\"mech-enum-variants\">{}</span></span>",name,variants)
1536 } else {
1537 format!("<{}> := {}", name, variants)
1538 }
1539 }
1540
1541 pub fn enum_variant(&mut self, node: &EnumVariant) -> String {
1542 let name = node.name.to_string();
1543 let mut kind = "".to_string();
1544 match &node.value {
1545 Some(k) => {
1546 kind = self.kind_annotation(&k.kind);
1547 },
1548 None => {},
1549 }
1550 if self.html {
1551 format!("<span class=\"mech-enum-variant\"><span class=\"mech-enum-variant-name\">{}</span><span class=\"mech-enum-variant-kind\">{}</span></span>",name,kind)
1552 } else {
1553 format!("{}{}", name, kind)
1554 }
1555 }
1556
1557 pub fn kind_define(&mut self, node: &KindDefine) -> String {
1558 let name = node.name.to_string();
1559 let kind = self.kind_annotation(&node.kind.kind);
1560 if self.html {
1561 format!("<span class=\"mech-kind-define\"><span class=\"mech-kind-annotation\"><<span class=\"mech-kind\">{}</span>></span><span class=\"mech-kind-define-op\">:=</span><span class=\"mech-kind-annotation\">{}</span></span>",name,kind)
1562 } else {
1563 format!("<{}> := {}", name, kind)
1564 }
1565 }
1566
1567 pub fn tuple_destructure(&mut self, node: &TupleDestructure) -> String {
1568 let mut vars = "".to_string();
1569 for (i, var) in node.vars.iter().enumerate() {
1570 let v = var.to_string();
1571 if i == 0 {
1572 if self.html {
1573 let id = format!("{}:{}",hash_str(&v),self.interpreter_id);
1574 vars = format!("<span id=\"{}\" class=\"mech-var-name mech-clickable\">{}</span>",id,v);
1575 } else {
1576 vars = format!("{}", v);
1577 }
1578 } else {
1579 if self.html {
1580 let id = format!("{}:{}",hash_str(&v),self.interpreter_id);
1581 vars = format!("{}, <span id=\"{}\" class=\"mech-var-name mech-clickable\">{}</span>", vars, id, v);
1582 } else {
1583 vars = format!("{}, {}", vars, v);
1584 }
1585 }
1586 }
1587 let expression = self.expression(&node.expression);
1588 if self.html {
1589 format!("<span class=\"mech-tuple-destructure\"><span class=\"mech-tuple-vars\">({})</span><span class=\"mech-assign-op\">:=</span><span class=\"mech-tuple-expression\">{}</span></span>",vars,expression)
1590 } else {
1591 format!("({}) := {}", vars, expression)
1592 }
1593 }
1594
1595 pub fn variable_assign(&mut self, node: &VariableAssign) -> String {
1596 let target = self.slice_ref(&node.target);
1597 let expression = self.expression(&node.expression);
1598 if self.html {
1599 format!("<span class=\"mech-variable-assign\">
1600 <span class=\"mech-target\">{}</span>
1601 <span class=\"mech-assign-op\">=</span>
1602 <span class=\"mech-expression\">{}</span>
1603 </span>",target,expression)
1604 } else {
1605 format!("{} = {}", target, expression)
1606 }
1607 }
1608
1609 pub fn op_assign(&mut self, node: &OpAssign) -> String {
1610 let target = self.slice_ref(&node.target);
1611 let op = self.op_assign_op(&node.op);
1612 let expression = self.expression(&node.expression);
1613 if self.html {
1614 format!("<span class=\"mech-op-assign\"><span class=\"mech-target\">{}</span><span class=\"mech-op\">{}</span><span class=\"mech-expression\">{}</span></span>",target,op,expression)
1615 } else {
1616 format!("{} {} {}", target, op, expression)
1617 }
1618 }
1619
1620 pub fn op_assign_op(&mut self, node: &OpAssignOp) -> String {
1621 let op = match node {
1622 OpAssignOp::Add => "+=".to_string(),
1623 OpAssignOp::Div => "/=".to_string(),
1624 OpAssignOp::Exp => "^=".to_string(),
1625 OpAssignOp::Mod => "%=".to_string(),
1626 OpAssignOp::Mul => "*=".to_string(),
1627 OpAssignOp::Sub => "-=".to_string(),
1628 };
1629 if self.html {
1630 format!("<span class=\"mech-op-assign-op\">{}</span>",op)
1631 } else {
1632 format!("{}", op)
1633 }
1634 }
1635
1636 pub fn slice_ref(&mut self, node: &SliceRef) -> String {
1637 let name = node.name.to_string();
1638 let mut subscript = "".to_string();
1639 match &node.subscript {
1640 Some(subs) => {
1641 for sub in subs.iter() {
1642 let s = self.subscript(sub);
1643 subscript = format!("{}{}", subscript, s);
1644 }
1645 },
1646 None => {},
1647 }
1648 let id = format!("{}:{}",hash_str(&name),self.interpreter_id);
1649 if self.html {
1650 format!("<span class=\"mech-slice-ref\"><span id=\"{}\" class=\"mech-var-name mech-clickable\">{}</span><span class=\"mech-subscript\">{}</span></span>",id,name,subscript)
1651 } else {
1652 format!("{}{}", name, subscript)
1653 }
1654 }
1655
1656 pub fn expression(&mut self, node: &Expression) -> String {
1657 let e = match node {
1658 Expression::Var(var) => self.var(var),
1659 Expression::Formula(factor) => self.factor(factor),
1660 Expression::Literal(literal) => self.literal(literal),
1661 Expression::Structure(structure) => self.structure(structure),
1662 Expression::Slice(slice) => self.slice(slice),
1663 Expression::FunctionCall(function_call) => self.function_call(function_call),
1664 Expression::Range(range) => self.range_expression(range),
1665 Expression::SetComprehension(set_comp) => self.set_comprehension(set_comp),
1666 _ => todo!(),
1667 };
1669 if self.html {
1670 format!("<span class=\"mech-expression\">{}</span>",e)
1671 } else {
1672 format!("{}", e)
1673 }
1674 }
1675
1676 pub fn set_comprehension(&mut self, node: &SetComprehension) -> String {
1677 let expr = self.expression(&node.expression);
1678
1679 let qualifiers = node
1680 .qualifiers
1681 .iter()
1682 .map(|q| self.comprehension_qualifier(q))
1683 .collect::<Vec<_>>()
1684 .join(", ");
1685
1686 if self.html {
1687 format!(
1688 "<span class=\"mech-set-comprehension\">\
1689 <span class=\"mech-set-open\">{{</span>\
1690 <span class=\"mech-set-expression\">{}</span>\
1691 <span class=\"mech-set-bar\"> | </span>\
1692 <span class=\"mech-set-qualifiers\">{}</span>\
1693 <span class=\"mech-set-close\">}}</span>\
1694 </span>",
1695 expr, qualifiers
1696 )
1697 } else {
1698 format!("{{ {} | {} }}", expr, qualifiers)
1699 }
1700 }
1701
1702 pub fn comprehension_qualifier(&mut self, node: &ComprehensionQualifier) -> String {
1703 match node {
1704 ComprehensionQualifier::Generator((pattern, expr)) => {
1705 self.generator(pattern, expr)
1706 }
1707 ComprehensionQualifier::Let(var_def) => {
1708 self.variable_define(var_def)
1709 }
1710 ComprehensionQualifier::Filter(expr) => {
1711 self.expression(expr)
1712 }
1713 }
1714 }
1715
1716 pub fn generator(&mut self, pattern: &Pattern, expr: &Expression) -> String {
1717 let p = self.pattern(pattern);
1718 let e = self.expression(expr);
1719
1720 if self.html {
1721 format!(
1722 "<span class=\"mech-generator\">\
1723 <span class=\"mech-generator-pattern\">{}</span>\
1724 <span class=\"mech-generator-arrow\"> <- </span>\
1725 <span class=\"mech-generator-expression\">{}</span>\
1726 </span>",
1727 p, e
1728 )
1729 } else {
1730 format!("{} <- {}", p, e)
1731 }
1732 }
1733
1734 pub fn range_expression(&mut self, node: &RangeExpression) -> String {
1735 let start = self.factor(&node.start);
1736 let operator = match &node.operator {
1737 RangeOp::Inclusive => "..=".to_string(),
1738 RangeOp::Exclusive => "..".to_string(),
1739 };
1740 let terminal = self.factor(&node.terminal);
1741 let increment = match &node.increment {
1742 Some((op, factor)) => {
1743 let o = match op {
1744 RangeOp::Inclusive => "..=".to_string(),
1745 RangeOp::Exclusive => "..".to_string(),
1746 };
1747 let f = self.factor(factor);
1748 if self.html {
1749 format!("<span class=\"mech-range-increment\">{}{}</span>",o,f)
1750 } else {
1751 format!("{}{}", o, f)
1752 }
1753 },
1754 None => "".to_string(),
1755 };
1756 if self.html {
1757 format!("<span class=\"mech-range-expression\"><span class=\"mech-range-start\">{}</span><span class=\"mech-range-operator\">{}</span><span class=\"mech-range-terminal\">{}</span>{}</span>",start,operator,terminal,increment)
1758 } else {
1759 format!("{}{}{}{}", start, operator, terminal, increment)
1760 }
1761 }
1762
1763 pub fn function_call(&mut self, node: &FunctionCall) -> String {
1764 let name = node.name.to_string();
1765 let mut args = "".to_string();
1766 for (i, arg) in node.args.iter().enumerate() {
1767 let a = self.argument(arg);
1768 if i == 0 {
1769 args = format!("{}", a);
1770 } else {
1771 args = format!("{}, {}", args, a);
1772 }
1773 }
1774 let id = format!("{}:{}",hash_str(&name),self.interpreter_id);
1775 if self.html {
1776 format!("<span class=\"mech-function-call\"><span id=\"{}\" class=\"mech-function-name mech-clickable\">{}</span><span class=\"mech-left-paren\">(</span><span class=\"mech-argument-list\">{}</span><span class=\"mech-right-paren\">)</span></span>",id,name,args)
1777 } else {
1778 format!("{}({})", name, args)
1779 }
1780 }
1781
1782 pub fn argument(&mut self, node: &(Option<Identifier>, Expression)) -> String {
1783 let (name, expr) = node;
1784 let n = match name {
1785 Some(ident) => ident.to_string(),
1786 None => "".to_string(),
1787 };
1788 let e = self.expression(expr);
1789 if self.html {
1790 format!("<span class=\"mech-argument\"><span class=\"mech-argument-name\">{}</span><span class=\"mech-argument-expression\">{}</span></span>",n,e)
1791 } else {
1792 format!("{}{}", n, e)
1793 }
1794 }
1795
1796 pub fn slice(&mut self, node: &Slice) -> String {
1797 let name = node.name.to_string();
1798 let mut subscript = "".to_string();
1799 for (i, sub) in node.subscript.iter().enumerate() {
1800 let s = self.subscript(sub);
1801 subscript = format!("{}{}", subscript, s);
1802 }
1803 let id = format!("{}:{}",hash_str(&name),self.interpreter_id);
1804 if self.html {
1805 format!("<span class=\"mech-slice\"><span id=\"{}\" class=\"mech-var-name mech-clickable\">{}</span><span class=\"mech-subscript\">{}</span></span>",id,name,subscript)
1806 } else {
1807 format!("{}{}", name, subscript)
1808 }
1809 }
1810
1811 pub fn subscript(&mut self, node: &Subscript) -> String {
1812 match node {
1813 Subscript::Bracket(subs) => self.bracket(subs),
1814 Subscript::Formula(factor) => self.factor(factor),
1815 Subscript::All => self.all(),
1816 Subscript::Dot(ident) => self.dot(ident),
1817 Subscript::Swizzle(idents) => self.swizzle(idents),
1818 Subscript::Range(range) => self.range_expression(range),
1819 Subscript::Brace(subs) => self.brace(subs),
1820 Subscript::DotInt(real) => self.dot_int(real),
1821 }
1822 }
1823
1824 pub fn brace(&mut self, node: &Vec<Subscript>) -> String {
1825 let mut src = "".to_string();
1826 for (i, sub) in node.iter().enumerate() {
1827 let s = self.subscript(sub);
1828 if i == 0 {
1829 src = format!("{}", s);
1830 } else {
1831 src = format!("{},{}", src, s);
1832 }
1833 }
1834 if self.html {
1835 format!("<span class=\"mech-brace\">{{{}}}</span>",src)
1836 } else {
1837 format!("{{{}}}",src)
1838 }
1839 }
1840
1841 pub fn swizzle(&mut self, node: &Vec<Identifier>) -> String {
1842 let mut src = "".to_string();
1843 for (i, ident) in node.iter().enumerate() {
1844 let s = self.dot(ident);
1845 if i == 0 {
1846 src = format!("{}", s);
1847 } else {
1848 src = format!("{},{}", src, s);
1849 }
1850 }
1851 if self.html {
1852 format!("<span class=\"mech-swizzle\">{}</span>",src)
1853 } else {
1854 format!("{}",src)
1855 }
1856 }
1857
1858 pub fn dot_int(&mut self, node: &RealNumber) -> String {
1859 let node_str = match node {
1860 RealNumber::Integer(tkn) => tkn.to_string(),
1861 _ => "".to_string(),
1862 };
1863 if self.html {
1864 format!(".<span class=\"mech-dot-int\">{}</span>",node_str)
1865 } else {
1866 format!(".{}",node_str)
1867 }
1868 }
1869
1870 pub fn dot(&mut self, node: &Identifier) -> String {
1871 if self.html {
1872 format!(".<span class=\"mech-dot\">{}</span>",node.to_string())
1873 } else {
1874 format!(".{}",node.to_string())
1875 }
1876 }
1877
1878 pub fn all(&mut self) -> String {
1879 if self.html {
1880 format!("<span class=\"mech-all\">:</span>")
1881 } else {
1882 ":".to_string()
1883 }
1884 }
1885
1886 pub fn bracket(&mut self, node: &Vec<Subscript>) -> String {
1887 let mut src = "".to_string();
1888 for (i, sub) in node.iter().enumerate() {
1889 let s = self.subscript(sub);
1890 if i == 0 {
1891 src = format!("{}", s);
1892 } else {
1893 src = format!("{},{}", src, s);
1894 }
1895 }
1896 if self.html {
1897 format!("<span class=\"mech-bracket\">[{}]</span>",src)
1898 } else {
1899 format!("[{}]",src)
1900 }
1901 }
1902
1903 pub fn structure(&mut self, node: &Structure) -> String {
1904 let s = match node {
1905 Structure::Matrix(matrix) => self.matrix(matrix),
1906 Structure::Record(record) => self.record(record),
1907 Structure::Empty => "_".to_string(),
1908 Structure::Table(table) => self.table(table),
1909 Structure::Tuple(tuple) => self.tuple(tuple),
1910 Structure::TupleStruct(tuple_struct) => self.tuple_struct(tuple_struct),
1911 Structure::Set(set) => self.set(set),
1912 Structure::Map(map) => self.map(map),
1913 };
1914 if self.html {
1915 format!("<span class=\"mech-structure\">{}</span>",s)
1916 } else {
1917 format!("{}", s)
1918 }
1919 }
1920
1921 pub fn map(&mut self, node: &Map) -> String {
1922 let mut src = "".to_string();
1923 for (i, mapping) in node.elements.iter().enumerate() {
1924 let m = self.mapping(mapping);
1925 if i == 0 {
1926 src = format!("{}", m);
1927 } else {
1928 src = format!("{}, {}", src, m);
1929 }
1930 }
1931 if self.html {
1932 format!("<span class=\"mech-map\"><span class=\"mech-start-brace\">{{</span>{}<span class=\"mech-end-brace\">}}</span></span>",src)
1933 } else {
1934 format!("{{{}}}", src)
1935 }
1936 }
1937
1938 pub fn mapping(&mut self, node: &Mapping) -> String {
1939 let key = self.expression(&node.key);
1940 let value = self.expression(&node.value);
1941 if self.html {
1942 format!("<span class=\"mech-mapping\"><span class=\"mech-key\">{}</span><span class=\"mech-colon-op\">:</span><span class=\"mech-value\">{}</span></span>",key,value)
1943 } else {
1944 format!("{}: {}", key, value)
1945 }
1946 }
1947
1948 pub fn set(&mut self, node: &Set) -> String {
1949 let mut src = "".to_string();
1950 for (i, element) in node.elements.iter().enumerate() {
1951 let e = self.expression(element);
1952 if i == 0 {
1953 src = format!("{}", e);
1954 } else {
1955 src = format!("{}, {}", src, e);
1956 }
1957 }
1958 if self.html {
1959 format!("<span class=\"mech-set\"><span class=\"mech-start-brace\">{{</span>{}<span class=\"mech-end-brace\">}}</span></span>",src)
1960 } else {
1961 format!("{{{}}}", src)
1962 }
1963 }
1964
1965 pub fn tuple_struct(&mut self, node: &TupleStruct) -> String {
1966 let name = node.name.to_string();
1967 let value = self.expression(&node.value);
1968 if self.html {
1969 format!("<span class=\"mech-tuple-struct\"><span class=\"mech-tuple-struct-name\">{}</span><span class=\"mech-tuple-struct-value\">{}</span></span>",name,value)
1970 } else {
1971 format!("{}{}", name, value)
1972 }
1973 }
1974
1975 pub fn table(&mut self, node: &Table) -> String {
1976 let header = self.table_header(&node.header);
1977 let mut rows = "".to_string();
1978 for (i, row) in node.rows.iter().enumerate() {
1979 let r = self.table_row(row);
1980 if i == 0 {
1981 rows = format!("{}", r);
1982 } else {
1983 rows = format!("{}{}", rows, r);
1984 }
1985 }
1986 if self.html {
1987 format!("<table class=\"mech-table\">{}<tbody class=\"mech-table-body\">{}</tbody></table>",header,rows)
1988 } else {
1989 format!("{}{}", header, rows)
1990 }
1991 }
1992
1993 pub fn table_header(&mut self, node: &TableHeader) -> String {
1994 let mut src = "".to_string();
1995 for (i, field) in node.0.iter().enumerate() {
1996 let f = self.field(field);
1997 if self.html {
1998 src = format!("{}<th class=\"mech-table-field\">{}</th>",src, f);
1999 } else {
2000 src = format!("{}{}",src, f);
2001 }
2002 }
2003 if self.html {
2004 format!("<thead class=\"mech-table-header\"><tr>{}</tr></thead>",src)
2005 } else {
2006 src
2007 }
2008 }
2009
2010 pub fn table_row(&mut self, node: &TableRow) -> String {
2011 let mut src = "".to_string();
2012 for (i, column) in node.columns.iter().enumerate() {
2013 let c = self.table_column(column);
2014 if i == 0 {
2015 src = format!("{}", c);
2016 } else {
2017 src = format!("{} {}", src, c);
2018 }
2019 }
2020 if self.html {
2021 format!("<tr class=\"mech-table-row\">{}</tr>",src)
2022 } else {
2023 src
2024 }
2025 }
2026
2027 pub fn table_column(&mut self, node: &TableColumn) -> String {
2028 let element = self.expression(&node.element);
2029 if self.html {
2030 format!("<td class=\"mech-table-column\">{}</td>",element)
2031 } else {
2032 element
2033 }
2034 }
2035
2036 pub fn field(&mut self, node: &Field) -> String {
2037 let name = node.name.to_string();
2038 let kind = if let Some(kind) = &node.kind {
2039 self.kind_annotation(&kind.kind)
2040 } else {
2041 "".to_string()
2042 };
2043 if self.html {
2044 format!("<div class=\"mech-field\"><span class=\"mech-field-name\">{}</span><span class=\"mech-field-kind\">{}</span></div>",name,kind)
2045 } else {
2046 format!("{}: {}", name, kind)
2047 }
2048 }
2049
2050 pub fn tuple(&mut self, node: &Tuple) -> String {
2051 let mut src = "".to_string();
2052 for (i, element) in node.elements.iter().enumerate() {
2053 let e = self.expression(element);
2054 if i == 0 {
2055 src = format!("{}", e);
2056 } else {
2057 src = format!("{},{}", src, e);
2058 }
2059 }
2060 if self.html {
2061 format!("<span class=\"mech-tuple\"><span class=\"mech-start-paren\">(</span>{}<span class=\"mech-end-paren\">)</span></span>",src)
2062 } else {
2063 format!("({})", src)
2064 }
2065 }
2066
2067 pub fn record(&mut self, node: &Record) -> String {
2068 let mut src = "".to_string();
2069 for (i, binding) in node.bindings.iter().enumerate() {
2070 let b = self.binding(binding);
2071 if i == 0 {
2072 src = format!("{}", b);
2073 } else {
2074 src = format!("{}, {}", src, b);
2075 }
2076 }
2077 if self.html {
2078 format!("<span class=\"mech-record\"><span class=\"mech-start-brace\">{{</span>{}<span class=\"mech-end-brace\">}}</span></span>",src)
2079 } else {
2080 format!("{{{}}}",src)
2081 }
2082 }
2083
2084 pub fn binding(&mut self, node: &Binding) -> String {
2085 let name = node.name.to_string();
2086 let kind = if let Some(kind) = &node.kind {
2087 self.kind_annotation(&kind.kind)
2088 } else {
2089 "".to_string()
2090 };
2091 let value = self.expression(&node.value);
2092 if self.html {
2093 format!("<span class=\"mech-binding\"><span class=\"mech-binding-name\">{}</span><span class=\"mech-binding-kind\">{}</span><span class=\"mech-binding-colon-op\">:</span><span class=\"mech-binding-value\">{}</span></span>",name,kind,value)
2094 } else {
2095 format!("{}{}: {}", name, kind, value)
2096 }
2097 }
2098
2099 pub fn matrix(&mut self, node: &Matrix) -> String {
2100 let mut src = "".to_string();
2101 if node.rows.len() == 0 {
2102 if self.html {
2103 return format!("<span class=\"mech-matrix empty\"><span class=\"mech-bracket start\">[</span><span class=\"mech-bracket end\">]</span></span>");
2104 } else {
2105 return format!("[]");
2106 }
2107 }
2108 let column_count = node.rows[0].columns.len(); for col_index in 0..column_count {
2111 let mut column_elements = Vec::new();
2112 for row in &node.rows {
2113 column_elements.push(&row.columns[col_index]);
2114 }
2115 let c = self.matrix_column_elements(&column_elements);
2116
2117 if col_index == 0 {
2118 src = format!("{}", c);
2119 } else {
2120 src = format!("{} {}", src, c);
2121 }
2122 }
2123
2124 if self.html {
2125 format!("<span class=\"mech-matrix\"><span class=\"mech-bracket start\">[</span>{}<span class=\"mech-bracket end\">]</span></span>", src)
2126 } else {
2127 format!("[{}]", src)
2128 }
2129}
2130
2131pub fn matrix_column_elements(&mut self, column_elements: &[&MatrixColumn]) -> String {
2132 let mut src = "".to_string();
2133 for (i, cell) in column_elements.iter().enumerate() {
2134 let c = self.matrix_column(cell);
2135 if i == 0 {
2136 src = format!("{}", c);
2137 } else {
2138 src = format!("{} {}", src, c);
2139 }
2140 }
2141 if self.html {
2142 format!("<div class=\"mech-matrix-column\">{}</div>", src)
2143 } else {
2144 src
2145 }
2146}
2147
2148
2149 pub fn matrix_row(&mut self, node: &MatrixRow) -> String {
2150 let mut src = "".to_string();
2151 for (i, cell) in node.columns.iter().enumerate() {
2152 let c = self.matrix_column(cell);
2153 if i == 0 {
2154 src = format!("{}", c);
2155 } else {
2156 src = format!("{} {}", src, c);
2157 }
2158 }
2159 if self.html {
2160 format!("<div class=\"mech-matrix-row\">{}</div>",src)
2161 } else {
2162 src
2163 }
2164 }
2165
2166 pub fn matrix_column(&mut self, node: &MatrixColumn) -> String {
2167 let element = self.expression(&node.element);
2168 if self.html {
2169 format!("<span class=\"mech-matrix-element\">{}</span>",element)
2170 } else {
2171 element
2172 }
2173 }
2174
2175 pub fn var(&mut self, node: &Var) -> String {
2176 let annotation = if let Some(kind) = &node.kind {
2177 self.kind_annotation(&kind.kind)
2178 } else {
2179 "".to_string()
2180 };
2181 let name = &node.name.to_string();
2182 let id = format!("{}:{}",hash_str(&name),self.interpreter_id);
2183 if self.html {
2184 format!("<span class=\"mech-var-name mech-clickable\" id=\"{}\">{}</span>{}", id, node.name.to_string(), annotation)
2185 } else {
2186 format!("{}{}", node.name.to_string(), annotation)
2187 }
2188 }
2189
2190 pub fn kind_annotation(&mut self, node: &Kind) -> String {
2191 let kind = self.kind(node);
2192 if self.html {
2193 format!("<span class=\"mech-kind-annotation\"><{}></span>",kind)
2194 } else {
2195 format!("<{}>", kind)
2196 }
2197 }
2198
2199 pub fn kind(&mut self, node: &Kind) -> String {
2200 let annotation = match node {
2201 Kind::Kind(kind) => {
2202 let kind_kind = self.kind(kind);
2203 if self.html {
2204 format!("<span class=\"mech-kind-annotation\"><{}></span>",kind_kind)
2205 } else {
2206 format!("<{}>", kind_kind)
2207 }
2208 },
2209 Kind::Option(kind) => {
2210 let k = self.kind(kind);
2211 if self.html {
2212 format!("{}<span class=\"mech-option-question\">?</span>", k)
2213 } else {
2214 format!("{}?", k)
2215 }
2216 },
2217 Kind::Set(kind,size) => {
2218 let k = self.kind(kind);
2219 let size_str = match size{
2220 Some(size) => {
2221 let size_ltrl = self.literal(size);
2222 format!(":{}", size_ltrl)
2223 }
2224 None => "".to_string(),
2225 };
2226 format!("{{{}}}{}", k, size_str)
2227 },
2228 Kind::Any => "*".to_string(),
2229 Kind::Scalar(ident) => ident.to_string(),
2230 Kind::Empty => "_".to_string(),
2231 Kind::Atom(ident) => format!(":{}",ident.to_string()),
2232 Kind::Tuple(kinds) => {
2233 let mut src = "".to_string();
2234 for (i, kind) in kinds.iter().enumerate() {
2235 let k = self.kind(kind);
2236 if i == 0 {
2237 src = format!("{}", k);
2238 } else {
2239 src = format!("{},{}", src, k);
2240 }
2241 }
2242 format!("({})", src)
2243 },
2244 Kind::Matrix((kind, literals)) => {
2245 let mut src = "".to_string();
2246 let k = self.kind(kind);
2247 src = format!("{}", k);
2248 let mut src2 = "".to_string();
2249 for (i, literal) in literals.iter().enumerate() {
2250 let l = self.literal(literal);
2251 if i == 0 {
2252 src2 = format!(":{}", l);
2253 } else {
2254 src2 = format!("{},{}", src2, l);
2255 }
2256 }
2257 format!("[{}]{}", src, src2)
2258 },
2259 Kind::Record(kinds) => {
2260 let mut src = "".to_string();
2261 for (i, (ident, kind)) in kinds.iter().enumerate() {
2262 let k = self.kind(kind);
2263 let ident_s = ident.to_string();
2264 if i == 0 {
2265 src = format!("{}<{}>", ident_s, k);
2266 } else {
2267 src = format!("{},{}<{}>", src, ident_s, k);
2268 }
2269 }
2270 format!("{{{}}}", src)
2271 },
2272 Kind::Table((kinds, literal)) => {
2273 let mut src = "".to_string();
2274 for (i, (ident,kind)) in kinds.iter().enumerate() {
2275 let k = self.kind(kind);
2276 let ident_s = ident.to_string();
2277 if i == 0 {
2278 src = format!("{}<{}>", ident_s, k);
2279 } else {
2280 src = format!("{},{}<{}>", src, ident_s, k);
2281 }
2282 }
2283 let mut src2 = "".to_string();
2284 let sz = match &**literal {
2285 Literal::Empty(_) => "".to_string(),
2286 _ => format!(":{}", self.literal(literal)),
2287 };
2288 format!("|{}|{}", src, sz)
2289 },
2290 Kind::Map(kind1, kind2) => {
2291 let k1 = self.kind(kind1);
2292 let k2 = self.kind(kind2);
2293 format!("{{{}:{}}}", k1, k2)
2294 },
2295 };
2296 if self.html {
2297 format!("<span class=\"mech-kind\">{}</span>",annotation)
2298 } else {
2299 annotation
2300 }
2301 }
2302
2303 pub fn factor(&mut self, node: &Factor) -> String {
2304 let f = match node {
2305 Factor::Term(term) => self.term(term),
2306 Factor::Expression(expr) => self.expression(expr),
2307 Factor::Parenthetical(paren) => {
2308 if self.html {
2309 format!("<span class=\"mech-parenthetical\">({})</span>", self.factor(paren))
2310 } else {
2311 format!("({})", self.factor(&paren))
2312 }
2313 }
2314 Factor::Negate(factor) => {
2315 if self.html {
2316 format!("<span class=\"mech-negate-op\">-</span><span class=\"mech-negate\">{}</span>", self.factor(factor))
2317 } else {
2318 format!("-{}", self.factor(factor))
2319 }
2320 }
2321 Factor::Not(factor) => {
2322 if self.html {
2323 format!("<span class=\"mech-not-op\">¬</span><span class=\"mech-not\">{}</span>", self.factor(factor))
2324 } else {
2325 format!("¬{}", self.factor(factor))
2326 }
2327 }
2328 Factor::Transpose(factor) => {
2329 if self.html {
2330 format!("<span class=\"mech-transpose\">{}</span><span class=\"mech-transpose-op\">'</span>", self.factor(factor))
2331 } else {
2332 format!("{}'", self.factor(factor))
2333 }
2334 }
2335 };
2336 if self.html {
2337 format!("<span class=\"mech-factor\">{}</span>",f)
2338 } else {
2339 f
2340 }
2341 }
2342
2343 pub fn term(&mut self, node: &Term) -> String {
2344 let mut src = self.factor(&node.lhs);
2345 for (formula_operator, rhs) in &node.rhs {
2346 let op = self.formula_operator(formula_operator);
2347 let rhs = self.factor(rhs);
2348 src = format!("{}{}{}", src, op, rhs);
2349 }
2350 if self.html {
2351 format!("<span class=\"mech-term\">{}</span>",src)
2352 } else {
2353 src
2354 }
2355 }
2356
2357 pub fn formula_operator(&mut self, node: &FormulaOperator) -> String {
2358 let f = match node {
2359 FormulaOperator::AddSub(op) => self.add_sub_op(op),
2360 FormulaOperator::MulDiv(op) => self.mul_div_op(op),
2361 FormulaOperator::Power(op) => self.power_op(op),
2362 FormulaOperator::Vec(op) => self.vec_op(op),
2363 FormulaOperator::Comparison(op) => self.comparison_op(op),
2364 FormulaOperator::Logic(op) => self.logic_op(op),
2365 FormulaOperator::Table(op) => self.table_op(op),
2366 FormulaOperator::Set(op) => self.set_op(op),
2367 };
2368 if self.html {
2369 format!("<span class=\"mech-formula-operator\">{}</span>",f)
2370 } else {
2371 format!(" {} ", f)
2372 }
2373 }
2374
2375 pub fn table_op(&mut self, node: &TableOp) -> String {
2376 match node {
2377 TableOp::InnerJoin => "⋈".to_string(),
2378 TableOp::LeftOuterJoin => "⟕".to_string(),
2379 TableOp::RightOuterJoin => "⟖".to_string(),
2380 TableOp::FullOuterJoin => "⟗".to_string(),
2381 TableOp::LeftSemiJoin => "⋉".to_string(),
2382 TableOp::LeftAntiJoin => "▷".to_string(),
2383 }
2384 }
2385
2386 pub fn set_op(&mut self, node: &SetOp) -> String {
2387 match node {
2388 SetOp::Union => "∪".to_string(),
2389 SetOp::Intersection => "∩".to_string(),
2390 SetOp::Difference => "∖".to_string(),
2391 SetOp::Complement => "∁".to_string(),
2392 SetOp::Subset => "⊂".to_string(),
2393 SetOp::Superset => "⊃".to_string(),
2394 SetOp::ProperSubset => "⊊".to_string(),
2395 SetOp::ProperSuperset => "⊋".to_string(),
2396 SetOp::ElementOf => "∈".to_string(),
2397 SetOp::NotElementOf => "∉".to_string(),
2398 SetOp::SymmetricDifference => "Δ".to_string(),
2399 }
2400 }
2401
2402 pub fn add_sub_op(&mut self, node: &AddSubOp) -> String {
2403 match node {
2404 AddSubOp::Add => "+".to_string(),
2405 AddSubOp::Sub => "-".to_string(),
2406 }
2407 }
2408
2409 pub fn mul_div_op(&mut self, node: &MulDivOp) -> String {
2410 match node {
2411 MulDivOp::Div => "/".to_string(),
2412 MulDivOp::Mod => "%".to_string(),
2413 MulDivOp::Mul => "*".to_string(),
2414 }
2415 }
2416
2417 pub fn power_op(&mut self, node: &PowerOp) -> String {
2418 match node {
2419 PowerOp::Pow => "^".to_string(),
2420 }
2421 }
2422
2423 pub fn vec_op(&mut self, node: &VecOp) -> String {
2424 match node {
2425 VecOp::MatMul => "**".to_string(),
2426 VecOp::Solve => "\\".to_string(),
2427 VecOp::Cross => "×".to_string(),
2428 VecOp::Dot => "·".to_string(),
2429 }
2430 }
2431
2432 pub fn comparison_op(&mut self, node: &ComparisonOp) -> String {
2433 match node {
2434 ComparisonOp::Equal => "⩵".to_string(),
2435 ComparisonOp::StrictEqual => "=:=".to_string(),
2436 ComparisonOp::StrictNotEqual => "=/=".to_string(),
2437 ComparisonOp::NotEqual => "≠".to_string(),
2438 ComparisonOp::GreaterThan => ">".to_string(),
2439 ComparisonOp::GreaterThanEqual => "≥".to_string(),
2440 ComparisonOp::LessThan => "<".to_string(),
2441 ComparisonOp::LessThanEqual => "≤".to_string(),
2442 }
2443 }
2444
2445 pub fn logic_op(&mut self, node: &LogicOp) -> String {
2446 match node {
2447 LogicOp::And => "&&".to_string(),
2448 LogicOp::Or => "||".to_string(),
2449 LogicOp::Xor => "⊻".to_string(),
2450 LogicOp::Not => "¬".to_string(),
2451 }
2452 }
2453
2454 pub fn boolean(&mut self, node: &Token) -> String {
2455 let b = node.to_string();
2456 if self.html {
2457 format!("<span class=\"mech-boolean\">{}</span>", b)
2458 } else {
2459 b
2460 }
2461 }
2462
2463 pub fn empty(&mut self, node: &Token) -> String {
2464 let e = node.to_string();
2465 if self.html {
2466 format!("<span class=\"mech-empty\">{}</span>", e)
2467 } else {
2468 e
2469 }
2470 }
2471
2472 pub fn literal(&mut self, node: &Literal) -> String {
2473 let l = match node {
2474 Literal::Empty(tkn) => self.empty(tkn),
2475 Literal::Boolean(tkn) => self.boolean(tkn),
2476 Literal::Number(num) => self.number(num),
2477 Literal::String(mech_string) => self.string(mech_string),
2478 Literal::Atom(atm) => self.atom(atm),
2479 Literal::Kind(knd) => self.kind_annotation(knd),
2480 Literal::TypedLiteral((boxed_literal, kind_annotation)) => {
2481 let literal = self.literal(boxed_literal);
2482 let annotation = self.kind_annotation(&kind_annotation.kind);
2483 format!("{}{}", literal, annotation)
2484 }
2485 };
2486 if self.html {
2487 format!("<span class=\"mech-literal\">{}</span>",l)
2488 } else {
2489 l
2490 }
2491 }
2492
2493 pub fn atom(&mut self, node: &Atom) -> String {
2494 if self.html {
2495 format!("<span class=\"mech-atom\"><span class=\"mech-atom-name\">:{}</span></span>",node.name.to_string())
2496 } else {
2497 format!(":{}", node.name.to_string())
2498 }
2499 }
2500
2501 pub fn string(&mut self, node: &MechString) -> String {
2502 if self.html {
2503 format!("<span class=\"mech-string\">\"{}\"</span>", node.text.to_string())
2504 } else {
2505 format!("\"{}\"", node.text.to_string())
2506 }
2507 }
2508
2509 pub fn number(&mut self, node: &Number) -> String {
2510 let n = match node {
2511 Number::Real(real) => self.real_number(real),
2512 Number::Complex(complex) => self.complex_numer(complex),
2513 };
2514 if self.html {
2515 format!("<span class=\"mech-number\">{}</span>",n)
2516 } else {
2517 n
2518 }
2519 }
2520
2521 pub fn real_number(&mut self, node: &RealNumber) -> String {
2522 match node {
2523 RealNumber::Negated(real_number) => format!("-{}", self.real_number(real_number)),
2524 RealNumber::Integer(token) => token.to_string(),
2525 RealNumber::Float((whole, part)) => format!("{}.{}", whole.to_string(), part.to_string()),
2526 RealNumber::Decimal(token) => format!("0d{}", token.to_string()),
2527 RealNumber::Hexadecimal(token) => format!("0x{}", token.to_string()),
2528 RealNumber::Octal(token) => format!("0o{}", token.to_string()),
2529 RealNumber::Binary(token) => format!("0b{}", token.to_string()),
2530 RealNumber::Scientific(((whole, part), (sign, ewhole, epart))) => format!("{}.{}e{}{}.{}", whole.to_string(), part.to_string(), if *sign { "-" } else { "+" }, ewhole.to_string(), epart.to_string()),
2531 RealNumber::Rational((numerator, denominator)) => format!("{}/{}", numerator.to_string(), denominator.to_string()),
2532 RealNumber::TypedInteger((token, kind_annotation)) => {
2533 let num = token.to_string();
2534 let annotation = &kind_annotation.kind.tokens().iter().map(|tkn| tkn.to_string()).collect::<Vec<String>>().join("");
2535 format!("{}{}", num, annotation)
2536 }
2537 }
2538 }
2539
2540 pub fn complex_numer(&mut self, node: &C64Node) -> String {
2541 let real = if let Some(real) = &node.real {
2542 let num = self.real_number(&real);
2543 format!("{}+", num)
2544 } else {
2545 "".to_string()
2546 };
2547 let im = self.imaginary_number(&node.imaginary);
2548 format!("{}{}", real, im)
2549 }
2550
2551 pub fn imaginary_number(&mut self, node: &ImaginaryNumber) -> String {
2552 let real = self.real_number(&node.number);
2553 format!("{}i", real)
2554 }
2555
2556 pub fn humanize_html(input: String) -> String {
2557 let mut result = String::new();
2558 let mut indent_level = 0;
2559 let mut in_special_tag = false;
2560 let mut special_tag = "";
2561 let chars: Vec<char> = input.chars().collect();
2562 let mut i = 0;
2563
2564 let self_closing_tags = HashSet::from([
2565 "area", "base", "br", "col", "embed", "hr", "img", "input",
2566 "link", "meta", "param", "source", "track", "wbr"
2567 ]);
2568
2569 fn matches_tag(chars: &[char], pos: usize, tag: &str) -> bool {
2570 let tag_chars: Vec<char> = tag.chars().collect();
2571 pos + tag_chars.len() <= chars.len() && chars[pos..pos+tag_chars.len()] == tag_chars[..]
2572 }
2573
2574 while i < chars.len() {
2575 if !in_special_tag && (matches_tag(&chars, i, "<pre") || matches_tag(&chars, i, "<code")) {
2577 in_special_tag = true;
2578 special_tag = if matches_tag(&chars, i, "<pre") { "pre" } else { "code" };
2579
2580 result.push('\n');
2581 result.push_str(&" ".repeat(indent_level));
2582
2583 while i < chars.len() && chars[i] != '>' {
2585 result.push(chars[i]);
2586 i += 1;
2587 }
2588 result.push('>');
2589 i += 1;
2590 indent_level += 1;
2591
2592 let start = i;
2594 while i < chars.len() && !matches_tag(&chars, i, &format!("</{}>", special_tag)) {
2595 i += 1;
2596 }
2597
2598 result.extend(chars[start..i].iter());
2600
2601 if i < chars.len() {
2603 result.push_str(&format!("</{}>", special_tag));
2604 i += special_tag.len() + 3;
2605 in_special_tag = false;
2606 indent_level -= 1;
2607 }
2608 } else if !in_special_tag && i < chars.len() && chars[i] == '<' && i+1 < chars.len() && chars[i+1] != '/' {
2610 let tag_start = i + 1;
2611 let mut j = tag_start;
2612
2613 while j < chars.len() && chars[j].is_alphanumeric() {
2615 j += 1;
2616 }
2617
2618 let tag_name: String = chars[tag_start..j].iter().collect();
2619 let is_self_closing = self_closing_tags.contains(tag_name.as_str());
2620
2621 result.push('\n');
2623 result.push_str(&" ".repeat(indent_level));
2624
2625 while i < chars.len() && chars[i] != '>' {
2627 result.push(chars[i]);
2628 i += 1;
2629 }
2630 result.push('>');
2631 i += 1;
2632
2633 if !is_self_closing {
2634 indent_level += 1;
2635 }
2636 } else if !in_special_tag && i < chars.len() && chars[i] == '<' && i+1 < chars.len() && chars[i+1] == '/' {
2638 indent_level = indent_level.saturating_sub(1);
2639
2640 result.push('\n');
2641 result.push_str(&" ".repeat(indent_level));
2642
2643 while i < chars.len() && chars[i] != '>' {
2644 result.push(chars[i]);
2645 i += 1;
2646 }
2647 result.push('>');
2648 i += 1;
2649 } else if !in_special_tag {
2651 let start = i;
2652 while i < chars.len() && chars[i] != '<' {
2653 i += 1;
2654 }
2655
2656 let content: String = chars[start..i].iter().collect();
2657 if !content.trim().is_empty() {
2658 result.push('\n');
2659 result.push_str(&" ".repeat(indent_level));
2660 result.push_str(&content);
2661 }
2662 } else {
2664 result.push(chars[i]);
2665 i += 1;
2666 }
2667 }
2668 result.push('\n');
2669 result
2670 }
2671}