rustpm 0.2.1

A fast, friendly APT frontend with kernel, desktop, and sources management
use nu_ansi_term::Style;
use unicode_width::UnicodeWidthStr;

pub struct Column {
    pub header: String,
    pub style: Option<Style>,
}

impl Column {
    pub fn new(header: impl Into<String>) -> Self {
        Self { header: header.into(), style: None }
    }

    pub fn with_style(mut self, style: Style) -> Self {
        self.style = Some(style);
        self
    }
}

pub struct Row {
    pub cells: Vec<String>,
    pub style: Option<Style>,
}

impl Row {
    pub fn new(cells: Vec<impl Into<String>>) -> Self {
        Self {
            cells: cells.into_iter().map(|c| c.into()).collect(),
            style: None,
        }
    }

    pub fn with_style(mut self, style: Style) -> Self {
        self.style = Some(style);
        self
    }
}

pub fn print_table(columns: &[Column], rows: &[Row]) {
    if rows.is_empty() {
        return;
    }

    let num_cols = columns.len();
    let mut widths: Vec<usize> = columns.iter().map(|c| c.header.width()).collect();

    for row in rows {
        for (i, cell) in row.cells.iter().enumerate() {
            if i < num_cols {
                widths[i] = widths[i].max(cell.width());
            }
        }
    }

    // Print header
    let header_line: String = columns
        .iter()
        .enumerate()
        .map(|(i, col)| {
            let padded = format!("{:<width$}", col.header, width = widths[i]);
            let style = col.style.unwrap_or_default();
            format!("{}", style.paint(&padded))
        })
        .collect::<Vec<_>>()
        .join("  ");

    println!("{}", header_line);

    let sep: String = widths.iter().map(|w| "".repeat(*w)).collect::<Vec<_>>().join("  ");
    println!("{}", sep);

    for row in rows {
        let line: String = row
            .cells
            .iter()
            .enumerate()
            .map(|(i, cell)| {
                let w = widths.get(i).copied().unwrap_or(0);
                let padded = format!("{:<width$}", cell, width = w);
                if let Some(style) = row.style {
                    format!("{}", style.paint(&padded))
                } else {
                    padded
                }
            })
            .collect::<Vec<_>>()
            .join("  ");
        println!("{}", line);
    }
}