WIP/ Checkout to new tabled (#6286)

* nu-table/ Use latest tabled

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* nu-table/ Fix first column alignment

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* nu-table: Fix cargo clippy

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* nu-table: Fix color issue

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* nu-table: Fix footer row

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* nu-table: Bump tabled

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* nu-table: Bump tabled

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* nu-table: Bump tabled

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Update

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* nu-table/ Update

* Use latest tabled

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Add optional -e, -c argument to `table` command for different view

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Fix clippy

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Fix clippy

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Update

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Fix cargo clippy

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Fix tests

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* nu-table: Add footer into -e/c mode

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Publish new expand mode

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Add width ctrl for Expand mode

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Refactorings

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Refactorings

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Add tests

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Add tests

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Merge with main

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Fix clippy

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Fix tests

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Fix tests

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Bump tabled

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* Add record expand and fix empty list issue

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>

* refactoring

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
This commit is contained in:
Maxim Zhiburt
2022-10-03 19:40:16 +03:00
committed by GitHub
parent e629ef203a
commit 5921c19bc0
16 changed files with 2126 additions and 1054 deletions

729
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,6 @@ exclude = ["images"]
homepage = "https://www.nushell.sh"
license = "MIT"
name = "nu"
readme = "README.md"
repository = "https://github.com/nushell/nushell"
rust-version = "1.60"
version = "0.69.2"

File diff suppressed because it is too large Load Diff

View File

@ -74,6 +74,7 @@ mod split_by;
mod split_column;
mod split_row;
mod str_;
mod table;
mod take;
mod touch;
mod transpose;

View File

@ -0,0 +1,137 @@
use nu_test_support::nu;
#[test]
fn table_0() {
let actual = nu!(r#"[[a b, c]; [1 2 3] [4 5 [1 2 3]]] | table"#);
assert_eq!(
actual.out,
"╭───┬───┬───┬────────────────╮\
│ # │ a │ b │ c │\
├───┼───┼───┼────────────────┤\
│ 0 │ 1 │ 2 │ 3 │\
│ 1 │ 4 │ 5 │ [list 3 items] │\
╰───┴───┴───┴────────────────╯"
);
}
#[test]
fn table_collapse_0() {
let actual = nu!(r#"[[a b, c]; [1 2 3] [4 5 [1 2 3]]] | table --collapse"#);
assert_eq!(
actual.out,
"\u{1b}[37m╭───\u{1b}[39m\u{1b}[37m┬───\u{1b}[39m\u{1b}[37m┬───╮\u{1b}[39m\u{1b}[37m│\u{1b}[39m a \u{1b}[37m│\u{1b}[39m b \u{1b}[37m│\u{1b}[39m c \u{1b}[37m│\u{1b}[39m\u{1b}[37m ───\u{1b}[39m\u{1b}[37m ───\u{1b}[39m\u{1b}[37m ─── \u{1b}[39m\u{1b}[37m│\u{1b}[39m 1 \u{1b}[37m│\u{1b}[39m 2 \u{1b}[37m│\u{1b}[39m 3 \u{1b}[37m│\u{1b}[39m\u{1b}[37m ───\u{1b}[39m\u{1b}[37m ───\u{1b}[39m\u{1b}[37m ─── \u{1b}[39m\u{1b}[37m│\u{1b}[39m 4 \u{1b}[37m│\u{1b}[39m 5 \u{1b}[37m│\u{1b}[39m 1 \u{1b}[37m│\u{1b}[39m\u{1b}[37m│\u{1b}[39m \u{1b}[37m│\u{1b}[39m \u{1b}[37m ─── \u{1b}[39m\u{1b}[37m│\u{1b}[39m \u{1b}[37m│\u{1b}[39m \u{1b}[37m│\u{1b}[39m 2 \u{1b}[37m│\u{1b}[39m\u{1b}[37m│\u{1b}[39m \u{1b}[37m│\u{1b}[39m \u{1b}[37m ─── \u{1b}[39m\u{1b}[37m│\u{1b}[39m \u{1b}[37m│\u{1b}[39m \u{1b}[37m│\u{1b}[39m 3 \u{1b}[37m│\u{1b}[39m\u{1b}[37m╰───\u{1b}[39m\u{1b}[37m┴───\u{1b}[39m\u{1b}[37m┴───╯\u{1b}[39m"
);
}
#[test]
fn table_expand_0() {
let actual = nu!(r#"[[a b, c]; [1 2 3] [4 5 [1 2 3]]] | table --expand"#);
assert_eq!(
actual.out,
"╭───┬───┬───┬───────────╮\
│ # │ a │ b │ c │\
├───┼───┼───┼───────────┤\
│ 0 │ 1 │ 2 │ 3 │\
│ 1 │ 4 │ 5 │ ╭───┬───╮ │\
│ │ │ │ │ 0 │ 1 │ │\
│ │ │ │ │ 1 │ 2 │ │\
│ │ │ │ │ 2 │ 3 │ │\
│ │ │ │ ╰───┴───╯ │\
╰───┴───┴───┴───────────╯"
);
}
#[test]
fn table_expand_deep_0() {
let actual = nu!(r#"[[a b, c]; [1 2 3] [4 5 [1 2 [1 2 3]]]] | table --expand --expand-deep=1"#);
assert_eq!(
actual.out,
"╭───┬───┬───┬────────────────────────╮\
│ # │ a │ b │ c │\
├───┼───┼───┼────────────────────────┤\
│ 0 │ 1 │ 2 │ 3 │\
│ 1 │ 4 │ 5 │ ╭───┬────────────────╮ │\
│ │ │ │ │ 0 │ 1 │ │\
│ │ │ │ │ 1 │ 2 │ │\
│ │ │ │ │ 2 │ [list 3 items] │ │\
│ │ │ │ ╰───┴────────────────╯ │\
╰───┴───┴───┴────────────────────────╯"
);
}
#[test]
fn table_expand_deep_1() {
let actual = nu!(r#"[[a b, c]; [1 2 3] [4 5 [1 2 [1 2 3]]]] | table --expand --expand-deep=0"#);
assert_eq!(
actual.out,
"╭───┬───┬───┬────────────────╮\
│ # │ a │ b │ c │\
├───┼───┼───┼────────────────┤\
│ 0 │ 1 │ 2 │ 3 │\
│ 1 │ 4 │ 5 │ [list 3 items] │\
╰───┴───┴───┴────────────────╯"
);
}
#[test]
fn table_expand_flatten_0() {
let actual = nu!(r#"[[a b, c]; [1 2 3] [4 5 [1 2 [1 1 1]]]] | table --expand --flatten "#);
assert_eq!(
actual.out,
"╭───┬───┬───┬───────────────╮\
│ # │ a │ b │ c │\
├───┼───┼───┼───────────────┤\
│ 0 │ 1 │ 2 │ 3 │\
│ 1 │ 4 │ 5 │ ╭───┬───────╮ │\
│ │ │ │ │ 0 │ 1 │ │\
│ │ │ │ │ 1 │ 2 │ │\
│ │ │ │ │ 2 │ 1 1 1 │ │\
│ │ │ │ ╰───┴───────╯ │\
╰───┴───┴───┴───────────────╯"
);
}
#[test]
fn table_expand_flatten_1() {
let actual = nu!(
r#"[[a b, c]; [1 2 3] [4 5 [1 2 [1 1 1]]]] | table --expand --flatten --flatten-separator=,"#
);
assert_eq!(
actual.out,
"╭───┬───┬───┬───────────────╮\
│ # │ a │ b │ c │\
├───┼───┼───┼───────────────┤\
│ 0 │ 1 │ 2 │ 3 │\
│ 1 │ 4 │ 5 │ ╭───┬───────╮ │\
│ │ │ │ │ 0 │ 1 │ │\
│ │ │ │ │ 1 │ 2 │ │\
│ │ │ │ │ 2 │ 1,1,1 │ │\
│ │ │ │ ╰───┴───────╯ │\
╰───┴───┴───┴───────────────╯"
);
}
#[test]
fn table_expand_flatten_and_deep_1() {
let actual = nu!(
r#"[[a b, c]; [1 2 3] [4 5 [1 2 [1 [1 1 1] 1]]]] | table --expand --expand-deep=2 --flatten --flatten-separator=,"#
);
assert_eq!(
actual.out,
"╭───┬───┬───┬────────────────────────────────╮\
│ # │ a │ b │ c │\
├───┼───┼───┼────────────────────────────────┤\
│ 0 │ 1 │ 2 │ 3 │\
│ 1 │ 4 │ 5 │ ╭───┬────────────────────────╮ │\
│ │ │ │ │ 0 │ 1 │ │\
│ │ │ │ │ 1 │ 2 │ │\
│ │ │ │ │ 2 │ ╭───┬────────────────╮ │ │\
│ │ │ │ │ │ │ 0 │ 1 │ │ │\
│ │ │ │ │ │ │ 1 │ [list 3 items] │ │ │\
│ │ │ │ │ │ │ 2 │ 1 │ │ │\
│ │ │ │ │ │ ╰───┴────────────────╯ │ │\
│ │ │ │ ╰───┴────────────────────────╯ │\
╰───┴───┴───┴────────────────────────────────╯"
);
}

View File

@ -17,4 +17,6 @@ nu-ansi-term = "0.46.0"
nu-protocol = { path = "../nu-protocol", version = "0.69.2" }
strip-ansi-escapes = "0.1.1"
atty = "0.2.14"
tabled = { version = "0.8.0", features = ["color"] }
tabled = { version = "0.9.0", features = ["color"], default-features = false }
json_to_table = { version = "0.1.0", features = ["color"] }
serde_json = "*"

View File

@ -1,8 +1,13 @@
mod nu_protocol_table;
mod table;
mod table_theme;
mod textstyle;
mod width_control;
pub use nu_protocol_table::NuTable;
pub use table::{Alignments, Table};
pub use table_theme::TableTheme;
pub use textstyle::{Alignment, StyledString, TextStyle};
pub use textstyle::{Alignment, TextStyle};
pub fn string_width(text: &str) -> usize {
tabled::papergrid::util::string_width_multiline_tab(text, 4)
}

View File

@ -1,6 +1,7 @@
use nu_protocol::Config;
use nu_table::{Alignments, StyledString, Table, TableTheme, TextStyle};
use nu_table::{Alignments, Table, TableTheme, TextStyle};
use std::collections::HashMap;
use tabled::papergrid::records::{cell_info::CellInfo, tcell::TCell};
fn main() {
let args: Vec<_> = std::env::args().collect();
@ -23,14 +24,23 @@ fn main() {
// The table rows
let rows = vec_of_str_to_vec_of_styledstr(&row_data, false);
// The table itself
let table = Table::new(headers, vec![rows; 3], TableTheme::rounded());
let count_cols = std::cmp::max(rows.len(), headers.len());
let mut rows = vec![rows; 3];
rows.insert(0, headers);
let table = Table::new(rows, (3, count_cols), width, true, false);
// FIXME: Config isn't available from here so just put these here to compile
let color_hm: HashMap<String, nu_ansi_term::Style> = HashMap::new();
// get the default config
let config = Config::default();
// Capture the table as a string
let output_table = table
.draw_table(&config, &color_hm, Alignments::default(), width)
.draw_table(
&config,
&color_hm,
Alignments::default(),
&TableTheme::rounded(),
width,
)
.unwrap_or_else(|| format!("Couldn't fit table into {} columns!", width));
// Draw the table
println!("{}", output_table)
@ -74,17 +84,23 @@ fn make_table_data() -> (Vec<&'static str>, Vec<&'static str>) {
(table_headers, row_data)
}
fn vec_of_str_to_vec_of_styledstr(data: &[&str], is_header: bool) -> Vec<StyledString> {
fn vec_of_str_to_vec_of_styledstr(
data: &[&str],
is_header: bool,
) -> Vec<TCell<CellInfo<'static>, TextStyle>> {
let mut v = vec![];
for x in data {
if is_header {
v.push(StyledString::new(
v.push(Table::create_cell(
String::from(*x),
TextStyle::default_header(),
))
} else {
v.push(StyledString::new(String::from(*x), TextStyle::basic_left()))
v.push(Table::create_cell(
String::from(*x),
TextStyle::basic_left(),
))
}
}
v

View File

@ -0,0 +1,218 @@
use std::collections::HashMap;
use nu_protocol::{Config, Span, Value};
use tabled::{color::Color, papergrid::records::Records, Table};
use crate::{table::TrimStrategyModifier, TableTheme};
/// NuTable has a recursive table representation of nu_prorocol::Value.
///
/// It doesn't support alignement and a proper width controll.
pub struct NuTable {
inner: tabled::Table,
}
impl NuTable {
pub fn new(
value: Value,
collapse: bool,
termwidth: usize,
config: &Config,
color_hm: &HashMap<String, nu_ansi_term::Style>,
theme: &TableTheme,
with_footer: bool,
) -> Self {
let mut table = tabled::Table::new([""]);
load_theme(&mut table, color_hm, theme);
let cfg = table.get_config().clone();
let val = nu_protocol_value_to_json(value, config, with_footer);
let mut table = json_to_table::json_to_table(&val);
table.set_config(cfg);
if collapse {
table.collapse();
}
let mut table: Table<_> = table.into();
table.with(TrimStrategyModifier::new(termwidth, &config.trim_strategy));
Self { inner: table }
}
pub fn draw(&self) -> Option<String> {
Some(self.inner.to_string())
}
}
fn nu_protocol_value_to_json(
value: Value,
config: &Config,
with_footer: bool,
) -> serde_json::Value {
match value {
Value::Record { cols, vals, .. } => {
let mut map = serde_json::Map::new();
for (key, value) in cols.into_iter().zip(vals) {
let val = nu_protocol_value_to_json(value, config, false);
map.insert(key, val);
}
serde_json::Value::Object(map)
}
Value::List { vals, .. } => {
let mut used_cols: Option<&[String]> = None;
for val in &vals {
match val {
Value::Record { cols, .. } => match &used_cols {
Some(_cols) => {
if _cols != cols {
used_cols = None;
break;
}
}
None => used_cols = Some(cols),
},
_ => {
used_cols = None;
break;
}
}
}
if let Some(cols) = used_cols {
// rebuild array as a map
if cols.len() > 1 {
let mut arr = vec![];
let head = cols.iter().map(|s| Value::String {
val: s.to_owned(),
span: Span::new(0, 0),
});
let head = build_map(head, config);
arr.push(serde_json::Value::Object(head.clone()));
for value in &vals {
if let Ok((_, vals)) = value.as_record() {
let vals = build_map(vals.iter().cloned(), config);
let mut map = serde_json::Map::new();
connect_maps(&mut map, serde_json::Value::Object(vals));
arr.push(serde_json::Value::Object(map));
}
}
if with_footer {
arr.push(serde_json::Value::Object(head));
}
return serde_json::Value::Array(arr);
} else {
let mut map = vec![];
let head = serde_json::Value::Array(vec![serde_json::Value::String(
cols[0].to_owned(),
)]);
map.push(head.clone());
for value in vals {
if let Value::Record { vals, .. } = value {
let list = Value::List {
vals,
span: Span::new(0, 0),
};
let val = nu_protocol_value_to_json(list, config, false); // rebuild array as a map
map.push(val);
}
}
if with_footer {
map.push(head);
}
return serde_json::Value::Array(map);
};
}
let mut map = Vec::new();
for value in vals {
let val = nu_protocol_value_to_json(value, config, false);
map.push(val);
}
serde_json::Value::Array(map)
}
val => serde_json::Value::String(val.into_abbreviated_string(config)),
}
}
fn build_map(
values: impl Iterator<Item = Value> + DoubleEndedIterator,
config: &Config,
) -> serde_json::Map<String, serde_json::Value> {
let mut map = serde_json::Map::new();
let mut last_val: Option<Value> = None;
for val in values.rev() {
if map.is_empty() {
match last_val.take() {
Some(prev_val) => {
let col = val.into_abbreviated_string(&Config::default());
let prev = nu_protocol_value_to_json(prev_val, config, false);
map.insert(col, prev);
}
None => {
last_val = Some(val);
}
}
} else {
let mut new_m = serde_json::Map::new();
let col = val.into_abbreviated_string(&Config::default());
new_m.insert(col, serde_json::Value::Object(map));
map = new_m;
}
}
// if last_val.is_some() && map.is_empty() {
// let val = nu_protocol_value_to_json(last_val.unwrap());
// return serde_json::Value::Array(vec![val]);
// }
map
}
fn connect_maps(map: &mut serde_json::Map<String, serde_json::Value>, value: serde_json::Value) {
if let serde_json::Value::Object(m) = value {
for (key, value) in m {
if value.is_object() {
let mut new_m = serde_json::Map::new();
connect_maps(&mut new_m, value);
map.insert(key, serde_json::Value::Object(new_m));
} else {
map.insert(key, value);
}
}
}
}
fn load_theme<R>(
table: &mut tabled::Table<R>,
color_hm: &HashMap<String, nu_ansi_term::Style>,
theme: &TableTheme,
) where
R: Records,
{
let mut theme = theme.theme.clone();
theme.set_horizontals(HashMap::default());
table.with(theme);
if let Some(color) = color_hm.get("separator") {
let color = color.paint(" ").to_string();
if let Ok(color) = Color::try_from(color) {
table.with(color);
}
}
}

View File

@ -1,31 +1,127 @@
use std::collections::HashMap;
use std::{collections::HashMap, fmt::Display};
use nu_ansi_term::Style;
use nu_protocol::{Config, FooterMode, TableIndexMode, TrimStrategy};
use nu_protocol::{Config, FooterMode, TrimStrategy};
use tabled::{
alignment::AlignmentHorizontal,
builder::Builder,
formatting_settings::AlignmentStrategy,
color::Color,
formatting::AlignmentStrategy,
object::{Cell, Columns, Rows, Segment},
papergrid,
style::Color,
Alignment, AlignmentHorizontal, Modify, ModifyObject, TableOption, Width,
papergrid::{
self,
records::{
cell_info::CellInfo, tcell::TCell, vec_records::VecRecords, Records, RecordsMut,
},
width::CfgWidthFunction,
},
Alignment, Modify, ModifyObject, TableOption, Width,
};
use crate::{table_theme::TableTheme, width_control::maybe_truncate_columns, StyledString};
use crate::{table_theme::TableTheme, TextStyle};
/// Table represent a table view.
#[derive(Debug)]
pub struct Table {
headers: Option<Vec<StyledString>>,
data: Vec<Vec<StyledString>>,
theme: TableTheme,
data: Data,
is_empty: bool,
with_header: bool,
with_index: bool,
}
#[derive(Debug)]
type Data = VecRecords<TCell<CellInfo<'static>, TextStyle>>;
impl Table {
/// Creates a [Table] instance.
///
/// If `headers.is_empty` then no headers will be rendered.
pub fn new(
mut data: Vec<Vec<TCell<CellInfo<'static>, TextStyle>>>,
size: (usize, usize),
termwidth: usize,
with_header: bool,
with_index: bool,
) -> Table {
// it's not guaranted that data will have all rows with the same number of columns.
// but VecRecords::with_hint require this constrain.
for row in &mut data {
if row.len() < size.1 {
row.extend(
std::iter::repeat(Self::create_cell(String::default(), TextStyle::default()))
.take(size.1 - row.len()),
);
}
}
let mut data = VecRecords::with_hint(data, size.1);
let is_empty = maybe_truncate_columns(&mut data, size.1, termwidth);
Table {
data,
is_empty,
with_header,
with_index,
}
}
pub fn create_cell(text: String, style: TextStyle) -> TCell<CellInfo<'static>, TextStyle> {
TCell::new(CellInfo::new(text, CfgWidthFunction::new(4)), style)
}
pub fn is_empty(&self) -> bool {
self.is_empty
}
pub fn truncate(&mut self, width: usize, theme: &TableTheme) -> bool {
let mut truncated = false;
while self.data.count_rows() > 0 && self.data.count_columns() > 0 {
let mut table = Builder::custom(self.data.clone()).build();
load_theme(&mut table, &HashMap::new(), theme, false, false);
let total = table.total_width();
drop(table);
if total > width {
truncated = true;
self.data.truncate(self.data.count_columns() - 1);
} else {
break;
}
}
let is_empty = self.data.count_rows() == 0 || self.data.count_columns() == 0;
if is_empty {
return true;
}
if truncated {
self.data.push(Table::create_cell(
String::from("..."),
TextStyle::default(),
));
}
false
}
/// Draws a trable on a String.
///
/// It returns None in case where table cannot be fit to a terminal width.
pub fn draw_table(
self,
config: &Config,
color_hm: &HashMap<String, nu_ansi_term::Style>,
alignments: Alignments,
theme: &TableTheme,
termwidth: usize,
) -> Option<String> {
draw_table(self, config, color_hm, alignments, theme, termwidth)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Alignments {
data: AlignmentHorizontal,
index: AlignmentHorizontal,
header: AlignmentHorizontal,
pub(crate) data: AlignmentHorizontal,
pub(crate) index: AlignmentHorizontal,
pub(crate) header: AlignmentHorizontal,
}
impl Default for Alignments {
@ -38,84 +134,30 @@ impl Default for Alignments {
}
}
impl Table {
/// Creates a [Table] instance.
///
/// If `headers.is_empty` then no headers will be rendered.
pub fn new(
headers: Vec<StyledString>,
data: Vec<Vec<StyledString>>,
theme: TableTheme,
) -> Table {
let headers = if headers.is_empty() {
None
} else {
Some(headers)
};
Table {
headers,
data,
theme,
}
}
/// Draws a trable on a String.
///
/// It returns None in case where table cannot be fit to a terminal width.
pub fn draw_table(
&self,
config: &Config,
color_hm: &HashMap<String, Style>,
alignments: Alignments,
termwidth: usize,
) -> Option<String> {
draw_table(self, config, color_hm, alignments, termwidth)
}
}
fn draw_table(
table: &Table,
mut table: Table,
config: &Config,
color_hm: &HashMap<String, Style>,
color_hm: &HashMap<String, nu_ansi_term::Style>,
alignments: Alignments,
theme: &TableTheme,
termwidth: usize,
) -> Option<String> {
let mut headers = colorize_headers(table.headers.as_deref());
let mut data = colorize_data(&table.data, table.headers.as_ref().map_or(0, |h| h.len()));
let count_columns = table_fix_lengths(headers.as_mut(), &mut data);
let is_empty = maybe_truncate_columns(&mut headers, &mut data, count_columns, termwidth);
if is_empty {
if table.is_empty {
return None;
}
let table_data = &table.data;
let theme = &table.theme;
let with_header = headers.is_some();
let with_footer = with_header && need_footer(config, data.len() as u64);
let with_index = match config.table_index_mode {
TableIndexMode::Always => true,
TableIndexMode::Never => false,
TableIndexMode::Auto => table
.headers
.iter()
.flatten()
.any(|header| header.contents == "index"),
};
let with_header = table.with_header;
let with_footer = with_header && need_footer(config, (&table.data).size().0 as u64);
let with_index = table.with_index;
let table = build_table(data, headers, with_footer);
let table = load_theme(table, color_hm, theme, with_footer, with_header);
let table = align_table(
table,
alignments,
with_index,
with_header,
with_footer,
table_data,
);
let table = table_trim_columns(table, termwidth, &config.trim_strategy);
if with_footer {
table.data.duplicate_row(0);
}
let mut table = Builder::custom(table.data).build();
load_theme(&mut table, color_hm, theme, with_footer, with_header);
align_table(&mut table, alignments, with_index, with_header, with_footer);
table_trim_columns(&mut table, termwidth, &config.trim_strategy);
let table = print_table(table, config);
if table_width(&table) > termwidth {
@ -125,7 +167,7 @@ fn draw_table(
}
}
fn print_table(table: tabled::Table, config: &Config) -> String {
fn print_table(table: tabled::Table<Data>, config: &Config) -> String {
let output = table.to_string();
// the atty is for when people do ls from vim, there should be no coloring there
@ -142,72 +184,20 @@ fn print_table(table: tabled::Table, config: &Config) -> String {
}
fn table_width(table: &str) -> usize {
table.lines().next().map_or(0, papergrid::string_width)
}
fn colorize_data(table_data: &[Vec<StyledString>], count_columns: usize) -> Vec<Vec<String>> {
let mut data = vec![Vec::with_capacity(count_columns); table_data.len()];
for (row, row_data) in table_data.iter().enumerate() {
for cell in row_data {
let colored_text = cell
.style
.color_style
.as_ref()
.map(|color| color.paint(&cell.contents).to_string())
.unwrap_or_else(|| cell.contents.clone());
data[row].push(colored_text)
}
}
data
}
fn colorize_headers(headers: Option<&[StyledString]>) -> Option<Vec<String>> {
headers.map(|table_headers| {
let mut headers = Vec::with_capacity(table_headers.len());
for cell in table_headers {
let colored_text = cell
.style
.color_style
.as_ref()
.map(|color| color.paint(&cell.contents).to_string())
.unwrap_or_else(|| cell.contents.clone());
headers.push(colored_text)
}
headers
})
}
fn build_table(
data: Vec<Vec<String>>,
headers: Option<Vec<String>>,
need_footer: bool,
) -> tabled::Table {
let mut builder = Builder::from(data);
if let Some(headers) = headers {
builder.set_columns(headers.clone());
if need_footer {
builder.add_record(headers);
}
}
builder.build()
table
.lines()
.next()
.map_or(0, papergrid::util::string_width)
}
fn align_table(
mut table: tabled::Table,
table: &mut tabled::Table<Data>,
alignments: Alignments,
with_index: bool,
with_header: bool,
with_footer: bool,
data: &[Vec<StyledString>],
) -> tabled::Table {
table = table.with(
) {
table.with(
Modify::new(Segment::all())
.with(Alignment::Horizontal(alignments.data))
.with(AlignmentStrategy::PerLine),
@ -216,81 +206,77 @@ fn align_table(
if with_header {
let alignment = Alignment::Horizontal(alignments.header);
if with_footer {
table = table.with(Modify::new(Rows::last()).with(alignment.clone()));
table.with(Modify::new(Rows::last()).with(alignment.clone()));
}
table = table.with(Modify::new(Rows::first()).with(alignment));
table.with(Modify::new(Rows::first()).with(alignment));
}
if with_index {
table =
table.with(Modify::new(Columns::first()).with(Alignment::Horizontal(alignments.index)));
}
table = override_alignments(table, data, with_header, with_index, alignments);
table
override_alignments(table, with_header, with_index, alignments);
}
fn override_alignments(
mut table: tabled::Table,
data: &[Vec<StyledString>],
table: &mut tabled::Table<Data>,
header_present: bool,
index_present: bool,
alignments: Alignments,
) -> tabled::Table {
) {
let offset = if header_present { 1 } else { 0 };
for (row, rows) in data.iter().enumerate() {
for (col, s) in rows.iter().enumerate() {
if index_present && col == 0 && s.style.alignment == alignments.index {
let (count_rows, count_columns) = table.shape();
for row in offset..count_rows {
for col in 0..count_columns {
let alignment = table.get_records()[(row, col)].get_data().alignment;
if index_present && col == 0 && alignment == alignments.index {
continue;
}
if s.style.alignment == alignments.data {
if alignment == alignments.data {
continue;
}
table = table.with(
Cell(row + offset, col)
table.with(
Cell(row, col)
.modify()
.with(Alignment::Horizontal(s.style.alignment)),
.with(Alignment::Horizontal(alignment)),
);
}
}
table
}
fn load_theme(
mut table: tabled::Table,
color_hm: &HashMap<String, Style>,
fn load_theme<R>(
table: &mut tabled::Table<R>,
color_hm: &HashMap<String, nu_ansi_term::Style>,
theme: &TableTheme,
with_footer: bool,
with_header: bool,
) -> tabled::Table {
) where
R: Records,
{
let mut theme = theme.theme.clone();
if !with_header {
theme.set_lines(HashMap::default());
theme.set_horizontals(HashMap::default());
}
table = table.with(theme);
table.with(theme);
if let Some(color) = color_hm.get("separator") {
let color = color.paint(" ").to_string();
if let Ok(color) = Color::try_from(color) {
table = table.with(color);
table.with(color);
}
}
if with_footer {
table = table.with(FooterStyle).with(
table.with(FooterStyle).with(
Modify::new(Rows::last())
.with(Alignment::center())
.with(AlignmentStrategy::PerCell),
);
}
table
}
fn need_footer(config: &Config, count_records: u64) -> bool {
@ -300,27 +286,30 @@ fn need_footer(config: &Config, count_records: u64) -> bool {
struct FooterStyle;
impl TableOption for FooterStyle {
fn change(&mut self, grid: &mut papergrid::Grid) {
if grid.count_columns() == 0 || grid.count_rows() == 0 {
impl<R> TableOption<R> for FooterStyle
where
R: Records,
{
fn change(&mut self, table: &mut tabled::Table<R>) {
if table.is_empty() {
return;
}
if let Some(line) = grid.clone().get_split_line(1) {
grid.set_split_line(grid.count_rows() - 1, line.clone());
if let Some(line) = table.get_config().get_horizontal_line(1).cloned() {
let count_rows = table.shape().0;
table
.get_config_mut()
.set_horizontal_line(count_rows - 1, line);
}
}
}
fn table_trim_columns(
table: tabled::Table,
table: &mut tabled::Table<Data>,
termwidth: usize,
trim_strategy: &TrimStrategy,
) -> tabled::Table {
table.with(&TrimStrategyModifier {
termwidth,
trim_strategy,
})
) {
table.with(TrimStrategyModifier::new(termwidth, trim_strategy));
}
pub struct TrimStrategyModifier<'a> {
@ -328,49 +317,77 @@ pub struct TrimStrategyModifier<'a> {
trim_strategy: &'a TrimStrategy,
}
impl tabled::TableOption for &TrimStrategyModifier<'_> {
fn change(&mut self, grid: &mut papergrid::Grid) {
impl<'a> TrimStrategyModifier<'a> {
pub fn new(termwidth: usize, trim_strategy: &'a TrimStrategy) -> Self {
Self {
termwidth,
trim_strategy,
}
}
}
impl<R> tabled::TableOption<R> for TrimStrategyModifier<'_>
where
R: Records + RecordsMut<String>,
{
fn change(&mut self, table: &mut tabled::Table<R>) {
match self.trim_strategy {
TrimStrategy::Wrap { try_to_keep_words } => {
let mut w = Width::wrap(self.termwidth).priority::<tabled::width::PriorityMax>();
let mut w = Width::wrap(self.termwidth).priority::<tabled::peaker::PriorityMax>();
if *try_to_keep_words {
w = w.keep_words();
}
w.change(grid)
w.change(table)
}
TrimStrategy::Truncate { suffix } => {
let mut w =
Width::truncate(self.termwidth).priority::<tabled::width::PriorityMax>();
Width::truncate(self.termwidth).priority::<tabled::peaker::PriorityMax>();
if let Some(suffix) = suffix {
w = w.suffix(suffix).suffix_try_color(true);
}
w.change(grid);
w.change(table);
}
};
}
}
fn table_fix_lengths(headers: Option<&mut Vec<String>>, data: &mut [Vec<String>]) -> usize {
let length = table_find_max_length(headers.as_deref(), data);
if let Some(headers) = headers {
headers.extend(std::iter::repeat(String::default()).take(length - headers.len()));
fn maybe_truncate_columns(data: &mut Data, length: usize, termwidth: usize) -> bool {
// Make sure we have enough space for the columns we have
let max_num_of_columns = termwidth / 10;
if max_num_of_columns == 0 {
return true;
}
for row in data {
row.extend(std::iter::repeat(String::default()).take(length - row.len()));
// If we have too many columns, truncate the table
if max_num_of_columns < length {
data.truncate(max_num_of_columns);
data.push(Table::create_cell(
String::from("..."),
TextStyle::default(),
));
}
length
false
}
fn table_find_max_length<T>(headers: Option<&Vec<T>>, data: &[Vec<T>]) -> usize {
let mut length = headers.map_or(0, |h| h.len());
for row in data {
length = std::cmp::max(length, row.len());
impl papergrid::Color for TextStyle {
fn fmt_prefix(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(color) = &self.color_style {
color.prefix().fmt(f)?;
}
length
Ok(())
}
fn fmt_suffix(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(color) = &self.color_style {
if !color.is_plain() {
f.write_str("\u{1b}[0m")?;
}
}
Ok(())
}
}

View File

@ -1,4 +1,7 @@
use tabled::style::{Line, RawStyle, Style};
use tabled::{
style::RawStyle,
style::{HorizontalLine, Line, Style},
};
#[derive(Debug, Clone)]
pub struct TableTheme {
@ -21,7 +24,10 @@ impl TableTheme {
pub fn light() -> TableTheme {
Self {
theme: Style::blank()
.lines([(1, Line::new(Some('─'), Some('─'), None, None))])
.horizontals([HorizontalLine::new(
1,
Line::new(Some('─'), Some('─'), None, None),
)])
.into(),
}
}
@ -32,7 +38,9 @@ impl TableTheme {
.off_left()
.off_right()
.off_horizontal()
.lines([(1, Style::modern().get_horizontal().left(None).right(None))])
.horizontals([HorizontalLine::new(1, Style::modern().get_horizontal())
.left(None)
.right(None)])
.into(),
}
}
@ -43,7 +51,10 @@ impl TableTheme {
.top('❤')
.bottom('❤')
.vertical('❤')
.lines([(1, Line::new(Some('❤'), Some('❤'), None, None))])
.horizontals([HorizontalLine::new(
1,
Line::new(Some('❤'), Some('❤'), None, None),
)])
.into(),
}
}
@ -54,7 +65,9 @@ impl TableTheme {
.off_left()
.off_right()
.off_horizontal()
.lines([(1, Style::extended().get_horizontal().left(None).right(None))])
.horizontals([HorizontalLine::new(1, Style::extended().get_horizontal())
.left(None)
.right(None)])
.into(),
}
}
@ -91,7 +104,7 @@ impl TableTheme {
.top_right_corner('┓')
.bottom_left_corner('┗')
.bottom_right_corner('┛')
.lines([(1, Line::full('━', '╋', '┣', '┫'))])
.horizontals([HorizontalLine::new(1, Line::full('━', '╋', '┣', '┫'))])
.into(),
}
}

View File

@ -1,6 +1,6 @@
use nu_ansi_term::{Color, Style};
pub type Alignment = tabled::AlignmentHorizontal;
pub type Alignment = tabled::alignment::AlignmentHorizontal;
#[derive(Debug, Clone, Copy)]
pub struct TextStyle {
@ -239,19 +239,3 @@ impl Default for TextStyle {
Self::new()
}
}
#[derive(Debug, Clone, Default)]
pub struct StyledString {
pub contents: String,
pub style: TextStyle,
}
impl StyledString {
pub fn new(contents: String, style: TextStyle) -> StyledString {
StyledString { contents, style }
}
pub fn set_style(&mut self, style: TextStyle) {
self.style = style;
}
}

View File

@ -1,29 +0,0 @@
pub(crate) fn maybe_truncate_columns(
headers: &mut Option<Vec<String>>,
data: &mut [Vec<String>],
length: usize,
termwidth: usize,
) -> bool {
// Make sure we have enough space for the columns we have
let max_num_of_columns = termwidth / 10;
if max_num_of_columns == 0 {
return true;
}
// If we have too many columns, truncate the table
if let Some(headers) = headers {
if max_num_of_columns < length {
headers.truncate(max_num_of_columns);
headers.push(String::from("..."));
}
}
if max_num_of_columns < length {
for entry in data.iter_mut() {
entry.truncate(max_num_of_columns);
entry.push(String::from("..."));
}
}
false
}

View File

@ -1,11 +1,20 @@
use std::{collections::HashMap, usize};
use nu_protocol::{Config, TrimStrategy};
use nu_table::{Alignments, StyledString, Table, TableTheme as theme, TextStyle};
use nu_table::{Alignments, Table, TableTheme as theme, TextStyle};
use tabled::papergrid::records::{cell_info::CellInfo, tcell::TCell};
#[test]
fn data_and_header_has_different_size() {
let table = Table::new(row(3), vec![row(5); 2], theme::heavy());
let table = Table::new(
vec![row(3), row(5), row(5)],
(3, 5),
usize::MAX,
true,
false,
);
let table = draw_table(table, usize::MAX, &Config::default());
let expected = "┏━━━┳━━━┳━━━┳━━━┳━━━┓\n\
┃ 0 ┃ 1 ┃ 2 ┃ ┃ ┃\n\
@ -14,12 +23,16 @@ fn data_and_header_has_different_size() {
┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃ 4 ┃\n\
┗━━━┻━━━┻━━━┻━━━┻━━━┛";
assert_eq!(
draw_table(&table, usize::MAX, &Config::default()).as_deref(),
Some(expected)
);
assert_eq!(table.as_deref(), Some(expected));
let table = Table::new(row(5), vec![row(3); 2], theme::heavy());
let table = Table::new(
vec![row(5), row(3), row(3)],
(3, 5),
usize::MAX,
true,
false,
);
let table = draw_table(table, usize::MAX, &Config::default());
let expected = "┏━━━┳━━━┳━━━┳━━━┳━━━┓\n\
┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃ 4 ┃\n\
@ -28,22 +41,19 @@ fn data_and_header_has_different_size() {
┃ 0 ┃ 1 ┃ 2 ┃ ┃ ┃\n\
┗━━━┻━━━┻━━━┻━━━┻━━━┛";
assert_eq!(
draw_table(&table, usize::MAX, &Config::default()).as_deref(),
Some(expected)
);
assert_eq!(table.as_deref(), Some(expected));
}
#[test]
fn termwidth_too_small() {
let table = Table::new(row(3), vec![row(5); 2], theme::heavy());
let cfg = Config::default();
for i in 0..10 {
assert!(draw_table(&table, i, &cfg).is_none());
let table = Table::new(vec![row(3), row(3), row(5)], (3, 5), i, true, false);
assert!(draw_table(table, i, &cfg).is_none());
}
assert!(draw_table(&table, 11, &cfg).is_some());
let table = Table::new(vec![row(3), row(3), row(5)], (3, 5), 11, true, false);
assert!(draw_table(table, 11, &cfg).is_some());
let cfg = Config {
trim_strategy: TrimStrategy::Truncate { suffix: None },
@ -51,10 +61,12 @@ fn termwidth_too_small() {
};
for i in 0..10 {
assert!(draw_table(&table, i, &cfg).is_none());
let table = Table::new(vec![row(3), row(3), row(5)], (3, 5), i, true, false);
assert!(draw_table(table, i, &cfg).is_none());
}
assert!(draw_table(&table, 11, &cfg).is_some());
let table = Table::new(vec![row(3), row(3), row(5)], (3, 5), 11, true, false);
assert!(draw_table(table, 11, &cfg).is_some());
}
#[test]
@ -65,23 +77,22 @@ fn wrap_test() {
},
..Default::default()
};
let table = table_with_data();
for i in 0..10 {
assert!(draw_table(&table, i, &cfg).is_none());
assert!(draw_table(table_with_data(i), i, &cfg).is_none());
}
assert_eq!(draw_table(&table, 10, &cfg).unwrap(), "┏━━━━┳━━━┓\n┃ 12 ┃ . ┃\n┃ 3 ┃ . ┃\n┃ 45 ┃ . ┃\n┃ 67 ┃ ┃\n 8 ┃ ┃\n┣━━━━╋━━━┫\n┃ 0 ┃ . ┃\n┃ ┃ . ┃\n┃ ┃ . ┃\n┃ 0 ┃ . ┃\n┃ ┃ . ┃\n┃ ┃ . ┃\n┗━━━━┻━━━┛");
assert_eq!(draw_table(table_with_data(10), 10, &cfg).unwrap(), "┏━━━━┳━━━┓\n┃ 12 ┃ . ┃\n┃ 3 ┃ . ┃\n┃ 45 ┃ . ┃\n┃ 67 ┃ ┃\n┃ 8 ┃ ┃\n┣━━━━╋━━━┫\n┃ 0 ┃ . ┃\n┃ ┃ . ┃\n┃ ┃ . ┃\n┃ 0 ┃ . ┃\n┃ ┃ . ┃\n┃ ┃ . ┃\n┗━━━━┻━━━┛");
assert_eq!(
draw_table(&table, 21, &cfg).unwrap(),
draw_table(table_with_data(21), 21, &cfg).unwrap(),
"┏━━━━━━┳━━━━━━┳━━━━━┓\n┃ 123 ┃ qweq ┃ ... ┃\n┃ 4567 ┃ w eq ┃ ┃\n┃ 8 ┃ we ┃ ┃\n┣━━━━━━╋━━━━━━╋━━━━━┫\n┃ 0 ┃ 1 ┃ ... ┃\n┃ 0 ┃ 1 ┃ ... ┃\n┗━━━━━━┻━━━━━━┻━━━━━┛"
);
assert_eq!(
draw_table(&table, 29, &cfg).unwrap(),
draw_table(table_with_data(29), 29, &cfg).unwrap(),
"┏━━━━━━━━━━┳━━━━━━━━━━┳━━━━━┓\n┃ 123 4567 ┃ qweqw eq ┃ ... ┃\n┃ 8 ┃ we ┃ ┃\n┣━━━━━━━━━━╋━━━━━━━━━━╋━━━━━┫\n┃ 0 ┃ 1 ┃ ... ┃\n┃ 0 ┃ 1 ┃ ... ┃\n┗━━━━━━━━━━┻━━━━━━━━━━┻━━━━━┛"
);
assert_eq!(
draw_table(&table, 49, &cfg).unwrap(),
draw_table(table_with_data(49), 49, &cfg).unwrap(),
"┏━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━┓\n┃ 123 4567 ┃ qweqw eq ┃ xxx xx ┃ qqq qqq ┃ ... ┃\n┃ 8 ┃ we ┃ xx x xx ┃ qqqq q ┃ ┃\n┃ ┃ ┃ x xx x ┃ qq qq ┃ ┃\n┃ ┃ ┃ x ┃ ┃ ┃\n┣━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━╋━━━━━┫\n┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃ ... ┃\n┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃ ... ┃\n┗━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━┻━━━━━┛"
);
}
@ -94,24 +105,23 @@ fn wrap_keep_words_test() {
},
..Default::default()
};
let table = table_with_data();
for i in 0..10 {
assert!(draw_table(&table, i, &cfg).is_none());
assert!(draw_table(table_with_data(i), i, &cfg).is_none());
}
assert_eq!(draw_table(&table, 10, &cfg).unwrap(), "┏━━━━┳━━━┓\n┃ 12 ┃ . ┃\n┃ 34 ┃ . ┃\n┃ 56 ┃ . ┃\n78 ┃ ┃\n┣━━━━╋━━━┫\n┃ 0 ┃ . ┃\n┃ ┃ . ┃\n┃ ┃ . ┃\n┃ 0 ┃ . ┃\n┃ ┃ . ┃\n┃ ┃ . ┃\n┗━━━━┻━━━┛");
assert_eq!(draw_table(table_with_data(10), 10, &cfg).unwrap(), "┏━━━━┳━━━┓\n┃ 12 ┃ . ┃\n┃ 3 ┃ . ┃\n45 ┃ . ┃\n67 ┃ ┃\n┃ 8 ┃ ┃\n┣━━━━╋━━━┫\n┃ 0 ┃ . ┃\n┃ ┃ . ┃\n┃ ┃ . ┃\n┃ 0 ┃ . ┃\n┃ ┃ . ┃\n┃ ┃ . ┃\n┗━━━━┻━━━┛");
assert_eq!(
draw_table(&table, 21, &cfg).unwrap(),
draw_table(table_with_data(21), 21, &cfg).unwrap(),
"┏━━━━━━┳━━━━━━┳━━━━━┓\n┃ 123 ┃ qweq ┃ ... ┃\n┃ 4567 ┃ w ┃ ┃\n┃ 8 ┃ eqwe ┃ ┃\n┣━━━━━━╋━━━━━━╋━━━━━┫\n┃ 0 ┃ 1 ┃ ... ┃\n┃ 0 ┃ 1 ┃ ... ┃\n┗━━━━━━┻━━━━━━┻━━━━━┛"
);
assert_eq!(
draw_table(&table, 29, &cfg).unwrap(),
draw_table(table_with_data(29), 29, &cfg).unwrap(),
"┏━━━━━━━━━━┳━━━━━━━━━━┳━━━━━┓\n┃ 123 ┃ qweqw ┃ ... ┃\n┃ 45678 ┃ eqwe ┃ ┃\n┣━━━━━━━━━━╋━━━━━━━━━━╋━━━━━┫\n┃ 0 ┃ 1 ┃ ... ┃\n┃ 0 ┃ 1 ┃ ... ┃\n┗━━━━━━━━━━┻━━━━━━━━━━┻━━━━━┛"
);
assert_eq!(
draw_table(&table, 49, &cfg).unwrap(),
"┏━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━┓\n┃ 123 ┃ qweqw ┃ xxx xx ┃ qqq qqq ┃ ... ┃\n┃ 45678 ┃ eqwe ┃ xx x xx ┃ qqqq ┃ ┃\n┃ ┃ ┃ x xx xx ┃ qqq qq ┃ ┃\n┣━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━╋━━━━━┫\n┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃ ... ┃\n┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃ ... ┃\n┗━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━┻━━━━━┛"
draw_table(table_with_data(49), 49, &cfg).unwrap(),
"┏━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━┓\n 123 ┃ qweqw ┃ xxx xx ┃ qqq qqq ┃ ... ┃\n┃ 45678 ┃ eqwe ┃ xx x xx ┃ qqqq ┃ ┃\n┃ ┃ ┃ x xx ┃ qqq qq ┃\n┃ ┃ ┃ xx ┃ ┃\n┣━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━╋━━━━━┫\n┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃ ... ┃\n┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃ ... ┃\n┗━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━┻━━━━━┛"
);
}
@ -121,26 +131,25 @@ fn truncate_test() {
trim_strategy: TrimStrategy::Truncate { suffix: None },
..Default::default()
};
let table = table_with_data();
for i in 0..10 {
assert!(draw_table(&table, i, &cfg).is_none());
assert!(draw_table(table_with_data(i), i, &cfg).is_none());
}
assert_eq!(
draw_table(&table, 10, &cfg).unwrap(),
draw_table(table_with_data(10), 10, &cfg).unwrap(),
"┏━━━━┳━━━┓\n┃ 12 ┃ . ┃\n┣━━━━╋━━━┫\n┃ 0 ┃ . ┃\n┃ 0 ┃ . ┃\n┗━━━━┻━━━┛"
);
assert_eq!(
draw_table(&table, 21, &cfg).unwrap(),
draw_table(table_with_data(21), 21, &cfg).unwrap(),
"┏━━━━━━┳━━━━━━┳━━━━━┓\n┃ 123 ┃ qweq ┃ ... ┃\n┣━━━━━━╋━━━━━━╋━━━━━┫\n┃ 0 ┃ 1 ┃ ... ┃\n┃ 0 ┃ 1 ┃ ... ┃\n┗━━━━━━┻━━━━━━┻━━━━━┛"
);
assert_eq!(
draw_table(&table, 29, &cfg).unwrap(),
draw_table(table_with_data(29), 29, &cfg).unwrap(),
"┏━━━━━━━━━━┳━━━━━━━━━━┳━━━━━┓\n┃ 123 4567 ┃ qweqw eq ┃ ... ┃\n┣━━━━━━━━━━╋━━━━━━━━━━╋━━━━━┫\n┃ 0 ┃ 1 ┃ ... ┃\n┃ 0 ┃ 1 ┃ ... ┃\n┗━━━━━━━━━━┻━━━━━━━━━━┻━━━━━┛"
);
assert_eq!(
draw_table(&table, 49, &cfg).unwrap(),
draw_table(table_with_data(49), 49, &cfg).unwrap(),
"┏━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━┓\n┃ 123 4567 ┃ qweqw eq ┃ xxx xx ┃ qqq qqq ┃ ... ┃\n┣━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━╋━━━━━┫\n┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃ ... ┃\n┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃ ... ┃\n┗━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━┻━━━━━┛"
);
}
@ -153,60 +162,58 @@ fn truncate_with_suffix_test() {
},
..Default::default()
};
let table = table_with_data();
for i in 0..10 {
assert!(draw_table(&table, i, &cfg).is_none());
assert!(draw_table(table_with_data(i), i, &cfg).is_none());
}
assert_eq!(
draw_table(&table, 10, &cfg).unwrap(),
draw_table(table_with_data(10), 10, &cfg).unwrap(),
"┏━━━━┳━━━┓\n┃ .. ┃ . ┃\n┣━━━━╋━━━┫\n┃ 0 ┃ . ┃\n┃ 0 ┃ . ┃\n┗━━━━┻━━━┛"
);
assert_eq!(
draw_table(&table, 21, &cfg).unwrap(),
draw_table(table_with_data(21), 21, &cfg).unwrap(),
"┏━━━━━━┳━━━━━━┳━━━━━┓\n┃ 1... ┃ q... ┃ ... ┃\n┣━━━━━━╋━━━━━━╋━━━━━┫\n┃ 0 ┃ 1 ┃ ... ┃\n┃ 0 ┃ 1 ┃ ... ┃\n┗━━━━━━┻━━━━━━┻━━━━━┛"
);
assert_eq!(
draw_table(&table, 29, &cfg).unwrap(),
draw_table(table_with_data(29), 29, &cfg).unwrap(),
"┏━━━━━━━━━━┳━━━━━━━━━━┳━━━━━┓\n┃ 123 4... ┃ qweqw... ┃ ... ┃\n┣━━━━━━━━━━╋━━━━━━━━━━╋━━━━━┫\n┃ 0 ┃ 1 ┃ ... ┃\n┃ 0 ┃ 1 ┃ ... ┃\n┗━━━━━━━━━━┻━━━━━━━━━━┻━━━━━┛"
);
assert_eq!(
draw_table(&table, 49, &cfg).unwrap(),
draw_table(table_with_data(49), 49, &cfg).unwrap(),
"┏━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━┓\n┃ 123 4... ┃ qweqw... ┃ xxx ... ┃ qqq ... ┃ ... ┃\n┣━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━╋━━━━━┫\n┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃ ... ┃\n┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃ ... ┃\n┗━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━┻━━━━━┛"
);
}
fn draw_table(table: &Table, limit: usize, cfg: &Config) -> Option<String> {
fn draw_table(table: Table, limit: usize, cfg: &Config) -> Option<String> {
let styles = HashMap::default();
let alignments = Alignments::default();
table.draw_table(cfg, &styles, alignments, limit)
table.draw_table(cfg, &styles, alignments, &theme::heavy(), limit)
}
fn row(count_columns: usize) -> Vec<StyledString> {
fn row(count_columns: usize) -> Vec<TCell<CellInfo<'static>, TextStyle>> {
let mut row = Vec::with_capacity(count_columns);
for i in 0..count_columns {
row.push(StyledString::new(i.to_string(), TextStyle::default()));
row.push(Table::create_cell(i.to_string(), TextStyle::default()));
}
row
}
fn styled_str(s: &str) -> StyledString {
StyledString::new(s.to_string(), TextStyle::default())
fn styled_str(s: &str) -> TCell<CellInfo<'static>, TextStyle> {
Table::create_cell(s.to_string(), TextStyle::default())
}
fn table_with_data() -> Table {
Table::new(
vec![
fn table_with_data(termwidth: usize) -> Table {
let header = vec![
styled_str("123 45678"),
styled_str("qweqw eqwe"),
styled_str("xxx xx xx x xx x xx xx"),
styled_str("qqq qqq qqqq qqq qq"),
styled_str("qw"),
],
vec![row(5); 2],
theme::heavy(),
)
];
let data = vec![header, row(5), row(5)];
Table::new(data, (3, 5), termwidth, true, false)
}

View File

@ -1,12 +1,13 @@
use std::collections::HashMap;
use nu_protocol::Config;
use nu_table::{Alignments, StyledString, Table, TableTheme as theme, TextStyle};
use nu_table::{Alignments, Table, TableTheme as theme, TextStyle};
use tabled::papergrid::records::{cell_info::CellInfo, tcell::TCell};
#[test]
fn test_rounded() {
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 2], theme::rounded())),
draw_table(vec![row(4); 3], 4, true, theme::rounded()),
"╭───┬───┬───┬───╮\n\
│ 0 │ 1 │ 2 │ 3 │\n\
├───┼───┼───┼───┤\n\
@ -16,7 +17,7 @@ fn test_rounded() {
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 1], theme::rounded())),
draw_table(vec![row(4); 2], 4, true, theme::rounded()),
"╭───┬───┬───┬───╮\n\
│ 0 │ 1 │ 2 │ 3 │\n\
├───┼───┼───┼───┤\n\
@ -25,30 +26,34 @@ fn test_rounded() {
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 0], theme::rounded())),
draw_table(vec![row(4); 1], 4, true, theme::rounded()),
"╭───┬───┬───┬───╮\n\
│ 0 │ 1 │ 2 │ 3 │\n\
╰───┴───┴───┴───╯"
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(4); 2], theme::rounded())),
draw_table(vec![row(4); 1], 4, false, theme::rounded()),
"╭───┬───┬───┬───╮\n\
│ 0 │ 1 │ 2 │ 3 │\n\
╰───┴───┴───┴───╯"
);
assert_eq!(
draw_table(vec![row(4); 2], 4, false, theme::rounded()),
"╭───┬───┬───┬───╮\n\
│ 0 │ 1 │ 2 │ 3 │\n\
│ 0 │ 1 │ 2 │ 3 │\n\
╰───┴───┴───┴───╯"
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(0); 0], theme::rounded())),
""
);
assert_eq!(draw_table(vec![row(4); 0], 4, false, theme::rounded()), "");
}
#[test]
fn test_basic() {
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 2], theme::basic())),
draw_table(vec![row(4); 3], 4, true, theme::basic()),
"+---+---+---+---+\n\
| 0 | 1 | 2 | 3 |\n\
+---+---+---+---+\n\
@ -59,7 +64,7 @@ fn test_basic() {
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 1], theme::basic())),
draw_table(vec![row(4); 2], 4, true, theme::basic()),
"+---+---+---+---+\n\
| 0 | 1 | 2 | 3 |\n\
+---+---+---+---+\n\
@ -68,14 +73,21 @@ fn test_basic() {
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 0], theme::basic())),
draw_table(vec![row(4); 1], 4, true, theme::basic()),
"+---+---+---+---+\n\
| 0 | 1 | 2 | 3 |\n\
+---+---+---+---+"
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(4); 2], theme::basic())),
draw_table(vec![row(4); 1], 4, false, theme::basic()),
"+---+---+---+---+\n\
| 0 | 1 | 2 | 3 |\n\
+---+---+---+---+"
);
assert_eq!(
draw_table(vec![row(4); 2], 4, false, theme::basic()),
"+---+---+---+---+\n\
| 0 | 1 | 2 | 3 |\n\
+---+---+---+---+\n\
@ -83,16 +95,13 @@ fn test_basic() {
+---+---+---+---+"
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(0); 0], theme::basic())),
""
);
assert_eq!(draw_table(vec![row(4); 0], 4, false, theme::basic()), "");
}
#[test]
fn test_reinforced() {
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 2], theme::reinforced())),
draw_table(vec![row(4); 3], 4, true, theme::reinforced()),
"┏───┬───┬───┬───┓\n\
│ 0 │ 1 │ 2 │ 3 │\n\
│ 0 │ 1 │ 2 │ 3 │\n\
@ -101,7 +110,7 @@ fn test_reinforced() {
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 1], theme::reinforced())),
draw_table(vec![row(4); 2], 4, true, theme::reinforced()),
"┏───┬───┬───┬───┓\n\
│ 0 │ 1 │ 2 │ 3 │\n\
│ 0 │ 1 │ 2 │ 3 │\n\
@ -109,14 +118,21 @@ fn test_reinforced() {
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 0], theme::reinforced())),
draw_table(vec![row(4); 1], 4, true, theme::reinforced()),
"┏───┬───┬───┬───┓\n\
│ 0 │ 1 │ 2 │ 3 │\n\
┗───┴───┴───┴───┛"
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(4); 2], theme::reinforced())),
draw_table(vec![row(4); 1], 4, false, theme::reinforced()),
"┏───┬───┬───┬───┓\n\
│ 0 │ 1 │ 2 │ 3 │\n\
┗───┴───┴───┴───┛"
);
assert_eq!(
draw_table(vec![row(4); 2], 4, false, theme::reinforced()),
"┏───┬───┬───┬───┓\n\
│ 0 │ 1 │ 2 │ 3 │\n\
│ 0 │ 1 │ 2 │ 3 │\n\
@ -124,7 +140,7 @@ fn test_reinforced() {
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(0); 0], theme::reinforced())),
draw_table(vec![row(4); 0], 2, false, theme::reinforced()),
""
);
}
@ -132,7 +148,7 @@ fn test_reinforced() {
#[test]
fn test_compact() {
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 2], theme::compact())),
draw_table(vec![row(4); 3], 4, true, theme::compact()),
concat!(
"───┬───┬───┬───\n",
" 0 │ 1 │ 2 │ 3 \n",
@ -144,7 +160,7 @@ fn test_compact() {
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 1], theme::compact())),
draw_table(vec![row(4); 2], 4, true, theme::compact()),
concat!(
"───┬───┬───┬───\n",
" 0 │ 1 │ 2 │ 3 \n",
@ -155,12 +171,17 @@ fn test_compact() {
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 0], theme::compact())),
draw_table(vec![row(4); 1], 4, true, theme::compact()),
concat!("───┬───┬───┬───\n", " 0 │ 1 │ 2 │ 3 \n", "───┴───┴───┴───",)
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(4); 2], theme::compact())),
draw_table(vec![row(4); 1], 4, false, theme::compact()),
concat!("───┬───┬───┬───\n", " 0 │ 1 │ 2 │ 3 \n", "───┴───┴───┴───",)
);
assert_eq!(
draw_table(vec![row(4); 2], 4, false, theme::compact()),
concat!(
"───┬───┬───┬───\n",
" 0 │ 1 │ 2 │ 3 \n",
@ -169,20 +190,13 @@ fn test_compact() {
)
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(0); 0], theme::compact())),
""
);
assert_eq!(draw_table(vec![row(4); 0], 4, false, theme::compact()), "");
}
#[test]
fn test_compact_double() {
assert_eq!(
draw_table(&Table::new(
row(4),
vec![row(4); 2],
theme::compact_double()
)),
draw_table(vec![row(4); 3], 4, true, theme::compact_double()),
concat!(
"═══╦═══╦═══╦═══\n",
" 0 ║ 1 ║ 2 ║ 3 \n",
@ -194,11 +208,7 @@ fn test_compact_double() {
);
assert_eq!(
draw_table(&Table::new(
row(4),
vec![row(4); 1],
theme::compact_double()
)),
draw_table(vec![row(4); 2], 4, true, theme::compact_double()),
concat!(
"═══╦═══╦═══╦═══\n",
" 0 ║ 1 ║ 2 ║ 3 \n",
@ -209,20 +219,17 @@ fn test_compact_double() {
);
assert_eq!(
draw_table(&Table::new(
row(4),
vec![row(4); 0],
theme::compact_double()
)),
draw_table(vec![row(4); 1], 4, true, theme::compact_double()),
concat!("═══╦═══╦═══╦═══\n", " 0 ║ 1 ║ 2 ║ 3 \n", "═══╩═══╩═══╩═══",)
);
assert_eq!(
draw_table(&Table::new(
row(0),
vec![row(4); 2],
theme::compact_double()
)),
draw_table(vec![row(4); 1], 4, false, theme::compact_double()),
concat!("═══╦═══╦═══╦═══\n", " 0 ║ 1 ║ 2 ║ 3 \n", "═══╩═══╩═══╩═══",)
);
assert_eq!(
draw_table(vec![row(4); 2], 4, false, theme::compact_double()),
concat!(
"═══╦═══╦═══╦═══\n",
" 0 ║ 1 ║ 2 ║ 3 \n",
@ -232,11 +239,7 @@ fn test_compact_double() {
);
assert_eq!(
draw_table(&Table::new(
row(0),
vec![row(0); 0],
theme::compact_double()
)),
draw_table(vec![row(4); 0], 4, false, theme::compact_double()),
""
);
}
@ -244,7 +247,7 @@ fn test_compact_double() {
#[test]
fn test_heavy() {
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 2], theme::heavy())),
draw_table(vec![row(4); 3], 4, true, theme::heavy()),
"┏━━━┳━━━┳━━━┳━━━┓\n\
┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃\n\
┣━━━╋━━━╋━━━╋━━━┫\n\
@ -254,7 +257,7 @@ fn test_heavy() {
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 1], theme::heavy())),
draw_table(vec![row(4); 2], 4, true, theme::heavy()),
"┏━━━┳━━━┳━━━┳━━━┓\n\
┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃\n\
┣━━━╋━━━╋━━━╋━━━┫\n\
@ -263,30 +266,34 @@ fn test_heavy() {
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 0], theme::heavy())),
draw_table(vec![row(4); 1], 4, true, theme::heavy()),
"┏━━━┳━━━┳━━━┳━━━┓\n\
┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃\n\
┗━━━┻━━━┻━━━┻━━━┛"
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(4); 2], theme::heavy())),
draw_table(vec![row(4); 1], 4, false, theme::heavy()),
"┏━━━┳━━━┳━━━┳━━━┓\n\
┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃\n\
┗━━━┻━━━┻━━━┻━━━┛"
);
assert_eq!(
draw_table(vec![row(4); 2], 4, false, theme::heavy()),
"┏━━━┳━━━┳━━━┳━━━┓\n\
┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃\n\
┃ 0 ┃ 1 ┃ 2 ┃ 3 ┃\n\
┗━━━┻━━━┻━━━┻━━━┛"
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(0); 0], theme::heavy())),
""
);
assert_eq!(draw_table(vec![row(4); 0], 4, false, theme::heavy()), "");
}
#[test]
fn test_light() {
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 2], theme::light())),
draw_table(vec![row(4); 3], 4, true, theme::light()),
concat!(
" 0 1 2 3 \n",
"───────────────\n",
@ -296,58 +303,62 @@ fn test_light() {
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 1], theme::light())),
draw_table(vec![row(4); 2], 4, true, theme::light()),
concat!(" 0 1 2 3 \n", "───────────────\n", " 0 1 2 3 ")
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 0], theme::light())),
draw_table(vec![row(4); 1], 4, true, theme::light()),
concat!(" 0 1 2 3 ")
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(4); 2], theme::light())),
concat!(" 0 1 2 3 \n", " 0 1 2 3 ")
draw_table(vec![row(4); 1], 4, false, theme::light()),
concat!(" 0 1 2 3 ")
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(0); 0], theme::light())),
""
draw_table(vec![row(4); 2], 4, false, theme::light()),
concat!(" 0 1 2 3 \n", " 0 1 2 3 ")
);
assert_eq!(draw_table(vec![row(4); 0], 4, true, theme::light()), "");
}
#[test]
fn test_none() {
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 2], theme::none())),
draw_table(vec![row(4); 3], 4, true, theme::none()),
concat!(" 0 1 2 3 \n", " 0 1 2 3 \n", " 0 1 2 3 ")
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 1], theme::none())),
draw_table(vec![row(4); 2], 4, true, theme::none()),
concat!(" 0 1 2 3 \n", " 0 1 2 3 ")
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 0], theme::none())),
draw_table(vec![row(4); 1], 4, true, theme::none()),
concat!(" 0 1 2 3 ")
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(4); 2], theme::none())),
concat!(" 0 1 2 3 \n", " 0 1 2 3 ")
draw_table(vec![row(4); 1], 4, false, theme::none()),
concat!(" 0 1 2 3 ")
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(0); 0], theme::none())),
""
draw_table(vec![row(4); 2], 4, true, theme::none()),
concat!(" 0 1 2 3 \n", " 0 1 2 3 ")
);
assert_eq!(draw_table(vec![row(4); 0], 4, true, theme::none()), "");
}
#[test]
fn test_thin() {
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 2], theme::thin())),
draw_table(vec![row(4); 3], 4, true, theme::thin()),
"┌───┬───┬───┬───┐\n\
│ 0 │ 1 │ 2 │ 3 │\n\
├───┼───┼───┼───┤\n\
@ -358,7 +369,7 @@ fn test_thin() {
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 1], theme::thin())),
draw_table(vec![row(4); 2], 4, true, theme::thin()),
"┌───┬───┬───┬───┐\n\
│ 0 │ 1 │ 2 │ 3 │\n\
├───┼───┼───┼───┤\n\
@ -367,14 +378,21 @@ fn test_thin() {
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 0], theme::thin())),
draw_table(vec![row(4); 1], 4, true, theme::thin()),
"┌───┬───┬───┬───┐\n\
│ 0 │ 1 │ 2 │ 3 │\n\
└───┴───┴───┴───┘"
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(4); 2], theme::thin())),
draw_table(vec![row(4); 1], 4, false, theme::thin()),
"┌───┬───┬───┬───┐\n\
│ 0 │ 1 │ 2 │ 3 │\n\
└───┴───┴───┴───┘"
);
assert_eq!(
draw_table(vec![row(4); 2], 4, false, theme::thin()),
"┌───┬───┬───┬───┐\n\
│ 0 │ 1 │ 2 │ 3 │\n\
├───┼───┼───┼───┤\n\
@ -382,16 +400,13 @@ fn test_thin() {
└───┴───┴───┴───┘"
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(0); 0], theme::thin())),
""
);
assert_eq!(draw_table(vec![row(4); 0], 4, true, theme::thin()), "");
}
#[test]
fn test_with_love() {
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 2], theme::with_love())),
draw_table(vec![row(4); 3], 4, true, theme::with_love()),
concat!(
"❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤\n",
" 0 ❤ 1 ❤ 2 ❤ 3 \n",
@ -403,7 +418,7 @@ fn test_with_love() {
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 1], theme::with_love())),
draw_table(vec![row(4); 2], 4, true, theme::with_love()),
concat!(
"❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤\n",
" 0 ❤ 1 ❤ 2 ❤ 3 \n",
@ -414,12 +429,17 @@ fn test_with_love() {
);
assert_eq!(
draw_table(&Table::new(row(4), vec![row(4); 0], theme::with_love())),
draw_table(vec![row(4); 1], 4, true, theme::with_love()),
concat!("❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤\n", " 0 ❤ 1 ❤ 2 ❤ 3 \n", "❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤",)
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(4); 2], theme::with_love())),
draw_table(vec![row(4); 1], 4, false, theme::with_love()),
concat!("❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤\n", " 0 ❤ 1 ❤ 2 ❤ 3 \n", "❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤",)
);
assert_eq!(
draw_table(vec![row(4); 2], 4, false, theme::with_love()),
concat!(
"❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤\n",
" 0 ❤ 1 ❤ 2 ❤ 3 \n",
@ -428,26 +448,31 @@ fn test_with_love() {
)
);
assert_eq!(
draw_table(&Table::new(row(0), vec![row(0); 0], theme::with_love())),
""
);
assert_eq!(draw_table(vec![row(4); 0], 4, true, theme::with_love()), "");
}
fn draw_table(table: &Table) -> String {
fn draw_table(
data: Vec<Vec<TCell<CellInfo<'static>, TextStyle>>>,
count_columns: usize,
with_header: bool,
theme: theme,
) -> String {
let size = (data.len(), count_columns);
let table = Table::new(data, size, usize::MAX, with_header, false);
let cfg = Config::default();
let styles = HashMap::default();
let alignments = Alignments::default();
table
.draw_table(&cfg, &styles, alignments, std::usize::MAX)
.draw_table(&cfg, &styles, alignments, &theme, std::usize::MAX)
.expect("Unexpectdly got no table")
}
fn row(count_columns: usize) -> Vec<StyledString> {
fn row(count_columns: usize) -> Vec<TCell<CellInfo<'static>, TextStyle>> {
let mut row = Vec::with_capacity(count_columns);
for i in 0..count_columns {
row.push(StyledString::new(i.to_string(), TextStyle::default()));
row.push(Table::create_cell(i.to_string(), TextStyle::default()));
}
row

7
out.log Normal file

File diff suppressed because one or more lines are too long