mech_syntax/
formatter.rs

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