nu-commands/table (table -e) Recognize limited space better (#7861)

fix #7858

Once again we here 😞 

~~I am thinking is there some files with not flat structure we could use
to test table -e?
I mean it is clear it was a while ago were we had to create at least
some tests.
Do you have anything in mind (or maybe commands which is consistent
across systems)?~~

Take care

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
This commit is contained in:
Maxim Zhiburt 2023-01-26 23:06:17 +03:00 committed by GitHub
parent 9d6d43ee55
commit 731f5f8523
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 978 additions and 117 deletions

View File

@ -458,25 +458,16 @@ fn build_expanded_table(
) -> Result<Option<String>, ShellError> { ) -> Result<Option<String>, ShellError> {
let theme = load_theme_from_config(config); let theme = load_theme_from_config(config);
// calculate the width of a key part + the rest of table so we know the rest of the table width available for value.
let key_width = cols.iter().map(|col| string_width(col)).max().unwrap_or(0); let key_width = cols.iter().map(|col| string_width(col)).max().unwrap_or(0);
let key = NuTable::create_cell(" ".repeat(key_width), TextStyle::default());
let key_table = NuTable::new(vec![vec![key]], (1, 2));
let key_width = key_table
.draw(
create_table_config(config, style_computer, 1, false, false, false),
usize::MAX,
)
.map(|table| string_width(&table))
.unwrap_or(0);
// 3 - count borders (left, center, right) let count_borders =
// 2 - padding theme.has_inner() as usize + theme.has_right() as usize + theme.has_left() as usize;
if key_width + 3 + 2 > term_width { let padding = 2;
if key_width + count_borders + padding + padding > term_width {
return Ok(None); return Ok(None);
} }
let remaining_width = term_width - key_width - 3 - 2; let value_width = term_width - key_width - count_borders - padding - padding;
let mut data = Vec::with_capacity(cols.len()); let mut data = Vec::with_capacity(cols.len());
for (key, value) in cols.into_iter().zip(vals) { for (key, value) in cols.into_iter().zip(vals) {
@ -503,14 +494,11 @@ fn build_expanded_table(
deep, deep,
flatten, flatten,
flatten_sep, flatten_sep,
remaining_width, value_width,
)?; )?;
match table { match table {
Some((mut table, with_header, with_index)) => { Some((table, with_header, with_index)) => {
// control width via removing table columns.
table.truncate(remaining_width, &theme);
is_expanded = true; is_expanded = true;
let table_config = create_table_config( let table_config = create_table_config(
@ -522,7 +510,7 @@ fn build_expanded_table(
false, false,
); );
let val = table.draw(table_config, remaining_width); let val = table.draw(table_config, value_width);
match val { match val {
Some(result) => result, Some(result) => result,
None => return Ok(None), None => return Ok(None),
@ -531,7 +519,8 @@ fn build_expanded_table(
None => { None => {
// it means that the list is empty // it means that the list is empty
let value = Value::List { vals, span }; let value = Value::List { vals, span };
value_to_styled_string(&value, config, style_computer).0 let text = value_to_styled_string(&value, config, style_computer).0;
wrap_text(&text, value_width, config)
} }
} }
} }
@ -543,7 +532,7 @@ fn build_expanded_table(
ctrlc.clone(), ctrlc.clone(),
config, config,
style_computer, style_computer,
remaining_width, value_width,
deep, deep,
flatten, flatten,
flatten_sep, flatten_sep,
@ -561,13 +550,13 @@ fn build_expanded_table(
style_computer, style_computer,
); );
wrap_text(&failed_value.0, remaining_width, config) wrap_text(&failed_value.0, value_width, config)
} }
} }
} }
val => { val => {
let text = value_to_styled_string(&val, config, style_computer).0; let text = value_to_styled_string(&val, config, style_computer).0;
wrap_text(&text, remaining_width, config) wrap_text(&text, value_width, config)
} }
} }
}; };
@ -974,7 +963,8 @@ fn convert_to_table2<'a>(
const SPLIT_LINE_SPACE: usize = 1; const SPLIT_LINE_SPACE: usize = 1;
const ADDITIONAL_CELL_SPACE: usize = PADDING_SPACE + SPLIT_LINE_SPACE; const ADDITIONAL_CELL_SPACE: usize = PADDING_SPACE + SPLIT_LINE_SPACE;
const MIN_CELL_CONTENT_WIDTH: usize = 1; const MIN_CELL_CONTENT_WIDTH: usize = 1;
const TRUNCATE_CELL_WIDTH: usize = 3 + PADDING_SPACE; const TRUNCATE_CONTENT_WIDTH: usize = 3;
const TRUNCATE_CELL_WIDTH: usize = TRUNCATE_CONTENT_WIDTH + PADDING_SPACE;
if input.len() == 0 { if input.len() == 0 {
return Ok(None); return Ok(None);
@ -1009,8 +999,6 @@ fn convert_to_table2<'a>(
}; };
if with_index { if with_index {
let mut column_width = 0;
if with_header { if with_header {
data[0].push(NuTable::create_cell( data[0].push(NuTable::create_cell(
"#", "#",
@ -1018,6 +1006,7 @@ fn convert_to_table2<'a>(
)); ));
} }
let mut last_index = 0;
for (row, item) in input.clone().into_iter().enumerate() { for (row, item) in input.clone().into_iter().enumerate() {
if nu_utils::ctrl_c::was_pressed(&ctrlc) { if nu_utils::ctrl_c::was_pressed(&ctrlc) {
return Ok(None); return Ok(None);
@ -1031,18 +1020,18 @@ fn convert_to_table2<'a>(
let text = matches!(item, Value::Record { .. }) let text = matches!(item, Value::Record { .. })
.then(|| lookup_index_value(item, config).unwrap_or_else(|| index.to_string())) .then(|| lookup_index_value(item, config).unwrap_or_else(|| index.to_string()))
.unwrap_or_else(|| index.to_string()); .unwrap_or_else(|| index.to_string());
let value = make_index_string(text, style_computer); let value = make_index_string(text, style_computer);
let width = string_width(&value.0);
column_width = max(column_width, width);
let value = NuTable::create_cell(value.0, value.1); let value = NuTable::create_cell(value.0, value.1);
let row = if with_header { row + 1 } else { row }; let row = if with_header { row + 1 } else { row };
data[row].push(value); data[row].push(value);
last_index = index;
} }
let column_width = string_width(&last_index.to_string());
if column_width + ADDITIONAL_CELL_SPACE > available_width { if column_width + ADDITIONAL_CELL_SPACE > available_width {
available_width = 0; available_width = 0;
} else { } else {
@ -1087,34 +1076,64 @@ fn convert_to_table2<'a>(
return Ok(Some((table, with_header, with_index))); return Ok(Some((table, with_header, with_index)));
} }
let min_width = PADDING_SPACE + MIN_CELL_CONTENT_WIDTH; if !headers.is_empty() {
if available_width < min_width { let mut pad_space = PADDING_SPACE;
if headers.len() > 1 {
pad_space += SPLIT_LINE_SPACE;
}
if available_width < pad_space {
// there's no space for actual data so we don't return index if it's present.
// (also see the comment after the loop)
return Ok(None); return Ok(None);
} }
}
let count_columns = headers.len(); let count_columns = headers.len();
let mut widths = Vec::new(); let mut widths = Vec::new();
let mut truncate = false; let mut truncate = false;
let mut last_column_type_is_string = false; let mut rendered_column = 0;
let mut last_column_head_width = 0;
for (col, header) in headers.into_iter().enumerate() { for (col, header) in headers.into_iter().enumerate() {
let is_last_column = col + 1 == count_columns; let is_last_column = col + 1 == count_columns;
let mut necessary_space = PADDING_SPACE; let mut pad_space = PADDING_SPACE;
if !is_last_column { if !is_last_column {
necessary_space += SPLIT_LINE_SPACE; pad_space += SPLIT_LINE_SPACE;
} }
let available = available_width - necessary_space; let mut available = available_width - pad_space;
let mut column_width = string_width(&header); let mut column_width = string_width(&header);
last_column_head_width = column_width;
let headc = if !is_last_column {
// we need to make sure that we have a space for a next column if we use available width
// so we might need to decrease a bit it.
// we consider a header width be a minimum width
let pad_space = PADDING_SPACE + TRUNCATE_CONTENT_WIDTH;
if available > pad_space {
// In we have no space for a next column,
// We consider showing something better then nothing,
// So we try to decrease the width to show at least a truncution column
available -= pad_space;
} else {
truncate = true;
break;
}
if available < column_width {
truncate = true;
break;
}
}
let head_cell =
NuTable::create_cell(header.clone(), header_style(style_computer, header.clone())); NuTable::create_cell(header.clone(), header_style(style_computer, header.clone()));
data[0].push(headc); data[0].push(head_cell);
let mut is_string_column = true;
for (row, item) in input.clone().into_iter().enumerate() { for (row, item) in input.clone().into_iter().enumerate() {
if nu_utils::ctrl_c::was_pressed(&ctrlc) { if nu_utils::ctrl_c::was_pressed(&ctrlc) {
return Ok(None); return Ok(None);
@ -1124,9 +1143,7 @@ fn convert_to_table2<'a>(
return Err(error.clone()); return Err(error.clone());
} }
is_string_column = is_string_column && is_string_value(item, &header); let mut value = create_table2_entry(
let value = create_table2_entry(
item, item,
header.as_str(), header.as_str(),
head, head,
@ -1139,7 +1156,16 @@ fn convert_to_table2<'a>(
available, available,
); );
let value_width = string_width(&value.0); let mut value_width = string_width(&value.0);
if value_width > available {
// it must only happen when a string is produced, so we can safely wrap it.
// (it might be string table representation as well)
value.0 = wrap_text(&value.0, available, config);
value_width = available;
}
column_width = max(column_width, value_width); column_width = max(column_width, value_width);
let value = NuTable::create_cell(value.0, value.1); let value = NuTable::create_cell(value.0, value.1);
@ -1147,67 +1173,35 @@ fn convert_to_table2<'a>(
data[row + 1].push(value); data[row + 1].push(value);
} }
last_column_type_is_string = is_string_column;
widths.push(column_width);
if column_width > available { if column_width > available {
truncate = true; // remove the column we just inserted
break;
}
if !is_last_column {
let is_next_last = col + 2 == count_columns;
let mut next_nessary_space = PADDING_SPACE;
if !is_next_last {
next_nessary_space += SPLIT_LINE_SPACE;
}
let has_space_for_next =
available_width > column_width + necessary_space + next_nessary_space;
if !has_space_for_next {
truncate = true;
break;
}
}
available_width -= necessary_space + column_width;
}
if truncate {
let is_last_column = widths.len() == count_columns;
let mut additional_space = PADDING_SPACE;
if !is_last_column {
additional_space += SPLIT_LINE_SPACE;
}
let mut truncate_cell_width = TRUNCATE_CELL_WIDTH;
if is_last_column {
truncate_cell_width = 0;
}
let can_be_wrapped =
available_width >= last_column_head_width + additional_space + truncate_cell_width;
if can_be_wrapped && last_column_type_is_string {
// we can wrap the last column instead of just dropping it.
let width = available_width - additional_space - truncate_cell_width;
available_width -= additional_space + width;
*widths.last_mut().expect("...") = width;
for row in &mut data {
let cell = row.last_mut().expect("...");
let value = wrap_text(cell.as_ref(), width, config);
*cell = NuTable::create_cell(value, *cell.get_data());
}
} else {
// we can't do anything about it so get back to dropping
widths.pop();
for row in &mut data { for row in &mut data {
row.pop(); row.pop();
} }
truncate = true;
break;
} }
widths.push(column_width);
available_width -= pad_space + column_width;
rendered_column += 1;
}
if truncate && rendered_column == 0 {
// it means that no actual data was rendered, there might be only index present,
// so there's no point in rendering the table.
//
// It's actually quite important in case it's called recursively,
// cause we will back up to the basic table view as a string e.g. '[table 123 columns]'.
//
// But potentially if its reached as a 1st called function we might would love to see the index.
return Ok(None);
}
if truncate {
if available_width < TRUNCATE_CELL_WIDTH { if available_width < TRUNCATE_CELL_WIDTH {
// back up by removing last column. // back up by removing last column.
// it's LIKELY that removing only 1 column will leave us enough space for a shift column. // it's LIKELY that removing only 1 column will leave us enough space for a shift column.
@ -1254,23 +1248,6 @@ fn convert_to_table2<'a>(
Ok(Some((table, with_header, with_index))) Ok(Some((table, with_header, with_index)))
} }
fn is_string_value(val: &Value, head: &str) -> bool {
match val {
Value::Record { .. } => {
let path = PathMember::String {
val: head.to_owned(),
span: Span::unknown(),
};
let val = val.clone().follow_cell_path(&[path], false, false);
!matches!(val, Ok(Value::Record { .. } | Value::List { .. }))
}
Value::List { .. } => false,
_ => true,
}
}
fn lookup_index_value(item: &Value, config: &Config) -> Option<String> { fn lookup_index_value(item: &Value, config: &Config) -> Option<String> {
item.get_data_by_key(INDEX_COLUMN_NAME) item.get_data_by_key(INDEX_COLUMN_NAME)
.map(|value| value.into_string("", config)) .map(|value| value.into_string("", config))

View File

@ -1,4 +1,6 @@
use nu_test_support::nu; use nu_test_support::fs::Stub::FileWithContent;
use nu_test_support::playground::Playground;
use nu_test_support::{nu, pipeline};
#[test] #[test]
fn table_0() { fn table_0() {
@ -217,3 +219,856 @@ fn table_index_0() {
"╭───┬───╮│ 0 │ 1 ││ 1 │ 3 ││ 2 │ 1 ││ 3 │ 3 ││ 4 │ 2 ││ 5 │ 1 ││ 6 │ 1 │╰───┴───╯" "╭───┬───╮│ 0 │ 1 ││ 1 │ 3 ││ 2 │ 1 ││ 3 │ 3 ││ 4 │ 2 ││ 5 │ 1 ││ 6 │ 1 │╰───┴───╯"
); );
} }
#[test]
fn test_expand_big_0() {
Playground::setup("test_expand_big_0", |dirs, sandbox| {
sandbox.with_files(vec![FileWithContent(
"sample.toml",
r#"
[package]
authors = ["The Nushell Project Developers"]
default-run = "nu"
description = "A new type of shell"
documentation = "https://www.nushell.sh/book/"
edition = "2021"
exclude = ["images"]
homepage = "https://www.nushell.sh"
license = "MIT"
name = "nu"
repository = "https://github.com/nushell/nushell"
rust-version = "1.60"
version = "0.74.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[package.metadata.binstall]
pkg-url = "{ repo }/releases/download/{ version }/{ name }-{ version }-{ target }.{ archive-format }"
pkg-fmt = "tgz"
[package.metadata.binstall.overrides.x86_64-pc-windows-msvc]
pkg-fmt = "zip"
[workspace]
members = [
"crates/nu-cli",
"crates/nu-engine",
"crates/nu-parser",
"crates/nu-system",
"crates/nu-command",
"crates/nu-protocol",
"crates/nu-plugin",
"crates/nu_plugin_inc",
"crates/nu_plugin_gstat",
"crates/nu_plugin_example",
"crates/nu_plugin_query",
"crates/nu_plugin_custom_values",
"crates/nu-utils",
]
[dependencies]
chrono = { version = "0.4.23", features = ["serde"] }
crossterm = "0.24.0"
ctrlc = "3.2.1"
log = "0.4"
miette = { version = "5.5.0", features = ["fancy-no-backtrace"] }
nu-ansi-term = "0.46.0"
nu-cli = { path = "./crates/nu-cli", version = "0.74.1" }
nu-engine = { path = "./crates/nu-engine", version = "0.74.1" }
reedline = { version = "0.14.0", features = ["bashisms", "sqlite"] }
rayon = "1.6.1"
is_executable = "1.0.1"
simplelog = "0.12.0"
time = "0.3.12"
[target.'cfg(not(target_os = "windows"))'.dependencies]
# Our dependencies don't use OpenSSL on Windows
openssl = { version = "0.10.38", features = ["vendored"], optional = true }
signal-hook = { version = "0.3.14", default-features = false }
[target.'cfg(windows)'.build-dependencies]
winres = "0.1"
[target.'cfg(target_family = "unix")'.dependencies]
nix = { version = "0.25", default-features = false, features = ["signal", "process", "fs", "term"] }
atty = "0.2"
[dev-dependencies]
nu-test-support = { path = "./crates/nu-test-support", version = "0.74.1" }
tempfile = "3.2.0"
assert_cmd = "2.0.2"
criterion = "0.4"
pretty_assertions = "1.0.0"
serial_test = "0.10.0"
hamcrest2 = "0.3.0"
rstest = { version = "0.15.0", default-features = false }
itertools = "0.10.3"
[features]
plugin = [
"nu-plugin",
"nu-cli/plugin",
"nu-parser/plugin",
"nu-command/plugin",
"nu-protocol/plugin",
"nu-engine/plugin",
]
# extra used to be more useful but now it's the same as default. Leaving it in for backcompat with existing build scripts
extra = ["default"]
default = ["plugin", "which-support", "trash-support", "sqlite"]
stable = ["default"]
wasi = []
# Enable to statically link OpenSSL; otherwise the system version will be used. Not enabled by default because it takes a while to build
static-link-openssl = ["dep:openssl"]
# Stable (Default)
which-support = ["nu-command/which-support"]
trash-support = ["nu-command/trash-support"]
# Main nu binary
[[bin]]
name = "nu"
path = "src/main.rs"
# To use a development version of a dependency please use a global override here
# changing versions in each sub-crate of the workspace is tedious
[patch.crates-io]
reedline = { git = "https://github.com/nushell/reedline.git", branch = "main" }
# Criterion benchmarking setup
# Run all benchmarks with `cargo bench`
# Run individual benchmarks like `cargo bench -- <regex>` e.g. `cargo bench -- parse`
[[bench]]
name = "benchmarks"
harness = false
"#,
)]);
let actual = nu!(
cwd: dirs.test(), pipeline(
"open sample.toml | table --expand"
));
_print_lines(&actual.out, 80);
let expected = join_lines([
"╭──────────────────┬───────────────────────────────────────────────────────────╮",
"│ │ ╭───┬─────────┬────────────╮ │",
"│ bench │ │ # │ harness │ name │ │",
"│ │ ├───┼─────────┼────────────┤ │",
"│ │ │ 0 │ false │ benchmarks │ │",
"│ │ ╰───┴─────────┴────────────╯ │",
"│ │ ╭───┬──────┬─────────────╮ │",
"│ bin │ │ # │ name │ path │ │",
"│ │ ├───┼──────┼─────────────┤ │",
"│ │ │ 0 │ nu │ src/main.rs │ │",
"│ │ ╰───┴──────┴─────────────╯ │",
"│ │ ╭───────────────┬───────────────────────────────────────╮ │",
"│ dependencies │ │ │ ╭──────────┬───────────────╮ │ │",
"│ │ │ chrono │ │ │ ╭───┬───────╮ │ │ │",
"│ │ │ │ │ features │ │ 0 │ serde │ │ │ │",
"│ │ │ │ │ │ ╰───┴───────╯ │ │ │",
"│ │ │ │ │ version │ 0.4.23 │ │ │",
"│ │ │ │ ╰──────────┴───────────────╯ │ │",
"│ │ │ crossterm │ 0.24.0 │ │",
"│ │ │ ctrlc │ 3.2.1 │ │",
"│ │ │ is_executable │ 1.0.1 │ │",
"│ │ │ log │ 0.4 │ │",
"│ │ │ │ ╭──────────┬────────────────────────╮ │ │",
"│ │ │ miette │ │ │ ╭───┬────────────────╮ │ │ │",
"│ │ │ │ │ features │ │ 0 │ fancy-no-backt │ │ │ │",
"│ │ │ │ │ │ │ │ race │ │ │ │",
"│ │ │ │ │ │ ╰───┴────────────────╯ │ │ │",
"│ │ │ │ │ version │ 5.5.0 │ │ │",
"│ │ │ │ ╰──────────┴────────────────────────╯ │ │",
"│ │ │ nu-ansi-term │ 0.46.0 │ │",
"│ │ │ │ ╭─────────┬─────────────────╮ │ │",
"│ │ │ nu-cli │ │ path │ ./crates/nu-cli │ │ │",
"│ │ │ │ │ version │ 0.74.1 │ │ │",
"│ │ │ │ ╰─────────┴─────────────────╯ │ │",
"│ │ │ │ ╭────────────┬──────────────────────╮ │ │",
"│ │ │ nu-engine │ │ path │ ./crates/nu-engine │ │ │",
"│ │ │ │ │ version │ 0.74.1 │ │ │",
"│ │ │ │ ╰────────────┴──────────────────────╯ │ │",
"│ │ │ rayon │ 1.6.1 │ │",
"│ │ │ │ ╭─────────────┬─────────────────────╮ │ │",
"│ │ │ reedline │ │ │ ╭───┬──────────╮ │ │ │",
"│ │ │ │ │ features │ │ 0 │ bashisms │ │ │ │",
"│ │ │ │ │ │ │ 1 │ sqlite │ │ │ │",
"│ │ │ │ │ │ ╰───┴──────────╯ │ │ │",
"│ │ │ │ │ version │ 0.14.0 │ │ │",
"│ │ │ │ ╰─────────────┴─────────────────────╯ │ │",
"│ │ │ simplelog │ 0.12.0 │ │",
"│ │ │ time │ 0.3.12 │ │",
"│ │ ╰───────────────┴───────────────────────────────────────╯ │",
"│ │ ╭───────────────────┬───────────────────────────────────╮ │",
"│ dev-dependencies │ │ assert_cmd │ 2.0.2 │ │",
"│ │ │ criterion │ 0.4 │ │",
"│ │ │ hamcrest2 │ 0.3.0 │ │",
"│ │ │ itertools │ 0.10.3 │ │",
"│ │ │ │ ╭─────────┬─────────────────────╮ │ │",
"│ │ │ nu-test-support │ │ path │ ./crates/nu-test-su │ │ │",
"│ │ │ │ │ │ pport │ │ │",
"│ │ │ │ │ version │ 0.74.1 │ │ │",
"│ │ │ │ ╰─────────┴─────────────────────╯ │ │",
"│ │ │ pretty_assertions │ 1.0.0 │ │",
"│ │ │ │ ╭────────────────────┬──────────╮ │ │",
"│ │ │ rstest │ │ default-features │ false │ │ │",
"│ │ │ │ │ version │ 0.15.0 │ │ │",
"│ │ │ │ ╰────────────────────┴──────────╯ │ │",
"│ │ │ serial_test │ 0.10.0 │ │",
"│ │ │ tempfile │ 3.2.0 │ │",
"│ │ ╰───────────────────┴───────────────────────────────────╯ │",
"│ │ ╭─────────────────────┬─────────────────────────────────╮ │",
"│ features │ │ │ ╭───┬───────────────╮ │ │",
"│ │ │ default │ │ 0 │ plugin │ │ │",
"│ │ │ │ │ 1 │ which-support │ │ │",
"│ │ │ │ │ 2 │ trash-support │ │ │",
"│ │ │ │ │ 3 │ sqlite │ │ │",
"│ │ │ │ ╰───┴───────────────╯ │ │",
"│ │ │ │ ╭───┬─────────╮ │ │",
"│ │ │ extra │ │ 0 │ default │ │ │",
"│ │ │ │ ╰───┴─────────╯ │ │",
"│ │ │ │ ╭───┬────────────────────╮ │ │",
"│ │ │ plugin │ │ 0 │ nu-plugin │ │ │",
"│ │ │ │ │ 1 │ nu-cli/plugin │ │ │",
"│ │ │ │ │ 2 │ nu-parser/plugin │ │ │",
"│ │ │ │ │ 3 │ nu-command/plugin │ │ │",
"│ │ │ │ │ 4 │ nu-protocol/plugin │ │ │",
"│ │ │ │ │ 5 │ nu-engine/plugin │ │ │",
"│ │ │ │ ╰───┴────────────────────╯ │ │",
"│ │ │ │ ╭───┬─────────╮ │ │",
"│ │ │ stable │ │ 0 │ default │ │ │",
"│ │ │ │ ╰───┴─────────╯ │ │",
"│ │ │ │ ╭───┬─────────────╮ │ │",
"│ │ │ static-link-openssl │ │ 0 │ dep:openssl │ │ │",
"│ │ │ │ ╰───┴─────────────╯ │ │",
"│ │ │ │ ╭───┬─────────────────────────╮ │ │",
"│ │ │ trash-support │ │ 0 │ nu-command/trash-suppor │ │ │",
"│ │ │ │ │ │ t │ │ │",
"│ │ │ │ ╰───┴─────────────────────────╯ │ │",
"│ │ │ wasi │ [list 0 items] │ │",
"│ │ │ │ ╭───┬─────────────────────────╮ │ │",
"│ │ │ which-support │ │ 0 │ nu-command/which-suppor │ │ │",
"│ │ │ │ │ │ t │ │ │",
"│ │ │ │ ╰───┴─────────────────────────╯ │ │",
"│ │ ╰─────────────────────┴─────────────────────────────────╯ │",
"│ │ ╭───────────────┬───────────────────────────────────────╮ │",
"│ package │ │ │ ╭───┬───────────────────────────────╮ │ │",
"│ │ │ authors │ │ 0 │ The Nushell Project │ │ │",
"│ │ │ │ │ │ Developers │ │ │",
"│ │ │ │ ╰───┴───────────────────────────────╯ │ │",
"│ │ │ default-run │ nu │ │",
"│ │ │ description │ A new type of shell │ │",
"│ │ │ documentation │ https://www.nushell.sh/book/ │ │",
"│ │ │ edition │ 2021 │ │",
"│ │ │ │ ╭───┬────────╮ │ │",
"│ │ │ exclude │ │ 0 │ images │ │ │",
"│ │ │ │ ╰───┴────────╯ │ │",
"│ │ │ homepage │ https://www.nushell.sh │ │",
"│ │ │ license │ MIT │ │",
"│ │ │ │ ╭──────────┬────────────────────────╮ │ │",
"│ │ │ metadata │ │ │ ╭───────────┬────────╮ │ │ │",
"│ │ │ │ │ binstall │ │ overrides │ {recor │ │ │ │",
"│ │ │ │ │ │ │ │ d 1 │ │ │ │",
"│ │ │ │ │ │ │ │ field} │ │ │ │",
"│ │ │ │ │ │ │ pkg-fmt │ tgz │ │ │ │",
"│ │ │ │ │ │ │ pkg-url │ { repo │ │ │ │",
"│ │ │ │ │ │ │ │ │ │ │ │",
"│ │ │ │ │ │ │ │ }/rele │ │ │ │",
"│ │ │ │ │ │ │ │ ases/d │ │ │ │",
"│ │ │ │ │ │ │ │ ownloa │ │ │ │",
"│ │ │ │ │ │ │ │ d/{ │ │ │ │",
"│ │ │ │ │ │ │ │ versio │ │ │ │",
"│ │ │ │ │ │ │ │ n }/{ │ │ │ │",
"│ │ │ │ │ │ │ │ name │ │ │ │",
"│ │ │ │ │ │ │ │ }-{ │ │ │ │",
"│ │ │ │ │ │ │ │ versio │ │ │ │",
"│ │ │ │ │ │ │ │ n }-{ │ │ │ │",
"│ │ │ │ │ │ │ │ target │ │ │ │",
"│ │ │ │ │ │ │ │ }.{ │ │ │ │",
"│ │ │ │ │ │ │ │ archiv │ │ │ │",
"│ │ │ │ │ │ │ │ e-form │ │ │ │",
"│ │ │ │ │ │ │ │ at } │ │ │ │",
"│ │ │ │ │ │ ╰───────────┴────────╯ │ │ │",
"│ │ │ │ ╰──────────┴────────────────────────╯ │ │",
"│ │ │ name │ nu │ │",
"│ │ │ repository │ https://github.com/nushell/nushell │ │",
"│ │ │ rust-version │ 1.60 │ │",
"│ │ │ version │ 0.74.1 │ │",
"│ │ ╰───────────────┴───────────────────────────────────────╯ │",
"│ │ ╭───────────┬───────────────────────────────────────────╮ │",
"│ patch │ │ │ ╭──────────┬────────────────────────────╮ │ │",
"│ │ │ crates-io │ │ │ ╭────────┬───────────────╮ │ │ │",
"│ │ │ │ │ reedline │ │ branch │ main │ │ │ │",
"│ │ │ │ │ │ │ git │ https://githu │ │ │ │",
"│ │ │ │ │ │ │ │ b.com/nushell │ │ │ │",
"│ │ │ │ │ │ │ │ /reedline.git │ │ │ │",
"│ │ │ │ │ │ ╰────────┴───────────────╯ │ │ │",
"│ │ │ │ ╰──────────┴────────────────────────────╯ │ │",
"│ │ ╰───────────┴───────────────────────────────────────────╯ │",
"│ │ ╭─────────────────────────────────┬─────────────────────╮ │",
"│ target │ │ │ ╭──────────────┬──╮ │ │",
"│ │ │ cfg(not(target_os = \"windows\")) │ │ dependencies │ │ │ │",
"│ │ │ │ ╰──────────────┴──╯ │ │",
"│ │ │ │ ╭──────────────┬──╮ │ │",
"│ │ │ cfg(target_family = \"unix\") │ │ dependencies │ │ │ │",
"│ │ │ │ ╰──────────────┴──╯ │ │",
"│ │ │ cfg(windows) │ {record 1 field} │ │",
"│ │ ╰─────────────────────────────────┴─────────────────────╯ │",
"│ │ ╭───────────┬───────────────────────────────────────────╮ │",
"│ workspace │ │ │ ╭────┬────────────────────────────────╮ │ │",
"│ │ │ members │ │ 0 │ crates/nu-cli │ │ │",
"│ │ │ │ │ 1 │ crates/nu-engine │ │ │",
"│ │ │ │ │ 2 │ crates/nu-parser │ │ │",
"│ │ │ │ │ 3 │ crates/nu-system │ │ │",
"│ │ │ │ │ 4 │ crates/nu-command │ │ │",
"│ │ │ │ │ 5 │ crates/nu-protocol │ │ │",
"│ │ │ │ │ 6 │ crates/nu-plugin │ │ │",
"│ │ │ │ │ 7 │ crates/nu_plugin_inc │ │ │",
"│ │ │ │ │ 8 │ crates/nu_plugin_gstat │ │ │",
"│ │ │ │ │ 9 │ crates/nu_plugin_example │ │ │",
"│ │ │ │ │ 10 │ crates/nu_plugin_query │ │ │",
"│ │ │ │ │ 11 │ crates/nu_plugin_custom_values │ │ │",
"│ │ │ │ │ 12 │ crates/nu-utils │ │ │",
"│ │ │ │ ╰────┴────────────────────────────────╯ │ │",
"│ │ ╰───────────┴───────────────────────────────────────────╯ │",
"╰──────────────────┴───────────────────────────────────────────────────────────╯",
]);
assert_eq!(actual.out, expected);
let actual = nu!(
cwd: dirs.test(), pipeline(
"open sample.toml | table --expand --width=120"
));
_print_lines(&actual.out, 120);
let expected = join_lines([
"╭──────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────╮",
"│ │ ╭───┬─────────┬────────────╮ │",
"│ bench │ │ # │ harness │ name │ │",
"│ │ ├───┼─────────┼────────────┤ │",
"│ │ │ 0 │ false │ benchmarks │ │",
"│ │ ╰───┴─────────┴────────────╯ │",
"│ │ ╭───┬──────┬─────────────╮ │",
"│ bin │ │ # │ name │ path │ │",
"│ │ ├───┼──────┼─────────────┤ │",
"│ │ │ 0 │ nu │ src/main.rs │ │",
"│ │ ╰───┴──────┴─────────────╯ │",
"│ │ ╭───────────────┬───────────────────────────────────────────╮ │",
"│ dependencies │ │ │ ╭──────────┬───────────────╮ │ │",
"│ │ │ chrono │ │ │ ╭───┬───────╮ │ │ │",
"│ │ │ │ │ features │ │ 0 │ serde │ │ │ │",
"│ │ │ │ │ │ ╰───┴───────╯ │ │ │",
"│ │ │ │ │ version │ 0.4.23 │ │ │",
"│ │ │ │ ╰──────────┴───────────────╯ │ │",
"│ │ │ crossterm │ 0.24.0 │ │",
"│ │ │ ctrlc │ 3.2.1 │ │",
"│ │ │ is_executable │ 1.0.1 │ │",
"│ │ │ log │ 0.4 │ │",
"│ │ │ │ ╭──────────┬────────────────────────────╮ │ │",
"│ │ │ miette │ │ │ ╭───┬────────────────────╮ │ │ │",
"│ │ │ │ │ features │ │ 0 │ fancy-no-backtrace │ │ │ │",
"│ │ │ │ │ │ ╰───┴────────────────────╯ │ │ │",
"│ │ │ │ │ version │ 5.5.0 │ │ │",
"│ │ │ │ ╰──────────┴────────────────────────────╯ │ │",
"│ │ │ nu-ansi-term │ 0.46.0 │ │",
"│ │ │ │ ╭─────────┬─────────────────╮ │ │",
"│ │ │ nu-cli │ │ path │ ./crates/nu-cli │ │ │",
"│ │ │ │ │ version │ 0.74.1 │ │ │",
"│ │ │ │ ╰─────────┴─────────────────╯ │ │",
"│ │ │ │ ╭─────────┬────────────────────╮ │ │",
"│ │ │ nu-engine │ │ path │ ./crates/nu-engine │ │ │",
"│ │ │ │ │ version │ 0.74.1 │ │ │",
"│ │ │ │ ╰─────────┴────────────────────╯ │ │",
"│ │ │ rayon │ 1.6.1 │ │",
"│ │ │ │ ╭──────────┬──────────────────╮ │ │",
"│ │ │ reedline │ │ │ ╭───┬──────────╮ │ │ │",
"│ │ │ │ │ features │ │ 0 │ bashisms │ │ │ │",
"│ │ │ │ │ │ │ 1 │ sqlite │ │ │ │",
"│ │ │ │ │ │ ╰───┴──────────╯ │ │ │",
"│ │ │ │ │ version │ 0.14.0 │ │ │",
"│ │ │ │ ╰──────────┴──────────────────╯ │ │",
"│ │ │ simplelog │ 0.12.0 │ │",
"│ │ │ time │ 0.3.12 │ │",
"│ │ ╰───────────────┴───────────────────────────────────────────╯ │",
"│ │ ╭───────────────────┬────────────────────────────────────────╮ │",
"│ dev-dependencies │ │ assert_cmd │ 2.0.2 │ │",
"│ │ │ criterion │ 0.4 │ │",
"│ │ │ hamcrest2 │ 0.3.0 │ │",
"│ │ │ itertools │ 0.10.3 │ │",
"│ │ │ │ ╭─────────┬──────────────────────────╮ │ │",
"│ │ │ nu-test-support │ │ path │ ./crates/nu-test-support │ │ │",
"│ │ │ │ │ version │ 0.74.1 │ │ │",
"│ │ │ │ ╰─────────┴──────────────────────────╯ │ │",
"│ │ │ pretty_assertions │ 1.0.0 │ │",
"│ │ │ │ ╭──────────────────┬────────╮ │ │",
"│ │ │ rstest │ │ default-features │ false │ │ │",
"│ │ │ │ │ version │ 0.15.0 │ │ │",
"│ │ │ │ ╰──────────────────┴────────╯ │ │",
"│ │ │ serial_test │ 0.10.0 │ │",
"│ │ │ tempfile │ 3.2.0 │ │",
"│ │ ╰───────────────────┴────────────────────────────────────────╯ │",
"│ │ ╭─────────────────────┬──────────────────────────────────╮ │",
"│ features │ │ │ ╭───┬───────────────╮ │ │",
"│ │ │ default │ │ 0 │ plugin │ │ │",
"│ │ │ │ │ 1 │ which-support │ │ │",
"│ │ │ │ │ 2 │ trash-support │ │ │",
"│ │ │ │ │ 3 │ sqlite │ │ │",
"│ │ │ │ ╰───┴───────────────╯ │ │",
"│ │ │ │ ╭───┬─────────╮ │ │",
"│ │ │ extra │ │ 0 │ default │ │ │",
"│ │ │ │ ╰───┴─────────╯ │ │",
"│ │ │ │ ╭───┬────────────────────╮ │ │",
"│ │ │ plugin │ │ 0 │ nu-plugin │ │ │",
"│ │ │ │ │ 1 │ nu-cli/plugin │ │ │",
"│ │ │ │ │ 2 │ nu-parser/plugin │ │ │",
"│ │ │ │ │ 3 │ nu-command/plugin │ │ │",
"│ │ │ │ │ 4 │ nu-protocol/plugin │ │ │",
"│ │ │ │ │ 5 │ nu-engine/plugin │ │ │",
"│ │ │ │ ╰───┴────────────────────╯ │ │",
"│ │ │ │ ╭───┬─────────╮ │ │",
"│ │ │ stable │ │ 0 │ default │ │ │",
"│ │ │ │ ╰───┴─────────╯ │ │",
"│ │ │ │ ╭───┬─────────────╮ │ │",
"│ │ │ static-link-openssl │ │ 0 │ dep:openssl │ │ │",
"│ │ │ │ ╰───┴─────────────╯ │ │",
"│ │ │ │ ╭───┬──────────────────────────╮ │ │",
"│ │ │ trash-support │ │ 0 │ nu-command/trash-support │ │ │",
"│ │ │ │ ╰───┴──────────────────────────╯ │ │",
"│ │ │ wasi │ [list 0 items] │ │",
"│ │ │ │ ╭───┬──────────────────────────╮ │ │",
"│ │ │ which-support │ │ 0 │ nu-command/which-support │ │ │",
"│ │ │ │ ╰───┴──────────────────────────╯ │ │",
"│ │ ╰─────────────────────┴──────────────────────────────────╯ │",
"│ │ ╭───────────────┬───────────────────────────────────────────────────────────────────────────────╮ │",
"│ package │ │ │ ╭───┬────────────────────────────────╮ │ │",
"│ │ │ authors │ │ 0 │ The Nushell Project Developers │ │ │",
"│ │ │ │ ╰───┴────────────────────────────────╯ │ │",
"│ │ │ default-run │ nu │ │",
"│ │ │ description │ A new type of shell │ │",
"│ │ │ documentation │ https://www.nushell.sh/book/ │ │",
"│ │ │ edition │ 2021 │ │",
"│ │ │ │ ╭───┬────────╮ │ │",
"│ │ │ exclude │ │ 0 │ images │ │ │",
"│ │ │ │ ╰───┴────────╯ │ │",
"│ │ │ homepage │ https://www.nushell.sh │ │",
"│ │ │ license │ MIT │ │",
"│ │ │ │ ╭──────────┬────────────────────────────────────────────────────────────────╮ │ │",
"│ │ │ metadata │ │ │ ╭───────────┬────────────────────────────────────────────────╮ │ │ │",
"│ │ │ │ │ binstall │ │ │ ╭────────────────────────┬───────────────────╮ │ │ │ │",
"│ │ │ │ │ │ │ overrides │ │ │ ╭─────────┬─────╮ │ │ │ │ │",
"│ │ │ │ │ │ │ │ │ x86_64-pc-windows-msvc │ │ pkg-fmt │ zip │ │ │ │ │ │",
"│ │ │ │ │ │ │ │ │ │ ╰─────────┴─────╯ │ │ │ │ │",
"│ │ │ │ │ │ │ │ ╰────────────────────────┴───────────────────╯ │ │ │ │",
"│ │ │ │ │ │ │ pkg-fmt │ tgz │ │ │ │",
"│ │ │ │ │ │ │ pkg-url │ { repo }/releases/download/{ version }/{ name │ │ │ │",
"│ │ │ │ │ │ │ │ }-{ version }-{ target }.{ archive-format } │ │ │ │",
"│ │ │ │ │ │ ╰───────────┴────────────────────────────────────────────────╯ │ │ │",
"│ │ │ │ ╰──────────┴────────────────────────────────────────────────────────────────╯ │ │",
"│ │ │ name │ nu │ │",
"│ │ │ repository │ https://github.com/nushell/nushell │ │",
"│ │ │ rust-version │ 1.60 │ │",
"│ │ │ version │ 0.74.1 │ │",
"│ │ ╰───────────────┴───────────────────────────────────────────────────────────────────────────────╯ │",
"│ │ ╭───────────┬───────────────────────────────────────────────────────────────────────────────────╮ │",
"│ patch │ │ │ ╭─────────────────┬─────────────────────────────────────────────────────────────╮ │ │",
"│ │ │ crates-io │ │ │ ╭────────┬─────────────────────────────────────────╮ │ │ │",
"│ │ │ │ │ reedline │ │ branch │ main │ │ │ │",
"│ │ │ │ │ │ │ git │ https://github.com/nushell/reedline.git │ │ │ │",
"│ │ │ │ │ │ ╰────────┴─────────────────────────────────────────╯ │ │ │",
"│ │ │ │ ╰─────────────────┴─────────────────────────────────────────────────────────────╯ │ │",
"│ │ ╰───────────┴───────────────────────────────────────────────────────────────────────────────────╯ │",
"│ │ ╭─────────────────────────────────┬─────────────────────────────────────────────────────────────╮ │",
"│ target │ │ │ ╭──────────────┬──────────────────────────────────────────╮ │ │",
"│ │ │ cfg(not(target_os = \"windows\")) │ │ │ ╭────────────────┬─────────────────────╮ │ │ │",
"│ │ │ │ │ dependencies │ │ openssl │ {record 3 fields} │ │ │ │",
"│ │ │ │ │ │ │ signal-hook │ {record 2 fields} │ │ │ │",
"│ │ │ │ │ │ ╰────────────────┴─────────────────────╯ │ │ │",
"│ │ │ │ ╰──────────────┴──────────────────────────────────────────╯ │ │",
"│ │ │ │ ╭──────────────┬──────────────────────────────╮ │ │",
"│ │ │ cfg(target_family = \"unix\") │ │ │ ╭──────┬───────────────────╮ │ │ │",
"│ │ │ │ │ dependencies │ │ atty │ 0.2 │ │ │ │",
"│ │ │ │ │ │ │ nix │ {record 3 fields} │ │ │ │",
"│ │ │ │ │ │ ╰──────┴───────────────────╯ │ │ │",
"│ │ │ │ ╰──────────────┴──────────────────────────────╯ │ │",
"│ │ │ │ ╭────────────────────┬──────────────────╮ │ │",
"│ │ │ cfg(windows) │ │ │ ╭────────┬─────╮ │ │ │",
"│ │ │ │ │ build-dependencies │ │ winres │ 0.1 │ │ │ │",
"│ │ │ │ │ │ ╰────────┴─────╯ │ │ │",
"│ │ │ │ ╰────────────────────┴──────────────────╯ │ │",
"│ │ ╰─────────────────────────────────┴─────────────────────────────────────────────────────────────╯ │",
"│ │ ╭─────────┬─────────────────────────────────────────╮ │",
"│ workspace │ │ │ ╭────┬────────────────────────────────╮ │ │",
"│ │ │ members │ │ 0 │ crates/nu-cli │ │ │",
"│ │ │ │ │ 1 │ crates/nu-engine │ │ │",
"│ │ │ │ │ 2 │ crates/nu-parser │ │ │",
"│ │ │ │ │ 3 │ crates/nu-system │ │ │",
"│ │ │ │ │ 4 │ crates/nu-command │ │ │",
"│ │ │ │ │ 5 │ crates/nu-protocol │ │ │",
"│ │ │ │ │ 6 │ crates/nu-plugin │ │ │",
"│ │ │ │ │ 7 │ crates/nu_plugin_inc │ │ │",
"│ │ │ │ │ 8 │ crates/nu_plugin_gstat │ │ │",
"│ │ │ │ │ 9 │ crates/nu_plugin_example │ │ │",
"│ │ │ │ │ 10 │ crates/nu_plugin_query │ │ │",
"│ │ │ │ │ 11 │ crates/nu_plugin_custom_values │ │ │",
"│ │ │ │ │ 12 │ crates/nu-utils │ │ │",
"│ │ │ │ ╰────┴────────────────────────────────╯ │ │",
"│ │ ╰─────────┴─────────────────────────────────────────╯ │",
"╰──────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────╯",
]);
assert_eq!(actual.out, expected);
let actual = nu!(
cwd: dirs.test(), pipeline(
"open sample.toml | table --expand --width=60"
));
_print_lines(&actual.out, 60);
let expected = join_lines([
"╭──────────────────┬───────────────────────────────────────╮",
"│ │ ╭───┬─────────┬────────────╮ │",
"│ bench │ │ # │ harness │ name │ │",
"│ │ ├───┼─────────┼────────────┤ │",
"│ │ │ 0 │ false │ benchmarks │ │",
"│ │ ╰───┴─────────┴────────────╯ │",
"│ │ ╭───┬──────┬─────────────╮ │",
"│ bin │ │ # │ name │ path │ │",
"│ │ ├───┼──────┼─────────────┤ │",
"│ │ │ 0 │ nu │ src/main.rs │ │",
"│ │ ╰───┴──────┴─────────────╯ │",
"│ │ ╭───────────────┬───────────────────╮ │",
"│ dependencies │ │ │ ╭──────────┬────╮ │ │",
"│ │ │ chrono │ │ features │ [l │ │ │",
"│ │ │ │ │ │ is │ │ │",
"│ │ │ │ │ │ t │ │ │",
"│ │ │ │ │ │ 1 │ │ │",
"│ │ │ │ │ │ it │ │ │",
"│ │ │ │ │ │ em │ │ │",
"│ │ │ │ │ │ ] │ │ │",
"│ │ │ │ │ version │ 0. │ │ │",
"│ │ │ │ │ │ 4. │ │ │",
"│ │ │ │ │ │ 23 │ │ │",
"│ │ │ │ ╰──────────┴────╯ │ │",
"│ │ │ crossterm │ 0.24.0 │ │",
"│ │ │ ctrlc │ 3.2.1 │ │",
"│ │ │ is_executable │ 1.0.1 │ │",
"│ │ │ log │ 0.4 │ │",
"│ │ │ │ ╭──────────┬────╮ │ │",
"│ │ │ miette │ │ features │ [l │ │ │",
"│ │ │ │ │ │ is │ │ │",
"│ │ │ │ │ │ t │ │ │",
"│ │ │ │ │ │ 1 │ │ │",
"│ │ │ │ │ │ it │ │ │",
"│ │ │ │ │ │ em │ │ │",
"│ │ │ │ │ │ ] │ │ │",
"│ │ │ │ │ version │ 5. │ │ │",
"│ │ │ │ │ │ 5. │ │ │",
"│ │ │ │ │ │ 0 │ │ │",
"│ │ │ │ ╰──────────┴────╯ │ │",
"│ │ │ nu-ansi-term │ 0.46.0 │ │",
"│ │ │ │ ╭─────────┬─────╮ │ │",
"│ │ │ nu-cli │ │ path │ ./c │ │ │",
"│ │ │ │ │ │ rat │ │ │",
"│ │ │ │ │ │ es/ │ │ │",
"│ │ │ │ │ │ nu- │ │ │",
"│ │ │ │ │ │ cli │ │ │",
"│ │ │ │ │ version │ 0.7 │ │ │",
"│ │ │ │ │ │ 4.1 │ │ │",
"│ │ │ │ ╰─────────┴─────╯ │ │",
"│ │ │ │ ╭─────────┬─────╮ │ │",
"│ │ │ nu-engine │ │ path │ ./c │ │ │",
"│ │ │ │ │ │ rat │ │ │",
"│ │ │ │ │ │ es/ │ │ │",
"│ │ │ │ │ │ nu- │ │ │",
"│ │ │ │ │ │ eng │ │ │",
"│ │ │ │ │ │ ine │ │ │",
"│ │ │ │ │ version │ 0.7 │ │ │",
"│ │ │ │ │ │ 4.1 │ │ │",
"│ │ │ │ ╰─────────┴─────╯ │ │",
"│ │ │ rayon │ 1.6.1 │ │",
"│ │ │ │ ╭──────────┬────╮ │ │",
"│ │ │ reedline │ │ features │ [l │ │ │",
"│ │ │ │ │ │ is │ │ │",
"│ │ │ │ │ │ t │ │ │",
"│ │ │ │ │ │ 2 │ │ │",
"│ │ │ │ │ │ it │ │ │",
"│ │ │ │ │ │ em │ │ │",
"│ │ │ │ │ │ s] │ │ │",
"│ │ │ │ │ version │ 0. │ │ │",
"│ │ │ │ │ │ 14 │ │ │",
"│ │ │ │ │ │ .0 │ │ │",
"│ │ │ │ ╰──────────┴────╯ │ │",
"│ │ │ simplelog │ 0.12.0 │ │",
"│ │ │ time │ 0.3.12 │ │",
"│ │ ╰───────────────┴───────────────────╯ │",
"│ │ ╭───────────────────┬───────────────╮ │",
"│ dev-dependencies │ │ assert_cmd │ 2.0.2 │ │",
"│ │ │ criterion │ 0.4 │ │",
"│ │ │ hamcrest2 │ 0.3.0 │ │",
"│ │ │ itertools │ 0.10.3 │ │",
"│ │ │ nu-test-support │ {record 2 │ │",
"│ │ │ │ fields} │ │",
"│ │ │ pretty_assertions │ 1.0.0 │ │",
"│ │ │ rstest │ {record 2 │ │",
"│ │ │ │ fields} │ │",
"│ │ │ serial_test │ 0.10.0 │ │",
"│ │ │ tempfile │ 3.2.0 │ │",
"│ │ ╰───────────────────┴───────────────╯ │",
"│ │ ╭─────────────────────┬─────────────╮ │",
"│ features │ │ │ ╭───┬─────╮ │ │",
"│ │ │ default │ │ 0 │ plu │ │ │",
"│ │ │ │ │ │ gin │ │ │",
"│ │ │ │ │ 1 │ whi │ │ │",
"│ │ │ │ │ │ ch- │ │ │",
"│ │ │ │ │ │ sup │ │ │",
"│ │ │ │ │ │ por │ │ │",
"│ │ │ │ │ │ t │ │ │",
"│ │ │ │ │ 2 │ tra │ │ │",
"│ │ │ │ │ │ sh- │ │ │",
"│ │ │ │ │ │ sup │ │ │",
"│ │ │ │ │ │ por │ │ │",
"│ │ │ │ │ │ t │ │ │",
"│ │ │ │ │ 3 │ sql │ │ │",
"│ │ │ │ │ │ ite │ │ │",
"│ │ │ │ ╰───┴─────╯ │ │",
"│ │ │ │ ╭───┬─────╮ │ │",
"│ │ │ extra │ │ 0 │ def │ │ │",
"│ │ │ │ │ │ aul │ │ │",
"│ │ │ │ │ │ t │ │ │",
"│ │ │ │ ╰───┴─────╯ │ │",
"│ │ │ │ ╭───┬─────╮ │ │",
"│ │ │ plugin │ │ 0 │ nu- │ │ │",
"│ │ │ │ │ │ plu │ │ │",
"│ │ │ │ │ │ gin │ │ │",
"│ │ │ │ │ 1 │ nu- │ │ │",
"│ │ │ │ │ │ cli │ │ │",
"│ │ │ │ │ │ /pl │ │ │",
"│ │ │ │ │ │ ugi │ │ │",
"│ │ │ │ │ │ n │ │ │",
"│ │ │ │ │ 2 │ nu- │ │ │",
"│ │ │ │ │ │ par │ │ │",
"│ │ │ │ │ │ ser │ │ │",
"│ │ │ │ │ │ /pl │ │ │",
"│ │ │ │ │ │ ugi │ │ │",
"│ │ │ │ │ │ n │ │ │",
"│ │ │ │ │ 3 │ nu- │ │ │",
"│ │ │ │ │ │ com │ │ │",
"│ │ │ │ │ │ man │ │ │",
"│ │ │ │ │ │ d/p │ │ │",
"│ │ │ │ │ │ lug │ │ │",
"│ │ │ │ │ │ in │ │ │",
"│ │ │ │ │ 4 │ nu- │ │ │",
"│ │ │ │ │ │ pro │ │ │",
"│ │ │ │ │ │ toc │ │ │",
"│ │ │ │ │ │ ol/ │ │ │",
"│ │ │ │ │ │ plu │ │ │",
"│ │ │ │ │ │ gin │ │ │",
"│ │ │ │ │ 5 │ nu- │ │ │",
"│ │ │ │ │ │ eng │ │ │",
"│ │ │ │ │ │ ine │ │ │",
"│ │ │ │ │ │ /pl │ │ │",
"│ │ │ │ │ │ ugi │ │ │",
"│ │ │ │ │ │ n │ │ │",
"│ │ │ │ ╰───┴─────╯ │ │",
"│ │ │ │ ╭───┬─────╮ │ │",
"│ │ │ stable │ │ 0 │ def │ │ │",
"│ │ │ │ │ │ aul │ │ │",
"│ │ │ │ │ │ t │ │ │",
"│ │ │ │ ╰───┴─────╯ │ │",
"│ │ │ │ ╭───┬─────╮ │ │",
"│ │ │ static-link-openssl │ │ 0 │ dep │ │ │",
"│ │ │ │ │ │ :op │ │ │",
"│ │ │ │ │ │ ens │ │ │",
"│ │ │ │ │ │ sl │ │ │",
"│ │ │ │ ╰───┴─────╯ │ │",
"│ │ │ │ ╭───┬─────╮ │ │",
"│ │ │ trash-support │ │ 0 │ nu- │ │ │",
"│ │ │ │ │ │ com │ │ │",
"│ │ │ │ │ │ man │ │ │",
"│ │ │ │ │ │ d/t │ │ │",
"│ │ │ │ │ │ ras │ │ │",
"│ │ │ │ │ │ h-s │ │ │",
"│ │ │ │ │ │ upp │ │ │",
"│ │ │ │ │ │ ort │ │ │",
"│ │ │ │ ╰───┴─────╯ │ │",
"│ │ │ wasi │ [list 0 │ │",
"│ │ │ │ items] │ │",
"│ │ │ │ ╭───┬─────╮ │ │",
"│ │ │ which-support │ │ 0 │ nu- │ │ │",
"│ │ │ │ │ │ com │ │ │",
"│ │ │ │ │ │ man │ │ │",
"│ │ │ │ │ │ d/w │ │ │",
"│ │ │ │ │ │ hic │ │ │",
"│ │ │ │ │ │ h-s │ │ │",
"│ │ │ │ │ │ upp │ │ │",
"│ │ │ │ │ │ ort │ │ │",
"│ │ │ │ ╰───┴─────╯ │ │",
"│ │ ╰─────────────────────┴─────────────╯ │",
"│ │ ╭───────────────┬───────────────────╮ │",
"│ package │ │ │ ╭───┬───────────╮ │ │",
"│ │ │ authors │ │ 0 │ The │ │ │",
"│ │ │ │ │ │ Nushell │ │ │",
"│ │ │ │ │ │ Project │ │ │",
"│ │ │ │ │ │ Developer │ │ │",
"│ │ │ │ │ │ s │ │ │",
"│ │ │ │ ╰───┴───────────╯ │ │",
"│ │ │ default-run │ nu │ │",
"│ │ │ description │ A new type of │ │",
"│ │ │ │ shell │ │",
"│ │ │ documentation │ https://www.nushe │ │",
"│ │ │ │ ll.sh/book/ │ │",
"│ │ │ edition │ 2021 │ │",
"│ │ │ │ ╭───┬────────╮ │ │",
"│ │ │ exclude │ │ 0 │ images │ │ │",
"│ │ │ │ ╰───┴────────╯ │ │",
"│ │ │ homepage │ https://www.nushe │ │",
"│ │ │ │ ll.sh │ │",
"│ │ │ license │ MIT │ │",
"│ │ │ │ ╭──────────┬────╮ │ │",
"│ │ │ metadata │ │ binstall │ {r │ │ │",
"│ │ │ │ │ │ ec │ │ │",
"│ │ │ │ │ │ or │ │ │",
"│ │ │ │ │ │ d │ │ │",
"│ │ │ │ │ │ 3 │ │ │",
"│ │ │ │ │ │ fi │ │ │",
"│ │ │ │ │ │ el │ │ │",
"│ │ │ │ │ │ ds │ │ │",
"│ │ │ │ │ │ } │ │ │",
"│ │ │ │ ╰──────────┴────╯ │ │",
"│ │ │ name │ nu │ │",
"│ │ │ repository │ https://github.co │ │",
"│ │ │ │ m/nushell/nushell │ │",
"│ │ │ rust-version │ 1.60 │ │",
"│ │ │ version │ 0.74.1 │ │",
"│ │ ╰───────────────┴───────────────────╯ │",
"│ │ ╭───────────┬───────────────────────╮ │",
"│ patch │ │ │ ╭──────────┬────────╮ │ │",
"│ │ │ crates-io │ │ reedline │ {recor │ │ │",
"│ │ │ │ │ │ d 2 │ │ │",
"│ │ │ │ │ │ fields │ │ │",
"│ │ │ │ │ │ } │ │ │",
"│ │ │ │ ╰──────────┴────────╯ │ │",
"│ │ ╰───────────┴───────────────────────╯ │",
"│ target │ {record 3 fields} │",
"│ │ ╭─────────┬─────────────────────────╮ │",
"│ workspace │ │ │ ╭────┬────────────────╮ │ │",
"│ │ │ members │ │ 0 │ crates/nu-cli │ │ │",
"│ │ │ │ │ 1 │ crates/nu-engi │ │ │",
"│ │ │ │ │ │ ne │ │ │",
"│ │ │ │ │ 2 │ crates/nu-pars │ │ │",
"│ │ │ │ │ │ er │ │ │",
"│ │ │ │ │ 3 │ crates/nu-syst │ │ │",
"│ │ │ │ │ │ em │ │ │",
"│ │ │ │ │ 4 │ crates/nu-comm │ │ │",
"│ │ │ │ │ │ and │ │ │",
"│ │ │ │ │ 5 │ crates/nu-prot │ │ │",
"│ │ │ │ │ │ ocol │ │ │",
"│ │ │ │ │ 6 │ crates/nu-plug │ │ │",
"│ │ │ │ │ │ in │ │ │",
"│ │ │ │ │ 7 │ crates/nu_plug │ │ │",
"│ │ │ │ │ │ in_inc │ │ │",
"│ │ │ │ │ 8 │ crates/nu_plug │ │ │",
"│ │ │ │ │ │ in_gstat │ │ │",
"│ │ │ │ │ 9 │ crates/nu_plug │ │ │",
"│ │ │ │ │ │ in_example │ │ │",
"│ │ │ │ │ 10 │ crates/nu_plug │ │ │",
"│ │ │ │ │ │ in_query │ │ │",
"│ │ │ │ │ 11 │ crates/nu_plug │ │ │",
"│ │ │ │ │ │ in_custom_valu │ │ │",
"│ │ │ │ │ │ es │ │ │",
"│ │ │ │ │ 12 │ crates/nu-util │ │ │",
"│ │ │ │ │ │ s │ │ │",
"│ │ │ │ ╰────┴────────────────╯ │ │",
"│ │ ╰─────────┴─────────────────────────╯ │",
"╰──────────────────┴───────────────────────────────────────╯",
]);
assert_eq!(actual.out, expected);
let actual = nu!(
cwd: dirs.test(), pipeline(
"open sample.toml | table --expand --width=40"
));
_print_lines(&actual.out, 40);
let expected = join_lines([
"╭──────────────────┬───────────────────╮",
"│ bench │ [table 1 row] │",
"│ bin │ [table 1 row] │",
"│ dependencies │ {record 13 │",
"│ │ fields} │",
"│ dev-dependencies │ {record 9 fields} │",
"│ features │ {record 8 fields} │",
"│ package │ {record 13 │",
"│ │ fields} │",
"│ │ ╭───────────┬───╮ │",
"│ patch │ │ crates-io │ { │ │",
"│ │ │ │ r │ │",
"│ │ │ │ e │ │",
"│ │ │ │ c │ │",
"│ │ │ │ o │ │",
"│ │ │ │ r │ │",
"│ │ │ │ d │ │",
"│ │ │ │ │ │",
"│ │ │ │ 1 │ │",
"│ │ │ │ │ │",
"│ │ │ │ f │ │",
"│ │ │ │ i │ │",
"│ │ │ │ e │ │",
"│ │ │ │ l │ │",
"│ │ │ │ d │ │",
"│ │ │ │ } │ │",
"│ │ ╰───────────┴───╯ │",
"│ target │ {record 3 fields} │",
"│ workspace │ {record 1 field} │",
"╰──────────────────┴───────────────────╯",
]);
assert_eq!(actual.out, expected);
})
}
fn join_lines(lines: impl IntoIterator<Item = impl AsRef<str>>) -> String {
lines
.into_iter()
.map(|s| s.as_ref().to_string())
.collect::<Vec<_>>()
.join("")
}
// util function to easier copy && paste
fn _print_lines(s: &str, w: usize) {
eprintln!("{:#?}", _split_str_by_width(s, w));
}
// util function to easier copy && paste
// todo: make UTF-8 friendly
fn _split_str_by_width(s: &str, w: usize) -> Vec<String> {
let mut lines = vec![];
let mut line = String::new();
let mut i = 0;
for c in s.chars() {
if i < w {
i += 1;
line.push(c);
} else {
lines.push(line);
line = String::new();
line.push(c);
i = 1;
}
}
lines.push(line);
lines
}

View File

@ -1,5 +1,4 @@
use nu_test_support::nu; use nu_test_support::nu;
#[cfg(feature = "sqlite")]
use nu_test_support::pipeline; use nu_test_support::pipeline;
#[test] #[test]

View File

@ -6,18 +6,21 @@ use tabled::{
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TableTheme { pub struct TableTheme {
pub(crate) theme: RawStyle, pub(crate) theme: RawStyle,
has_inner: bool,
} }
impl TableTheme { impl TableTheme {
pub fn basic() -> TableTheme { pub fn basic() -> TableTheme {
Self { Self {
theme: Style::ascii().into(), theme: Style::ascii().into(),
has_inner: true,
} }
} }
pub fn thin() -> TableTheme { pub fn thin() -> TableTheme {
Self { Self {
theme: Style::modern().into(), theme: Style::modern().into(),
has_inner: true,
} }
} }
@ -29,6 +32,8 @@ impl TableTheme {
Line::new(Some('─'), Some('─'), None, None), Line::new(Some('─'), Some('─'), None, None),
)]) )])
.into(), .into(),
has_inner: true,
} }
} }
@ -42,6 +47,7 @@ impl TableTheme {
.left(None) .left(None)
.right(None)]) .right(None)])
.into(), .into(),
has_inner: true,
} }
} }
@ -56,6 +62,7 @@ impl TableTheme {
Line::new(Some('❤'), Some('❤'), None, None), Line::new(Some('❤'), Some('❤'), None, None),
)]) )])
.into(), .into(),
has_inner: true,
} }
} }
@ -69,12 +76,14 @@ impl TableTheme {
.left(None) .left(None)
.right(None)]) .right(None)])
.into(), .into(),
has_inner: true,
} }
} }
pub fn rounded() -> TableTheme { pub fn rounded() -> TableTheme {
Self { Self {
theme: Style::rounded().into(), theme: Style::rounded().into(),
has_inner: true,
} }
} }
@ -87,6 +96,7 @@ impl TableTheme {
.bottom_right_corner('┛') .bottom_right_corner('┛')
.off_horizontal() .off_horizontal()
.into(), .into(),
has_inner: true,
} }
} }
@ -106,12 +116,14 @@ impl TableTheme {
.bottom_right_corner('┛') .bottom_right_corner('┛')
.horizontals([HorizontalLine::new(1, Line::full('━', '╋', '┣', '┫'))]) .horizontals([HorizontalLine::new(1, Line::full('━', '╋', '┣', '┫'))])
.into(), .into(),
has_inner: true,
} }
} }
pub fn none() -> TableTheme { pub fn none() -> TableTheme {
Self { Self {
theme: Style::blank().into(), theme: Style::blank().into(),
has_inner: true,
} }
} }
@ -121,4 +133,22 @@ impl TableTheme {
|| self.theme.get_top_left().is_some() || self.theme.get_top_left().is_some()
|| self.theme.get_top_right().is_some() || self.theme.get_top_right().is_some()
} }
pub fn has_left(&self) -> bool {
self.theme.get_left().is_some()
|| self.theme.get_left_intersection().is_some()
|| self.theme.get_top_left().is_some()
|| self.theme.get_bottom_left().is_some()
}
pub fn has_right(&self) -> bool {
self.theme.get_right().is_some()
|| self.theme.get_right_intersection().is_some()
|| self.theme.get_top_right().is_some()
|| self.theme.get_bottom_right().is_some()
}
pub fn has_inner(&self) -> bool {
self.has_inner
}
} }