diff --git a/crates/nu-table/src/common.rs b/crates/nu-table/src/common.rs index 1564d5104..c35eecf2f 100644 --- a/crates/nu-table/src/common.rs +++ b/crates/nu-table/src/common.rs @@ -2,7 +2,9 @@ use nu_color_config::{Alignment, StyleComputer, TextStyle}; use nu_protocol::TrimStrategy; use nu_protocol::{Config, FooterMode, ShellError, Span, Value}; -use crate::{clean_charset, string_wrap, NuTableConfig, TableOutput, TableTheme}; +use crate::{ + clean_charset, colorize_space_str, string_wrap, NuTableConfig, TableOutput, TableTheme, +}; pub type NuText = (String, TextStyle); pub type TableResult = Result, ShellError>; @@ -34,9 +36,11 @@ pub fn nu_value_to_string(val: &Value, cfg: &Config, style: &StyleComputer) -> N make_styled_string(style, text, Some(val), float_precision) } -pub fn nu_value_to_string_clean(val: &Value, cfg: &Config, style: &StyleComputer) -> NuText { - let (text, style) = nu_value_to_string(val, cfg, style); - let text = clean_charset(&text); +pub fn nu_value_to_string_clean(val: &Value, cfg: &Config, style_comp: &StyleComputer) -> NuText { + let (text, style) = nu_value_to_string(val, cfg, style_comp); + let mut text = clean_charset(&text); + colorize_space_str(&mut text, style_comp); + (text, style) } diff --git a/crates/nu-table/src/table.rs b/crates/nu-table/src/table.rs index 1b4fbc321..6a41a77c3 100644 --- a/crates/nu-table/src/table.rs +++ b/crates/nu-table/src/table.rs @@ -1,4 +1,4 @@ -use crate::table_theme::TableTheme; +use crate::{convert_style, table_theme::TableTheme}; use nu_ansi_term::Style; use nu_color_config::TextStyle; use nu_protocol::TrimStrategy; @@ -41,8 +41,6 @@ struct Styles { index: AnsiColor<'static>, header: AnsiColor<'static>, data: EntityMap>, - space_lead: Option>, - space_trail: Option>, data_is_set: bool, } @@ -140,17 +138,14 @@ 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); } + pub fn get_records_mut(&mut self) -> &mut NuRecords { + &mut self.data + } + /// Converts a table to a String. /// /// It returns None in case where table cannot be fit to a terminal width. @@ -235,7 +230,7 @@ fn build_table( } fn draw_table( - mut data: NuRecords, + data: NuRecords, alignments: Alignments, styles: Styles, widths: Vec, @@ -249,12 +244,6 @@ 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(); @@ -727,10 +716,6 @@ impl TableOption for SetAlignment { } } -fn convert_style(style: Style) -> Color { - Color::new(style.prefix().to_string(), style.suffix().to_string()) -} - struct SetDimensions(Vec); impl TableOption, ColoredConfig> for SetDimensions { @@ -928,51 +913,6 @@ 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); - } - } -} - struct StripColorFromRow(usize); impl TableOption, ColoredConfig> for StripColorFromRow { diff --git a/crates/nu-table/src/types/expanded.rs b/crates/nu-table/src/types/expanded.rs index 73a9d17b9..3b2ad16b8 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, - 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, + 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,10 +178,6 @@ 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))); } @@ -341,10 +337,6 @@ 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))) } @@ -395,10 +387,6 @@ 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 4782ecc75..5301c683d 100644 --- a/crates/nu-table/src/types/general.rs +++ b/crates/nu-table/src/types/general.rs @@ -3,10 +3,10 @@ use nu_engine::column::get_columns; use nu_protocol::{ast::PathMember, Config, Record, ShellError, Span, TableIndexMode, Value}; use crate::{ - clean_charset, + clean_charset, colorize_space, common::{ create_nu_table_config, get_empty_style, get_header_style, get_index_style, - get_leading_trailing_space_style, get_value_style, NuText, INDEX_COLUMN_NAME, + get_value_style, NuText, INDEX_COLUMN_NAME, }, NuTable, NuTableCell, StringResult, TableOpts, TableOutput, TableResult, }; @@ -30,6 +30,8 @@ fn create_table(input: &[Value], opts: TableOpts<'_>) -> Result, let right = opts.config.table_indent.right; out.table.set_indent(left, right); + colorize_space(out.table.get_records_mut(), opts.style_computer); + let table_config = create_nu_table_config(opts.config, opts.style_computer, &out, false); Ok(out.table.draw(table_config, opts.width)) @@ -57,13 +59,11 @@ fn kv_table(record: &Record, opts: TableOpts<'_>) -> StringResult { row.push(value); } + colorize_space(&mut data, opts.style_computer); + 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; @@ -125,10 +125,6 @@ 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()); } @@ -168,10 +164,6 @@ 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); diff --git a/crates/nu-table/src/util.rs b/crates/nu-table/src/util.rs index 48ff0b072..ecdf91863 100644 --- a/crates/nu-table/src/util.rs +++ b/crates/nu-table/src/util.rs @@ -1,9 +1,14 @@ +use nu_color_config::StyleComputer; use tabled::{ builder::Builder, - grid::util::string::string_width_multiline, - settings::{width::Truncate, Modify, Padding, Style, Width}, + grid::{ + color::AnsiColor, records::vec_records::CellInfo, util::string::string_width_multiline, + }, + settings::{width::Truncate, Color, Modify, Padding, Style, Width}, }; +use crate::common::get_leading_trailing_space_style; + pub fn string_width(text: &str) -> usize { string_width_multiline(text) } @@ -47,3 +52,75 @@ pub fn clean_charset(text: &str) -> String { // todo: optimize, I bet it can be done in 1 path text.replace('\t', " ").replace('\r', "") } + +pub fn colorize_space(data: &mut [Vec>], style_computer: &StyleComputer<'_>) { + if let Some(style) = get_leading_trailing_space_style(style_computer).color_style { + let style = convert_style(style).into(); + colorize_lead_trail_space(data, Some(&style), Some(&style)); + } +} + +pub fn colorize_space_str(text: &mut String, style_computer: &StyleComputer<'_>) { + if let Some(style) = get_leading_trailing_space_style(style_computer).color_style { + let style = convert_style(style).into(); + *text = colorize_space_one(text, Some(&style), Some(&style)); + } +} + +fn colorize_lead_trail_space( + data: &mut [Vec>], + lead: Option<&AnsiColor<'_>>, + trail: Option<&AnsiColor<'_>>, +) { + if lead.is_none() && trail.is_none() { + return; + } + + for row in data.iter_mut() { + for cell in row { + let buf = colorize_space_one(cell.as_ref(), lead, trail); + *cell = CellInfo::new(buf); + } + } +} + +fn colorize_space_one( + text: &str, + lead: Option<&AnsiColor<'_>>, + trail: Option<&AnsiColor<'_>>, +) -> String { + 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")); + + let mut buf = text.to_owned(); + + if let Some(color) = &lead { + buf = RE_LEADING + .replace_all(&buf, |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, |cap: &Captures| { + let spaces = cap.get(1).expect("valid").as_str(); + format!("{}{}{}", color.get_prefix(), spaces, color.get_suffix()) + }) + .into_owned(); + } + + buf +} + +pub fn convert_style(style: nu_ansi_term::Style) -> Color { + Color::new(style.prefix().to_string(), style.suffix().to_string()) +}