mirror of
https://github.com/nushell/nushell.git
synced 2024-11-29 03:44:19 +01:00
extend it-expansion to externals (#1682)
* extend it-expansion to externals * trim the carriage return for external strings
This commit is contained in:
parent
73d5310c9c
commit
db8219e798
@ -9,7 +9,7 @@ use std::sync::mpsc;
|
|||||||
|
|
||||||
use bytes::{BufMut, Bytes, BytesMut};
|
use bytes::{BufMut, Bytes, BytesMut};
|
||||||
use futures::executor::block_on_stream;
|
use futures::executor::block_on_stream;
|
||||||
use futures::stream::StreamExt;
|
// use futures::stream::StreamExt;
|
||||||
use futures_codec::FramedRead;
|
use futures_codec::FramedRead;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
@ -82,20 +82,6 @@ impl futures_codec::Decoder for MaybeTextCodec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nu_value_to_string(name_tag: &Tag, from: &Value) -> Result<String, ShellError> {
|
|
||||||
match &from.value {
|
|
||||||
UntaggedValue::Primitive(Primitive::Int(i)) => Ok(i.to_string()),
|
|
||||||
UntaggedValue::Primitive(Primitive::String(s))
|
|
||||||
| UntaggedValue::Primitive(Primitive::Line(s)) => Ok(s.clone()),
|
|
||||||
UntaggedValue::Primitive(Primitive::Path(p)) => Ok(p.to_string_lossy().to_string()),
|
|
||||||
unsupported => Err(ShellError::labeled_error(
|
|
||||||
format!("needs string data (given: {})", unsupported.type_name()),
|
|
||||||
"expected a string",
|
|
||||||
name_tag,
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn run_external_command(
|
pub(crate) async fn run_external_command(
|
||||||
command: ExternalCommand,
|
command: ExternalCommand,
|
||||||
context: &mut Context,
|
context: &mut Context,
|
||||||
@ -113,85 +99,7 @@ pub(crate) async fn run_external_command(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if command.has_it_argument() {
|
|
||||||
run_with_iterator_arg(command, context, input, scope, is_last)
|
|
||||||
} else {
|
|
||||||
run_with_stdin(command, context, input, scope, is_last)
|
run_with_stdin(command, context, input, scope, is_last)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_with_iterator_arg(
|
|
||||||
command: ExternalCommand,
|
|
||||||
context: &mut Context,
|
|
||||||
input: InputStream,
|
|
||||||
scope: &Scope,
|
|
||||||
is_last: bool,
|
|
||||||
) -> Result<InputStream, ShellError> {
|
|
||||||
let path = context.shell_manager.path();
|
|
||||||
|
|
||||||
let mut inputs: InputStream =
|
|
||||||
trace_stream!(target: "nu::trace_stream::external::it", "input" = input);
|
|
||||||
|
|
||||||
let name_tag = command.name_tag.clone();
|
|
||||||
let scope = scope.clone();
|
|
||||||
let context = context.clone();
|
|
||||||
|
|
||||||
let stream = async_stream! {
|
|
||||||
while let Some(value) = inputs.next().await {
|
|
||||||
// Evaluate the expressions into values, and from values into strings for each iteration
|
|
||||||
let mut command_args = vec![];
|
|
||||||
let scope = scope.clone().set_it(value);
|
|
||||||
for arg in command.args.iter() {
|
|
||||||
let value = evaluate_baseline_expr(arg, &context.registry, &scope)?;
|
|
||||||
command_args.push(nu_value_to_string(&name_tag, &value)?);
|
|
||||||
}
|
|
||||||
|
|
||||||
let process_args = command_args
|
|
||||||
.iter()
|
|
||||||
.map(|arg| {
|
|
||||||
let arg = expand_tilde(arg.deref(), dirs::home_dir);
|
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
{
|
|
||||||
if argument_contains_whitespace(&arg) && argument_is_quoted(&arg) {
|
|
||||||
if let Some(unquoted) = remove_quotes(&arg) {
|
|
||||||
format!(r#""{}""#, unquoted)
|
|
||||||
} else {
|
|
||||||
arg.as_ref().to_string()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
arg.as_ref().to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(windows)]
|
|
||||||
{
|
|
||||||
if let Some(unquoted) = remove_quotes(&arg) {
|
|
||||||
unquoted.to_string()
|
|
||||||
} else {
|
|
||||||
arg.as_ref().to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<String>>();
|
|
||||||
|
|
||||||
match spawn(&command, &path, &process_args[..], InputStream::empty(), is_last) {
|
|
||||||
Ok(mut res) => {
|
|
||||||
while let Some(item) = res.next().await {
|
|
||||||
yield Ok(item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(reason) => {
|
|
||||||
yield Ok(Value {
|
|
||||||
value: UntaggedValue::Error(reason),
|
|
||||||
tag: name_tag
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(stream.to_input_stream())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_with_stdin(
|
fn run_with_stdin(
|
||||||
@ -208,7 +116,7 @@ fn run_with_stdin(
|
|||||||
let mut command_args = vec![];
|
let mut command_args = vec![];
|
||||||
for arg in command.args.iter() {
|
for arg in command.args.iter() {
|
||||||
let value = evaluate_baseline_expr(arg, &context.registry, scope)?;
|
let value = evaluate_baseline_expr(arg, &context.registry, scope)?;
|
||||||
command_args.push(value.as_string()?);
|
command_args.push(value.as_string()?.trim_end_matches('\n').to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
let process_args = command_args
|
let process_args = command_args
|
||||||
@ -514,6 +422,7 @@ fn add_quotes(argument: &str) -> String {
|
|||||||
format!("\"{}\"", argument)
|
format!("\"{}\"", argument)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
fn remove_quotes(argument: &str) -> Option<&str> {
|
fn remove_quotes(argument: &str) -> Option<&str> {
|
||||||
if !argument_is_quoted(argument) {
|
if !argument_is_quoted(argument) {
|
||||||
return None;
|
return None;
|
||||||
|
@ -4,9 +4,11 @@ use crate::context::CommandRegistry;
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use futures::stream::once;
|
use futures::stream::once;
|
||||||
|
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{hir::Block, ReturnSuccess, Signature, SyntaxShape};
|
use nu_protocol::{
|
||||||
|
hir::Block, hir::Expression, hir::SpannedExpression, hir::Synthetic, ReturnSuccess, Signature,
|
||||||
|
SyntaxShape,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct Each;
|
pub struct Each;
|
||||||
|
|
||||||
@ -41,6 +43,16 @@ impl WholeStreamCommand for Each {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_expanded_it_usage(head: &SpannedExpression) -> bool {
|
||||||
|
match &*head {
|
||||||
|
SpannedExpression {
|
||||||
|
expr: Expression::Synthetic(Synthetic::String(s)),
|
||||||
|
..
|
||||||
|
} if s == "expanded-each" => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn each(
|
fn each(
|
||||||
each_args: EachArgs,
|
each_args: EachArgs,
|
||||||
context: RunnableContext,
|
context: RunnableContext,
|
||||||
@ -53,8 +65,13 @@ fn each(
|
|||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
while let Some(input) = input_stream.next().await {
|
while let Some(input) = input_stream.next().await {
|
||||||
let mut context = Context::from_raw(&raw_args, ®istry);
|
let mut context = Context::from_raw(&raw_args, ®istry);
|
||||||
|
|
||||||
let input_clone = input.clone();
|
let input_clone = input.clone();
|
||||||
let input_stream = once(async { Ok(input) }).to_input_stream();
|
let input_stream = if is_expanded_it_usage(&raw_args.call_info.args.head) {
|
||||||
|
InputStream::empty()
|
||||||
|
} else {
|
||||||
|
once(async { Ok(input) }).to_input_stream()
|
||||||
|
};
|
||||||
|
|
||||||
let result = run_block(
|
let result = run_block(
|
||||||
&block,
|
&block,
|
||||||
|
@ -81,16 +81,6 @@ impl ClassifiedCommand {
|
|||||||
pub fn has_it_iteration(&self) -> bool {
|
pub fn has_it_iteration(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
ClassifiedCommand::Internal(command) => {
|
ClassifiedCommand::Internal(command) => {
|
||||||
if let SpannedExpression {
|
|
||||||
expr: Expression::Literal(Literal::String(s)),
|
|
||||||
..
|
|
||||||
} = &*command.args.head
|
|
||||||
{
|
|
||||||
if s == "run_external" {
|
|
||||||
// For now, don't it-expand externals
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut result = command.args.head.has_shallow_it_usage();
|
let mut result = command.args.head.has_shallow_it_usage();
|
||||||
|
|
||||||
if let Some(positionals) = &command.args.positional {
|
if let Some(positionals) = &command.args.positional {
|
||||||
@ -109,17 +99,6 @@ 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) => {
|
||||||
if let SpannedExpression {
|
|
||||||
expr: Expression::Literal(Literal::String(s)),
|
|
||||||
..
|
|
||||||
} = &*command.args.head
|
|
||||||
{
|
|
||||||
if s == "run_external" {
|
|
||||||
// For now, don't it-expand externals
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(positionals) = &mut command.args.positional {
|
if let Some(positionals) = &mut command.args.positional {
|
||||||
for arg in positionals {
|
for arg in positionals {
|
||||||
if let SpannedExpression {
|
if let SpannedExpression {
|
||||||
@ -179,7 +158,9 @@ impl Commands {
|
|||||||
name_span: self.span,
|
name_span: self.span,
|
||||||
args: hir::Call {
|
args: hir::Call {
|
||||||
head: Box::new(SpannedExpression {
|
head: Box::new(SpannedExpression {
|
||||||
expr: Expression::Synthetic(Synthetic::String("each".to_string())),
|
expr: Expression::Synthetic(Synthetic::String(
|
||||||
|
"expanded-each".to_string(),
|
||||||
|
)),
|
||||||
span: self.span,
|
span: self.span,
|
||||||
}),
|
}),
|
||||||
named: None,
|
named: None,
|
||||||
|
@ -1,15 +1,5 @@
|
|||||||
use nu_test_support::{nu, nu_error};
|
use nu_test_support::{nu, nu_error};
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn shows_error_for_command_that_fails() {
|
|
||||||
// let actual = nu_error!(
|
|
||||||
// cwd: ".",
|
|
||||||
// "fail"
|
|
||||||
// );
|
|
||||||
|
|
||||||
// assert!(actual.contains("External command failed"));
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn shows_error_for_command_not_found() {
|
fn shows_error_for_command_not_found() {
|
||||||
let actual = nu_error!(
|
let actual = nu_error!(
|
||||||
|
Loading…
Reference in New Issue
Block a user