subscript_compiler/codegen/
html.rs1use std::borrow::Cow;
2use std::collections::HashMap;
3use crate::frontend::data::{LayoutKind, Text};
4
5#[derive(Clone)]
10pub enum Image {
11 Svg {
12 kind: LayoutKind,
13 payload: String,
14 },
15}
16
17impl std::fmt::Debug for Image {
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 match self {
20 Image::Svg{kind, payload} => {
21 f.debug_struct("Svg")
22 .field("kind", &kind)
23 .field("payload", &String::from("DataNotShown"))
24 .finish()
25 }
26 }
27 }
28}
29
30#[derive(Debug, Clone)]
31pub enum ImageType {
32 Svg,
33}
34
35impl Image {
36 pub fn layout(&self) -> LayoutKind {
37 match self {
38 Self::Svg { kind, payload } => kind.clone(),
39 }
40 }
41 pub fn image_type(&self) -> ImageType {
42 match self {
43 Self::Svg {..} => ImageType::Svg,
44 }
45 }
46}
47
48
49#[derive(Debug, Clone)]
54pub struct Element<'a> {
55 pub name: Text<'a>,
56 pub attributes: HashMap<Text<'a>, Text<'a>>,
57 pub children: Vec<Node<'a>>,
58}
59
60
61#[derive(Debug, Clone)]
62pub enum Node<'a> {
63 Element(Element<'a>),
64 Text(Text<'a>),
65 Image(Image),
66 Fragment(Vec<Node<'a>>),
67}
68
69impl<'a> Node<'a> {
70 pub fn new_text(val: &'a str) -> Self {
71 Node::Text(Text::new(val))
72 }
73 pub fn to_html_str(self) -> Text<'a> {
74 match self {
75 Node::Text(node) => node,
76 Node::Element(node) => {
77 let attributes = node.attributes
78 .into_iter()
79 .map(|(left, right)| -> String {
80 let mut result = String::new();
81 let key: &str = &left.0;
82 let value: &str = &right.0;
83 let value = value.strip_prefix("\'").unwrap_or(value);
84 let value = value.strip_prefix("\"").unwrap_or(value);
85 let value = value.strip_suffix("\'").unwrap_or(value);
86 let value = value.strip_suffix("\"").unwrap_or(value);
87 result.push_str(key);
88 result.push_str("=");
89 result.push_str(&format!("{:?}", value));
90 result
91 })
92 .collect::<Vec<_>>()
93 .join(" ");
94 let attributes = {
95 if attributes.is_empty() {
96 Text::default()
97 } else {
98 let mut attrs = attributes;
99 attrs.insert(0, ' ');
100 Text::from_string(attrs)
101 }
102 };
103 let children = node.children
104 .into_iter()
105 .map(Node::to_html_str)
106 .map(|x| x.0)
107 .collect::<Vec<_>>()
108 .join("");
109 let children = Text::from_string(children);
110 Text::from_string(format!(
111 "<{name}{attrs}>{children}</{name}>",
112 name=node.name,
113 attrs=attributes,
114 children=children,
115 ))
116 }
117 Node::Fragment(nodes) => {
118 let children = nodes
119 .into_iter()
120 .map(Node::to_html_str)
121 .map(|x| x.0)
122 .collect::<Vec<_>>()
123 .join("");
124 Text::from_string(children)
125 }
126 Node::Image(image) => {
127 unimplemented!()
128 }
129 }
130 }
131}
132
133
134#[derive(Debug, Clone)]
136pub struct Document<'a> {
137 pub toc: Node<'a>,
138 pub body: Vec<Node<'a>>
139}
140
141impl<'a> Document<'a> {
142 pub fn from_source(source: &'a str) -> Document<'a> {
143 let body = crate::frontend::pass::pp_normalize::run_compiler_frontend(source);
144 let body = crate::frontend::pass::html_normalize::html_canonicalization(body);
145 let body = body
146 .into_iter()
147 .map(crate::frontend::pass::math::latex_pass)
148 .collect::<Vec<_>>();
149 let toc = crate::frontend
150 ::pass
151 ::html_normalize
152 ::generate_table_of_contents_tree(
153 &crate::frontend::ast::Node::new_fragment(body.clone())
154 );
155 let toc = crate::frontend::pass::to_html::node_to_html(
156 crate::frontend::pass::math::latex_pass(toc)
157 );
158 let body = body
159 .into_iter()
160 .map(crate::frontend::pass::html_normalize::annotate_heading_nodes)
161 .map(crate::frontend::pass::to_html::node_to_html)
162 .collect::<Vec<_>>();
163 Document{toc, body}
164 }
165 pub fn render_to_string(self) -> String {
166 let toc = self.toc.to_html_str().to_string();
167 let body = self.body
168 .into_iter()
169 .map(Node::to_html_str)
170 .map(|x| x.0)
171 .collect::<Vec<_>>()
172 .join("\n");
173 String::from(include_str!("../../assets/template.html"))
174 .replace("<!--{{deps}}-->", include_str!("../../assets/deps.html"))
175 .replace("/*{{css}}*/", include_str!("../../assets/styling.css"))
176 .replace("<!--{{toc}}-->", &toc)
177 .replace("<!--{{body}}-->", &body)
178 }
179}
180
181
182