rst_renderer/
html.rs

1mod elems_cats;
2mod multi;
3#[cfg(test)]
4pub mod tests;
5
6use std::io::Write;
7
8use anyhow::Error;
9
10// use crate::url::Url;
11use document_tree::{Document, HasChildren};
12
13/// Render document as HTML
14///
15/// # Errors
16/// Returns error if serialization fails
17pub fn render_html<W>(document: &Document, stream: W, standalone: bool) -> Result<(), Error>
18where
19    W: Write,
20{
21    let mut renderer = HTMLRenderer { stream, level: 0 };
22    if standalone {
23        document.render_html(&mut renderer)
24    } else {
25        document.children().render_html(&mut renderer)
26    }
27}
28
29fn escape_html(text: &str) -> String {
30    text.replace('&', "&amp;")
31        .replace('<', "&lt;")
32        .replace('>', "&gt;")
33        .replace('"', "&quot;")
34}
35
36struct HTMLRenderer<W>
37where
38    W: Write,
39{
40    stream: W,
41    level: u8,
42}
43
44trait HTMLRender {
45    fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error>
46    where
47        W: Write;
48}
49
50pub const FOOTNOTE_SYMBOLS: [char; 10] = ['*', '†', '‡', '§', '¶', '#', '♠', '♥', '♦', '♣'];
51
52pub fn footnote_symbol(n: usize) -> String {
53    FOOTNOTE_SYMBOLS
54        .iter()
55        .cycle()
56        .nth(n - 1)
57        .unwrap()
58        .to_string()
59}
60
61const HEAD: &str = r#"<head>
62<meta charset="utf-8">
63<meta name="color-scheme" content="dark light">
64<meta name="viewport" content="width=device-width, initial-scale=1">
65<style>
66@counter-style footnote-numeric {
67    system: numeric;
68    symbols: '0' '1' '2' '3' '4' '5' '6' '7' '8' '9';
69    prefix: '[';
70    suffix: '] ';
71}
72@counter-style footnote-symbolic {
73    system: symbolic;
74    symbols: '*' '†' '‡' '§' '¶' '#' '♠' '♥' '♦' '♣';
75    prefix: '';
76    suffix: ' ';
77}
78.footnote-reference:target,
79ol.footnotes > li:target {
80    background-color: hsl(60 100% 50% / 0.2);
81}
82ol.footnotes > li {
83    list-style-type: footnote-numeric;
84}
85ol.footnotes > li.symbol {
86    list-style-type: footnote-symbolic;
87}
88ol.footnotes > li > .backrefs {
89    float: left;
90    font-size: 0.8em;
91}
92</style>
93</head>"#;
94
95impl HTMLRender for Document {
96    fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error>
97    where
98        W: Write,
99    {
100        writeln!(renderer.stream, "<!doctype html>\n<html>\n{HEAD}\n<body>")?;
101        self.children().render_html(renderer)?;
102        writeln!(renderer.stream, "</body>\n</html>")?;
103        Ok(())
104    }
105}
106
107//------------\\
108//Things to do\\
109//------------\\
110
111//TODO: prettyprint option list
112//TODO: render admonitions: Admonition, Attention, Hint, Note, Caution, Danger, Error, Important, Tip, Warning
113//TODO: properly render tables
114
115//TODO: add reference target: FootnoteReference, CitationReference, TitleReference
116//TODO: add title: Abbr, Acronym
117//TODO: convert math, set display attr
118//TODO: add id: Rubric, Target, TargetInline