Fix it expansion and add collect (#2065)

This commit is contained in:
Jonathan Turner 2020-06-27 17:38:19 +12:00 committed by GitHub
parent 05781607f4
commit 4e2a4236f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 133 additions and 34 deletions

View file

@ -303,6 +303,7 @@ pub fn create_default_context(
whole_stream_command(StrSet),
whole_stream_command(StrToDatetime),
whole_stream_command(StrTrim),
whole_stream_command(StrCollect),
whole_stream_command(BuildString),
whole_stream_command(Ansi),
// Column manipulation
@ -657,10 +658,12 @@ pub async fn cli(
if let Ok(result) = nu_parser::lite_parse(&prompt_line, 0).map_err(ShellError::from)
{
let prompt_block = nu_parser::classify_block(&result, context.registry());
let mut prompt_block = nu_parser::classify_block(&result, context.registry());
let env = context.get_env();
prompt_block.block.expand_it_usage();
match run_block(
&prompt_block.block,
&mut context,

View file

@ -240,8 +240,8 @@ pub(crate) use split::SplitColumn;
pub(crate) use split::SplitRow;
pub(crate) use split_by::SplitBy;
pub(crate) use str_::{
Str, StrCapitalize, StrDowncase, StrFindReplace, StrSet, StrSubstring, StrToDatetime,
StrToDecimal, StrToInteger, StrTrim, StrUpcase,
Str, StrCapitalize, StrCollect, StrDowncase, StrFindReplace, StrSet, StrSubstring,
StrToDatetime, StrToDecimal, StrToInteger, StrTrim, StrUpcase,
};
#[allow(unused_imports)]
pub(crate) use t_sort_by::TSortBy;

View file

@ -0,0 +1,56 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue, Value};
pub struct SubCommand;
#[async_trait]
impl WholeStreamCommand for SubCommand {
fn name(&self) -> &str {
"str collect"
}
fn signature(&self) -> Signature {
Signature::build("str collect")
}
fn usage(&self) -> &str {
"collects a list of strings into a string"
}
async fn run(
&self,
args: CommandArgs,
_registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let output = args
.input
.collect_string(args.call_info.name_tag.clone())
.await?;
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::string(output.item).into_value(output.tag),
)))
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Collect a list of string",
example: "echo ['a' 'b' 'c'] | str collect",
result: Some(vec![Value::from("abc")]),
}]
}
}
#[cfg(test)]
mod tests {
use super::SubCommand;
#[test]
fn examples_work_as_expected() {
use crate::examples::test as test_examples;
test_examples(SubCommand {})
}
}

View file

@ -1,4 +1,5 @@
mod capitalize;
mod collect;
mod command;
mod downcase;
mod find_replace;
@ -11,6 +12,7 @@ mod trim;
mod upcase;
pub use capitalize::SubCommand as StrCapitalize;
pub use collect::SubCommand as StrCollect;
pub use command::Command as Str;
pub use downcase::SubCommand as StrDowncase;
pub use find_replace::SubCommand as StrFindReplace;

View file

@ -1,7 +1,7 @@
use crate::prelude::*;
use futures::stream::{iter, once};
use nu_errors::ShellError;
use nu_protocol::{Primitive, UntaggedValue, Value};
use nu_protocol::{Primitive, Type, UntaggedValue, Value};
use nu_source::{Tagged, TaggedItem};
pub struct InputStream {
@ -74,12 +74,18 @@ impl InputStream {
value_tag = value_t;
bytes.extend_from_slice(&b);
}
Some(Value { tag: value_tag, .. }) => {
Some(Value {
tag: value_tag,
value,
}) => {
return Err(ShellError::labeled_error_with_secondary(
"Expected a string from pipeline",
"requires string input",
tag,
"value originates from here",
format!(
"{} originates from here",
Type::from_value(&value).plain_string(100000)
),
value_tag,
))
}

View file

@ -44,6 +44,14 @@ impl InternalCommand {
),
}
}
pub fn expand_it_usage(&mut self) {
if let Some(positionals) = &mut self.args.positional {
for arg in positionals {
arg.expand_it_usage();
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
@ -109,34 +117,8 @@ impl ClassifiedCommand {
pub fn expand_it_usage(&mut self) {
match self {
ClassifiedCommand::Internal(command) => {
if let Some(positionals) = &mut command.args.positional {
for arg in positionals {
if let SpannedExpression {
expr: Expression::Block(block),
..
} = arg
{
block.expand_it_usage();
}
}
}
}
ClassifiedCommand::Expr(expr) => {
if let SpannedExpression {
expr: Expression::Block(ref block),
span,
} = **expr
{
let mut block = block.clone();
block.expand_it_usage();
*expr = Box::new(SpannedExpression {
expr: Expression::Block(block),
span,
});
}
}
ClassifiedCommand::Internal(command) => command.expand_it_usage(),
ClassifiedCommand::Expr(expr) => expr.expand_it_usage(),
_ => {}
}
}
@ -588,6 +570,44 @@ impl SpannedExpression {
_ => false,
}
}
pub fn expand_it_usage(&mut self) {
match self {
SpannedExpression {
expr: Expression::Block(block),
..
} => {
block.expand_it_usage();
}
SpannedExpression {
expr: Expression::Invocation(block),
..
} => {
block.expand_it_usage();
}
SpannedExpression {
expr: Expression::List(list),
..
} => {
for item in list.iter_mut() {
item.expand_it_usage();
}
}
SpannedExpression {
expr: Expression::Path(path),
..
} => {
if let SpannedExpression {
expr: Expression::Invocation(block),
..
} = &mut path.head
{
block.expand_it_usage();
}
}
_ => {}
}
}
}
impl std::ops::Deref for SpannedExpression {

View file

@ -72,6 +72,18 @@ fn it_expansion_of_list() {
assert_eq!(actual.out, "[\"bar\",\"foo\"]");
}
#[test]
fn it_expansion_of_invocation() {
let actual = nu!(
cwd: ".",
r#"
echo $(echo "4" | echo $it | str to-int )
"#
);
assert_eq!(actual.out, "4");
}
#[test]
fn argument_invocation() {
let actual = nu!(