1use 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
18pub 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 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}