From 73d3708006d269c2b09c8a1625cbfc45e9af6475 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Wed, 13 Sep 2023 12:47:53 +0000 Subject: [PATCH] Patch restore lead trail space bg color (#10351) ```nu $env.config.color_config.leading_trailing_space_bg = { bg: 'white' }; [[a b, 'c ']; [' 1 ' ' 2' '3 '] [' 4 ' "hello \n world " [' 1 ' 2 [1 ' 2 ' 3]]]] | table --expand ``` ![image](https://github.com/nushell/nushell/assets/20165848/01a35042-0e36-4c51-99a9-3011fabb551b) ref: #2794 close: #10317 note: test are not actually make scenes cause `nu!` strips colors. (Ideally it would need a flag to not do so) note: It does does does ... slower down quite a bit rendering... ( PS: Maybe it's better being a flag to `table` rather then a configuration option? PS: I am not sure why the logic was removed in a first place --- Cargo.lock | 2 + crates/nu-command/tests/commands/table.rs | 22 ++++++++ crates/nu-table/Cargo.toml | 2 + crates/nu-table/src/common.rs | 10 ++++ crates/nu-table/src/table.rs | 62 ++++++++++++++++++++++- crates/nu-table/src/types/expanded.rs | 16 +++++- crates/nu-table/src/types/general.rs | 14 ++++- 7 files changed, 124 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 91aa3518d..53dd69e4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3078,11 +3078,13 @@ dependencies = [ name = "nu-table" version = "0.84.1" dependencies = [ + "fancy-regex", "nu-ansi-term", "nu-color-config", "nu-engine", "nu-protocol", "nu-utils", + "once_cell", "tabled", ] diff --git a/crates/nu-command/tests/commands/table.rs b/crates/nu-command/tests/commands/table.rs index 1b5ba1f14..5897f4a55 100644 --- a/crates/nu-command/tests/commands/table.rs +++ b/crates/nu-command/tests/commands/table.rs @@ -2664,3 +2664,25 @@ fn table_collapse_padding_zero() { ╰─┴─┴─╯" ); } + +#[test] +fn table_leading_trailing_space_bg() { + let actual = nu!( + r#"$env.config.color_config.leading_trailing_space_bg = { bg: 'white' }; [[a b, 'c ']; [' 1 ' ' 2' '3 '] [' 4 ' "hello\nworld" [' 1 ' 2 [1 ' 2 ' 3]]]] | table"# + ); + assert_eq!( + actual.out, + "╭───┬───────┬───────┬────────────────╮│ # │ a │ b │ c │├───┼───────┼───────┼────────────────┤│ 0 │ 1 │ 2 │ 3 ││ 1 │ 4 │ hello │ [list 3 items] ││ │ │ world │ │╰───┴───────┴───────┴────────────────╯" + ); +} + +#[test] +fn table_leading_trailing_space_bg_expand() { + let actual = nu!( + r#"$env.config.color_config.leading_trailing_space_bg = { bg: 'white' }; [[a b, 'c ']; [' 1 ' ' 2' '3 '] [' 4 ' "hello\nworld" [' 1 ' 2 [1 ' 2 ' 3]]]] | table --expand"# + ); + assert_eq!( + actual.out, + "╭───┬───────┬───────┬───────────────────────╮│ # │ a │ b │ c │├───┼───────┼───────┼───────────────────────┤│ 0 │ 1 │ 2 │ 3 ││ 1 │ 4 │ hello │ ╭───┬───────────────╮ ││ │ │ world │ │ 0 │ 1 │ ││ │ │ │ │ 1 │ 2 │ ││ │ │ │ │ 2 │ ╭───┬───────╮ │ ││ │ │ │ │ │ │ 0 │ 1 │ │ ││ │ │ │ │ │ │ 1 │ 2 │ │ ││ │ │ │ │ │ │ 2 │ 3 │ │ ││ │ │ │ │ │ ╰───┴───────╯ │ ││ │ │ │ ╰───┴───────────────╯ │╰───┴───────┴───────┴───────────────────────╯" + ); +} diff --git a/crates/nu-table/Cargo.toml b/crates/nu-table/Cargo.toml index 83d0e83e4..3d56d7acd 100644 --- a/crates/nu-table/Cargo.toml +++ b/crates/nu-table/Cargo.toml @@ -16,6 +16,8 @@ nu-utils = { path = "../nu-utils", version = "0.84.1" } nu-engine = { path = "../nu-engine", version = "0.84.1" } nu-color-config = { path = "../nu-color-config", version = "0.84.1" } nu-ansi-term = "0.49.0" +once_cell = "1.18" +fancy-regex = "0.11" tabled = { version = "0.14.0", features = ["color"], default-features = false } [dev-dependencies] diff --git a/crates/nu-table/src/common.rs b/crates/nu-table/src/common.rs index f4749f339..1564d5104 100644 --- a/crates/nu-table/src/common.rs +++ b/crates/nu-table/src/common.rs @@ -62,6 +62,16 @@ pub fn get_index_style(style_computer: &StyleComputer) -> TextStyle { ) } +pub fn get_leading_trailing_space_style(style_computer: &StyleComputer) -> TextStyle { + TextStyle::with_style( + Alignment::Right, + style_computer.compute( + "leading_trailing_space_bg", + &Value::string("", Span::unknown()), + ), + ) +} + pub fn get_value_style(value: &Value, config: &Config, style_computer: &StyleComputer) -> NuText { match value { // Float precision is required here. diff --git a/crates/nu-table/src/table.rs b/crates/nu-table/src/table.rs index b8559e62c..3980cd6ed 100644 --- a/crates/nu-table/src/table.rs +++ b/crates/nu-table/src/table.rs @@ -40,6 +40,8 @@ struct Styles { index: AnsiColor<'static>, header: AnsiColor<'static>, data: EntityMap>, + space_lead: Option>, + space_trail: Option>, data_is_set: bool, } @@ -137,6 +139,13 @@ impl NuTable { self.alignments.data = convert_alignment(style.alignment); } + pub fn set_trail_lead_style(&mut self, head: Style, tail: Style) { + let style_head = AnsiColor::from(convert_style(head)); + let style_tail = AnsiColor::from(convert_style(tail)); + self.styles.space_trail = Some(style_tail); + self.styles.space_lead = Some(style_head); + } + pub fn set_indent(&mut self, left: usize, right: usize) { self.indent = (left, right); } @@ -225,7 +234,7 @@ fn build_table( } fn draw_table( - data: NuRecords, + mut data: NuRecords, alignments: Alignments, styles: Styles, widths: Vec, @@ -239,6 +248,12 @@ fn draw_table( let sep_color = cfg.split_color; let border_header = cfg.header_on_border; + colorize_lead_trail_space( + &mut data, + styles.space_lead.clone(), + styles.space_trail.clone(), + ); + let data: Vec> = data.into(); let mut table = Builder::from(data).build(); @@ -908,3 +923,48 @@ fn remove_row(recs: &mut NuRecords, row: usize) -> Vec { columns } + +fn colorize_lead_trail_space( + data: &mut NuRecords, + lead: Option>, + trail: Option>, +) { + use fancy_regex::Captures; + use fancy_regex::Regex; + use once_cell::sync::Lazy; + + static RE_LEADING: Lazy = + Lazy::new(|| Regex::new(r"(?m)(?P^\s+)").expect("error with leading space regex")); + static RE_TRAILING: Lazy = + Lazy::new(|| Regex::new(r"(?m)(?P\s+$)").expect("error with trailing space regex")); + + if lead.is_none() && trail.is_none() { + return; + } + + for row in data.iter_mut() { + for cell in row { + let mut buf = cell.as_ref().to_owned(); + + if let Some(color) = &lead { + buf = RE_LEADING + .replace_all(cell.as_ref(), |cap: &Captures| { + let spaces = cap.get(1).expect("valid").as_str(); + format!("{}{}{}", color.get_prefix(), spaces, color.get_suffix()) + }) + .into_owned(); + } + + if let Some(color) = &trail { + buf = RE_TRAILING + .replace_all(buf.as_ref(), |cap: &Captures| { + let spaces = cap.get(1).expect("valid").as_str(); + format!("{}{}{}", color.get_prefix(), spaces, color.get_suffix()) + }) + .into_owned(); + } + + *cell = CellInfo::new(buf); + } + } +} diff --git a/crates/nu-table/src/types/expanded.rs b/crates/nu-table/src/types/expanded.rs index 3b2ad16b8..73a9d17b9 100644 --- a/crates/nu-table/src/types/expanded.rs +++ b/crates/nu-table/src/types/expanded.rs @@ -9,8 +9,8 @@ use tabled::grid::config::Position; use crate::{ common::{ create_nu_table_config, error_sign, get_header_style, get_index_style, - load_theme_from_config, nu_value_to_string, nu_value_to_string_clean, wrap_text, NuText, - StringResult, TableResult, INDEX_COLUMN_NAME, + get_leading_trailing_space_style, load_theme_from_config, nu_value_to_string, + nu_value_to_string_clean, wrap_text, NuText, StringResult, TableResult, INDEX_COLUMN_NAME, }, string_width, NuTable, NuTableCell, TableOpts, TableOutput, }; @@ -178,6 +178,10 @@ fn expanded_table_list(input: &[Value], cfg: Cfg<'_>) -> TableResult { table.set_index_style(get_index_style(cfg.opts.style_computer)); set_data_styles(&mut table, data_styles); + if let Some(style) = get_leading_trailing_space_style(cfg.opts.style_computer).color_style { + table.set_trail_lead_style(style, style); + } + return Ok(Some(TableOutput::new(table, false, with_index))); } @@ -337,6 +341,10 @@ fn expanded_table_list(input: &[Value], cfg: Cfg<'_>) -> TableResult { table.set_indent(cfg.opts.indent.0, cfg.opts.indent.1); set_data_styles(&mut table, data_styles); + if let Some(style) = get_leading_trailing_space_style(cfg.opts.style_computer).color_style { + table.set_trail_lead_style(style, style); + } + Ok(Some(TableOutput::new(table, true, with_index))) } @@ -387,6 +395,10 @@ fn expanded_table_kv(record: &Record, cfg: Cfg<'_>) -> StringResult { table.set_index_style(get_key_style(&cfg)); table.set_indent(cfg.opts.indent.0, cfg.opts.indent.1); + if let Some(style) = get_leading_trailing_space_style(cfg.opts.style_computer).color_style { + table.set_trail_lead_style(style, style); + } + let out = TableOutput::new(table, false, true); maybe_expand_table(out, cfg.opts.width, &cfg.opts) diff --git a/crates/nu-table/src/types/general.rs b/crates/nu-table/src/types/general.rs index 6114e03bb..4782ecc75 100644 --- a/crates/nu-table/src/types/general.rs +++ b/crates/nu-table/src/types/general.rs @@ -6,7 +6,7 @@ use crate::{ clean_charset, common::{ create_nu_table_config, get_empty_style, get_header_style, get_index_style, - get_value_style, NuText, INDEX_COLUMN_NAME, + get_leading_trailing_space_style, get_value_style, NuText, INDEX_COLUMN_NAME, }, NuTable, NuTableCell, StringResult, TableOpts, TableOutput, TableResult, }; @@ -60,6 +60,10 @@ fn kv_table(record: &Record, opts: TableOpts<'_>) -> StringResult { let mut table = NuTable::from(data); table.set_index_style(TextStyle::default_field()); + if let Some(style) = get_leading_trailing_space_style(opts.style_computer).color_style { + table.set_trail_lead_style(style, style); + } + let mut out = TableOutput::new(table, false, true); let left = opts.config.table_indent.left; @@ -121,6 +125,10 @@ fn to_table_with_header( table.set_header_style(get_header_style(opts.style_computer)); table.set_index_style(get_index_style(opts.style_computer)); + if let Some(style) = get_leading_trailing_space_style(opts.style_computer).color_style { + table.set_trail_lead_style(style, style); + } + for (i, text) in headers.iter().enumerate() { table.insert((0, i), text.to_owned()); } @@ -160,6 +168,10 @@ fn to_table_with_no_header( let mut table = NuTable::new(input.len(), with_index as usize + 1); table.set_index_style(get_index_style(opts.style_computer)); + if let Some(style) = get_leading_trailing_space_style(opts.style_computer).color_style { + table.set_trail_lead_style(style, style); + } + for (row, item) in input.iter().enumerate() { if nu_utils::ctrl_c::was_pressed(&opts.ctrlc) { return Ok(None);