mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-05 17:15:12 +00:00
refactor table system (#132)
* init table trait * add shrink_col_index and max_width method to Table trait * make unicodes work when shrinking * improve readability of the table * replace old table system with new one * update changelog
This commit is contained in:
parent
cb296a5d98
commit
cddb7bde37
|
@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Vim table containing emoji [#122]
|
||||
- IDLE mode after network interruption [#123]
|
||||
- Output redirected to `stderr` [#130]
|
||||
- Refactor table system [#132]
|
||||
|
||||
## [0.2.6] - 2021-04-17
|
||||
|
||||
|
@ -209,3 +210,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
[#125]: https://github.com/soywod/himalaya/issues/125
|
||||
[#126]: https://github.com/soywod/himalaya/issues/126
|
||||
[#130]: https://github.com/soywod/himalaya/issues/130
|
||||
[#132]: https://github.com/soywod/himalaya/issues/132
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "himalaya"
|
||||
description = "📫 The CLI email client."
|
||||
description = "📫 CLI email client"
|
||||
version = "0.2.7"
|
||||
authors = ["soywod <clement.douin@posteo.net>"]
|
||||
edition = "2018"
|
||||
|
@ -16,10 +16,10 @@ log = "0.4.14"
|
|||
mailparse = "0.13.1"
|
||||
native-tls = "0.2"
|
||||
rfc2047-decoder = "0.1.2"
|
||||
serde = { version = "1.0.118", features = ["derive"] }
|
||||
serde = {version = "1.0.118", features = ["derive"]}
|
||||
serde_json = "1.0.61"
|
||||
terminal_size = "0.1.15"
|
||||
toml = "0.5.8"
|
||||
tree_magic = "0.2.3"
|
||||
unicode-width = "0.1.7"
|
||||
uuid = { version = "0.8", features = ["v4"] }
|
||||
uuid = {version = "0.8", features = ["v4"]}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# 📫 Himalaya [![gh-actions](https://github.com/soywod/himalaya/workflows/deployment/badge.svg)](https://github.com/soywod/himalaya/actions?query=workflow%3Adeployment)
|
||||
|
||||
The CLI email client.
|
||||
CLI email client written in Rust.
|
||||
|
||||
*The project is under active development. Do not use in production before the
|
||||
`v1.0.0` (see the [roadmap](https://github.com/soywod/himalaya/milestone/5)).*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
description = "The CLI email client.";
|
||||
description = "📫 CLI email client";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
|
|
|
@ -43,11 +43,11 @@ impl<'f> ToString for Flags<'f> {
|
|||
flags.push_str(if self.0.contains(&Flag::Seen) {
|
||||
" "
|
||||
} else {
|
||||
"🟓"
|
||||
"✷"
|
||||
});
|
||||
|
||||
flags.push_str(if self.0.contains(&Flag::Answered) {
|
||||
"↩"
|
||||
"↵"
|
||||
} else {
|
||||
" "
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::fmt;
|
|||
|
||||
use crate::{
|
||||
output::fmt::{get_output_fmt, OutputFmt, Response},
|
||||
table::{self, DisplayRow, DisplayTable},
|
||||
table::{Cell, Row, Table},
|
||||
};
|
||||
|
||||
// Mbox
|
||||
|
@ -26,15 +26,25 @@ impl Mbox {
|
|||
}
|
||||
}
|
||||
|
||||
impl DisplayRow for Mbox {
|
||||
fn to_row(&self) -> Vec<table::Cell> {
|
||||
use crate::table::*;
|
||||
impl Table for Mbox {
|
||||
fn head() -> Row {
|
||||
Row::new()
|
||||
.cell(Cell::new("DELIM").bold().underline().white())
|
||||
.cell(Cell::new("NAME").bold().underline().white())
|
||||
.cell(
|
||||
Cell::new("ATTRIBUTES")
|
||||
.shrinkable()
|
||||
.bold()
|
||||
.underline()
|
||||
.white(),
|
||||
)
|
||||
}
|
||||
|
||||
vec![
|
||||
Cell::new(&[BLUE], &self.delim),
|
||||
Cell::new(&[GREEN], &self.name),
|
||||
FlexCell::new(&[YELLOW], &self.attributes.join(", ")),
|
||||
]
|
||||
fn row(&self) -> Row {
|
||||
Row::new()
|
||||
.cell(Cell::new(&self.delim).red())
|
||||
.cell(Cell::new(&self.name).green())
|
||||
.cell(Cell::new(&self.attributes.join(", ")).shrinkable().yellow())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,28 +53,12 @@ impl DisplayRow for Mbox {
|
|||
#[derive(Debug, Serialize)]
|
||||
pub struct Mboxes(pub Vec<Mbox>);
|
||||
|
||||
impl<'a> DisplayTable<'a, Mbox> for Mboxes {
|
||||
fn header_row() -> Vec<table::Cell> {
|
||||
use crate::table::*;
|
||||
|
||||
vec![
|
||||
Cell::new(&[BOLD, UNDERLINE, WHITE], "DELIM"),
|
||||
Cell::new(&[BOLD, UNDERLINE, WHITE], "NAME"),
|
||||
FlexCell::new(&[BOLD, UNDERLINE, WHITE], "ATTRIBUTES"),
|
||||
]
|
||||
}
|
||||
|
||||
fn rows(&self) -> &Vec<Mbox> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Mboxes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
unsafe {
|
||||
match get_output_fmt() {
|
||||
&OutputFmt::Plain => {
|
||||
writeln!(f, "\n{}", self.to_table())
|
||||
writeln!(f, "\n{}", Table::render(&self.0))
|
||||
}
|
||||
&OutputFmt::Json => {
|
||||
let res = serde_json::to_string(&Response::new(self)).unwrap();
|
||||
|
|
|
@ -16,7 +16,7 @@ use crate::{
|
|||
config::model::{Account, Config},
|
||||
flag::model::{Flag, Flags},
|
||||
output::fmt::{get_output_fmt, OutputFmt, Response},
|
||||
table::{self, DisplayRow, DisplayTable},
|
||||
table::{Cell, Row, Table},
|
||||
};
|
||||
|
||||
error_chain! {
|
||||
|
@ -624,23 +624,29 @@ struct MsgSpec {
|
|||
default_content: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl<'m> DisplayRow for Msg<'m> {
|
||||
fn to_row(&self) -> Vec<table::Cell> {
|
||||
use crate::table::*;
|
||||
impl<'m> Table for Msg<'m> {
|
||||
fn head() -> Row {
|
||||
Row::new()
|
||||
.cell(Cell::new("UID").bold().underline().white())
|
||||
.cell(Cell::new("FLAGS").bold().underline().white())
|
||||
.cell(Cell::new("SUBJECT").shrinkable().bold().underline().white())
|
||||
.cell(Cell::new("SENDER").bold().underline().white())
|
||||
.cell(Cell::new("DATE").bold().underline().white())
|
||||
}
|
||||
|
||||
let unseen = if self.flags.contains(&Flag::Seen) {
|
||||
RESET
|
||||
} else {
|
||||
BOLD
|
||||
};
|
||||
|
||||
vec![
|
||||
Cell::new(&[unseen.to_owned(), RED], &self.uid.to_string()),
|
||||
Cell::new(&[unseen.to_owned(), WHITE], &self.flags.to_string()),
|
||||
FlexCell::new(&[unseen.to_owned(), GREEN], &self.subject),
|
||||
Cell::new(&[unseen.to_owned(), BLUE], &self.sender),
|
||||
Cell::new(&[unseen.to_owned(), YELLOW], &self.date),
|
||||
]
|
||||
fn row(&self) -> Row {
|
||||
let is_seen = !self.flags.contains(&Flag::Seen);
|
||||
Row::new()
|
||||
.cell(Cell::new(&self.uid.to_string()).bold_if(is_seen).red())
|
||||
.cell(Cell::new(&self.flags.to_string()).bold_if(is_seen).white())
|
||||
.cell(
|
||||
Cell::new(&self.subject)
|
||||
.shrinkable()
|
||||
.bold_if(is_seen)
|
||||
.green(),
|
||||
)
|
||||
.cell(Cell::new(&self.sender).bold_if(is_seen).blue())
|
||||
.cell(Cell::new(&self.date).bold_if(is_seen).yellow())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -649,24 +655,6 @@ impl<'m> DisplayRow for Msg<'m> {
|
|||
#[derive(Debug, Serialize)]
|
||||
pub struct Msgs<'m>(pub Vec<Msg<'m>>);
|
||||
|
||||
impl<'m> DisplayTable<'m, Msg<'m>> for Msgs<'m> {
|
||||
fn header_row() -> Vec<table::Cell> {
|
||||
use crate::table::*;
|
||||
|
||||
vec![
|
||||
Cell::new(&[BOLD, UNDERLINE, WHITE], "UID"),
|
||||
Cell::new(&[BOLD, UNDERLINE, WHITE], "FLAGS"),
|
||||
FlexCell::new(&[BOLD, UNDERLINE, WHITE], "SUBJECT"),
|
||||
Cell::new(&[BOLD, UNDERLINE, WHITE], "SENDER"),
|
||||
Cell::new(&[BOLD, UNDERLINE, WHITE], "DATE"),
|
||||
]
|
||||
}
|
||||
|
||||
fn rows(&self) -> &Vec<Msg<'m>> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'m> From<&'m imap::types::ZeroCopy<Vec<imap::types::Fetch>>> for Msgs<'m> {
|
||||
fn from(fetches: &'m imap::types::ZeroCopy<Vec<imap::types::Fetch>>) -> Self {
|
||||
Self(fetches.iter().rev().map(Msg::from).collect::<Vec<_>>())
|
||||
|
@ -678,7 +666,7 @@ impl<'m> fmt::Display for Msgs<'m> {
|
|||
unsafe {
|
||||
match get_output_fmt() {
|
||||
&OutputFmt::Plain => {
|
||||
writeln!(f, "\n{}", self.to_table())
|
||||
writeln!(f, "\n{}", Table::render(&self.0))
|
||||
}
|
||||
&OutputFmt::Json => {
|
||||
let res = serde_json::to_string(&Response::new(self)).unwrap();
|
||||
|
|
454
src/table.rs
454
src/table.rs
|
@ -1,30 +1,26 @@
|
|||
use std::fmt;
|
||||
use terminal_size::terminal_size;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct Style(u8, u8, u8);
|
||||
|
||||
impl fmt::Display for Style {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Style(color, bright, shade) = self;
|
||||
|
||||
let bright_str: String = if *bright > 0 {
|
||||
String::from(";") + &bright.to_string()
|
||||
} else {
|
||||
String::from("")
|
||||
};
|
||||
|
||||
let shade_str: String = if *shade > 0 {
|
||||
String::from(";") + &shade.to_string()
|
||||
} else {
|
||||
String::from("")
|
||||
};
|
||||
|
||||
let mut style = String::from("\x1b[");
|
||||
|
||||
style.push_str(&color.to_string());
|
||||
style.push_str(&bright_str);
|
||||
style.push_str(&shade_str);
|
||||
|
||||
if *bright > 0 {
|
||||
style.push_str(";");
|
||||
style.push_str(&bright.to_string());
|
||||
};
|
||||
|
||||
if *shade > 0 {
|
||||
style.push_str(";");
|
||||
style.push_str(&shade.to_string());
|
||||
};
|
||||
|
||||
style.push_str("m");
|
||||
|
||||
write!(f, "{}", style)
|
||||
|
@ -33,17 +29,17 @@ impl fmt::Display for Style {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct Cell {
|
||||
pub styles: Vec<Style>,
|
||||
pub value: String,
|
||||
pub flex: bool,
|
||||
styles: Vec<Style>,
|
||||
value: String,
|
||||
shrinkable: bool,
|
||||
}
|
||||
|
||||
impl Cell {
|
||||
pub fn new(styles: &[Style], value: &str) -> Self {
|
||||
pub fn new<T: AsRef<str>>(value: T) -> Self {
|
||||
Self {
|
||||
styles: styles.to_vec(),
|
||||
value: value.trim().to_string(),
|
||||
flex: false,
|
||||
styles: Vec::new(),
|
||||
value: String::from(value.as_ref()),
|
||||
shrinkable: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,209 +47,299 @@ impl Cell {
|
|||
UnicodeWidthStr::width(self.value.as_str())
|
||||
}
|
||||
|
||||
pub fn render(&self, col_size: usize) -> String {
|
||||
let style_begin = self
|
||||
.styles
|
||||
.iter()
|
||||
.map(|style| style.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.concat();
|
||||
let style_end = "\x1b[0m";
|
||||
let unicode_width = self.unicode_width();
|
||||
|
||||
if col_size > 0 && unicode_width > col_size {
|
||||
String::from(style_begin + &self.value[0..=col_size - 2] + "… " + style_end)
|
||||
} else {
|
||||
let padding = if col_size == 0 {
|
||||
"".to_string()
|
||||
} else {
|
||||
" ".repeat(col_size - unicode_width + 1)
|
||||
};
|
||||
|
||||
String::from(style_begin + &self.value + &padding + style_end)
|
||||
pub fn shrinkable(mut self) -> Self {
|
||||
self.shrinkable = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_shrinkable(&self) -> bool {
|
||||
self.shrinkable
|
||||
}
|
||||
|
||||
pub fn bold(mut self) -> Self {
|
||||
self.styles.push(Style(1, 0, 0));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn bold_if(self, predicate: bool) -> Self {
|
||||
if predicate {
|
||||
self.bold()
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn underline(mut self) -> Self {
|
||||
self.styles.push(Style(4, 0, 0));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn red(mut self) -> Self {
|
||||
self.styles.push(Style(31, 0, 0));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn green(mut self) -> Self {
|
||||
self.styles.push(Style(32, 0, 0));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn yellow(mut self) -> Self {
|
||||
self.styles.push(Style(33, 0, 0));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn blue(mut self) -> Self {
|
||||
self.styles.push(Style(34, 0, 0));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn white(mut self) -> Self {
|
||||
self.styles.push(Style(37, 0, 0));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn ext(mut self, shade: u8) -> Self {
|
||||
self.styles.push(Style(38, 5, shade));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Cell {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
for style in &self.styles {
|
||||
write!(f, "{}", style)?;
|
||||
}
|
||||
|
||||
write!(f, "{}", self.value)?;
|
||||
|
||||
if !self.styles.is_empty() {
|
||||
write!(f, "{}", Style(0, 0, 0))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FlexCell;
|
||||
pub struct Row(pub Vec<Cell>);
|
||||
|
||||
impl FlexCell {
|
||||
pub fn new(styles: &[Style], value: &str) -> Cell {
|
||||
Cell {
|
||||
flex: true,
|
||||
..Cell::new(styles, value)
|
||||
impl Row {
|
||||
pub fn new() -> Self {
|
||||
Self(Vec::new())
|
||||
}
|
||||
|
||||
pub fn cell(mut self, cell: Cell) -> Self {
|
||||
self.0.push(cell);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DisplayRow {
|
||||
fn to_row(&self) -> Vec<Cell>;
|
||||
}
|
||||
pub trait Table
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn head() -> Row;
|
||||
fn row(&self) -> Row;
|
||||
|
||||
pub trait DisplayTable<'a, T: DisplayRow + 'a> {
|
||||
fn header_row() -> Vec<Cell>;
|
||||
fn rows(&self) -> &Vec<T>;
|
||||
fn max_width() -> usize {
|
||||
terminal_size::terminal_size()
|
||||
.map(|(w, _)| w.0 as usize)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn to_table(&self) -> String {
|
||||
let mut col_sizes = vec![];
|
||||
let head = Self::header_row();
|
||||
|
||||
head.iter().for_each(|cell| {
|
||||
col_sizes.push(cell.unicode_width());
|
||||
});
|
||||
|
||||
let mut table = self
|
||||
.rows()
|
||||
fn build(items: &[Self]) -> Vec<Vec<String>> {
|
||||
let mut table = vec![Self::head()];
|
||||
let mut cell_widths: Vec<usize> =
|
||||
table[0].0.iter().map(|cell| cell.unicode_width()).collect();
|
||||
table.extend(
|
||||
items
|
||||
.iter()
|
||||
.map(|item| {
|
||||
let row = item.to_row();
|
||||
row.iter()
|
||||
.enumerate()
|
||||
.for_each(|(i, cell)| col_sizes[i] = col_sizes[i].max(cell.unicode_width()));
|
||||
let row = item.row();
|
||||
row.0.iter().enumerate().for_each(|(i, cell)| {
|
||||
cell_widths[i] = cell_widths[i].max(cell.unicode_width());
|
||||
});
|
||||
row
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
table.insert(0, head);
|
||||
let spaces_plus_separators_len = cell_widths.len() * 2 - 1;
|
||||
let table_width = cell_widths.iter().sum::<usize>() + spaces_plus_separators_len;
|
||||
|
||||
let term_width = terminal_size().map(|size| size.0 .0).unwrap_or(0) as usize;
|
||||
let seps_width = 2 * col_sizes.len() - 1;
|
||||
let table_width = col_sizes.iter().sum::<usize>() + seps_width;
|
||||
let diff_width = if table_width < term_width {
|
||||
0
|
||||
} else {
|
||||
table_width - term_width
|
||||
};
|
||||
|
||||
table.iter().fold(String::new(), |output, row| {
|
||||
let row_str = row
|
||||
.iter()
|
||||
table
|
||||
.iter_mut()
|
||||
.map(|row| {
|
||||
row.0
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
.map(|(i, cell)| {
|
||||
if cell.flex && col_sizes[i] > diff_width {
|
||||
cell.render(col_sizes[i] - diff_width)
|
||||
let table_is_overflowing = table_width > Self::max_width();
|
||||
|
||||
if table_is_overflowing && cell.is_shrinkable() {
|
||||
let shrink_width = table_width - Self::max_width();
|
||||
let cell_width = cell_widths[i] - shrink_width;
|
||||
let cell_is_overflowing = cell.unicode_width() > cell_width;
|
||||
|
||||
if cell_is_overflowing {
|
||||
let mut value = String::new();
|
||||
let mut chars_width = 0;
|
||||
|
||||
for c in cell.value.chars() {
|
||||
let char_width = UnicodeWidthStr::width(c.to_string().as_str());
|
||||
if chars_width + char_width >= cell_width {
|
||||
break;
|
||||
}
|
||||
|
||||
chars_width += char_width;
|
||||
value.push(c);
|
||||
}
|
||||
|
||||
value.push_str("… ");
|
||||
let repeat_count = cell_width - chars_width - 1;
|
||||
value.push_str(&" ".repeat(repeat_count));
|
||||
cell.value = value;
|
||||
cell.to_string()
|
||||
} else {
|
||||
cell.render(col_sizes[i])
|
||||
let repeat_len = cell_width - cell.unicode_width() + 1;
|
||||
cell.value.push_str(&" ".repeat(repeat_len));
|
||||
cell.to_string()
|
||||
}
|
||||
} else {
|
||||
let repeat_count = cell_widths[i] - cell.unicode_width() + 1;
|
||||
cell.value.push_str(&" ".repeat(repeat_count));
|
||||
cell.to_string()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(&Cell::new(&[ext(8)], "|").render(0));
|
||||
|
||||
output + &row_str + "\n"
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn render(items: &[Self]) -> String {
|
||||
Self::build(items)
|
||||
.iter()
|
||||
.map(|row| row.join(&Cell::new("|").ext(8).to_string()))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const RESET: Style = Style(0, 0, 0);
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BOLD: Style = Style(1, 0, 0);
|
||||
struct Item {
|
||||
id: u16,
|
||||
name: String,
|
||||
desc: String,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const UNDERLINE: Style = Style(4, 0, 0);
|
||||
impl<'a> Item {
|
||||
pub fn new(id: u16, name: &'a str, desc: &'a str) -> Self {
|
||||
Self {
|
||||
id,
|
||||
name: String::from(name),
|
||||
desc: String::from(desc),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const REVERSED: Style = Style(7, 0, 0);
|
||||
impl Table for Item {
|
||||
fn head() -> Row {
|
||||
Row::new()
|
||||
.cell(Cell::new("ID"))
|
||||
.cell(Cell::new("NAME").shrinkable())
|
||||
.cell(Cell::new("DESC"))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BLACK: Style = Style(30, 0, 0);
|
||||
fn row(&self) -> Row {
|
||||
Row::new()
|
||||
.cell(Cell::new(self.id.to_string()))
|
||||
.cell(Cell::new(self.name.as_str()).shrinkable())
|
||||
.cell(Cell::new(self.desc.as_str()))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const RED: Style = Style(31, 0, 0);
|
||||
fn max_width() -> usize {
|
||||
20
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const GREEN: Style = Style(32, 0, 0);
|
||||
#[test]
|
||||
fn row_smaller_than_head() {
|
||||
let items = vec![
|
||||
Item::new(1, "a", "aa"),
|
||||
Item::new(2, "b", "bb"),
|
||||
Item::new(3, "c", "cc"),
|
||||
];
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const YELLOW: Style = Style(33, 0, 0);
|
||||
let table = vec![
|
||||
vec!["ID ", "NAME ", "DESC "],
|
||||
vec!["1 ", "a ", "aa "],
|
||||
vec!["2 ", "b ", "bb "],
|
||||
vec!["3 ", "c ", "cc "],
|
||||
];
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BLUE: Style = Style(34, 0, 0);
|
||||
assert_eq!(table, Table::build(&items));
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const MAGENTA: Style = Style(35, 0, 0);
|
||||
#[test]
|
||||
fn row_bigger_than_head() {
|
||||
let items = vec![
|
||||
Item::new(1, "a", "aa"),
|
||||
Item::new(2222, "bbbbb", "bbbbb"),
|
||||
Item::new(3, "c", "cc"),
|
||||
];
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const CYAN: Style = Style(36, 0, 0);
|
||||
let table = vec![
|
||||
vec!["ID ", "NAME ", "DESC "],
|
||||
vec!["1 ", "a ", "aa "],
|
||||
vec!["2222 ", "bbbbb ", "bbbbb "],
|
||||
vec!["3 ", "c ", "cc "],
|
||||
];
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const WHITE: Style = Style(37, 0, 0);
|
||||
assert_eq!(table, Table::build(&items));
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BRIGHT_BLACK: Style = Style(30, 1, 0);
|
||||
let items = vec![
|
||||
Item::new(1, "a", "aa"),
|
||||
Item::new(2222, "bbbbb", "bbbbb"),
|
||||
Item::new(3, "cccccc", "cc"),
|
||||
];
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BRIGHT_RED: Style = Style(31, 1, 0);
|
||||
let table = vec![
|
||||
vec!["ID ", "NAME ", "DESC "],
|
||||
vec!["1 ", "a ", "aa "],
|
||||
vec!["2222 ", "bbbbb ", "bbbbb "],
|
||||
vec!["3 ", "cccccc ", "cc "],
|
||||
];
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BRIGHT_GREEN: Style = Style(32, 1, 0);
|
||||
assert_eq!(table, Table::build(&items));
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BRIGHT_YELLOW: Style = Style(33, 1, 0);
|
||||
#[test]
|
||||
fn shrink() {
|
||||
let items = vec![
|
||||
Item::new(1, "short", "desc"),
|
||||
Item::new(2, "loooooong", "desc"),
|
||||
Item::new(3, "shriiiiink", "desc"),
|
||||
Item::new(4, "shriiiiiiiiiink", "desc"),
|
||||
Item::new(5, "😍😍😍😍", "desc"),
|
||||
Item::new(6, "😍😍😍😍😍", "desc"),
|
||||
Item::new(7, "!😍😍😍😍😍", "desc"),
|
||||
];
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BRIGHT_BLUE: Style = Style(34, 1, 0);
|
||||
let table = vec![
|
||||
vec!["ID ", "NAME ", "DESC "],
|
||||
vec!["1 ", "short ", "desc "],
|
||||
vec!["2 ", "loooooong ", "desc "],
|
||||
vec!["3 ", "shriiiii… ", "desc "],
|
||||
vec!["4 ", "shriiiii… ", "desc "],
|
||||
vec!["5 ", "😍😍😍😍 ", "desc "],
|
||||
vec!["6 ", "😍😍😍😍… ", "desc "],
|
||||
vec!["7 ", "!😍😍😍… ", "desc "],
|
||||
];
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BRIGHT_MAGENTA: Style = Style(35, 1, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BRIGHT_CYAN: Style = Style(36, 1, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BRIGHT_WHITE: Style = Style(37, 1, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_BLACK: Style = Style(40, 0, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_RED: Style = Style(41, 0, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_GREEN: Style = Style(42, 0, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_YELLOW: Style = Style(43, 0, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_BLUE: Style = Style(44, 0, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_MAGENTA: Style = Style(45, 0, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_CYAN: Style = Style(46, 0, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_WHITE: Style = Style(47, 0, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_BRIGHT_BLACK: Style = Style(40, 1, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_BRIGHT_RED: Style = Style(41, 1, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_BRIGHT_GREEN: Style = Style(42, 1, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_BRIGHT_YELLOW: Style = Style(43, 1, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_BRIGHT_BLUE: Style = Style(44, 1, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_BRIGHT_MAGENTA: Style = Style(45, 1, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_BRIGHT_CYAN: Style = Style(46, 1, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BG_BRIGHT_WHITE: Style = Style(47, 1, 0);
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn ext(n: u8) -> Style {
|
||||
Style(38, 5, n)
|
||||
assert_eq!(table, Table::build(&items));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue