diff --git a/crates/nu-cli/src/commands/format.rs b/crates/nu-cli/src/commands/format.rs index 9d79de9a1c..8dc6bf7548 100644 --- a/crates/nu-cli/src/commands/format.rs +++ b/crates/nu-cli/src/commands/format.rs @@ -2,7 +2,11 @@ use crate::commands::PerItemCommand; use crate::context::CommandRegistry; use crate::prelude::*; use nu_errors::ShellError; -use nu_protocol::{CallInfo, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; +use nu_protocol::{ + CallInfo, ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value, +}; +use nu_source::Tagged; +use nu_value_ext::{as_column_path, get_data_by_column_path}; use std::borrow::Borrow; use nom::{ @@ -45,35 +49,46 @@ impl PerItemCommand for Format { ShellError::labeled_error( "Could not create format pattern", "could not create format pattern", - pattern_tag, + &pattern_tag, ) })?; let commands = format_pattern.1; - let output = if let Value { - value: UntaggedValue::Row(dict), - .. - } = value - { - let mut output = String::new(); + let output = match value { + value + @ + Value { + value: UntaggedValue::Row(_), + .. + } => { + let mut output = String::new(); - for command in &commands { - match command { - FormatCommand::Text(s) => { - output.push_str(s); - } - FormatCommand::Column(c) => { - if let Some(c) = dict.entries.get(c) { - output.push_str(&value::format_leaf(c.borrow()).plain_string(100_000)) + for command in &commands { + match command { + FormatCommand::Text(s) => { + output.push_str(s); + } + FormatCommand::Column(c) => { + let key = to_column_path(&c, &pattern_tag)?; + + let fetcher = get_data_by_column_path( + &value, + &key, + Box::new(move |(_, _, error)| error), + ); + + if let Ok(c) = fetcher { + output + .push_str(&value::format_leaf(c.borrow()).plain_string(100_000)) + } + // That column doesn't match, so don't emit anything } - // That column doesn't match, so don't emit anything } } - } - output - } else { - String::new() + output + } + _ => String::new(), }; Ok(futures::stream::iter(vec![ReturnSuccess::value( @@ -116,3 +131,27 @@ fn format(input: &str) -> IResult<&str, Vec> { Ok((loop_input, output)) } + +fn to_column_path( + path_members: &str, + tag: impl Into, +) -> Result, ShellError> { + let tag = tag.into(); + + as_column_path( + &UntaggedValue::Table( + path_members + .split('.') + .map(|x| { + let member = match x.parse::() { + Ok(v) => UntaggedValue::int(v), + Err(_) => UntaggedValue::string(x), + }; + + member.into_value(&tag) + }) + .collect(), + ) + .into_value(&tag), + ) +} diff --git a/crates/nu-cli/tests/commands/format.rs b/crates/nu-cli/tests/commands/format.rs index 3540f60264..8701fc2d4c 100644 --- a/crates/nu-cli/tests/commands/format.rs +++ b/crates/nu-cli/tests/commands/format.rs @@ -14,3 +14,17 @@ fn creates_the_resulting_string_from_the_given_fields() { assert_eq!(actual, "nu has license ISC"); } + +#[test] +fn given_fields_can_be_column_paths() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open cargo_sample.toml + | format "{package.name} is {package.description}" + | echo $it + "# + )); + + assert_eq!(actual, "nu is a new type of shell"); +} diff --git a/crates/nu-cli/tests/commands/save.rs b/crates/nu-cli/tests/commands/save.rs index b09cd51563..be01c18fcb 100644 --- a/crates/nu-cli/tests/commands/save.rs +++ b/crates/nu-cli/tests/commands/save.rs @@ -42,6 +42,6 @@ fn writes_out_csv() { ); let actual = file_contents(expected_file); - assert!(actual.contains("[Table],A shell for the GitHub era,2018,ISC,nu,0.1.1")); + assert!(actual.contains("[Table],a new type of shell,2018,ISC,nu,0.1.1")); }) } diff --git a/tests/fixtures/formats/cargo_sample.toml b/tests/fixtures/formats/cargo_sample.toml index cdecccd4c0..cdf27ec470 100644 --- a/tests/fixtures/formats/cargo_sample.toml +++ b/tests/fixtures/formats/cargo_sample.toml @@ -2,7 +2,7 @@ name = "nu" version = "0.1.1" authors = ["Yehuda Katz "] -description = "A shell for the GitHub era" +description = "a new type of shell" license = "ISC" edition = "2018"