diff --git a/crates/nu-command/src/formats/to/xml.rs b/crates/nu-command/src/formats/to/xml.rs index 36c5e87783..6bccfbfd76 100644 --- a/crates/nu-command/src/formats/to/xml.rs +++ b/crates/nu-command/src/formats/to/xml.rs @@ -148,7 +148,7 @@ pub fn write_xml_events( } } _ => { - let s = current.clone().into_abbreviated_string(config); + let s = current.into_abbreviated_string(config); writer .write_event(Event::Text(BytesText::from_plain_str(s.as_str()))) .expect("Couldn't write XML text"); diff --git a/crates/nu-command/src/viewers/table.rs b/crates/nu-command/src/viewers/table.rs index 7071c7eccf..6ae19360c9 100644 --- a/crates/nu-command/src/viewers/table.rs +++ b/crates/nu-command/src/viewers/table.rs @@ -52,7 +52,7 @@ impl Command for Table { match input { PipelineData::Value(Value::List { vals, .. }, ..) => { - let table = convert_to_table(0, vals, ctrlc, &config, call.head)?; + let table = convert_to_table(0, &vals, ctrlc, &config, call.head)?; if let Some(table) = table { let result = nu_table::draw_table(&table, term_width, &color_hm, &config); @@ -215,20 +215,35 @@ impl Command for Table { } } +fn get_columns(input: &[Value]) -> Vec { + let mut columns = vec![]; + + for item in input { + if let Value::Record { cols, vals: _, .. } = item { + for col in cols { + if !columns.contains(col) { + columns.push(col.to_string()); + } + } + } + } + + columns +} + fn convert_to_table( row_offset: usize, - iter: impl IntoIterator, + input: &[Value], ctrlc: Option>, config: &Config, head: Span, ) -> Result, ShellError> { - let mut iter = iter.into_iter().peekable(); + let mut headers = get_columns(input); + let mut input = input.iter().peekable(); let color_hm = get_color_config(config); let float_precision = config.float_precision as usize; - if let Some(first) = iter.peek() { - let mut headers = first.columns(); - + if input.peek().is_some() { if !headers.is_empty() { headers.insert(0, "#".into()); } @@ -236,41 +251,34 @@ fn convert_to_table( // Vec of Vec of String1, String2 where String1 is datatype and String2 is value let mut data: Vec> = Vec::new(); - for (row_num, item) in iter.enumerate() { + for (row_num, item) in input.enumerate() { if let Some(ctrlc) = &ctrlc { if ctrlc.load(Ordering::SeqCst) { return Ok(None); } } if let Value::Error { error } = item { - return Err(error); + return Err(error.clone()); } // String1 = datatype, String2 = value as string let mut row: Vec<(String, String)> = vec![("string".to_string(), (row_num + row_offset).to_string())]; - if headers.is_empty() { - // if header row is empty, this is probably a list so format it that way - row.push(("list".to_string(), item.into_abbreviated_string(config))) - } else { - for header in headers.iter().skip(1) { - let result = match item { - Value::Record { .. } => { - item.clone().follow_cell_path(&[PathMember::String { - val: header.into(), - span: head, - }]) - } - _ => Ok(item.clone()), - }; + for header in headers.iter().skip(1) { + let result = match item { + Value::Record { .. } => item.clone().follow_cell_path(&[PathMember::String { + val: header.into(), + span: head, + }]), + _ => Ok(item.clone()), + }; - match result { - Ok(value) => row.push(( - (&value.get_type()).to_string(), - value.into_abbreviated_string(config), - )), - Err(_) => row.push(("empty".to_string(), String::new())), - } + match result { + Ok(value) => row.push(( + (&value.get_type()).to_string(), + value.into_abbreviated_string(config), + )), + Err(_) => row.push(("empty".to_string(), "❎".into())), } } @@ -397,7 +405,7 @@ impl Iterator for PagingTableCreator { let table = convert_to_table( self.row_offset, - batch.into_iter(), + &batch, self.ctrlc.clone(), &self.config, self.head, diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index 80fd2d8eed..61f84127c5 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -386,22 +386,22 @@ impl Value { } /// Convert Value into string. Note that Streams will be consumed. - pub fn into_abbreviated_string(self, config: &Config) -> String { + pub fn into_abbreviated_string(&self, config: &Config) -> String { match self { Value::Bool { val, .. } => val.to_string(), Value::Int { val, .. } => val.to_string(), Value::Float { val, .. } => val.to_string(), - Value::Filesize { val, .. } => format_filesize(val, config), - Value::Duration { val, .. } => format_duration(val), - Value::Date { val, .. } => HumanTime::from(val).to_string(), + Value::Filesize { val, .. } => format_filesize(*val, config), + Value::Duration { val, .. } => format_duration(*val), + Value::Date { val, .. } => HumanTime::from(*val).to_string(), Value::Range { val, .. } => { format!( "{}..{}", - val.from.into_string(", ", config), - val.to.into_string(", ", config) + val.from.clone().into_string(", ", config), + val.to.clone().into_string(", ", config) ) } - Value::String { val, .. } => val, + Value::String { val, .. } => val.to_string(), Value::List { ref vals, .. } => match &vals[..] { [Value::Record { .. }, _end @ ..] => format!( "[table {} row{}]",