bundle_sources/
html.rs

1// Copyright 2020 Ian Jackson
2// SPDX-License-Identifier: GPL-3.0-or-later
3// There is NO WARRANTY.
4
5use crate::imports::*;
6use crate::utils::ErrorMap;
7
8use percent_encoding::{utf8_percent_encode,NON_ALPHANUMERIC};
9
10#[derive(Debug,Clone,Eq,PartialEq)]
11#[derive(Serialize,Deserialize)]
12pub struct Html(pub String);
13
14#[derive(Debug,Eq,PartialEq)]
15#[derive(Serialize,Deserialize)]
16pub struct HtmlRef<'r>(pub &'r str);
17
18impl Html {
19  pub fn from_literal(lit : &str) -> Html {
20    Html(htmlescape::encode_minimal(lit))
21  }
22  pub fn as_ref(&self) -> HtmlRef { HtmlRef(self.0.as_ref()) }
23}
24
25impl HtmlRef<'_> {
26  pub fn to_owned(&self) -> Html { Html(self.0.to_owned()) }
27}
28
29pub const INDEX_BASENAME : &str = "index";
30pub const INDEX          : &str = "index.html";
31    
32pub struct IndexWriter {
33  f : BufWriter<File>,
34  deferred_error : Result<(),io::Error>,
35}
36
37enum TableState {
38  Unstarted(Html),
39  Working,
40}
41use TableState::*;
42
43pub struct TableWriter<'i> {
44  i : &'i mut IndexWriter,
45  s : TableState,
46}
47
48impl IndexWriter {
49  #[throws(E)]
50  pub fn new(outdir : &str, title : &HtmlRef) -> IndexWriter {
51    let f = File::create(outdir.to_owned() + "/" + INDEX).cxm(||format!(
52      "create index file {}", INDEX))?;
53    let mut f = BufWriter::new(f);
54
55    writeln!(&mut f,
56             r#"<html><head><title>{}</title><head><body>"#,
57             title.0)?;
58    
59    IndexWriter { f, deferred_error : Ok(()) }
60  }
61
62  #[throws(E)]
63  fn check(&mut self) {
64    replace(&mut self.deferred_error, Ok(()))?;
65  }
66
67  #[throws(E)]
68  pub fn table(&mut self, heading : Html) -> TableWriter {
69    self.check()?;
70    TableWriter { i : self, s : Unstarted(heading) }
71  }
72
73  #[throws(E)]
74  pub fn finish(mut self) {
75    self.check()?;
76    writeln!(&mut self.f,
77             r#"</body></html>"#)?;
78    self.f.flush()?;
79  }
80}
81  
82impl TableWriter<'_> {
83  #[throws(E)]
84  pub fn entry(&mut self, filename : &str, desc : &HtmlRef) {
85    match &mut self.s {
86      Unstarted(ref mut heading) => {
87        writeln!(&mut self.i.f,
88                 r#"<h1>{}</h1><table>"#,
89                 heading.0)?;
90        self.s = Working;
91      },
92      Working => { },
93    }
94
95    writeln!(&mut self.i.f,
96             r#"<tr><th align="left"><a href="{}">{}</a></th><td>{}</td>"#,
97             utf8_percent_encode(filename, NON_ALPHANUMERIC),
98             Html::from_literal(filename).0,
99             desc.0
100    )?;
101  }
102}
103
104impl Drop for TableWriter<'_> {
105  fn drop(&mut self) {
106    match self.s {
107      Unstarted(_) => { }
108      Working => {
109        self.i.deferred_error =
110          writeln!(&mut self.i.f, r#"</table>"#);
111      }
112    }
113  }
114}