evobench_tools/output_table/
html.rs1use ahtml::{AVec, HtmlAllocator, Node, att, util::SoftPre};
2
3use crate::{
4 output_table::{BarKind, CellValue, OutputStyle, OutputTable},
5 utillib::html_util::anchor,
6 warn,
7};
8
9use super::{OutputTableTitle, Row};
10
11impl OutputStyle {
12 fn to_css_style(self) -> String {
13 let OutputStyle {
14 faded,
15 bold,
16 italic,
17 color,
18 font_size,
19 } = self;
20
21 let mut s = String::new();
22
23 if italic {
24 s.push_str("font-style: italic; ");
25 }
26 if bold {
27 s.push_str("font-weight: bold; ");
28 }
29
30 let mut htmlcolor: Option<&str> = None;
31 if let Some(col) = color {
32 match col {
33 4 => {
34 htmlcolor = {
35 Some("#e46000")
38 }
39 }
40 _ => {
41 warn!("ignoring unknown color code {col}");
42 }
43 }
44 }
45 if faded {
46 if htmlcolor.is_some() {
47 warn!(
48 "both 'faded' and 'color' were given, ignoring 'faded' (should it shade color?)"
49 );
50 } else {
51 htmlcolor = Some("gray");
52 }
53 }
54 if let Some(htmlcol) = htmlcolor {
55 s.push_str("color: ");
56 s.push_str(htmlcol);
57 s.push_str("; ");
58 }
59
60 if let Some(fs) = font_size {
61 s.push_str("font-size: ");
62 s.push_str(fs.as_ref());
63 s.push_str("; ");
64 }
65
66 s.truncate(s.trim_end().len());
68
69 s
70 }
71}
72
73pub struct HtmlTable<'allocator> {
74 num_columns: usize,
75 table_body: AVec<'allocator, Node>,
76 }
79
80impl<'allocator> HtmlTable<'allocator> {
81 pub fn new(num_columns: usize, html: &'allocator HtmlAllocator) -> Self {
82 Self {
83 num_columns,
84 table_body: html.new_vec(),
85 }
86 }
87}
88
89impl<'allocator> OutputTable for HtmlTable<'allocator> {
90 type Output = AVec<'allocator, Node>;
91
92 fn num_columns(&self) -> usize {
93 self.num_columns
94 }
95
96 fn write_row<'url, V: CellValue<'url>>(
97 &mut self,
98 row: Row<V>,
99 line_style: Option<OutputStyle>,
100 ) -> anyhow::Result<()> {
101 let htmlstyle = line_style.map(OutputStyle::to_css_style);
102 let html = self.table_body.allocator();
103 let mut cells = html.new_vec();
104 match row {
105 Row::WithSpans(items) => {
106 for item in items {
107 let OutputTableTitle {
108 text,
109 span,
110 anchor_name,
111 } = item;
112 let s: &str = text.as_ref();
113 let text_node = html.text(s)?;
114 let text = if let Some(style) = &htmlstyle {
115 html.span([att("style", style)], text_node)?
116 } else {
117 text_node
118 };
119 let content = if let Some(anchor_name) = anchor_name {
120 anchor(anchor_name, text, html)?
121 } else {
122 text
123 };
124 cells.push(html.td([att("colspan", *span)], content)?)?;
125 }
126 }
127 Row::PlainStrings(items) => {
128 for item in items {
129 let s: &str = item.as_ref();
130 let text_node = html.text(s)?;
131 let text = if let Some(style) = &htmlstyle {
132 html.span([att("style", style)], text_node)?
133 } else {
134 text_node
135 };
136 let content = if let Some(url) = item.perhaps_url() {
137 html.a([att("href", url)], text)?
138 } else {
139 text
140 };
141 let content = if let Some(name) = item.perhaps_anchor_name() {
142 anchor(name, content, html)?
143 } else {
144 content
145 };
146 cells.push(html.td([], content)?)?;
147 }
148 }
149 }
150 self.table_body.push(html.tr([], cells)?)
151 }
152
153 fn write_title_row(
157 &mut self,
158 titles: &[OutputTableTitle],
159 line_style: Option<OutputStyle>,
160 ) -> anyhow::Result<()> {
161 let htmlstyle = line_style.map(OutputStyle::to_css_style);
162 let html = self.table_body.allocator();
163 let mut cells = html.new_vec();
164 for item in titles {
165 let OutputTableTitle {
166 text,
167 span,
168 anchor_name,
169 } = item;
170 let s: &str = text.as_ref();
171 let text_node = html.text(s)?;
172 let text = if let Some(style) = &htmlstyle {
173 html.span([att("style", style)], text_node)?
174 } else {
175 text_node
176 };
177 let content = if let Some(anchor_name) = anchor_name {
178 anchor(anchor_name, text, html)?
179 } else {
180 text
181 };
182 cells.push(html.th([att("colspan", *span)], content)?)?;
183 }
184 self.table_body.push(html.tr([], cells)?)
185 }
186
187 fn write_bar(&mut self, bar_kind: BarKind, anchor_name: Option<&str>) -> anyhow::Result<()> {
188 let html = self.table_body.allocator();
189
190 let style = match bar_kind {
191 BarKind::Thin => "width: 100%; border-style: dashed;",
192 BarKind::Thick => "width: 100%;",
193 };
194
195 let hr = html.hr([att("style", style)], [])?;
196 let content = if let Some(anchor_name) = anchor_name {
197 anchor(anchor_name, hr, html)?
198 } else {
199 hr
200 };
201
202 self.table_body
203 .push(html.tr([], html.td([att("colspan", self.num_columns())], content)?)?)
204 }
205
206 fn print<'url, V: CellValue<'url>>(&mut self, value: V) -> anyhow::Result<()> {
207 let html = self.table_body.allocator();
208 let soft_pre = SoftPre {
209 tabs_to_nbsp: Some(8),
210 autolink: true,
211 input_line_separator: "\n",
212 trailing_br: false,
213 };
214 let text = soft_pre.format(value.as_ref(), html)?;
215 let contents = if let Some(link) = value.perhaps_url() {
216 html.a([att("href", link)], text)?
217 } else {
218 text
219 };
220 self.table_body
221 .push(html.tr([], html.td([att("colspan", self.num_columns())], contents)?)?)
222 }
223
224 fn finish(self) -> anyhow::Result<Self::Output> {
225 Ok(self.table_body)
226 }
227}