diff --git a/crates/nu-command/src/viewers/table.rs b/crates/nu-command/src/viewers/table.rs index 14041cc33b..74234de89a 100644 --- a/crates/nu-command/src/viewers/table.rs +++ b/crates/nu-command/src/viewers/table.rs @@ -354,10 +354,14 @@ fn handle_record( }; if let Some(limit) = cfg.abbreviation { - if record.cols.len() > limit * 2 + 1 { - record.cols = abbreviate_list(&record.cols, limit, String::from("...")); - record.vals = - abbreviate_list(&record.vals, limit, Value::string("...", Span::unknown())); + let prev_len = record.len(); + if record.len() > limit * 2 + 1 { + // TODO: see if the following table builders would be happy with a simple iterator + let mut record_iter = record.into_iter(); + record = Record::with_capacity(limit * 2 + 1); + record.extend(record_iter.by_ref().take(limit)); + record.push(String::from("..."), Value::string("...", Span::unknown())); + record.extend(record_iter.skip(prev_len - 2 * limit)); } } @@ -456,26 +460,19 @@ fn handle_row_stream( None => None, }; let ls_colors = get_ls_colors(ls_colors_env_str); - let span = input.call.head; ListStream::from_stream( stream.map(move |mut x| match &mut x { Value::Record { val: record, .. } => { - let mut idx = 0; - - while idx < record.len() { - // Only the name column gets special colors, for now - if record.cols[idx] == "name" { - let span = record.vals.get(idx).map(|v| v.span()).unwrap_or(span); - if let Some(Value::String { val, .. }) = record.vals.get(idx) { - let val = render_path_name(val, &config, &ls_colors, span); - if let Some(val) = val { - record.vals[idx] = val; - } + // Only the name column gets special colors, for now + if let Some(value) = record.get_mut("name") { + let span = value.span(); + if let Value::String { val, .. } = value { + if let Some(val) = render_path_name(val, &config, &ls_colors, span) + { + *value = val; } } - - idx += 1; } x @@ -490,36 +487,34 @@ fn handle_row_stream( data_source: DataSource::HtmlThemes, }) => { let ctrlc = ctrlc.clone(); - let span = input.call.head; ListStream::from_stream( stream.map(move |mut x| match &mut x { Value::Record { val: record, .. } => { - let mut idx = 0; - // Every column in the HTML theme table except 'name' is colored - while idx < record.len() { - if record.cols[idx] != "name" { - // Simple routine to grab the hex code, convert to a style, - // then place it in a new Value::String. - - let span = record.vals.get(idx).map(|v| v.span()).unwrap_or(span); - if let Some(Value::String { val, .. }) = record.vals.get(idx) { - let s = match color_from_hex(val) { - Ok(c) => match c { - // .normal() just sets the text foreground color. - Some(c) => c.normal(), - None => nu_ansi_term::Style::default(), - }, - Err(_) => nu_ansi_term::Style::default(), - }; - record.vals[idx] = Value::string( - // Apply the style (ANSI codes) to the string - s.paint(val).to_string(), - span, - ); - } + for (rec_col, rec_val) in record.iter_mut() { + // Every column in the HTML theme table except 'name' is colored + if rec_col != "name" { + continue; + } + // Simple routine to grab the hex code, convert to a style, + // then place it in a new Value::String. + + let span = rec_val.span(); + if let Value::String { val, .. } = rec_val { + let s = match color_from_hex(val) { + Ok(c) => match c { + // .normal() just sets the text foreground color. + Some(c) => c.normal(), + None => nu_ansi_term::Style::default(), + }, + Err(_) => nu_ansi_term::Style::default(), + }; + *rec_val = Value::string( + // Apply the style (ANSI codes) to the string + s.paint(&*val).to_string(), + span, + ); } - idx += 1; } x } @@ -756,10 +751,19 @@ impl Iterator for PagingTableCreator { if limit > 0 && is_record_list { // in case it's a record list we set a default text to each column instead of a single value. - let cols = batch[0].as_record().expect("ok").cols.clone(); - let vals = - vec![Value::string(String::from("..."), Span::unknown()); cols.len()]; - batch[limit] = Value::record(Record { cols, vals }, Span::unknown()); + let dummy: Record = batch[0] + .as_record() + .expect("ok") + .columns() + .map(|k| { + ( + k.to_owned(), + Value::string(String::from("..."), Span::unknown()), + ) + }) + .collect(); + + batch[limit] = Value::record(dummy, Span::unknown()); } } } diff --git a/crates/nu-table/src/types/collapse.rs b/crates/nu-table/src/types/collapse.rs index 9682460130..6a7931bf2f 100644 --- a/crates/nu-table/src/types/collapse.rs +++ b/crates/nu-table/src/types/collapse.rs @@ -1,5 +1,5 @@ use nu_color_config::StyleComputer; -use nu_protocol::{Config, Value}; +use nu_protocol::{Config, Record, Value}; use crate::UnstructuredTable; @@ -40,17 +40,22 @@ fn collapsed_table( fn colorize_value(value: &mut Value, config: &Config, style_computer: &StyleComputer) { match value { - Value::Record { val: record, .. } => { - for val in &mut record.vals { - colorize_value(val, config, style_computer); - } - + Value::Record { ref mut val, .. } => { let style = get_index_style(style_computer); - if let Some(color) = style.color_style { - for header in &mut record.cols { - *header = color.paint(header.to_owned()).to_string(); - } - } + // Take ownership of the record and reassign to &mut + // We do this to have owned keys through `.into_iter` + let record = std::mem::take(val); + *val = record + .into_iter() + .map(|(mut header, mut val)| { + colorize_value(&mut val, config, style_computer); + + if let Some(color) = style.color_style { + header = color.paint(header).to_string(); + } + (header, val) + }) + .collect::(); } Value::List { vals, .. } => { for val in vals { diff --git a/crates/nu-table/src/types/expanded.rs b/crates/nu-table/src/types/expanded.rs index 9e5c11928e..1fe6e9be7a 100644 --- a/crates/nu-table/src/types/expanded.rs +++ b/crates/nu-table/src/types/expanded.rs @@ -344,8 +344,7 @@ fn expanded_table_list(input: &[Value], cfg: Cfg<'_>) -> TableResult { fn expanded_table_kv(record: &Record, cfg: Cfg<'_>) -> StringResult { let theme = load_theme_from_config(cfg.opts.config); let key_width = record - .cols - .iter() + .columns() .map(|col| string_width(col)) .max() .unwrap_or(0); diff --git a/crates/nu-table/src/unstructured_table.rs b/crates/nu-table/src/unstructured_table.rs index a5b2e5d123..4ae7d35b1f 100644 --- a/crates/nu-table/src/unstructured_table.rs +++ b/crates/nu-table/src/unstructured_table.rs @@ -157,17 +157,18 @@ fn build_vertical_array(vals: Vec, config: &Config) -> TableValue { } fn is_valid_record(vals: &[Value]) -> bool { - let mut used_cols: Option<&[String]> = None; + let mut first_record: Option<&Record> = None; for val in vals { match val { Value::Record { val, .. } => { - let cols_are_not_equal = - used_cols.is_some() && !matches!(used_cols, Some(used) if val.cols == used); - if cols_are_not_equal { - return false; - } - - used_cols = Some(&val.cols); + if let Some(known) = first_record { + let equal = known.columns().eq(val.columns()); + if !equal { + return false; + } + } else { + first_record = Some(val) + }; } _ => return false, } @@ -195,8 +196,8 @@ fn build_map_from_record(vals: Vec, config: &Config) -> TableValue { for val in vals { match val { Value::Record { val, .. } => { - for (i, cell) in val.vals.into_iter().take(count_columns).enumerate() { - let cell = convert_nu_value_to_table_value(cell, config); + for (i, (_key, val)) in val.into_iter().take(count_columns).enumerate() { + let cell = convert_nu_value_to_table_value(val, config); list[i].push(cell); } } @@ -211,7 +212,7 @@ fn build_map_from_record(vals: Vec, config: &Config) -> TableValue { fn get_columns_in_record(vals: &[Value]) -> Vec { match vals.iter().next() { - Some(Value::Record { val, .. }) => val.cols.clone(), + Some(Value::Record { val, .. }) => val.columns().cloned().collect(), _ => vec![], } }