extern crate ansi_term;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate std_prelude;
extern crate tabwriter;
use std::io;
use std_prelude::*;
use ansi_term::Color as AColor;
pub fn from_str<E, F>(_from_str: F, s: &str) -> Result<Vec<El>, E>
where
F: Fn(&str) -> Result<Vec<ElRaw>, E>,
{
let raw: Vec<ElRaw> = _from_str(s)?;
let mut out: Vec<El> = Vec::new();
flatten_raw(&mut out, raw);
Ok(out)
}
pub fn paint<W: io::Write>(w: &mut W, items: &[El]) -> io::Result<()> {
for item in items {
item.paint(w)?;
}
Ok(())
}
pub fn eprint_diff(expected: &[u8], result: &[u8]) -> (String, String) {
let mut expected_repr: Vec<u8> = Vec::new();
write_repr(&mut expected_repr, expected).unwrap();
let mut result_repr: Vec<u8> = Vec::new();
write_repr(&mut result_repr, result).unwrap();
if result == expected {
return (
String::from_utf8(expected_repr).unwrap(),
String::from_utf8(result_repr).unwrap(),
);
}
eprintln!("Bytes are not equal");
eprintln!("## EXPECTED");
{
io::stderr().write_all(expected).unwrap();
}
eprintln!("\n# RAW-EXPECTED");
eprint_repr(expected);
eprintln!("\n\n## RESULT");
{
io::stderr().write_all(result).unwrap();
}
eprintln!("\n# RAW-RESULT");
eprint_repr(result);
eprintln!();
(
String::from_utf8(expected_repr).unwrap(),
String::from_utf8(result_repr).unwrap(),
)
}
pub fn write_repr<W: io::Write>(w: &mut W, bytes: &[u8]) -> io::Result<()> {
for b in bytes {
match *b {
b'\t' => write!(w, r"\t")?,
b'\n' => write!(w, r"\n")?,
b'\r' => write!(w, r"\r")?,
b'\\' => write!(w, r"\\")?,
32...126 => write!(w, "{}", *b as char)?, _ => write!(w, r"\x{:0>2x}", b)?,
}
}
Ok(())
}
#[test]
fn sanity_repr() {
let r = |b| {
let mut w: Vec<u8> = Vec::new();
write_repr(&mut w, b).unwrap();
String::from_utf8(w).unwrap()
};
assert_eq!(r"foo", r(b"foo"));
assert_eq!(r"\\", r(b"\\"));
assert_eq!(r"\x8a", r(b"\x8a"));
assert_eq!(r"\x8a", r(&[0x8a]));
}
pub fn print_repr(bytes: &[u8]) {
write_repr(&mut io::stdout(), bytes).expect("print_repr");
}
pub fn eprint_repr(bytes: &[u8]) {
write_repr(&mut io::stderr(), bytes).expect("eprint_repr");
}
#[derive(Debug, Eq, PartialEq)]
pub enum El {
Text(Text),
Table(Table),
}
#[derive(Debug, Eq, PartialEq)]
pub struct Table {
table: Vec<Vec<Vec<Text>>>,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Color {
Plain,
Black,
Red,
Green,
Yellow,
Blue,
Purple,
Cyan,
White,
}
#[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
#[serde(default)]
pub struct Text {
t: String, b: bool, i: bool, c: Color, bg: Color, }
impl Default for Color {
fn default() -> Color {
Color::Plain
}
}
impl Color {
fn to_ansi(&self) -> Option<AColor> {
match *self {
Color::Plain => None,
Color::Black => Some(AColor::Black),
Color::Red => Some(AColor::Red),
Color::Green => Some(AColor::Green),
Color::Yellow => Some(AColor::Yellow),
Color::Blue => Some(AColor::Blue),
Color::Purple => Some(AColor::Purple),
Color::Cyan => Some(AColor::Cyan),
Color::White => Some(AColor::White),
}
}
}
impl El {
pub fn plain(t: String) -> El {
El::Text(Text::new(t))
}
pub fn set_plain(&mut self) {
match *self {
El::Text(ref mut t) => t.set_plain(),
El::Table(ref mut t) => t.set_plain(),
}
}
pub fn paint<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
match *self {
El::Text(ref t) => t.paint(w),
El::Table(ref t) => t.paint(w),
}
}
}
impl Table {
pub fn new(table: Vec<Vec<Vec<Text>>>) -> Table {
Table { table: table }
}
pub fn set_plain(&mut self) {
for row in &mut self.table {
for col in row {
for t in col {
t.set_plain();
}
}
}
}
pub fn paint<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
let mut tw = tabwriter::TabWriter::new(Vec::new()).padding(1);
for row in &self.table {
for (i, cell) in row.iter().enumerate() {
for text in cell {
text.paint(&mut tw)?;
}
if i < row.len() - 1 {
write!(&mut tw, "\t")?;
}
}
write!(&mut tw, "\n")?;
}
tw.flush()?;
w.write_all(&tw.into_inner().unwrap())
}
}
impl Text {
pub fn new(t: String) -> Text {
Text {
t: t,
b: false,
i: false,
c: Color::default(),
bg: Color::default(),
}
}
pub fn bold(mut self) -> Text {
self.b = true;
self
}
pub fn italic(mut self) -> Text {
self.i = true;
self
}
pub fn color(mut self, color: Color) -> Text {
self.c = color;
self
}
#[cfg(unix)]
fn style(&self) -> ansi_term::Style {
let mut style = ansi_term::Style::new();
if self.b {
style = style.bold();
}
if self.i {
style = style.italic();
}
style = match self.c.to_ansi() {
None => style,
Some(c) => style.fg(c),
};
style = match self.bg.to_ansi() {
None => style,
Some(c) => style.on(c),
};
style
}
#[cfg(not(unix))]
fn style(&self) -> ansi_term::Style {
ansi_term::Style::new()
}
pub fn paint<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
let style = self.style();
write!(w, "{}", style.paint(self.t.as_str()))
}
pub fn is_bold(&self) -> bool {
self.b
}
pub fn is_italic(&self) -> bool {
self.i
}
pub fn is_plain(&self) -> bool {
self.c == Color::Plain
}
pub fn get_color(&self) -> Color {
self.c
}
pub fn set_plain(&mut self) {
self.b = false;
self.i = false;
self.c = Color::Plain;
self.bg = Color::Plain;
}
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ElRaw {
Table(TableRaw),
Text(TextsRaw),
}
#[derive(Debug, Serialize, Deserialize)]
pub struct TableRaw {
table: Vec<Vec<TextsRaw>>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum TextsRaw {
Single(TextRaw),
Multi(Vec<TextRaw>),
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum TextRaw {
Simple(String),
Full(Text),
}
fn flatten_raw(into: &mut Vec<El>, mut raw: Vec<ElRaw>) {
for el in raw.drain(..) {
flatten_el(into, el);
}
}
fn flatten_el(into: &mut Vec<El>, raw: ElRaw) {
match raw {
ElRaw::Text(t) => flatten_texts(into, t),
ElRaw::Table(mut table_raw) => {
let mut table = Vec::new();
for mut row_raw in table_raw.table.drain(..) {
let mut row = Vec::new();
for cell_raw in row_raw.drain(..) {
let mut cell = Vec::new();
flatten_texts_only(&mut cell, cell_raw);
row.push(cell);
}
table.push(row);
}
into.push(El::Table(Table { table: table }));
}
}
}
fn flatten_texts(into: &mut Vec<El>, raw: TextsRaw) {
match raw {
TextsRaw::Single(t) => into.push(El::Text(Text::from(t))),
TextsRaw::Multi(mut multi) => into.extend(multi.drain(..).map(|t| El::Text(Text::from(t)))),
}
}
fn flatten_texts_only(into: &mut Vec<Text>, raw: TextsRaw) {
match raw {
TextsRaw::Single(t) => into.push(Text::from(t)),
TextsRaw::Multi(mut multi) => into.extend(multi.drain(..).map(Text::from)),
}
}
impl From<TextRaw> for Text {
fn from(raw: TextRaw) -> Text {
match raw {
TextRaw::Simple(t) => Text::new(t),
TextRaw::Full(f) => f,
}
}
}