From 731f5f852304358c83abb4595b6d80e9156b31a5 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Thu, 26 Jan 2023 23:06:17 +0300 Subject: [PATCH] nu-commands/table (`table -e`) Recognize limited space better (#7861) fix #7858 Once again we here :disappointed: ~~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 --- crates/nu-command/src/viewers/table.rs | 207 +++-- crates/nu-command/tests/commands/table.rs | 857 ++++++++++++++++++++- crates/nu-command/tests/commands/where_.rs | 1 - crates/nu-table/src/table_theme.rs | 30 + 4 files changed, 978 insertions(+), 117 deletions(-) diff --git a/crates/nu-command/src/viewers/table.rs b/crates/nu-command/src/viewers/table.rs index aa348b1e71..d9e1f765cf 100644 --- a/crates/nu-command/src/viewers/table.rs +++ b/crates/nu-command/src/viewers/table.rs @@ -458,25 +458,16 @@ fn build_expanded_table( ) -> Result, ShellError> { 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 = 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) - // 2 - padding - if key_width + 3 + 2 > term_width { + let count_borders = + theme.has_inner() as usize + theme.has_right() as usize + theme.has_left() as usize; + let padding = 2; + if key_width + count_borders + padding + padding > term_width { 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()); for (key, value) in cols.into_iter().zip(vals) { @@ -503,14 +494,11 @@ fn build_expanded_table( deep, flatten, flatten_sep, - remaining_width, + value_width, )?; match table { - Some((mut table, with_header, with_index)) => { - // control width via removing table columns. - table.truncate(remaining_width, &theme); - + Some((table, with_header, with_index)) => { is_expanded = true; let table_config = create_table_config( @@ -522,7 +510,7 @@ fn build_expanded_table( false, ); - let val = table.draw(table_config, remaining_width); + let val = table.draw(table_config, value_width); match val { Some(result) => result, None => return Ok(None), @@ -531,7 +519,8 @@ fn build_expanded_table( None => { // it means that the list is empty 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(), config, style_computer, - remaining_width, + value_width, deep, flatten, flatten_sep, @@ -561,13 +550,13 @@ fn build_expanded_table( style_computer, ); - wrap_text(&failed_value.0, remaining_width, config) + wrap_text(&failed_value.0, value_width, config) } } } val => { 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 ADDITIONAL_CELL_SPACE: usize = PADDING_SPACE + SPLIT_LINE_SPACE; 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 { return Ok(None); @@ -1009,8 +999,6 @@ fn convert_to_table2<'a>( }; if with_index { - let mut column_width = 0; - if with_header { 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() { if nu_utils::ctrl_c::was_pressed(&ctrlc) { return Ok(None); @@ -1031,18 +1020,18 @@ fn convert_to_table2<'a>( let text = matches!(item, Value::Record { .. }) .then(|| lookup_index_value(item, config).unwrap_or_else(|| index.to_string())) .unwrap_or_else(|| index.to_string()); - 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 row = if with_header { row + 1 } else { row }; data[row].push(value); + + last_index = index; } + let column_width = string_width(&last_index.to_string()); + if column_width + ADDITIONAL_CELL_SPACE > available_width { available_width = 0; } else { @@ -1087,34 +1076,64 @@ fn convert_to_table2<'a>( return Ok(Some((table, with_header, with_index))); } - let min_width = PADDING_SPACE + MIN_CELL_CONTENT_WIDTH; - if available_width < min_width { - return Ok(None); + if !headers.is_empty() { + 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); + } } let count_columns = headers.len(); let mut widths = Vec::new(); let mut truncate = false; - let mut last_column_type_is_string = false; - let mut last_column_head_width = 0; + let mut rendered_column = 0; for (col, header) in headers.into_iter().enumerate() { let is_last_column = col + 1 == count_columns; - let mut necessary_space = PADDING_SPACE; + let mut pad_space = PADDING_SPACE; 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); - 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())); - data[0].push(headc); + data[0].push(head_cell); - let mut is_string_column = true; for (row, item) in input.clone().into_iter().enumerate() { if nu_utils::ctrl_c::was_pressed(&ctrlc) { return Ok(None); @@ -1124,9 +1143,7 @@ fn convert_to_table2<'a>( return Err(error.clone()); } - is_string_column = is_string_column && is_string_value(item, &header); - - let value = create_table2_entry( + let mut value = create_table2_entry( item, header.as_str(), head, @@ -1139,7 +1156,16 @@ fn convert_to_table2<'a>( 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); let value = NuTable::create_cell(value.0, value.1); @@ -1147,67 +1173,35 @@ fn convert_to_table2<'a>( data[row + 1].push(value); } - last_column_type_is_string = is_string_column; - widths.push(column_width); - if column_width > available { + // remove the column we just inserted + for row in &mut data { + row.pop(); + } + truncate = true; 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; - } + widths.push(column_width); - let has_space_for_next = - available_width > column_width + necessary_space + next_nessary_space; - if !has_space_for_next { - truncate = true; - break; - } - } + available_width -= pad_space + column_width; + rendered_column += 1; + } - available_width -= necessary_space + column_width; + 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 { - 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 { - row.pop(); - } - } - if available_width < TRUNCATE_CELL_WIDTH { // back up by removing last 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))) } -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 { item.get_data_by_key(INDEX_COLUMN_NAME) .map(|value| value.into_string("", config)) diff --git a/crates/nu-command/tests/commands/table.rs b/crates/nu-command/tests/commands/table.rs index 3dee2bb5a8..c17ceb5b49 100644 --- a/crates/nu-command/tests/commands/table.rs +++ b/crates/nu-command/tests/commands/table.rs @@ -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] 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 │╰───┴───╯" ); } + +#[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 -- ` 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>) -> String { + lines + .into_iter() + .map(|s| s.as_ref().to_string()) + .collect::>() + .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 { + 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 +} diff --git a/crates/nu-command/tests/commands/where_.rs b/crates/nu-command/tests/commands/where_.rs index c9bbbee2ef..11915aec84 100644 --- a/crates/nu-command/tests/commands/where_.rs +++ b/crates/nu-command/tests/commands/where_.rs @@ -1,5 +1,4 @@ use nu_test_support::nu; -#[cfg(feature = "sqlite")] use nu_test_support::pipeline; #[test] diff --git a/crates/nu-table/src/table_theme.rs b/crates/nu-table/src/table_theme.rs index 299eb8038c..c027c32abd 100644 --- a/crates/nu-table/src/table_theme.rs +++ b/crates/nu-table/src/table_theme.rs @@ -6,18 +6,21 @@ use tabled::{ #[derive(Debug, Clone)] pub struct TableTheme { pub(crate) theme: RawStyle, + has_inner: bool, } impl TableTheme { pub fn basic() -> TableTheme { Self { theme: Style::ascii().into(), + has_inner: true, } } pub fn thin() -> TableTheme { Self { theme: Style::modern().into(), + has_inner: true, } } @@ -29,6 +32,8 @@ impl TableTheme { Line::new(Some('─'), Some('─'), None, None), )]) .into(), + + has_inner: true, } } @@ -42,6 +47,7 @@ impl TableTheme { .left(None) .right(None)]) .into(), + has_inner: true, } } @@ -56,6 +62,7 @@ impl TableTheme { Line::new(Some('❤'), Some('❤'), None, None), )]) .into(), + has_inner: true, } } @@ -69,12 +76,14 @@ impl TableTheme { .left(None) .right(None)]) .into(), + has_inner: true, } } pub fn rounded() -> TableTheme { Self { theme: Style::rounded().into(), + has_inner: true, } } @@ -87,6 +96,7 @@ impl TableTheme { .bottom_right_corner('┛') .off_horizontal() .into(), + has_inner: true, } } @@ -106,12 +116,14 @@ impl TableTheme { .bottom_right_corner('┛') .horizontals([HorizontalLine::new(1, Line::full('━', '╋', '┣', '┫'))]) .into(), + has_inner: true, } } pub fn none() -> TableTheme { Self { theme: Style::blank().into(), + has_inner: true, } } @@ -121,4 +133,22 @@ impl TableTheme { || self.theme.get_top_left().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 + } }