let format access variables also (#1842)

This commit is contained in:
Jonathan Turner 2020-05-18 21:20:09 -07:00 committed by GitHub
parent 76b170cea0
commit b89976daef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 40 additions and 61 deletions

View File

@ -1,10 +1,10 @@
use crate::commands::WholeStreamCommand; use crate::commands::WholeStreamCommand;
use crate::context::CommandRegistry; use crate::context::CommandRegistry;
use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*; use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
use nu_source::Tagged; use nu_source::Tagged;
use nu_value_ext::{as_column_path, get_data_by_column_path};
use std::borrow::Borrow; use std::borrow::Borrow;
pub struct Format; pub struct Format;
@ -54,6 +54,7 @@ fn format_command(
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = registry.clone(); let registry = registry.clone();
let stream = async_stream! { let stream = async_stream! {
let scope = args.call_info.scope.clone();
let (FormatArgs { pattern }, mut input) = args.process(&registry).await?; let (FormatArgs { pattern }, mut input) = args.process(&registry).await?;
let pattern_tag = pattern.tag.clone(); let pattern_tag = pattern.tag.clone();
@ -61,44 +62,32 @@ fn format_command(
let commands = format_pattern; let commands = format_pattern;
while let Some(value) = input.next().await { while let Some(value) = input.next().await {
match value { let scope = scope.clone().set_it(value);
value let mut output = String::new();
@
Value {
value: UntaggedValue::Row(_),
..
} => {
let mut output = String::new();
for command in &commands { for command in &commands {
match command { match command {
FormatCommand::Text(s) => { FormatCommand::Text(s) => {
output.push_str(&s); output.push_str(&s);
} }
FormatCommand::Column(c) => { FormatCommand::Column(c) => {
let key = to_column_path(&c, &pattern_tag)?; // FIXME: use the correct spans
let full_column_path = nu_parser::parse_full_column_path(&(c.to_string()).spanned(Span::unknown()), &registry);
let fetcher = get_data_by_column_path( let result = evaluate_baseline_expr(&full_column_path.0, &registry, &scope).await;
&value,
&key,
Box::new(move |(_, _, error)| error),
);
if let Ok(c) = fetcher { if let Ok(c) = result {
output output
.push_str(&value::format_leaf(c.borrow()).plain_string(100_000)) .push_str(&value::format_leaf(c.borrow()).plain_string(100_000))
} } else {
// That column doesn't match, so don't emit anything // That column doesn't match, so don't emit anything
}
} }
} }
yield ReturnSuccess::value(
UntaggedValue::string(output).into_untagged_value())
} }
_ => yield ReturnSuccess::value( }
UntaggedValue::string(String::new()).into_untagged_value()),
}; yield ReturnSuccess::value(
UntaggedValue::string(output).into_untagged_value())
} }
}; };
@ -150,30 +139,6 @@ fn format(input: &str) -> Vec<FormatCommand> {
output output
} }
fn to_column_path(
path_members: &str,
tag: impl Into<Tag>,
) -> Result<Tagged<ColumnPath>, ShellError> {
let tag = tag.into();
as_column_path(
&UntaggedValue::Table(
path_members
.split('.')
.map(|x| {
let member = match x.parse::<u64>() {
Ok(v) => UntaggedValue::int(v),
Err(_) => UntaggedValue::string(x),
};
member.into_value(&tag)
})
.collect(),
)
.into_value(&tag),
)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Format; use super::Format;

View File

@ -192,7 +192,7 @@ async fn evaluate_invocation(
let mut context = Context::basic()?; let mut context = Context::basic()?;
context.registry = registry.clone(); context.registry = registry.clone();
let input = InputStream::one(scope.it.clone()); let input = InputStream::empty();
let result = run_block(&block, &mut context, input, &scope.clone()).await?; let result = run_block(&block, &mut context, input, &scope.clone()).await?;

View File

@ -28,3 +28,17 @@ fn given_fields_can_be_column_paths() {
assert_eq!(actual.out, "nu is a new type of shell"); assert_eq!(actual.out, "nu is a new type of shell");
} }
#[test]
fn can_use_variables() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
open cargo_sample.toml
| format "{$it.package.name} is {$it.package.description}"
| echo $it
"#
));
assert_eq!(actual.out, "nu is a new type of shell");
}

View File

@ -5,7 +5,7 @@ mod shapes;
mod signature; mod signature;
pub use crate::lite_parse::{lite_parse, LiteBlock}; pub use crate::lite_parse::{lite_parse, LiteBlock};
pub use crate::parse::{classify_block, garbage}; pub use crate::parse::{classify_block, garbage, parse_full_column_path};
pub use crate::path::expand_ndots; pub use crate::path::expand_ndots;
pub use crate::shapes::shapes; pub use crate::shapes::shapes;
pub use crate::signature::{Signature, SignatureRegistry}; pub use crate::signature::{Signature, SignatureRegistry};

View File

@ -73,7 +73,7 @@ fn parse_simple_column_path(lite_arg: &Spanned<String>) -> (SpannedExpression, O
} }
/// Parses a column path, adding in the preceding reference to $it if it's elided /// Parses a column path, adding in the preceding reference to $it if it's elided
fn parse_full_column_path( pub fn parse_full_column_path(
lite_arg: &Spanned<String>, lite_arg: &Spanned<String>,
registry: &dyn SignatureRegistry, registry: &dyn SignatureRegistry,
) -> (SpannedExpression, Option<ParseError>) { ) -> (SpannedExpression, Option<ParseError>) {