use {Alignment, Row, RowOrSep, Table};
use std;
pub struct Renderer<'a> {
table: &'a Table
}
impl<'a> Renderer<'a> {
pub fn new(table: &'a Table) -> Renderer<'a> {
Renderer {
table: table
}
}
pub fn write_to<T: std::io::Write>(&self, writer: &mut T) -> std::io::Result<()> {
fn separator<T: std::io::Write>(writer: &mut T, widths: &[usize]) -> std::io::Result<()> {
try!(write!(writer, "+"));
for &width in widths.iter() {
for _ in 0..width + 2 {
try!(write!(writer, "-"));
}
try!(write!(writer, "+"));
}
writeln!(writer, "")
}
fn row<T: std::io::Write>(writer: &mut T, row: &Row, widths: &[usize]) -> std::io::Result<()> {
let cells = row.cells().iter().map(|cell| {
cell.string().split('\n').collect::<Vec<_>>()
}).collect::<Vec<_>>();
let height = cells.iter().map(|lines| lines.len()).max().unwrap_or(1);
for i in 0..height {
try!(write!(writer, "|"));
for j in 0..cells.len() {
let ref cell = row.cells()[j];
let width = widths[j];
let len = cells[j].get(i).map_or(0, |line| line.len());
let (left_padding, right_padding) = match *cell.alignment() {
Alignment::Left => (1, width - len + 1),
Alignment::Center => {
let diff = width - len;
if diff % 2 == 0 {
(diff / 2 + 1, diff / 2 + 1)
} else {
(diff / 2 + 1, diff / 2 + 2)
}
},
Alignment::Right => (width - len + 1, 1)
};
for _ in 0..left_padding {
try!(write!(writer, " "));
}
if let Some(line) = cells[j].get(i) {
try!(write!(writer, "{}", line));
}
for _ in 0..right_padding {
try!(write!(writer, " "));
}
try!(write!(writer, "|"));
}
try!(writeln!(writer, ""))
}
Ok(())
}
let columns = self.table.rows().iter().filter_map(|row_or_sep| {
row_or_sep.row().map(|row| row.cells().len())
}).max().unwrap_or(0);
let widths = (0..columns).map(|i| {
self.table.rows().iter().filter_map(|row_or_sep| {
row_or_sep.row().map(|row| {
row.cells().get(i).map(|cell| {
cell.string().lines().map(|line| {
line.len()
}).max().unwrap_or(0)
}).unwrap_or(0)
})
}).max().unwrap_or(0)
}).collect::<Vec<_>>();
try!(separator(writer, &widths));
for row_or_sep in self.table.rows().iter() {
match *row_or_sep {
RowOrSep::Row(ref r) => try!(row(writer, r, &widths)),
RowOrSep::Sep => try!(separator(writer, &widths))
}
}
separator(writer, &widths)
}
pub fn write_to_string(&self) -> String {
let mut buf = Vec::new();
self.write_to(&mut buf).unwrap();
String::from_utf8(buf).unwrap()
}
}