mirror of
https://github.com/nushell/nushell.git
synced 2024-11-22 08:23:24 +01:00
Fix it expansion and add collect (#2065)
This commit is contained in:
parent
05781607f4
commit
4e2a4236f8
@ -303,6 +303,7 @@ pub fn create_default_context(
|
|||||||
whole_stream_command(StrSet),
|
whole_stream_command(StrSet),
|
||||||
whole_stream_command(StrToDatetime),
|
whole_stream_command(StrToDatetime),
|
||||||
whole_stream_command(StrTrim),
|
whole_stream_command(StrTrim),
|
||||||
|
whole_stream_command(StrCollect),
|
||||||
whole_stream_command(BuildString),
|
whole_stream_command(BuildString),
|
||||||
whole_stream_command(Ansi),
|
whole_stream_command(Ansi),
|
||||||
// Column manipulation
|
// 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)
|
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();
|
let env = context.get_env();
|
||||||
|
|
||||||
|
prompt_block.block.expand_it_usage();
|
||||||
|
|
||||||
match run_block(
|
match run_block(
|
||||||
&prompt_block.block,
|
&prompt_block.block,
|
||||||
&mut context,
|
&mut context,
|
||||||
|
@ -240,8 +240,8 @@ pub(crate) use split::SplitColumn;
|
|||||||
pub(crate) use split::SplitRow;
|
pub(crate) use split::SplitRow;
|
||||||
pub(crate) use split_by::SplitBy;
|
pub(crate) use split_by::SplitBy;
|
||||||
pub(crate) use str_::{
|
pub(crate) use str_::{
|
||||||
Str, StrCapitalize, StrDowncase, StrFindReplace, StrSet, StrSubstring, StrToDatetime,
|
Str, StrCapitalize, StrCollect, StrDowncase, StrFindReplace, StrSet, StrSubstring,
|
||||||
StrToDecimal, StrToInteger, StrTrim, StrUpcase,
|
StrToDatetime, StrToDecimal, StrToInteger, StrTrim, StrUpcase,
|
||||||
};
|
};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
pub(crate) use t_sort_by::TSortBy;
|
pub(crate) use t_sort_by::TSortBy;
|
||||||
|
56
crates/nu-cli/src/commands/str_/collect.rs
Normal file
56
crates/nu-cli/src/commands/str_/collect.rs
Normal 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 {})
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
mod capitalize;
|
mod capitalize;
|
||||||
|
mod collect;
|
||||||
mod command;
|
mod command;
|
||||||
mod downcase;
|
mod downcase;
|
||||||
mod find_replace;
|
mod find_replace;
|
||||||
@ -11,6 +12,7 @@ mod trim;
|
|||||||
mod upcase;
|
mod upcase;
|
||||||
|
|
||||||
pub use capitalize::SubCommand as StrCapitalize;
|
pub use capitalize::SubCommand as StrCapitalize;
|
||||||
|
pub use collect::SubCommand as StrCollect;
|
||||||
pub use command::Command as Str;
|
pub use command::Command as Str;
|
||||||
pub use downcase::SubCommand as StrDowncase;
|
pub use downcase::SubCommand as StrDowncase;
|
||||||
pub use find_replace::SubCommand as StrFindReplace;
|
pub use find_replace::SubCommand as StrFindReplace;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use futures::stream::{iter, once};
|
use futures::stream::{iter, once};
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Primitive, UntaggedValue, Value};
|
use nu_protocol::{Primitive, Type, UntaggedValue, Value};
|
||||||
use nu_source::{Tagged, TaggedItem};
|
use nu_source::{Tagged, TaggedItem};
|
||||||
|
|
||||||
pub struct InputStream {
|
pub struct InputStream {
|
||||||
@ -74,12 +74,18 @@ impl InputStream {
|
|||||||
value_tag = value_t;
|
value_tag = value_t;
|
||||||
bytes.extend_from_slice(&b);
|
bytes.extend_from_slice(&b);
|
||||||
}
|
}
|
||||||
Some(Value { tag: value_tag, .. }) => {
|
Some(Value {
|
||||||
|
tag: value_tag,
|
||||||
|
value,
|
||||||
|
}) => {
|
||||||
return Err(ShellError::labeled_error_with_secondary(
|
return Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a string from pipeline",
|
"Expected a string from pipeline",
|
||||||
"requires string input",
|
"requires string input",
|
||||||
tag,
|
tag,
|
||||||
"value originates from here",
|
format!(
|
||||||
|
"{} originates from here",
|
||||||
|
Type::from_value(&value).plain_string(100000)
|
||||||
|
),
|
||||||
value_tag,
|
value_tag,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -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)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
||||||
@ -109,34 +117,8 @@ impl ClassifiedCommand {
|
|||||||
|
|
||||||
pub fn expand_it_usage(&mut self) {
|
pub fn expand_it_usage(&mut self) {
|
||||||
match self {
|
match self {
|
||||||
ClassifiedCommand::Internal(command) => {
|
ClassifiedCommand::Internal(command) => command.expand_it_usage(),
|
||||||
if let Some(positionals) = &mut command.args.positional {
|
ClassifiedCommand::Expr(expr) => expr.expand_it_usage(),
|
||||||
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,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -588,6 +570,44 @@ impl SpannedExpression {
|
|||||||
_ => false,
|
_ => 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 {
|
impl std::ops::Deref for SpannedExpression {
|
||||||
|
@ -72,6 +72,18 @@ fn it_expansion_of_list() {
|
|||||||
assert_eq!(actual.out, "[\"bar\",\"foo\"]");
|
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]
|
#[test]
|
||||||
fn argument_invocation() {
|
fn argument_invocation() {
|
||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
|
Loading…
Reference in New Issue
Block a user