use std::io::BufRead;
use std::iter::Iterator;
-fn tally_marks(n: usize, mark: Option<&str>) -> String {
- match mark {
+const TALLY_FONT: &str = "BabelStone Han";
+
+fn tally_marks(n: usize, mark: Option<&str>) -> HTML {
+ HTML(match mark {
None => {
let fives = { 0..n / 5 }.map(|_| 'πΈ');
let ones = { 0..n % 5 }.map(|_| 'π·');
- fives.chain(ones).collect()
+ let marks: String = fives.chain(ones).collect();
+ format!("<span style=\"font-family: '{TALLY_FONT}'\">{marks}</span>")
}
Some(m) => { 0..n }.map(|_| m).collect(),
- }
+ })
}
#[derive(PartialEq, Eq, Debug)]
return Ok(std::mem::take(&mut self.row).map(Rowlike::Row)).transpose()
}
InputLine::Blank => return Some(Ok(Rowlike::Spacer)),
- InputLine::Entry(col, instance) => match &mut self.row {
+ InputLine::Entry(col, instance) => match self.row {
None => {
return Some(Err(std::io::Error::other(format!(
"line {}: Entry with no header",
let empty = HashMap::new();
let mut counts: Vec<_> = rows
.iter()
- .flat_map(|rl| match rl {
- Rowlike::Row(r) => r.entries.keys(),
+ .flat_map(|rl| match *rl {
+ Rowlike::Row(ref r) => r.entries.keys(),
Rowlike::Spacer => empty.keys(),
})
.fold(HashMap::new(), |mut cs, col| {
.into_iter()
.map(|(col, n)| (n, col))
.collect();
- counts.sort_unstable_by(|(an, acol), (bn, bcol)| bn.cmp(an).then(acol.cmp(bcol)));
+ counts.sort_unstable_by(|a, b| b.0.cmp(&a.0).then(a.1.cmp(&b.1)));
counts
}
fn column_order(config: &Config, rows: &[Rowlike]) -> Vec<String> {
let mut tally = 0;
let mut out = vec![];
for ins in instances {
- match ins {
+ match *ins {
None => tally += 1,
- Some(content) => {
+ Some(ref content) => {
if tally > 0 {
- out.push(HTML(tally_marks(tally, mark)));
+ out.push(tally_marks(tally, mark));
tally = 0;
}
out.push(HTML::escape(content));
}
}
if tally > 0 {
- out.push(HTML(tally_marks(tally, mark)));
+ out.push(tally_marks(tally, mark));
}
HTML(
out.into_iter()
- .map(|html| html.0) // Waiting for slice_concat_trait to stabilize
+ .map(|html| html.0)
.collect::<Vec<_>>()
.join(" "),
)
let instances: Option<&Vec<Option<String>>> = row.entries.get(col);
let is_empty = match instances {
None => true,
- Some(is) => is.iter().all(|ins| match ins {
+ Some(is) => is.iter().all(|ins| match *ins {
None => false,
- Some(content) => content == "Γ",
+ Some(ref content) => content == "Γ",
}),
};
let class = HTML::from(if is_empty { "" } else { r#" class="yes""# });
row.entries.get(notcol).expect("Key vanished?!"),
)
})
- .map(|html| html.0) // Waiting for slice_concat_trait to stabilize
+ .map(|html| html.0)
.collect::<Vec<_>>()
.join(", "),
)
}
fn render_row(config: &Config, columns: &[String], rowlike: &mut Rowlike) -> HTML {
- match rowlike {
+ match *rowlike {
Rowlike::Spacer => HTML::from("<tr><th class=\"spacer_row\"></th></tr>\n"),
- Rowlike::Row(row) => {
+ Rowlike::Row(ref mut row) => {
let row_label = HTML::escape(row.label.as_ref());
let static_cells = config
.static_columns
.iter()
- .map(|ocol| match ocol {
- Some(col) if config.hidden_columns.contains(col) => HTML::from(""),
- Some(col) => render_cell(config, col, row),
+ .map(|ocol| match *ocol {
+ Some(ref col) if config.hidden_columns.contains(col) => HTML::from(""),
+ Some(ref col) => render_cell(config, col, row),
None => HTML::from(r#"<td class="spacer_col"></td>"#),
})
.collect::<HTML>();
let dynamic_columns = columns.iter().map(Some);
static_columns
.chain(dynamic_columns)
- .filter(|ocol| ocol.map_or(true, |col| !config.hidden_columns.contains(col)))
+ .filter(|ocol| ocol.is_none_or(|col| !config.hidden_columns.contains(col)))
.map(|ocol| {
ocol.map(|col| match config.substitute_labels.get(col) {
None => col,
/// * there's an i/o error while reading `input`
/// * the log has invalid syntax:
/// * an indented line with no preceding non-indented line
-pub fn tablify(input: impl std::io::Read) -> Result<HTML, std::io::Error> {
+pub fn tablify<R: std::io::Read>(input: R) -> Result<HTML, std::io::Error> {
let (rows, config) = read_input(input)?;
let columns = column_order(&config, &rows);
Ok(HTML(format!(
#[test]
fn test_tally_marks() {
- assert_eq!(tally_marks(1, None), "π·");
- assert_eq!(tally_marks(2, None), "π·π·");
- assert_eq!(tally_marks(3, None), "π·π·π·");
- assert_eq!(tally_marks(4, None), "π·π·π·π·");
- assert_eq!(tally_marks(5, None), "πΈ");
- assert_eq!(tally_marks(6, None), "πΈπ·");
- assert_eq!(tally_marks(7, None), "πΈπ·π·");
- assert_eq!(tally_marks(8, None), "πΈπ·π·π·");
- assert_eq!(tally_marks(9, None), "πΈπ·π·π·π·");
- assert_eq!(tally_marks(10, None), "πΈπΈ");
- assert_eq!(tally_marks(11, None), "πΈπΈπ·");
- assert_eq!(tally_marks(1, Some("x")), "x");
- assert_eq!(tally_marks(4, Some("x")), "xxxx");
- assert_eq!(tally_marks(5, Some("x")), "xxxxx");
- assert_eq!(tally_marks(6, Some("x")), "xxxxxx");
- assert_eq!(tally_marks(2, Some("π")), "ππ");
+ assert_eq!(
+ tally_marks(1, None),
+ HTML(format!(
+ "<span style=\"font-family: '{TALLY_FONT}'\">π·</span>"
+ ))
+ );
+ assert_eq!(
+ tally_marks(2, None),
+ HTML(format!(
+ "<span style=\"font-family: '{TALLY_FONT}'\">π·π·</span>"
+ ))
+ );
+ assert_eq!(
+ tally_marks(3, None),
+ HTML(format!(
+ "<span style=\"font-family: '{TALLY_FONT}'\">π·π·π·</span>"
+ ))
+ );
+ assert_eq!(
+ tally_marks(4, None),
+ HTML(format!(
+ "<span style=\"font-family: '{TALLY_FONT}'\">π·π·π·π·</span>"
+ ))
+ );
+ assert_eq!(
+ tally_marks(5, None),
+ HTML(format!(
+ "<span style=\"font-family: '{TALLY_FONT}'\">πΈ</span>"
+ ))
+ );
+ assert_eq!(
+ tally_marks(6, None),
+ HTML(format!(
+ "<span style=\"font-family: '{TALLY_FONT}'\">πΈπ·</span>"
+ ))
+ );
+ assert_eq!(
+ tally_marks(7, None),
+ HTML(format!(
+ "<span style=\"font-family: '{TALLY_FONT}'\">πΈπ·π·</span>"
+ ))
+ );
+ assert_eq!(
+ tally_marks(8, None),
+ HTML(format!(
+ "<span style=\"font-family: '{TALLY_FONT}'\">πΈπ·π·π·</span>"
+ ))
+ );
+ assert_eq!(
+ tally_marks(9, None),
+ HTML(format!(
+ "<span style=\"font-family: '{TALLY_FONT}'\">πΈπ·π·π·π·</span>"
+ ))
+ );
+ assert_eq!(
+ tally_marks(10, None),
+ HTML(format!(
+ "<span style=\"font-family: '{TALLY_FONT}'\">πΈπΈ</span>"
+ ))
+ );
+ assert_eq!(
+ tally_marks(11, None),
+ HTML(format!(
+ "<span style=\"font-family: '{TALLY_FONT}'\">πΈπΈπ·</span>"
+ ))
+ );
+ assert_eq!(tally_marks(1, Some("x")), "x".into());
+ assert_eq!(tally_marks(4, Some("x")), "xxxx".into());
+ assert_eq!(tally_marks(5, Some("x")), "xxxxx".into());
+ assert_eq!(tally_marks(6, Some("x")), "xxxxxx".into());
+ assert_eq!(tally_marks(2, Some("π")), "ππ".into());
}
fn read_rows(input: impl std::io::Read) -> Result<Vec<Rowlike>, std::io::Error> {
}
),
HTML::from(
- r#"<td class="yes" onmouseover="h2('nope','foo')" onmouseout="ch2('nope','foo')">π·</td>"#
+ r#"<td class="yes" onmouseover="h2('nope','foo')" onmouseout="ch2('nope','foo')"><span style="font-family: 'BabelStone Han'">π·</span></td>"#
)
);
assert_eq!(
}
),
HTML::from(
- r#"<td class="yes" onmouseover="h2('nope','foo')" onmouseout="ch2('nope','foo')">π·π·</td>"#
+ r#"<td class="yes" onmouseover="h2('nope','foo')" onmouseout="ch2('nope','foo')"><span style="font-family: 'BabelStone Han'">π·π·</span></td>"#
)
);
assert_eq!(
}
),
HTML::from(
- r#"<td class="yes" onmouseover="h2('nope','foo')" onmouseout="ch2('nope','foo')">5 π·</td>"#
+ r#"<td class="yes" onmouseover="h2('nope','foo')" onmouseout="ch2('nope','foo')">5 <span style="font-family: 'BabelStone Han'">π·</span></td>"#
)
);
assert_eq!(
}
),
HTML::from(
- r#"<td class="yes" onmouseover="h2('bob's','foo')" onmouseout="ch2('bob's','foo')">π·</td>"#
+ r#"<td class="yes" onmouseover="h2('bob's','foo')" onmouseout="ch2('bob's','foo')"><span style="font-family: 'BabelStone Han'">π·</span></td>"#
)
);
assert_eq!(
]),
}
),
- HTML::from("bar: π·π·, foo")
+ HTML::from(r#"bar: <span style="font-family: 'BabelStone Han'">π·π·</span>, foo"#)
);
assert_eq!(
render_all_leftovers(
})
),
HTML::from(
- r#"<tr><th id="nope">nope</th><td class="yes" onmouseover="h2('nope','bar')" onmouseout="ch2('nope','bar')">π·</td><td class="leftover" onmouseover="highlight('nope')" onmouseout="clear_highlight('nope')"></td></tr>
+ r#"<tr><th id="nope">nope</th><td class="yes" onmouseover="h2('nope','bar')" onmouseout="ch2('nope','bar')"><span style="font-family: 'BabelStone Han'">π·</span></td><td class="leftover" onmouseover="highlight('nope')" onmouseout="clear_highlight('nope')"></td></tr>
"#
)
);