subscript_compiler/codegen/
html.rs

1use std::borrow::Cow;
2use std::collections::HashMap;
3use crate::frontend::data::{LayoutKind, Text};
4
5///////////////////////////////////////////////////////////////////////////////
6// BASICS
7///////////////////////////////////////////////////////////////////////////////
8
9#[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///////////////////////////////////////////////////////////////////////////////
50// HTML TREE
51///////////////////////////////////////////////////////////////////////////////
52
53#[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/// Render the entire document.
135#[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