use std::fs::File;
use std::io::prelude::*;
use std::io::{self, BufReader, BufWriter};
use std::path::PathBuf;
use anyhow::{anyhow, Context, Result};
use structopt::StructOpt;
use stybulate::*;
#[derive(Debug, StructOpt)]
#[structopt(name = "stybulate", about = "tabulate with style")]
struct Opt {
#[structopt(parse(from_os_str))]
path: Option<PathBuf>,
#[structopt(parse(from_os_str), short, long)]
output: Option<PathBuf>,
#[structopt(short = "1", long)]
header: bool,
#[structopt(short, long, default_value = "simple")]
fmt: String,
}
fn main() -> Result<()> {
let opt = Opt::from_args();
let fmt = Style::from(&opt.fmt).ok_or(anyhow!("Unsupported format \"{}\"", opt.fmt))?;
let mut writer: Box<dyn Write> = match opt.output {
None => Box::new(BufWriter::new(io::stdout())),
Some(opath) => Box::new(BufWriter::new(
File::create(opath).context("Could not write to specified output file")?,
)),
};
let reader: Box<dyn BufRead> = match opt.path {
None => Box::new(BufReader::new(io::stdin())),
Some(ipath) => Box::new(BufReader::new(
File::open(ipath).context("Could not read input file")?,
)),
};
let mut first = true;
let mut headers = None;
let mut contents: Vec<Vec<Cell>> = Vec::new();
for line in reader.lines() {
let l = line.unwrap();
let l = l.trim();
if opt.header && first {
first = false;
headers = Some(Headers::from(l.split_whitespace().collect()));
continue;
}
contents.push(
l.split_whitespace()
.map(|data| {
if let Ok(i) = data.parse::<i32>() {
Cell::Int(i)
} else if let Ok(f) = data.parse::<f64>() {
Cell::Float(f)
} else {
Cell::from(data)
}
})
.collect(),
);
}
writeln!(writer, "{}", Table::new(fmt, contents, headers).tabulate())?;
Ok(())
}