nib/
renderer.rs

1//!
2use std::io::{BufWriter, Error, ErrorKind};
3
4use rst_parser::parse;
5use rst_renderer::render_html;
6use document_tree::Document;
7use document_tree::attribute_types::FixedSpace;
8use document_tree::element_categories::{
9    BodyElement as BE, StructuralSubElement as SSE, SubStructure as SS,
10    TextOrInlineElement as TOIE,
11};
12use document_tree::elements::{LiteralBlock, Raw, Section};
13use document_tree::extra_attributes;
14
15use crate::document::{MyCommonAttributes, MyDocument, MyLiteralBlock, MySection};
16use crate::highlighter::Highlighter;
17
18/// returns HTML result rendered in partial mode.
19pub fn render(s: &str) -> Result<String, Error> {
20    match parse(s) {
21        Err(e) => {
22            eprintln!("err: {}", e);
23            Err(Error::new(ErrorKind::InvalidInput, e))
24        }
25        Ok(mut doc) => render_html_with_highlight(&mut doc),
26    }
27}
28
29fn highlight(lb: &LiteralBlock, hi: &Highlighter) -> Raw {
30    let mb: &mut MyLiteralBlock = unsafe {
31        #[allow(mutable_transmutes)]
32        #[allow(clippy::transmute_ptr_to_ptr)]
33        std::mem::transmute(&*lb)
34    };
35    let mc: &mut MyCommonAttributes = unsafe {
36        #[allow(mutable_transmutes)]
37        #[allow(clippy::transmute_ptr_to_ptr)]
38        std::mem::transmute(&mb.common)
39    };
40
41    let default_ext = &"txt".to_string();
42    let ext = mc.classes.first().unwrap_or(default_ext);
43
44    let mut txt = "".to_string();
45    for t in mb.children() {
46        if let TOIE::String(ref v) = t {
47            txt.push_str(&**v);
48        }
49    }
50
51    // LiteralBlock -> Raw (pre)
52    Raw::new(
53        mb.common.clone(),
54        extra_attributes::Raw {
55            space: FixedSpace::default(),
56            format: vec![],
57        },
58        vec![hi.apply(txt, ext)],
59    )
60}
61
62fn hightlight_doc(doc: &mut Document) {
63    let hi = Highlighter::new();
64    let md: &mut MyDocument =
65        unsafe { &mut *(doc as *mut Document as *mut MyDocument) };
66
67    for (i, e) in md.children().iter().enumerate() {
68        if let SSE::SubStructure(ref s1) = e {
69            match **s1 {
70                SS::Section(ref s) => {
71                    let ms: &mut MySection = unsafe {
72                        #[allow(clippy::cast_ref_to_mut)]
73                        #[allow(invalid_reference_casting)]
74                        &mut *(&**s as *const Section as *mut MySection)
75                    };
76                    for (j, se) in ms.children().iter().enumerate() {
77                        if let SSE::SubStructure(ref s2) = se {
78                            if let SS::BodyElement(ref be) = **s2 {
79                                if let BE::LiteralBlock(ref lb) = **be {
80                                    let rw = highlight(lb, &hi);
81                                    let nb = SS::BodyElement(Box::new(
82                                        BE::Raw(Box::new(rw)),
83                                    ));
84                                    ms.children[j] =
85                                        SSE::SubStructure(Box::new(nb));
86                                }
87                            }
88                        }
89                    }
90                    md.children[i] = (*e).clone();
91                }
92                SS::BodyElement(ref be) => {
93                    if let BE::LiteralBlock(ref lb) = **be {
94                        let rw = highlight(lb, &hi);
95                        let nb =
96                            SS::BodyElement(Box::new(BE::Raw(Box::new(rw))));
97                        md.children[i] = SSE::SubStructure(Box::new(nb));
98                    }
99                }
100                _ => (),
101            }
102        }
103    }
104}
105
106fn render_html_with_highlight(doc: &mut Document) -> Result<String, Error> {
107    let standalone = false;
108    let buf = Vec::new();
109    let mut stream = BufWriter::new(buf);
110
111    hightlight_doc(doc);
112
113    render_html(&doc, &mut stream, standalone)
114        .map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
115    let r = stream.into_inner().unwrap();
116    Ok(String::from_utf8_lossy(&r).into_owned())
117}