mech_syntax/
formatter.rs

1use mech_core::*;
2use mech_core::nodes::{Kind, Matrix};
3use std::collections::HashMap;
4use colored::Colorize;
5use std::io::{Read, Write, Cursor};
6
7#[derive(Debug, Clone, PartialEq)]
8pub struct Formatter{
9  code: String,
10  identifiers: HashMap<u64, String>,
11  rows: usize,
12  cols: usize,
13  indent: usize,
14  html: bool,
15  nested: bool
16}
17
18
19impl Formatter {
20
21  pub fn new() -> Formatter {
22    Formatter {
23      code: String::new(),
24      identifiers: HashMap::new(),
25      rows: 0,
26      cols: 0,
27      indent: 0,
28      html: false,
29      nested: false,
30    }
31  }
32
33  pub fn format(&mut self, tree: &Program) -> String {
34    self.html = false;
35    self.program(tree)
36  }
37
38  pub fn format_html(&mut self, tree: &Program, style: String) -> String {
39    self.html = true;
40    let formatted_src = self.program(tree);
41    let head = format!(r#"<html>
42    <head>
43        <meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
44        <link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
45        <style>
46                  {}
47        </style>
48    </head>
49    <body>"#, style);
50    let foot = format!(r#"
51    <div id = "mech-root"></div>
52    <script type="module">
53      import init, {{WasmMech}} from '/pkg/mech_wasm.js';
54      let wasm_core;
55      async function run() {{
56        await init();
57        wasm_core = new WasmMech();
58        var xhr = new XMLHttpRequest();
59        var codeUrl = `/code${{window.location.pathname}}`;
60        xhr.open('GET', codeUrl, true);
61        xhr.onload = function (e) {{
62          if (xhr.readyState === 4) {{
63            if (xhr.status === 200) {{
64              var src = xhr.responseText;
65              wasm_core.run_program(src);
66              wasm_core.init();
67            }} else {{
68              console.error(xhr.statusText);
69            }}
70          }}
71        }};
72        xhr.onerror = function (e) {{
73          console.error(xhr.statusText);
74        }};
75        xhr.send(null);        
76      }}
77      run();
78    </script>
79  </body>
80</html>"#);
81    format!("{}{}{}", head, formatted_src, foot)
82  }
83
84  pub fn program(&mut self, node: &Program) -> String {
85    let title = match &node.title {
86      Some(title) => self.title(&title),
87      None => "".to_string(),
88    };
89    let body = self.body(&node.body);
90    if self.html {
91      format!("<div class=\"mech-program\">{}{}</div>",title,body)
92    } else {
93      format!("{}{}",title,body)
94    }
95  }
96
97  pub fn title(&mut self, node: &Title) -> String {
98    if self.html {
99      format!("<h1 class=\"mech-program-title\">{}</h1>",node.to_string())
100    } else {
101      format!("{}\n===============================================================================\n",node.to_string()) 
102    }
103  }
104
105  pub fn subtitle(&mut self, node: &Subtitle) -> String {
106    let level = node.level;
107    if self.html {
108      format!("<h{} class=\"mech-program-subtitle\">{}</h{}>", level, node.to_string(), level)
109    } else {
110      format!("{}\n-------------------------------------------------------------------------------\n",node.to_string())
111    }
112  }
113
114  pub fn body(&mut self, node: &Body) -> String {
115    let mut src = "".to_string();
116    let section_count = node.sections.len();
117    for (i, section) in node.sections.iter().enumerate() {
118      let s = self.section(section);
119      src = format!("{}{}", src, s);
120    }
121    if self.html {
122      format!("<div class=\"mech-program-body\">{}</div>",src)
123    } else {
124      src
125    }
126  }
127
128  pub fn section(&mut self, node: &Section) -> String {
129    let mut src = match &node.subtitle {
130      Some(title) => self.subtitle(title),
131      None => "".to_string(),
132    };
133    for el in node.elements.iter() {
134      let el_str = self.section_element(el);
135      src = format!("{}{}", src, el_str);
136    }
137    if self.html {
138      format!("<section class=\"mech-program-section\">{}</section>",src)
139    } else {
140      src
141    }
142  }
143
144  pub fn paragraph(&mut self, node: &Paragraph) -> String {
145    if self.html {
146      format!("<p class=\"mech-paragraph\">{}</p>",node.to_string())
147    } else {
148      format!("{}\n",node.to_string())
149    }
150  }
151
152  pub fn section_element(&mut self, node: &SectionElement) -> String {
153    let element = match node {
154      SectionElement::Section(n) => self.section(n),
155      SectionElement::Comment(n) => self.comment(n),
156      SectionElement::Paragraph(n) => self.paragraph(n),
157      SectionElement::MechCode(n) => self.mech_code(n),
158      SectionElement::UnorderedList(n) => self.unordered_list(n),
159      SectionElement::CodeBlock => todo!(),
160      SectionElement::OrderedList => todo!(),
161      SectionElement::BlockQuote => todo!(),
162      SectionElement::ThematicBreak => todo!(),
163      SectionElement::Image => todo!(),
164    };
165    if self.html {
166      format!("<div class=\"mech-section-element\">{}</div>",element)
167    } else {
168      element
169    }
170  }
171
172  pub fn comment(&mut self, node: &Comment) -> String {
173    if self.html {
174      format!("<div class=\"mech-comment\">-- {}</div>",node.text.to_string())
175    } else {
176      format!("{}\n",node.text.to_string())
177    }
178  }
179
180  pub fn unordered_list(&mut self, node: &UnorderedList) -> String {
181    let mut lis = "".to_string();
182    for (i, item) in node.items.iter().enumerate() {
183      let it = self.paragraph(item);
184      if self.html {
185        lis = format!("{}<li class=\"mech-list-item\">{}</li>",lis,it);
186      } else {
187        lis = format!("{}- {}\n",lis,it); 
188      }
189    }
190    if self.html {
191      format!("<ul class=\"mech-unordered-list\">{}</ul>",lis)
192    } else {
193      lis
194    }
195  }
196
197  pub fn mech_code(&mut self, node: &Vec<MechCode>) -> String {
198    let mut src = String::new();
199    for code in node {
200      let c = match code {
201      MechCode::Expression(expr) => self.expression(expr),
202      MechCode::Statement(stmt) => self.statement(stmt),
203      MechCode::FsmSpecification(fsm_spec) => self.fsm_specification(fsm_spec),
204      MechCode::FsmImplementation(fsm_impl) => self.fsm_implementation(fsm_impl),
205      MechCode::Comment(cmnt) => self.comment(cmnt),
206      _ => todo!(),
207      //MechCode::FunctionDefine(func_def) => self.function_define(func_def, src),
208      };
209      if self.html {
210        src.push_str(&format!("<div class=\"mech-code\">{}</div>", c));
211      } else {
212        src.push_str(&format!("{}\n", c));
213      }
214    }
215    if self.html {
216      format!("<div class=\"mech-code-block\">{}</div>",src)
217    } else {
218      src
219    }
220  }
221
222  pub fn fsm_implementation(&mut self, node: &FsmImplementation) -> String {
223    let name = node.name.to_string();
224    let mut input = "".to_string();
225    for (i, ident) in node.input.iter().enumerate() {
226      let v = ident.to_string();
227      if i == 0 {
228        input = format!("{}", v);
229      } else {
230        input = format!("{}, {}", input, v);
231      }
232    }
233    let start = self.pattern(&node.start);
234    let mut arms = "".to_string();
235    for (i, arm) in node.arms.iter().enumerate() {
236      let a = self.fsm_arm(arm, i == node.arms.len() - 1);
237      if i == 0 {
238        arms = format!("{}", a);
239      } else {
240        arms = format!("{}{}", arms, a);
241      }
242    }
243    if self.html {
244      format!("<div class=\"mech-fsm-implementation\">
245        <div class=\"mech-fsm-implementation-header\">
246          <span class=\"mech-fsm-sigil\">#</span>
247          <span class=\"mech-fsm-name\">{}</span>
248          <span class=\"mech-left-paren\">(</span>
249          <span class=\"mech-fsm-input\">{}</span>
250          <span class=\"mech-right-paren\">)</span>
251          <span class=\"mech-fsm-define-op\">→</span>
252          <span class=\"mech-fsm-start\">{}</span>
253        </div>
254        <div class=\"mech-fsm-arms\">
255          {}
256        </div>
257      </div>",name,input,start,arms)
258    } else {
259      format!("#{}({}) {} {}\n{}", name, input, "->" , start, arms)
260    }
261  }
262
263  pub fn fsm_arm(&mut self, node: &FsmArm, last: bool) -> String {
264    let arm = match node {
265      FsmArm::Guard(pattern, guards) => {
266        let p = self.pattern(pattern);
267        let mut gs = "".to_string();
268        for (i, guard) in guards.iter().enumerate() {
269          let g = self.guard(guard);
270          if i == 0 {
271            if self.html {
272              gs = format!("<div class=\"mech-fsm-guard-arm\">├ {}</div>", g);
273            } else {
274              gs = format!("    ├ {}\n", g);
275            }
276          } else if i == guards.len() - 1 {
277            if self.html {
278              gs = format!("{}<div class=\"mech-fsm-guard-arm\">└ {}</div>", gs, g);
279            } else {
280              gs = format!("{}    └ {}", gs, g); 
281            }
282          } else {  
283            if self.html {
284              gs = format!("{}<div class=\"mech-fsm-guard-arm\">├ {}</div>", gs, g);
285            } else {
286              gs = format!("{}    ├ {}\n", gs, g);
287            }
288          }
289        }
290        if self.html {
291          format!("<div class=\"mech-fsm-arm-guard\">
292            <span class=\"mech-fsm-start\">{}</span>
293            <span class=\"mech-fsm-guards\">{}</span>
294          </div>",p,gs)
295        } else {
296          format!("  {}\n{}", p, gs)
297        }
298      },
299      FsmArm::Transition(pattern, transitions) => {
300        let p = self.pattern(pattern);
301        let mut ts = "".to_string();
302        for (i, transition) in transitions.iter().enumerate() {
303          let t = self.transition(transition);
304          if i == 0 {
305            ts = format!("{}", t);
306          } else {
307            ts = format!("{}{}", ts, t);
308          }
309        }
310        if self.html {
311          format!("<div class=\"mech-fsm-arm\">
312            <span class=\"mech-fsm-arm-pattern\">{}</span>
313            <span class=\"mech-fsm-arm-transitions\">{}</span>
314          </div>",p,ts)
315        } else {
316          format!("  {}{}", p, ts)
317        }
318      },
319    };
320    if self.html {
321      if last {
322        format!("<div class=\"mech-fsm-arm-last\">{}.</div>",arm)
323      } else {
324        format!("<div class=\"mech-fsm-arm\">{}</div>",arm)
325      }
326    } else {
327      if last { 
328        format!("{}.", arm)
329      } else {
330        format!("{}\n", arm)
331      }
332    }
333  }
334
335  pub fn guard(&mut self, node: &Guard) -> String {
336    let condition = self.pattern(&node.condition);
337    let mut transitions = "".to_string();
338    for (i, transition) in node.transitions.iter().enumerate() {
339      let t = self.transition(transition);
340      if i == 0 {
341        transitions = format!("{}", t);
342      } else {
343        transitions = format!("{}{}", transitions, t);
344      }
345    }
346    if self.html {
347      format!("<div class=\"mech-guard\">
348        <span class=\"mech-guard-condition\">{}</span>
349        <span class=\"mech-guard-transitions\">{}</span>
350      </div>",condition,transitions)
351    } else {
352      format!("{}{}", condition, transitions)
353    }
354  }
355 
356
357  pub fn pattern(&mut self, node: &Pattern) -> String {
358    let p = match node {
359      Pattern::Wildcard => {
360        if self.html {
361          format!("<span class=\"mech-pattern-wildcard\">*</span>")
362        } else {
363          format!("*")
364        }
365      },
366      Pattern::Formula(factor) => self.factor(factor),
367      Pattern::Expression(expr) => self.expression(expr),
368      Pattern::TupleStruct(tuple_struct) => self.pattern_tuple_struct(tuple_struct),
369    };
370    if self.html {
371      format!("<span class=\"mech-pattern\">{}</span>",p)
372    } else {
373      p
374    }
375  }
376
377  pub fn pattern_tuple_struct(&mut self, node: &PatternTupleStruct) -> String {
378    let name = node.name.to_string();
379    let mut patterns = "".to_string();
380    for (i, pattern) in node.patterns.iter().enumerate() {
381      let p = self.pattern(pattern);
382      if i == 0 {
383        patterns = format!("{}", p);
384      } else {
385        patterns = format!("{}, {}", patterns, p);
386      }
387    }
388    if self.html {
389      format!("<span class=\"mech-tuple-struct\">
390        `
391        <span class=\"mech-tuple-struct-name\">{}</span>
392        <span class=\"mech-left-paren\">(</span>
393        <span class=\"mech-tuple-struct-patterns\">{}</span>
394        <span class=\"mech-right-paren\">)</span>
395      </span>",name,patterns)
396    } else {
397      format!("`{}({})", name, patterns)
398    }
399  }
400
401  pub fn transition(&mut self, node: &Transition) -> String {
402    match node {
403      Transition::Next(pattern) => {
404        if self.html {
405          format!("<span class=\"mech-transition-next\">→ {}</span>",self.pattern(pattern))
406        } else {
407          format!(" {} {}", "->", self.pattern(pattern))
408        }
409      }
410      Transition::Output(pattern) => {
411        if self.html {
412          format!("<span class=\"mech-transition-output\">⇒ {}</span>",self.pattern(pattern))
413        } else {
414          format!(" {} {}", "=>", self.pattern(pattern))
415        }
416      }
417      Transition::Async(pattern) => {
418        if self.html {
419          format!("<span class=\"mech-transition-async\">↝ {}</span>",self.pattern(pattern))
420        } else {
421          format!(" {} {}", "~>", self.pattern(pattern))
422
423        }
424      }
425      Transition::Statement(stmt) => {
426        if self.html {
427          format!("<span class=\"mech-transition-statement\">→ {}</span>",self.statement(stmt))
428        } else {
429          format!(" {} {}", "->", self.statement(stmt))
430        }
431      }
432      Transition::CodeBlock(code) => {
433        let mut code_str = "".to_string();
434        let formatted = self.mech_code(code);
435        if self.html {
436          code_str.push_str(&format!("<span class=\"mech-transition-code\">→ {}</span>", formatted));
437        } else {
438          code_str.push_str(&format!(" {} {}", "->", formatted));
439        }
440        code_str
441      }
442    }
443  }
444
445  pub fn fsm_specification(&mut self, node: &FsmSpecification) -> String {
446    let name = node.name.to_string();
447    let mut input = "".to_string();
448    for (i, var) in node.input.iter().enumerate() {
449      let v = self.var(var);
450      if i == 0 {
451        input = format!("{}", v);
452      } else {
453        input = format!("{}, {}", input, v);
454      }
455    }
456    let output = match &node.output {
457      Some(kind) => format!(" {} {}", "⇒", self.kind_annotation(kind)),
458      None => "".to_string(),
459    };
460    let mut states = "".to_string();
461    for (i, state) in node.states.iter().enumerate() {
462      let v = self.state_definition(state);
463      let state_arm = if node.states.len() == 1 {
464        format!("{} {}", "└", v)
465      } else if i == 0 {
466        format!("{} {}", "├", v)
467      } else if i == node.states.len() - 1 {
468        format!("{} {}{}", "└", v, ".")
469      } else {
470        format!("{} {}", "├", v)
471      };
472      if self.html {
473        states = format!("{}<span class=\"mech-fsm-state\">{}</span>",states,state_arm);
474      } else {
475        states = format!("{}    {}\n",states,state_arm);
476      }
477    }
478    if self.html {
479      format!("<div class=\"mech-fsm-specification\">
480      <div class=\"mech-fsm-specification-header\">
481        <span class=\"mech-fsm-sigil\">#</span>
482        <span class=\"mech-fsm-name\">{}</span>
483        <span class=\"mech-left-paren\">(</span>
484        <span class=\"mech-fsm-input\">{}</span>
485        <span class=\"mech-right-paren\">)</span>
486        <span class=\"mech-fsm-output\">{}</span>
487        <span class=\"mech-fsm-define-op\">:=</span>
488      </div>
489      <div class=\"mech-fsm-states\">{}</div>
490      </div>",name,input,output,states)
491    } else {
492      format!("#{}({}){} {}\n{}", name, input, output, ":=", states)
493    }
494  }
495
496  pub fn state_definition(&mut self, node: &StateDefinition) -> String {
497    let name = node.name.to_string();
498    let mut state_variables = "".to_string();
499    match &node.state_variables {
500      Some(vars) => {
501        for (i, var) in vars.iter().enumerate() {
502          let v = self.var(var);
503          if i == 0 {
504            state_variables = format!("{}", v);
505          } else {
506            state_variables = format!("{}, {}", state_variables, v);
507          }
508        }
509      },
510      None => {}
511    }
512    if self.html {
513      format!("<div class=\"mech-state-definition\">
514      <span class=\"mech-state-name\">`{}</span>
515      <span class=\"mech-left-paren\">(</span>
516      <span class=\"mech-state-variables\">{}</span>
517      <span class=\"mech-right-paren\">)</span>
518      </div>",name,state_variables)
519    } else {
520      format!("{}({})", name, state_variables)
521    }
522  }
523
524  pub fn variable_define(&mut self, node: &VariableDefine) -> String {
525    let mut mutable = if node.mutable {
526      "~".to_string()
527    } else {
528      "".to_string()
529    };
530    let var = self.var(&node.var);
531    let expression = self.expression(&node.expression);
532    if self.html {
533      format!("<span class=\"mech-variable-define\"><span class=\"mech-variable-mutable\">{}</span>{}<span class=\"mech-variable-assign-op\">:=</span>{}</span>",mutable, var, expression)
534    } else {
535      format!("{}{} {} {}", mutable, var, ":=", expression)
536    }
537  }
538
539  pub fn statement(&mut self, node: &Statement) -> String {
540    let s = match node {
541      Statement::VariableDefine(var_def) => self.variable_define(var_def),
542      Statement::OpAssign(op_asgn) => self.op_assign(op_asgn),
543      Statement::VariableAssign(var_asgn) => self.variable_assign(var_asgn),
544      _ => todo!(),
545      //Statement::EnumDefine(enum_def) => self.enum_define(enum_def, src),
546      //Statement::FsmDeclare(fsm_decl) => self.fsm_declare(fsm_decl, src),
547      //Statement::KindDefine(kind_def) => self.kind_define(kind_def, src),
548    };
549    if self.html {
550      format!("<span class=\"mech-statement\">{}</span>",s)
551    } else {
552      format!("{}", s)
553    }
554  }
555
556  pub fn variable_assign(&mut self, node: &VariableAssign) -> String {
557    let target = self.slice_ref(&node.target);
558    let expression = self.expression(&node.expression);
559    if self.html {
560      format!("<span class=\"mech-variable-assign\">
561        <span class=\"mech-target\">{}</span>
562        <span class=\"mech-assign-op\">=</span>
563        <span class=\"mech-expression\">{}</span>
564      </span>",target,expression)
565    } else {
566      format!("{} = {}", target, expression)
567    }
568  }
569
570  pub fn op_assign(&mut self, node: &OpAssign) -> String {
571    let target = self.slice_ref(&node.target);
572    let op = self.op_assign_op(&node.op);
573    let expression = self.expression(&node.expression);
574    if self.html {
575      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)
576    } else {
577      format!("{} {} {}", target, op, expression)
578    }
579  }
580
581  pub fn op_assign_op(&mut self, node: &OpAssignOp) -> String {
582    let op = match node {
583      OpAssignOp::Add => "+=".to_string(),
584      OpAssignOp::Sub => "-=".to_string(),
585      OpAssignOp::Mul => "*=".to_string(),
586      OpAssignOp::Div => "/=".to_string(),
587      OpAssignOp::Exp => "^=".to_string(),
588    };
589    if self.html {
590      format!("<span class=\"mech-op-assign-op\">{}</span>",op)
591    } else {
592      format!("{}", op)
593    }
594  }
595
596  pub fn slice_ref(&mut self, node: &SliceRef) -> String {
597    let name = node.name.to_string();
598    let mut subscript = "".to_string();
599    match &node.subscript {
600      Some(subs) => {
601        for sub in subs.iter() {
602          let s = self.subscript(sub);
603          subscript = format!("{}{}", subscript, s);
604        }
605      },
606      None => {},
607    }
608    if self.html {
609      format!("<span class=\"mech-slice-ref\"><span id=\"{}\" class=\"mech-var-name mech-clickable\">{}</span><span class=\"mech-subscript\">{}</span></span>",hash_str(&name),name,subscript)
610    } else {
611      format!("{}{}", name, subscript)
612    }
613  }
614
615  pub fn expression(&mut self, node: &Expression) -> String {
616    let e = match node {
617      Expression::Var(var) => self.var(var),
618      Expression::Formula(factor) => self.factor(factor),
619      Expression::Literal(literal) => self.literal(literal),
620      Expression::Structure(structure) => self.structure(structure),
621      Expression::Slice(slice) => self.slice(slice),
622      Expression::FunctionCall(function_call) => self.function_call(function_call),
623      Expression::Range(range) => self.range_expression(range),
624      _ => todo!(),
625      //Expression::FsmPipe(fsm_pipe) => self.fsm_pipe(fsm_pipe, src),
626    };
627    if self.html {
628      format!("<span class=\"mech-expression\">{}</span>",e)
629    } else {
630      format!("{}", e)
631    }
632  }
633
634  pub fn range_expression(&mut self, node: &RangeExpression) -> String {
635    let start = self.factor(&node.start);
636    let operator = match &node.operator {
637      RangeOp::Inclusive => "..".to_string(),
638      RangeOp::Exclusive => "..".to_string(),
639    };
640    let terminal = self.factor(&node.terminal);
641    let increment = match &node.increment {
642      Some((op, factor)) => {
643        let o = match op {
644          RangeOp::Inclusive => "=..".to_string(),
645          RangeOp::Exclusive => "..".to_string(),
646        };
647        let f = self.factor(factor);
648        if self.html {
649          format!("<span class=\"mech-range-increment\">{}{}</span>",o,f)
650        } else {
651          format!("{}{}", o, f)
652        }
653      },
654      None => "".to_string(),
655    };
656    if self.html {
657      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)
658    } else {
659      format!("{}{}{}{}", start, operator, terminal, increment)
660    }
661  }
662
663  pub fn function_call(&mut self, node: &FunctionCall) -> String {
664    let name = node.name.to_string();
665    let mut args = "".to_string();
666    for (i, arg) in node.args.iter().enumerate() {
667      let a = self.argument(arg);
668      if i == 0 {
669        args = format!("{}", a);
670      } else {
671        args = format!("{}, {}", args, a);
672      }
673    }
674    if self.html {
675      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>",hash_str(&name),name,args)
676    } else {
677      format!("{}({})", name, args)
678    }
679  }
680
681  pub fn argument(&mut self, node: &(Option<Identifier>, Expression)) -> String {
682    let (name, expr) = node;
683    let n = match name {
684      Some(ident) => ident.to_string(),
685      None => "".to_string(),
686    };
687    let e = self.expression(expr);
688    if self.html {
689      format!("<span class=\"mech-argument\"><span class=\"mech-argument-name\">{}</span><span class=\"mech-argument-expression\">{}</span></span>",n,e)
690    } else {
691      format!("{}{}", n, e)
692    }
693  }
694
695  pub fn slice(&mut self, node: &Slice) -> String {
696    let name = node.name.to_string();
697    let mut subscript = "".to_string();
698    for (i, sub) in node.subscript.iter().enumerate() {
699      let s = self.subscript(sub);
700      subscript = format!("{}{}", subscript, s);
701    }
702    if self.html {
703      format!("<span class=\"mech-slice\"><span id=\"{}\" class=\"mech-var-name mech-clickable\">{}</span><span class=\"mech-subscript\">{}</span></span>",hash_str(&name),name,subscript)
704    } else {
705      format!("{}{}", name, subscript)
706    }
707  }
708
709  pub fn subscript(&mut self, node: &Subscript) -> String {
710    match node {
711      Subscript::Bracket(subs) => self.bracket(subs),
712      Subscript::Formula(factor) => self.factor(factor),
713      Subscript::All => self.all(),
714      Subscript::Dot(ident) => self.dot(ident),
715      Subscript::Swizzle(idents) => self.swizzle(idents),
716      Subscript::Range(range) => self.range_expression(range),
717      Subscript::Brace(subs) => self.brace(subs),
718      Subscript::DotInt(real) => self.dot_int(real),
719    }
720  }
721
722  pub fn brace(&mut self, node: &Vec<Subscript>) -> String {
723    let mut src = "".to_string();
724    for (i, sub) in node.iter().enumerate() {
725      let s = self.subscript(sub);
726      if i == 0 {
727        src = format!("{}", s);
728      } else {
729        src = format!("{},{}", src, s);
730      }
731    }
732    if self.html {
733      format!("<span class=\"mech-brace\">{{{}}}</span>",src)
734    } else {
735      format!("{{{}}}",src)
736    }
737  }
738
739  pub fn swizzle(&mut self, node: &Vec<Identifier>) -> String {
740    let mut src = "".to_string();
741    for (i, ident) in node.iter().enumerate() {
742      let s = self.dot(ident);
743      if i == 0 {
744        src = format!("{}", s);
745      } else {
746        src = format!("{},{}", src, s);
747      }
748    }
749    if self.html {
750      format!("<span class=\"mech-swizzle\">{}</span>",src)
751    } else {
752      format!("{}",src)
753    }
754  }
755
756  pub fn dot_int(&mut self, node: &RealNumber) -> String {
757    let node_str = match node {
758      RealNumber::Integer(tkn) => tkn.to_string(),
759      _ => "".to_string(),
760    };
761    if self.html {
762      format!(".<span class=\"mech-dot-int\">{}</span>",node_str)
763    } else {
764      format!(".{}",node_str)
765    }
766  } 
767
768  pub fn dot(&mut self, node: &Identifier) -> String {
769    if self.html {
770      format!(".<span class=\"mech-dot\">{}</span>",node.to_string())
771    } else {
772      format!(".{}",node.to_string())
773    }
774  }
775
776  pub fn all(&mut self) -> String {
777    if self.html {
778      format!("<span class=\"mech-all\">:</span>")
779    } else {
780      ":".to_string()
781    }
782  }
783
784  pub fn bracket(&mut self, node: &Vec<Subscript>) -> String {
785    let mut src = "".to_string();
786    for (i, sub) in node.iter().enumerate() {
787      let s = self.subscript(sub);
788      if i == 0 {
789        src = format!("{}", s);
790      } else {
791        src = format!("{},{}", src, s);
792      }
793    }
794    if self.html {
795      format!("<span class=\"mech-bracket\">[{}]</span>",src)
796    } else {
797      format!("[{}]",src)
798    }
799  }
800
801  pub fn structure(&mut self, node: &Structure) -> String {
802    let s = match node {
803      Structure::Matrix(matrix) => self.matrix(matrix),
804      Structure::Record(record) => self.record(record),
805      Structure::Empty => "_".to_string(),
806      Structure::Table(table) => self.table(table),
807      Structure::Tuple(tuple) => self.tuple(tuple),
808      Structure::TupleStruct(tuple_struct) => self.tuple_struct(tuple_struct),
809      Structure::Set(set) => self.set(set),
810      Structure::Map(map) => self.map(map),
811    };
812    if self.html {
813      format!("<span class=\"mech-structure\">{}</span>",s)
814    } else {
815      format!("{}", s)
816    }
817  }
818
819  pub fn map(&mut self, node: &Map) -> String {
820    let mut src = "".to_string();
821    for (i, mapping) in node.elements.iter().enumerate() {
822      let m = self.mapping(mapping);
823      if i == 0 {
824        src = format!("{}", m);
825      } else {
826        src = format!("{}, {}", src, m);
827      }
828    }
829    if self.html {
830      format!("<span class=\"mech-map\"><span class=\"mech-start-brace\">{{</span>{}}}<span class=\"mech-end-brace\">}}</span></span>",src)
831    } else {
832      format!("{{{}}}", src)
833    }
834  }
835
836  pub fn mapping(&mut self, node: &Mapping) -> String {
837    let key = self.expression(&node.key);
838    let value = self.expression(&node.value);
839    if self.html {
840      format!("<span class=\"mech-mapping\"><span class=\"mech-key\">{}</span><span class=\"mech-colon-op\">:</span><span class=\"mech-value\">{}</span></span>",key,value)
841    } else {
842      format!("{}: {}", key, value)
843    }
844  }
845
846  pub fn set(&mut self, node: &Set) -> String {
847    let mut src = "".to_string();
848    for (i, element) in node.elements.iter().enumerate() {
849      let e = self.expression(element);
850      if i == 0 {
851        src = format!("{}", e);
852      } else {
853        src = format!("{}, {}", src, e);
854      }
855    }
856    if self.html {
857      format!("<span class=\"mech-set\"><span class=\"mech-start-brace\">{{</span>{}<span class=\"mech-end-brace\">}}</span></span>",src)
858    } else {
859      format!("{{{}}}", src)
860    }
861  }
862
863  pub fn tuple_struct(&mut self, node: &TupleStruct) -> String {
864    let name = node.name.to_string();
865    let value = self.expression(&node.value);
866    if self.html {
867      format!("<span class=\"mech-tuple-struct\"><span class=\"mech-tuple-struct-name\">{}</span><span class=\"mech-tuple-struct-value\">{}</span></span>",name,value)
868    } else {
869      format!("{}{}", name, value)
870    }
871  }
872
873  pub fn table(&mut self, node: &Table) -> String {
874    let header = self.table_header(&node.header);
875    let mut rows = "".to_string();
876    for (i, row) in node.rows.iter().enumerate() {
877      let r = self.table_row(row);
878      if i == 0 {
879        rows = format!("{}", r);
880      } else {
881        rows = format!("{}{}", rows, r);
882      }
883    }
884    if self.html {
885      format!("<table class=\"mech-table\">{}<tbody class=\"mech-table-body\">{}</tbody></table>",header,rows)
886    } else {
887      format!("{}{}", header, rows)
888    }
889  }
890
891  pub fn table_header(&mut self, node: &TableHeader) -> String {
892    let mut src = "".to_string();
893    for (i, field) in node.iter().enumerate() {
894      let f = self.field(field);
895      if self.html {
896        src = format!("{}<th class=\"mech-table-field\">{}</th>",src, f);
897      } else {
898        src = format!("{}{}",src, f);
899      }
900    }
901    if self.html {
902      format!("<thead class=\"mech-table-header\"><tr>{}</tr></thead>",src)
903    } else {
904      src
905    }
906  }
907
908  pub fn table_row(&mut self, node: &TableRow) -> String {
909    let mut src = "".to_string();
910    for (i, column) in node.columns.iter().enumerate() {
911      let c = self.table_column(column);
912      if i == 0 {
913        src = format!("{}", c);
914      } else {
915        src = format!("{} {}", src, c);
916      }
917    }
918    if self.html {
919      format!("<tr class=\"mech-table-row\">{}</tr>",src)
920    } else {
921      src
922    }
923  }
924
925  pub fn table_column(&mut self, node: &TableColumn) -> String {
926    let element = self.expression(&node.element);
927    if self.html {
928      format!("<td class=\"mech-table-column\">{}</td>",element)
929    } else {
930      element
931    }
932  }
933
934  pub fn field(&mut self, node: &Field) -> String {
935    let name = node.name.to_string();
936    let kind = if let Some(kind) = &node.kind {
937      self.kind_annotation(kind)
938    } else {
939      "".to_string()
940    };
941    if self.html {
942      format!("<div class=\"mech-field\"><span class=\"mech-field-name\">{}</span><span class=\"mech-field-colon-op\">:</span><span class=\"mech-field-kind\">{}</span></div>",name,kind)
943    } else {
944      format!("{}: {}", name, kind)
945    }
946  }
947
948  pub fn tuple(&mut self, node: &Tuple) -> String {
949    let mut src = "".to_string();
950    for (i, element) in node.elements.iter().enumerate() {
951      let e = self.expression(element);
952      if i == 0 {
953        src = format!("{}", e);
954      } else {
955        src = format!("{},{}", src, e);
956      }
957    }
958    if self.html {
959      format!("<span class=\"mech-tuple\"><span class=\"mech-start-paren\">(</span>{})<span class=\"mech-end-paren\">)</span></span>",src)
960    } else {
961      format!("({})", src)
962    }
963  }
964
965  pub fn record(&mut self, node: &Record) -> String {
966    let mut src = "".to_string();
967    for (i, binding) in node.bindings.iter().enumerate() {
968      let b = self.binding(binding);
969      if i == 0 {
970        src = format!("{}", b);
971      } else {
972        src = format!("{}, {}", src, b);
973      }
974    }
975    if self.html {
976      format!("<span class=\"mech-record\"><span class=\"mech-start-brace\">{{</span>{}<span class=\"mech-end-brace\">}}</span></span>",src)
977    } else {
978      format!("{{{}}}",src)
979    }
980  }
981
982  pub fn binding(&mut self, node: &Binding) -> String {
983    let name = node.name.to_string();
984    let value = self.expression(&node.value);
985    if self.html {
986      format!("<span class=\"mech-binding\"><span class=\"mech-binding-name\">{}</span><span class=\"mech-binding-colon-op\">:</span><span class=\"mech-binding-value\">{}</span></span>",name,value)
987    } else {
988      format!("{}: {}", name, value)
989    }
990  }
991
992  pub fn matrix(&mut self, node: &Matrix) -> String {
993    let mut src = "".to_string();
994    if node.rows.len() == 0 {
995      if self.html {
996        return format!("<span class=\"mech-matrix empty\"><span class=\"mech-bracket start\">[</span><span class=\"mech-bracket end\">]</span></span>");
997      } else {
998        return format!("[]");
999      }
1000    }
1001    let column_count = node.rows[0].columns.len(); // Assume all rows have the same number of columns
1002
1003    for col_index in 0..column_count {
1004        let mut column_elements = Vec::new();
1005        for row in &node.rows {
1006            column_elements.push(&row.columns[col_index]);
1007        }
1008        let c = self.matrix_column_elements(&column_elements);
1009
1010        if col_index == 0 {
1011            src = format!("{}", c);
1012        } else {
1013            src = format!("{} {}", src, c);
1014        }
1015    }
1016
1017    if self.html {
1018        format!("<span class=\"mech-matrix\"><span class=\"mech-bracket start\">[</span>{}<span class=\"mech-bracket end\">]</span></span>", src)
1019    } else {
1020        format!("[{}]", src)
1021    }
1022}
1023
1024pub fn matrix_column_elements(&mut self, column_elements: &[&MatrixColumn]) -> String {
1025    let mut src = "".to_string();
1026    for (i, cell) in column_elements.iter().enumerate() {
1027        let c = self.matrix_column(cell);
1028        if i == 0 {
1029            src = format!("{}", c);
1030        } else {
1031            src = format!("{} {}", src, c);
1032        }
1033    }
1034    if self.html {
1035        format!("<div class=\"mech-matrix-column\">{}</div>", src)
1036    } else {
1037        src
1038    }
1039}
1040
1041
1042  pub fn matrix_row(&mut self, node: &MatrixRow) -> String {
1043    let mut src = "".to_string();
1044    for (i, cell) in node.columns.iter().enumerate() {
1045      let c = self.matrix_column(cell);
1046      if i == 0 {
1047        src = format!("{}", c);
1048      } else { 
1049        src = format!("{} {}", src, c);
1050      }
1051    }
1052    if self.html {
1053      format!("<div class=\"mech-matrix-row\">{}</div>",src)
1054    } else {
1055      src
1056    }
1057  }
1058
1059  pub fn matrix_column(&mut self, node: &MatrixColumn) -> String {
1060    let element = self.expression(&node.element);
1061    if self.html {
1062      format!("<span class=\"mech-matrix-element\">{}</span>",element)
1063    } else {
1064      element
1065    }    
1066  }  
1067
1068  pub fn var(&mut self, node: &Var) -> String {
1069    let annotation = if let Some(kind) = &node.kind {
1070      self.kind_annotation(kind)
1071    } else {
1072      "".to_string()
1073    };
1074    if self.html {
1075      format!("<span class=\"mech-var-name mech-clickable\" id=\"{}\">{}</span>{}",hash_str(&node.name.to_string()), node.name.to_string(), annotation)
1076    } else {
1077      format!("{}{}", node.name.to_string(), annotation)
1078    }
1079  }
1080
1081  pub fn kind_annotation(&mut self, node: &KindAnnotation) -> String {
1082    let kind = self.kind(&node.kind);
1083    if self.html {
1084      format!("<span class=\"mech-kind-annotation\"><{}></span>",kind)
1085    } else {
1086      format!("<{}>", kind)
1087    }
1088  }
1089
1090  pub fn kind(&mut self, node: &Kind) -> String {
1091    let annotation = match node {
1092      Kind::Scalar(ident) => ident.to_string(),
1093      Kind::Empty => "_".to_string(),
1094      Kind::Atom(ident) => format!("`{}",ident.to_string()),
1095      Kind::Tuple(kinds) => {
1096        let mut src = "".to_string();
1097        for (i, kind) in kinds.iter().enumerate() {
1098          let k = self.kind(kind);
1099          if i == 0 {
1100            src = format!("{}", k);
1101          } else {
1102            src = format!("{}, {}", src, k);
1103          }
1104        }
1105        format!("({})", src)
1106      },
1107      Kind::Bracket((kinds, literals)) => {
1108        let mut src = "".to_string();
1109        for (i, kind) in kinds.iter().enumerate() {
1110          let k = self.kind(kind);
1111          if i == 0 {
1112            src = format!("{}", k);
1113          } else {
1114            src = format!("{}, {}", src, k);
1115          }
1116        }
1117        let mut src2 = "".to_string();
1118        for (i, literal) in literals.iter().enumerate() {
1119          let l = self.literal(literal);
1120          if i == 0 {
1121            src2 = format!("{}", l);
1122          } else {
1123            src2 = format!("{}, {}", src2, l);
1124          }
1125        }
1126        format!("[{}]:{}", src, src2)
1127      },
1128      Kind::Brace((kinds, literals)) => {
1129        let mut src = "".to_string();
1130        for (i, kind) in kinds.iter().enumerate() {
1131          let k = self.kind(kind);
1132          if i == 0 {
1133            src = format!("{}", k);
1134          } else {
1135            src = format!("{}, {}", src, k);
1136          }
1137        }
1138        let mut src2 = "".to_string();
1139        for (i, literal) in literals.iter().enumerate() {
1140          let l = self.literal(literal);
1141          if i == 0 {
1142            src2 = format!("{}", l);
1143          } else {
1144            src2 = format!("{}, {}", src2, l);
1145          }
1146        }
1147        format!("{{{}}}:{}", src, src2)
1148      },
1149      Kind::Map(kind1, kind2) => {
1150        let k1 = self.kind(kind1);
1151        let k2 = self.kind(kind2);
1152        format!("{}:{}", k1, k2)
1153      },
1154      Kind::Function(input, output) => todo!(),
1155      Kind::Fsm(input, output) => todo!(),
1156    };
1157    if self.html {
1158      format!("<span class=\"mech-kind\">{}</span>",annotation)
1159    } else {
1160      annotation
1161    }
1162  }
1163
1164  pub fn factor(&mut self, node: &Factor) -> String {
1165    let f = match node {
1166      Factor::Term(term) => self.term(term),
1167      Factor::Expression(expr) => self.expression(expr),
1168      Factor::Parenthetical(paren) => {
1169        if self.html {
1170          format!("<span class=\"mech-parenthetical\">({})</span>", self.factor(paren))
1171        } else {
1172          format!("({})", self.factor(&paren))
1173        }
1174      }
1175      Factor::Negate(factor) => {
1176        if self.html {
1177          format!("<span class=\"mech-negate-op\">-</span><span class=\"mech-negate\">{}</span>", self.factor(factor))
1178        } else {
1179          format!("-{}", self.factor(factor))
1180        }
1181      }
1182      Factor::Not(factor) => {
1183        if self.html {
1184          format!("<span class=\"mech-not-op\">¬</span><span class=\"mech-not\">{}</span>", self.factor(factor))
1185        } else {
1186          format!("¬{}", self.factor(factor))
1187        }
1188      }
1189      Factor::Transpose(factor) => {
1190        if self.html {
1191          format!("<span class=\"mech-transpose\">{}</span><span class=\"mech-transpose-op\">'</span>", self.factor(factor))
1192        } else {
1193          format!("{}'", self.factor(factor))
1194        }
1195      }
1196    };
1197    if self.html {
1198      format!("<span class=\"mech-factor\">{}</span>",f)
1199    } else {
1200      f
1201    }
1202  }
1203
1204  pub fn term(&mut self, node: &Term) -> String {
1205    let mut src = self.factor(&node.lhs);
1206    for (formula_operator, rhs) in &node.rhs {
1207      let op = self.formula_operator(formula_operator);
1208      let rhs = self.factor(rhs);
1209      src = format!("{}{}{}", src, op, rhs);
1210    }
1211    if self.html {
1212      format!("<span class=\"mech-term\">{}</span>",src)
1213    } else {
1214      src
1215    }
1216  }
1217
1218  pub fn formula_operator(&mut self, node: &FormulaOperator) -> String {
1219    let f = match node {
1220      FormulaOperator::AddSub(op) => self.add_sub_op(op),
1221      FormulaOperator::MulDiv(op) => self.mul_div_op(op),
1222      FormulaOperator::Exponent(op) => self.exponent_op(op),
1223      FormulaOperator::Vec(op) => self.vec_op(op),
1224      FormulaOperator::Comparison(op) => self.comparison_op(op),
1225      FormulaOperator::Logic(op) => self.logic_op(op),
1226    };
1227    if self.html {
1228      format!("<span class=\"mech-formula-operator\">{}</span>",f)
1229    } else {
1230      format!(" {} ", f)
1231    }
1232  }
1233
1234  pub fn add_sub_op(&mut self, node: &AddSubOp) -> String {
1235    match node {
1236      AddSubOp::Add => "+".to_string(),
1237      AddSubOp::Sub => "-".to_string(),
1238    }
1239  }
1240
1241  pub fn mul_div_op(&mut self, node: &MulDivOp) -> String {
1242    match node {
1243      MulDivOp::Mul => "*".to_string(),
1244      MulDivOp::Div => "/".to_string(),
1245    }
1246  }
1247
1248  pub fn exponent_op(&mut self, node: &ExponentOp) -> String {
1249    match node {
1250      ExponentOp::Exp => "^".to_string(),
1251    }
1252  }
1253
1254  pub fn vec_op(&mut self, node: &VecOp) -> String {
1255    match node {
1256      VecOp::MatMul => "**".to_string(),
1257      VecOp::Solve => "\\".to_string(),
1258      VecOp::Cross => "×".to_string(),
1259      VecOp::Dot => "·".to_string(),
1260    }
1261  }
1262
1263  pub fn comparison_op(&mut self, node: &ComparisonOp) -> String {
1264    match node {
1265      ComparisonOp::Equal => "⩵".to_string(),
1266      ComparisonOp::NotEqual => "≠".to_string(),
1267      ComparisonOp::GreaterThan => ">".to_string(),
1268      ComparisonOp::GreaterThanEqual => "≥".to_string(),
1269      ComparisonOp::LessThan => "<".to_string(),
1270      ComparisonOp::LessThanEqual => "≤".to_string(),
1271    }
1272  }
1273
1274  pub fn logic_op(&mut self, node: &LogicOp) -> String {
1275    match node {
1276      LogicOp::And => "&".to_string(),
1277      LogicOp::Or => "|".to_string(),
1278      LogicOp::Xor => "xor".to_string(),
1279      LogicOp::Not => "¬".to_string(),
1280    }
1281  }
1282
1283  pub fn literal(&mut self, node: &Literal) -> String {
1284    let l = match node {
1285      Literal::Empty(token) => "_".to_string(),
1286      Literal::Boolean(token) => token.to_string(),
1287      Literal::Number(number) => self.number(number),
1288      Literal::String(mech_string) => self.string(mech_string),
1289      Literal::Atom(atom) => self.atom(atom),
1290      Literal::TypedLiteral((boxed_literal, kind_annotation)) => {
1291        let literal = self.literal(boxed_literal);
1292        let annotation = self.kind_annotation(kind_annotation);
1293        format!("{}{}", literal, annotation)
1294      }
1295    };
1296    if self.html {
1297      format!("<span class=\"mech-literal\">{}</span>",l)
1298    } else {
1299      l
1300    }
1301  }
1302
1303  pub fn atom(&mut self, node: &Atom) -> String {
1304    if self.html {
1305      format!("<span class=\"mech-atom\">{}</span>",node.name.to_string())
1306    } else {
1307      format!("`{}", node.name.to_string())
1308    }
1309  }
1310
1311  pub fn string(&mut self, node: &MechString) -> String {
1312    if self.html {
1313      format!("<span class=\"mech-string\">\"{}\"</span>", node.text.to_string())
1314    } else {
1315      format!("\"{}\"", node.text.to_string())
1316    }
1317  }
1318
1319  pub fn number(&mut self, node: &Number) -> String {
1320    let n = match node {
1321      Number::Real(real) => self.real_number(real),
1322      Number::Imaginary(complex) => self.complex_numer(complex),
1323    };
1324    if self.html {
1325      format!("<span class=\"mech-number\">{}</span>",n)
1326    } else {
1327      n
1328    }
1329  }
1330
1331  pub fn real_number(&mut self, node: &RealNumber) -> String {
1332    match node {
1333      RealNumber::Negated(real_number) => format!("-{}", self.real_number(real_number)),
1334      RealNumber::Integer(token) => token.to_string(),
1335      RealNumber::Float((whole, part)) => format!("{}.{}", whole.to_string(), part.to_string()),
1336      RealNumber::Decimal(token) => token.to_string(),
1337      RealNumber::Hexadecimal(token) => format!("0x{}", token.to_string()),
1338      RealNumber::Octal(token) => format!("0o{}", token.to_string()),
1339      RealNumber::Binary(token) => format!("0b{}", token.to_string()),
1340      RealNumber::Scientific(((whole, part), (sign, ewhole, epart))) => format!("{}.{}e{}{}.{}", whole.to_string(), part.to_string(), if *sign { "-" } else { "+" }, ewhole.to_string(), epart.to_string()),
1341      RealNumber::Rational((numerator, denominator)) => format!("{}/{}", numerator.to_string(), denominator.to_string()),
1342    }
1343  }
1344
1345  pub fn complex_numer(&mut self, node: &ComplexNumber) -> String {
1346    let real = if let Some(real) = &node.real {
1347      let num = self.real_number(&real);
1348      format!("{}+", num)
1349    } else {
1350      "".to_string()
1351    };
1352    let im = self.imaginary_number(&node.imaginary);
1353    format!("{}{}", real, im)
1354  }
1355
1356  pub fn imaginary_number(&mut self, node: &ImaginaryNumber) -> String {
1357    let real = self.real_number(&node.number);
1358    format!("{}i", real)
1359  }
1360
1361  pub fn humanize_html(input: String) -> String {
1362    let mut formatted = String::new();
1363    let mut indent_level: usize = 0;
1364    let mut i = 0;
1365    while i < input.len() {
1366      // Find the next tag
1367      if let Some(start) = input[i..].find('<') {
1368        let tag_start = i + start;
1369        if let Some(end) = input[tag_start..].find('>') {
1370          let tag_end = tag_start + end + 1;
1371          let tag = &input[tag_start..tag_end];
1372          // Add any content before the tag
1373          let content = &input[i..tag_start].trim();
1374          if !content.is_empty() {
1375            formatted.push('\n');
1376            formatted.push_str(&" ".repeat(indent_level));
1377            formatted.push_str(content);
1378          }
1379          // Check if this is a closing tag
1380          if tag.starts_with("</") {
1381            // Decrease indentation for closing tags
1382            indent_level = indent_level.saturating_sub(1);
1383            formatted.push('\n');
1384            formatted.push_str(&" ".repeat(indent_level));
1385            formatted.push_str(tag);
1386          } else if tag.ends_with("/>") {
1387            // Self-closing tag, no change in indentation
1388            formatted.push('\n');
1389            formatted.push_str(&" ".repeat(indent_level));
1390            formatted.push_str(tag);
1391          } else {
1392            // Opening tag
1393            formatted.push('\n');
1394            formatted.push_str(&" ".repeat(indent_level));
1395            formatted.push_str(tag);
1396            indent_level += 1;
1397          }
1398          // Move past the current tag
1399          i = tag_end;
1400          continue;
1401        }
1402      }
1403      // Handle remaining content (if no more tags)
1404      let content = &input[i..].trim();
1405      if !content.is_empty() {
1406        formatted.push('\n');
1407        formatted.push_str(&" ".repeat(indent_level));
1408        formatted.push_str(content);
1409      }
1410      break;
1411    }
1412    formatted
1413  }
1414 
1415}