]>
Commit | Line | Data |
---|---|---|
7cb339df WB |
1 | use std::collections::HashMap; |
2 | ||
48657113 LW |
3 | use handlebars::{ |
4 | Context, Handlebars, Helper, HelperResult, Output, RenderContext, | |
5 | RenderError as HandlebarsRenderError, | |
6 | }; | |
7 | use serde_json::Value; | |
48657113 LW |
8 | |
9 | use super::{table::Table, value_to_string}; | |
7cb339df WB |
10 | use crate::define_helper_with_prefix_and_postfix; |
11 | use crate::renderer::BlockRenderFunctions; | |
48657113 LW |
12 | |
13 | fn optimal_column_widths(table: &Table) -> HashMap<&str, usize> { | |
14 | let mut widths = HashMap::new(); | |
15 | ||
16 | for column in &table.schema.columns { | |
17 | let mut min_width = column.label.len(); | |
18 | ||
19 | for row in &table.data { | |
20 | let entry = row.get(&column.id).unwrap_or(&Value::Null); | |
21 | ||
22 | let text = if let Some(renderer) = &column.renderer { | |
d49fc1aa | 23 | renderer.render(entry) |
48657113 LW |
24 | } else { |
25 | value_to_string(entry) | |
26 | }; | |
27 | ||
28 | min_width = std::cmp::max(text.len(), min_width); | |
29 | } | |
30 | ||
31 | widths.insert(column.label.as_str(), min_width + 4); | |
32 | } | |
33 | ||
34 | widths | |
35 | } | |
36 | ||
37 | fn render_plaintext_table( | |
38 | h: &Helper, | |
39 | _: &Handlebars, | |
40 | _: &Context, | |
41 | _: &mut RenderContext, | |
42 | out: &mut dyn Output, | |
43 | ) -> HelperResult { | |
44 | let param = h | |
45 | .param(0) | |
46 | .ok_or_else(|| HandlebarsRenderError::new("parameter not found"))?; | |
47 | let value = param.value(); | |
48 | let table: Table = serde_json::from_value(value.clone())?; | |
49 | let widths = optimal_column_widths(&table); | |
50 | ||
51 | // Write header | |
52 | for column in &table.schema.columns { | |
53 | let width = widths.get(column.label.as_str()).unwrap_or(&0); | |
54 | out.write(&format!("{label:width$}", label = column.label))?; | |
55 | } | |
56 | ||
57 | out.write("\n")?; | |
58 | ||
59 | // Write individual rows | |
60 | for row in &table.data { | |
61 | for column in &table.schema.columns { | |
62 | let entry = row.get(&column.id).unwrap_or(&Value::Null); | |
63 | let width = widths.get(column.label.as_str()).unwrap_or(&0); | |
64 | ||
65 | let text = if let Some(renderer) = &column.renderer { | |
d49fc1aa | 66 | renderer.render(entry) |
48657113 LW |
67 | } else { |
68 | value_to_string(entry) | |
69 | }; | |
70 | ||
71 | out.write(&format!("{text:width$}",))?; | |
72 | } | |
73 | out.write("\n")?; | |
74 | } | |
75 | ||
76 | Ok(()) | |
77 | } | |
78 | ||
79 | macro_rules! define_underlining_heading_fn { | |
80 | ($name:ident, $underline:expr) => { | |
81 | fn $name<'reg, 'rc>( | |
82 | h: &Helper<'reg, 'rc>, | |
83 | _handlebars: &'reg Handlebars, | |
84 | _context: &'rc Context, | |
85 | _render_context: &mut RenderContext<'reg, 'rc>, | |
86 | out: &mut dyn Output, | |
87 | ) -> HelperResult { | |
88 | let param = h | |
89 | .param(0) | |
90 | .ok_or_else(|| HandlebarsRenderError::new("No parameter provided"))?; | |
91 | ||
92 | let value = param.value(); | |
93 | let text = value.as_str().ok_or_else(|| { | |
94 | HandlebarsRenderError::new(format!("value {value} is not a string")) | |
95 | })?; | |
96 | ||
97 | out.write(text)?; | |
98 | out.write("\n")?; | |
99 | ||
100 | for _ in 0..text.len() { | |
101 | out.write($underline)?; | |
102 | } | |
103 | Ok(()) | |
104 | } | |
105 | }; | |
106 | } | |
107 | ||
108 | define_helper_with_prefix_and_postfix!(verbatim_monospaced, "", ""); | |
109 | define_underlining_heading_fn!(heading_1, "="); | |
110 | define_underlining_heading_fn!(heading_2, "-"); | |
111 | define_helper_with_prefix_and_postfix!(verbatim, "", ""); | |
112 | ||
113 | fn render_object( | |
114 | h: &Helper, | |
115 | _: &Handlebars, | |
116 | _: &Context, | |
117 | _: &mut RenderContext, | |
118 | out: &mut dyn Output, | |
119 | ) -> HelperResult { | |
120 | let param = h | |
121 | .param(0) | |
122 | .ok_or_else(|| HandlebarsRenderError::new("parameter not found"))?; | |
123 | ||
124 | let value = param.value(); | |
125 | ||
126 | out.write("\n")?; | |
127 | out.write(&serde_json::to_string_pretty(&value)?)?; | |
128 | out.write("\n")?; | |
129 | ||
130 | Ok(()) | |
131 | } | |
132 | ||
133 | pub(super) fn block_render_functions() -> BlockRenderFunctions { | |
134 | BlockRenderFunctions { | |
135 | table: Box::new(render_plaintext_table), | |
136 | verbatim_monospaced: Box::new(verbatim_monospaced), | |
137 | verbatim: Box::new(verbatim), | |
138 | object: Box::new(render_object), | |
139 | heading_1: Box::new(heading_1), | |
140 | heading_2: Box::new(heading_2), | |
141 | } | |
142 | } |