blob: 4977e41975bc5b9c840104a39b0d78d0f64a3a45 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use algebra::monoid::*;
use algebra::zip::*;
use std::fmt::Write;
/// Format a matrix of strings (plus an optional row of headers) into an aligned table
/// e.g.
///
/// > tabulate(vec![vec![("yellow", "green", "blue")],
/// vec![("red", "orange", "fuchsia")]],
/// Some(vec!["First", "Second", "Third"]))
///
/// First Second Third
/// ======================
/// yellow green blue
/// red orange fuchsia
pub fn tabulate<S: AsRef<str>, T: AsRef<str>>(rows: Vec<Vec<S>>, headers: Option<Vec<T>>) -> String {
fn row_widths<S: AsRef<str>>(row: &Vec<S>) -> Zip<Max> {
Zip(row.iter().map(|s| Max(s.as_ref().len())).collect())
};
let header_widths = msum(headers.iter().map(row_widths));
let widths = msum(rows.iter().map(row_widths));
let widths = header_widths.mappend(&widths).map(|n| n.0 + 1).0;
let mut string = String::new();
for hs in headers {
write_row_padded(&mut string, &widths, &hs);
write_underline(&mut string, widths.iter().sum());
}
for row in rows {
write_row_padded(&mut string, &widths, &row);
}
string
}
/// Write an underline of a given length of '=' characters to a target string
fn write_underline(out: &mut String, length: usize) {
writeln!(out, "{:=<width$}", "", width = length).unwrap();
}
/// Write a row of fields padded to given widths to a target string
fn write_row_padded<S: AsRef<str>>(out: &mut String, widths: &Vec<usize>, row: &Vec<S>) {
for (text, cols) in row.iter().zip(widths.iter()) {
write!(out, "{:width$}", text.as_ref(), width = cols).unwrap();
}
writeln!(out, "").unwrap();
}