mirror of
https://github.com/nushell/nushell
synced 2024-11-15 09:27:08 +00:00
Aliases (#1589)
* WIP getting scopes right * finish adding initial support * Finish with alias and add startup commands
This commit is contained in:
parent
e3da037b80
commit
bd5836e25d
20 changed files with 332 additions and 38 deletions
|
@ -11,7 +11,7 @@ use futures_codec::FramedRead;
|
||||||
|
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::hir::{ClassifiedCommand, ExternalCommand};
|
use nu_protocol::hir::{ClassifiedCommand, ExternalCommand};
|
||||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
use nu_protocol::{Primitive, ReturnSuccess, Scope, Signature, UntaggedValue, Value};
|
||||||
|
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
|
@ -258,6 +258,7 @@ pub fn create_default_context(
|
||||||
whole_stream_command(What),
|
whole_stream_command(What),
|
||||||
whole_stream_command(Which),
|
whole_stream_command(Which),
|
||||||
whole_stream_command(Debug),
|
whole_stream_command(Debug),
|
||||||
|
per_item_command(Alias),
|
||||||
// Statistics
|
// Statistics
|
||||||
whole_stream_command(Size),
|
whole_stream_command(Size),
|
||||||
whole_stream_command(Count),
|
whole_stream_command(Count),
|
||||||
|
@ -442,6 +443,29 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||||
})
|
})
|
||||||
.expect("Error setting Ctrl-C handler");
|
.expect("Error setting Ctrl-C handler");
|
||||||
let mut ctrlcbreak = false;
|
let mut ctrlcbreak = false;
|
||||||
|
|
||||||
|
// before we start up, let's run our startup commands
|
||||||
|
if let Ok(config) = crate::data::config::config(Tag::unknown()) {
|
||||||
|
if let Some(commands) = config.get("startup") {
|
||||||
|
match commands {
|
||||||
|
Value {
|
||||||
|
value: UntaggedValue::Table(pipelines),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
for pipeline in pipelines {
|
||||||
|
if let Ok(pipeline_string) = pipeline.as_string() {
|
||||||
|
let _ =
|
||||||
|
run_pipeline_standalone(pipeline_string, false, &mut context).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("warning: expected a table of pipeline strings as startup commands");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if context.ctrl_c.load(Ordering::SeqCst) {
|
if context.ctrl_c.load(Ordering::SeqCst) {
|
||||||
context.ctrl_c.store(false, Ordering::SeqCst);
|
context.ctrl_c.store(false, Ordering::SeqCst);
|
||||||
|
@ -712,7 +736,7 @@ async fn process_line(
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
match run_pipeline(pipeline, ctx, input_stream).await {
|
match run_pipeline(pipeline, ctx, input_stream, &Scope::empty()).await {
|
||||||
Ok(Some(input)) => {
|
Ok(Some(input)) => {
|
||||||
// Running a pipeline gives us back a stream that we can then
|
// Running a pipeline gives us back a stream that we can then
|
||||||
// work through. At the top level, we just want to pull on the
|
// work through. At the top level, we just want to pull on the
|
||||||
|
|
|
@ -4,6 +4,7 @@ pub(crate) mod macros;
|
||||||
mod from_delimited_data;
|
mod from_delimited_data;
|
||||||
mod to_delimited_data;
|
mod to_delimited_data;
|
||||||
|
|
||||||
|
pub(crate) mod alias;
|
||||||
pub(crate) mod append;
|
pub(crate) mod append;
|
||||||
pub(crate) mod args;
|
pub(crate) mod args;
|
||||||
pub(crate) mod autoview;
|
pub(crate) mod autoview;
|
||||||
|
@ -75,6 +76,7 @@ pub(crate) mod reject;
|
||||||
pub(crate) mod rename;
|
pub(crate) mod rename;
|
||||||
pub(crate) mod reverse;
|
pub(crate) mod reverse;
|
||||||
pub(crate) mod rm;
|
pub(crate) mod rm;
|
||||||
|
pub(crate) mod run_alias;
|
||||||
pub(crate) mod save;
|
pub(crate) mod save;
|
||||||
pub(crate) mod shells;
|
pub(crate) mod shells;
|
||||||
pub(crate) mod shuffle;
|
pub(crate) mod shuffle;
|
||||||
|
@ -115,6 +117,7 @@ pub(crate) use command::{
|
||||||
WholeStreamCommand,
|
WholeStreamCommand,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub(crate) use alias::Alias;
|
||||||
pub(crate) use append::Append;
|
pub(crate) use append::Append;
|
||||||
pub(crate) use calc::Calc;
|
pub(crate) use calc::Calc;
|
||||||
pub(crate) use compact::Compact;
|
pub(crate) use compact::Compact;
|
||||||
|
|
65
crates/nu-cli/src/commands/alias.rs
Normal file
65
crates/nu-cli/src/commands/alias.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
use crate::commands::PerItemCommand;
|
||||||
|
use crate::context::CommandRegistry;
|
||||||
|
use crate::prelude::*;
|
||||||
|
use nu_errors::ShellError;
|
||||||
|
use nu_protocol::{
|
||||||
|
CallInfo, CommandAction, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Alias;
|
||||||
|
|
||||||
|
impl PerItemCommand for Alias {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"alias"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("alias")
|
||||||
|
.required("name", SyntaxShape::String, "the name of the alias")
|
||||||
|
.required("args", SyntaxShape::Table, "the arguments to the alias")
|
||||||
|
.required("block", SyntaxShape::Block, "the block to run on each row")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Run a block on each row of the table."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
call_info: &CallInfo,
|
||||||
|
_registry: &CommandRegistry,
|
||||||
|
_raw_args: &RawCommandArgs,
|
||||||
|
_input: Value,
|
||||||
|
) -> Result<OutputStream, ShellError> {
|
||||||
|
let call_info = call_info.clone();
|
||||||
|
let stream = async_stream! {
|
||||||
|
match (call_info.args.expect_nth(0)?, call_info.args.expect_nth(1)?, call_info.args.expect_nth(2)?) {
|
||||||
|
(Value {value: UntaggedValue::Primitive(Primitive::String(name)), .. },
|
||||||
|
Value { value: UntaggedValue::Table(list), .. },
|
||||||
|
Value {
|
||||||
|
value: UntaggedValue::Block(block),
|
||||||
|
tag
|
||||||
|
}) => {
|
||||||
|
let mut args: Vec<String> = vec![];
|
||||||
|
for item in list.iter() {
|
||||||
|
if let Ok(string) = item.as_string() {
|
||||||
|
args.push(format!("${}", string));
|
||||||
|
} else {
|
||||||
|
yield Err(ShellError::labeled_error("Expected a string", "expected a string", item.tag()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yield ReturnSuccess::action(CommandAction::AddAlias(name.to_string(), args, block.clone()))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
yield Err(ShellError::labeled_error(
|
||||||
|
"Expected `name [args] {block}",
|
||||||
|
"needs a name, args, and a block",
|
||||||
|
call_info.name_tag,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(stream.to_output_stream())
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ use crate::commands::WholeStreamCommand;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{hir, hir::Expression, hir::Literal, hir::SpannedExpression};
|
use nu_protocol::{hir, hir::Expression, hir::Literal, hir::SpannedExpression};
|
||||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
|
use nu_protocol::{Primitive, ReturnSuccess, Scope, Signature, UntaggedValue, Value};
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
|
@ -287,6 +287,7 @@ fn create_default_command_args(context: &RunnableContextWithoutInput) -> RawComm
|
||||||
span,
|
span,
|
||||||
},
|
},
|
||||||
name_tag: context.name.clone(),
|
name_tag: context.name.clone(),
|
||||||
|
scope: Scope::empty(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,9 @@ pub(crate) fn run_expression_block(
|
||||||
expr: SpannedExpression,
|
expr: SpannedExpression,
|
||||||
context: &mut Context,
|
context: &mut Context,
|
||||||
input: Option<InputStream>,
|
input: Option<InputStream>,
|
||||||
|
scope: &Scope,
|
||||||
) -> Result<Option<InputStream>, ShellError> {
|
) -> Result<Option<InputStream>, ShellError> {
|
||||||
|
let scope = scope.clone();
|
||||||
if log_enabled!(log::Level::Trace) {
|
if log_enabled!(log::Level::Trace) {
|
||||||
trace!(target: "nu::run::expr", "->");
|
trace!(target: "nu::run::expr", "->");
|
||||||
trace!(target: "nu::run::expr", "{:?}", expr);
|
trace!(target: "nu::run::expr", "{:?}", expr);
|
||||||
|
@ -25,10 +27,11 @@ pub(crate) fn run_expression_block(
|
||||||
pin_mut!(values);
|
pin_mut!(values);
|
||||||
|
|
||||||
while let Some(row) = values.next().await {
|
while let Some(row) = values.next().await {
|
||||||
yield evaluate_baseline_expr(&expr, ®istry, &Scope::new(row));
|
let scope = scope.clone().set_it(row);
|
||||||
|
yield evaluate_baseline_expr(&expr, ®istry, &scope);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
yield evaluate_baseline_expr(&expr, ®istry, &Scope::empty());
|
yield evaluate_baseline_expr(&expr, ®istry, &scope);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use futures_codec::FramedRead;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::hir::{ExternalArg, ExternalCommand};
|
use nu_protocol::hir::{ExternalArg, ExternalCommand};
|
||||||
use nu_protocol::{ColumnPath, Primitive, ShellTypeName, UntaggedValue, Value};
|
use nu_protocol::{ColumnPath, Primitive, Scope, ShellTypeName, UntaggedValue, Value};
|
||||||
use nu_source::{Tag, Tagged};
|
use nu_source::{Tag, Tagged};
|
||||||
use nu_value_ext::as_column_path;
|
use nu_value_ext::as_column_path;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
@ -97,6 +97,7 @@ pub(crate) async fn run_external_command(
|
||||||
command: ExternalCommand,
|
command: ExternalCommand,
|
||||||
context: &mut Context,
|
context: &mut Context,
|
||||||
input: Option<InputStream>,
|
input: Option<InputStream>,
|
||||||
|
_scope: &Scope,
|
||||||
is_last: bool,
|
is_last: bool,
|
||||||
) -> Result<Option<InputStream>, ShellError> {
|
) -> Result<Option<InputStream>, ShellError> {
|
||||||
trace!(target: "nu::run::external", "-> {}", command.name);
|
trace!(target: "nu::run::external", "-> {}", command.name);
|
||||||
|
@ -718,6 +719,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
use futures::executor::block_on;
|
use futures::executor::block_on;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
|
use nu_protocol::Scope;
|
||||||
use nu_test_support::commands::ExternalBuilder;
|
use nu_test_support::commands::ExternalBuilder;
|
||||||
|
|
||||||
// async fn read(mut stream: OutputStream) -> Option<Value> {
|
// async fn read(mut stream: OutputStream) -> Option<Value> {
|
||||||
|
@ -738,9 +740,11 @@ mod tests {
|
||||||
|
|
||||||
let mut ctx = Context::basic().expect("There was a problem creating a basic context.");
|
let mut ctx = Context::basic().expect("There was a problem creating a basic context.");
|
||||||
|
|
||||||
assert!(run_external_command(cmd, &mut ctx, None, false)
|
assert!(
|
||||||
|
run_external_command(cmd, &mut ctx, None, &Scope::empty(), false)
|
||||||
.await
|
.await
|
||||||
.is_err());
|
.is_err()
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
|
use crate::commands::command::per_item_command;
|
||||||
|
use crate::commands::run_alias::AliasCommand;
|
||||||
use crate::commands::UnevaluatedCallInfo;
|
use crate::commands::UnevaluatedCallInfo;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use log::{log_enabled, trace};
|
use log::{log_enabled, trace};
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::hir::InternalCommand;
|
use nu_protocol::hir::InternalCommand;
|
||||||
use nu_protocol::{CommandAction, Primitive, ReturnSuccess, UntaggedValue, Value};
|
use nu_protocol::{CommandAction, Primitive, ReturnSuccess, Scope, UntaggedValue, Value};
|
||||||
|
|
||||||
pub(crate) fn run_internal_command(
|
pub(crate) fn run_internal_command(
|
||||||
command: InternalCommand,
|
command: InternalCommand,
|
||||||
context: &mut Context,
|
context: &mut Context,
|
||||||
input: Option<InputStream>,
|
input: Option<InputStream>,
|
||||||
|
scope: &Scope,
|
||||||
) -> Result<Option<InputStream>, ShellError> {
|
) -> Result<Option<InputStream>, ShellError> {
|
||||||
if log_enabled!(log::Level::Trace) {
|
if log_enabled!(log::Level::Trace) {
|
||||||
trace!(target: "nu::run::internal", "->");
|
trace!(target: "nu::run::internal", "->");
|
||||||
|
@ -28,6 +31,7 @@ pub(crate) fn run_internal_command(
|
||||||
internal_command?,
|
internal_command?,
|
||||||
Tag::unknown_anchor(command.name_span),
|
Tag::unknown_anchor(command.name_span),
|
||||||
command.args.clone(),
|
command.args.clone(),
|
||||||
|
scope,
|
||||||
objects,
|
objects,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -68,6 +72,7 @@ pub(crate) fn run_internal_command(
|
||||||
span: Span::unknown()
|
span: Span::unknown()
|
||||||
},
|
},
|
||||||
name_tag: Tag::unknown_anchor(command.name_span),
|
name_tag: Tag::unknown_anchor(command.name_span),
|
||||||
|
scope: Scope::empty(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut result = converter.run(new_args.with_input(vec![tagged_contents]), &context.registry);
|
let mut result = converter.run(new_args.with_input(vec![tagged_contents]), &context.registry);
|
||||||
|
@ -120,6 +125,15 @@ pub(crate) fn run_internal_command(
|
||||||
FilesystemShell::with_location(location, context.registry().clone()),
|
FilesystemShell::with_location(location, context.registry().clone()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
CommandAction::AddAlias(name, args, commands) => {
|
||||||
|
context.add_commands(vec![
|
||||||
|
per_item_command(AliasCommand::new(
|
||||||
|
name,
|
||||||
|
args,
|
||||||
|
commands,
|
||||||
|
))
|
||||||
|
]);
|
||||||
|
}
|
||||||
CommandAction::PreviousShell => {
|
CommandAction::PreviousShell => {
|
||||||
context.shell_manager.prev();
|
context.shell_manager.prev();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,13 @@ use crate::context::Context;
|
||||||
use crate::stream::InputStream;
|
use crate::stream::InputStream;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::hir::{ClassifiedCommand, ClassifiedPipeline};
|
use nu_protocol::hir::{ClassifiedCommand, ClassifiedPipeline};
|
||||||
|
use nu_protocol::Scope;
|
||||||
|
|
||||||
pub(crate) async fn run_pipeline(
|
pub(crate) async fn run_pipeline(
|
||||||
pipeline: ClassifiedPipeline,
|
pipeline: ClassifiedPipeline,
|
||||||
ctx: &mut Context,
|
ctx: &mut Context,
|
||||||
mut input: Option<InputStream>,
|
mut input: Option<InputStream>,
|
||||||
|
scope: &Scope,
|
||||||
) -> Result<Option<InputStream>, ShellError> {
|
) -> Result<Option<InputStream>, ShellError> {
|
||||||
let mut iter = pipeline.commands.list.into_iter().peekable();
|
let mut iter = pipeline.commands.list.into_iter().peekable();
|
||||||
|
|
||||||
|
@ -22,18 +24,22 @@ pub(crate) async fn run_pipeline(
|
||||||
return Err(ShellError::unimplemented("Dynamic commands"))
|
return Err(ShellError::unimplemented("Dynamic commands"))
|
||||||
}
|
}
|
||||||
|
|
||||||
(Some(ClassifiedCommand::Expr(expr)), _) => run_expression_block(*expr, ctx, input)?,
|
(Some(ClassifiedCommand::Expr(expr)), _) => {
|
||||||
|
run_expression_block(*expr, ctx, input, scope)?
|
||||||
|
}
|
||||||
(Some(ClassifiedCommand::Error(err)), _) => return Err(err.into()),
|
(Some(ClassifiedCommand::Error(err)), _) => return Err(err.into()),
|
||||||
(_, Some(ClassifiedCommand::Error(err))) => return Err(err.clone().into()),
|
(_, Some(ClassifiedCommand::Error(err))) => return Err(err.clone().into()),
|
||||||
|
|
||||||
(Some(ClassifiedCommand::Internal(left)), _) => run_internal_command(left, ctx, input)?,
|
(Some(ClassifiedCommand::Internal(left)), _) => {
|
||||||
|
run_internal_command(left, ctx, input, scope)?
|
||||||
|
}
|
||||||
|
|
||||||
(Some(ClassifiedCommand::External(left)), None) => {
|
(Some(ClassifiedCommand::External(left)), None) => {
|
||||||
run_external_command(left, ctx, input, true).await?
|
run_external_command(left, ctx, input, scope, true).await?
|
||||||
}
|
}
|
||||||
|
|
||||||
(Some(ClassifiedCommand::External(left)), _) => {
|
(Some(ClassifiedCommand::External(left)), _) => {
|
||||||
run_external_command(left, ctx, input, false).await?
|
run_external_command(left, ctx, input, scope, false).await?
|
||||||
}
|
}
|
||||||
|
|
||||||
(None, _) => break,
|
(None, _) => break,
|
||||||
|
|
|
@ -16,15 +16,27 @@ use std::sync::atomic::AtomicBool;
|
||||||
pub struct UnevaluatedCallInfo {
|
pub struct UnevaluatedCallInfo {
|
||||||
pub args: hir::Call,
|
pub args: hir::Call,
|
||||||
pub name_tag: Tag,
|
pub name_tag: Tag,
|
||||||
|
pub scope: Scope,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnevaluatedCallInfo {
|
impl UnevaluatedCallInfo {
|
||||||
pub fn evaluate(
|
pub fn evaluate(self, registry: &CommandRegistry) -> Result<CallInfo, ShellError> {
|
||||||
|
let args = evaluate_args(&self.args, registry, &self.scope)?;
|
||||||
|
|
||||||
|
Ok(CallInfo {
|
||||||
|
args,
|
||||||
|
name_tag: self.name_tag,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn evaluate_with_new_it(
|
||||||
self,
|
self,
|
||||||
registry: &CommandRegistry,
|
registry: &CommandRegistry,
|
||||||
scope: &Scope,
|
it: &Value,
|
||||||
) -> Result<CallInfo, ShellError> {
|
) -> Result<CallInfo, ShellError> {
|
||||||
let args = evaluate_args(&self.args, registry, scope)?;
|
let mut scope = self.scope.clone();
|
||||||
|
scope = scope.set_it(it.clone());
|
||||||
|
let args = evaluate_args(&self.args, registry, &scope)?;
|
||||||
|
|
||||||
Ok(CallInfo {
|
Ok(CallInfo {
|
||||||
args,
|
args,
|
||||||
|
@ -113,7 +125,7 @@ impl CommandArgs {
|
||||||
let ctrl_c = self.ctrl_c.clone();
|
let ctrl_c = self.ctrl_c.clone();
|
||||||
let shell_manager = self.shell_manager.clone();
|
let shell_manager = self.shell_manager.clone();
|
||||||
let input = self.input;
|
let input = self.input;
|
||||||
let call_info = self.call_info.evaluate(registry, &Scope::empty())?;
|
let call_info = self.call_info.evaluate(registry)?;
|
||||||
|
|
||||||
Ok(EvaluatedWholeStreamCommandArgs::new(
|
Ok(EvaluatedWholeStreamCommandArgs::new(
|
||||||
host,
|
host,
|
||||||
|
@ -133,7 +145,12 @@ impl CommandArgs {
|
||||||
let ctrl_c = self.ctrl_c.clone();
|
let ctrl_c = self.ctrl_c.clone();
|
||||||
let shell_manager = self.shell_manager.clone();
|
let shell_manager = self.shell_manager.clone();
|
||||||
let input = self.input;
|
let input = self.input;
|
||||||
let call_info = self.call_info.evaluate(registry, scope)?;
|
let call_info = UnevaluatedCallInfo {
|
||||||
|
name_tag: self.call_info.name_tag,
|
||||||
|
args: self.call_info.args,
|
||||||
|
scope: scope.clone(),
|
||||||
|
};
|
||||||
|
let call_info = call_info.evaluate(registry)?;
|
||||||
|
|
||||||
Ok(EvaluatedWholeStreamCommandArgs::new(
|
Ok(EvaluatedWholeStreamCommandArgs::new(
|
||||||
host,
|
host,
|
||||||
|
@ -515,10 +532,16 @@ impl Command {
|
||||||
.input
|
.input
|
||||||
.values
|
.values
|
||||||
.map(move |x| {
|
.map(move |x| {
|
||||||
let call_info = raw_args
|
let call_info = UnevaluatedCallInfo {
|
||||||
.clone()
|
args: raw_args.call_info.args.clone(),
|
||||||
.call_info
|
name_tag: raw_args.call_info.name_tag.clone(),
|
||||||
.evaluate(®istry, &Scope::it_value(x.clone()));
|
scope: raw_args.call_info.scope.clone().set_it(x.clone()),
|
||||||
|
}
|
||||||
|
.evaluate(®istry);
|
||||||
|
// let call_info = raw_args
|
||||||
|
// .clone()
|
||||||
|
// .call_info
|
||||||
|
// .evaluate(®istry, &Scope::it_value(x.clone()));
|
||||||
|
|
||||||
match call_info {
|
match call_info {
|
||||||
Ok(call_info) => match command.run(&call_info, ®istry, &raw_args, x) {
|
Ok(call_info) => match command.run(&call_info, ®istry, &raw_args, x) {
|
||||||
|
@ -576,7 +599,7 @@ impl WholeStreamCommand for FnFilterCommand {
|
||||||
|
|
||||||
let result = input.values.map(move |it| {
|
let result = input.values.map(move |it| {
|
||||||
let registry = registry.clone();
|
let registry = registry.clone();
|
||||||
let call_info = match call_info.clone().evaluate(®istry, &Scope::it_value(it)) {
|
let call_info = match call_info.clone().evaluate_with_new_it(®istry, &it) {
|
||||||
Err(err) => return OutputStream::from(vec![Err(err)]).values,
|
Err(err) => return OutputStream::from(vec![Err(err)]).values,
|
||||||
Ok(args) => args,
|
Ok(args) => args,
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,8 @@ use crate::context::CommandRegistry;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
hir::ClassifiedPipeline, CallInfo, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
hir::ClassifiedPipeline, CallInfo, ReturnSuccess, Scope, Signature, SyntaxShape, UntaggedValue,
|
||||||
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Each;
|
pub struct Each;
|
||||||
|
@ -52,6 +53,7 @@ impl PerItemCommand for Each {
|
||||||
ClassifiedPipeline::new(block.clone(), None),
|
ClassifiedPipeline::new(block.clone(), None),
|
||||||
&mut context,
|
&mut context,
|
||||||
Some(input_stream),
|
Some(input_stream),
|
||||||
|
&Scope::empty(),
|
||||||
).await;
|
).await;
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
|
|
|
@ -104,6 +104,7 @@ impl PerItemCommand for Enter {
|
||||||
span: Span::unknown()
|
span: Span::unknown()
|
||||||
},
|
},
|
||||||
name_tag: raw_args.call_info.name_tag,
|
name_tag: raw_args.call_info.name_tag,
|
||||||
|
scope: raw_args.call_info.scope.clone()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let mut result = converter.run(
|
let mut result = converter.run(
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::prelude::*;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Primitive, ReturnSuccess, ReturnValue, Scope, Signature, UntaggedValue, Value};
|
use nu_protocol::{Primitive, ReturnSuccess, ReturnValue, Signature, UntaggedValue, Value};
|
||||||
use serde::{self, Deserialize, Serialize};
|
use serde::{self, Deserialize, Serialize};
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
|
@ -71,10 +71,13 @@ pub fn filter_plugin(
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
trace!("filter_plugin :: {}", path);
|
trace!("filter_plugin :: {}", path);
|
||||||
|
|
||||||
let args = args.evaluate_once_with_scope(
|
let scope = &args
|
||||||
registry,
|
.call_info
|
||||||
&Scope::it_value(UntaggedValue::string("$it").into_untagged_value()),
|
.scope
|
||||||
)?;
|
.clone()
|
||||||
|
.set_it(UntaggedValue::string("$it").into_untagged_value());
|
||||||
|
|
||||||
|
let args = args.evaluate_once_with_scope(registry, &scope)?;
|
||||||
|
|
||||||
let mut child = std::process::Command::new(path)
|
let mut child = std::process::Command::new(path)
|
||||||
.stdin(std::process::Stdio::piped())
|
.stdin(std::process::Stdio::piped())
|
||||||
|
|
93
crates/nu-cli/src/commands/run_alias.rs
Normal file
93
crates/nu-cli/src/commands/run_alias.rs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
use crate::commands::classified::pipeline::run_pipeline;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
use derive_new::new;
|
||||||
|
use nu_errors::ShellError;
|
||||||
|
use nu_protocol::{
|
||||||
|
hir::ClassifiedPipeline, hir::Commands, CallInfo, ReturnSuccess, Scope, Signature, SyntaxShape,
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(new)]
|
||||||
|
pub struct AliasCommand {
|
||||||
|
name: String,
|
||||||
|
args: Vec<String>,
|
||||||
|
block: Commands,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PerItemCommand for AliasCommand {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
let mut alias = Signature::build(&self.name);
|
||||||
|
|
||||||
|
for arg in &self.args {
|
||||||
|
alias = alias.required(arg, SyntaxShape::Any, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
alias
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
call_info: &CallInfo,
|
||||||
|
registry: &CommandRegistry,
|
||||||
|
raw_args: &RawCommandArgs,
|
||||||
|
input: Value,
|
||||||
|
) -> Result<OutputStream, ShellError> {
|
||||||
|
let tag = call_info.name_tag.clone();
|
||||||
|
let call_info = call_info.clone();
|
||||||
|
let registry = registry.clone();
|
||||||
|
let raw_args = raw_args.clone();
|
||||||
|
let block = self.block.clone();
|
||||||
|
|
||||||
|
let mut scope = Scope::empty();
|
||||||
|
if let Some(positional) = &call_info.args.positional {
|
||||||
|
for (pos, arg) in positional.iter().enumerate() {
|
||||||
|
scope = scope.set_var(self.args[pos].to_string(), arg.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let stream = async_stream! {
|
||||||
|
let mut context = Context::from_raw(&raw_args, ®istry);
|
||||||
|
let input_stream = async_stream! {
|
||||||
|
yield Ok(input.clone())
|
||||||
|
}.to_input_stream();
|
||||||
|
|
||||||
|
let result = run_pipeline(
|
||||||
|
ClassifiedPipeline::new(block.clone(), None),
|
||||||
|
&mut context,
|
||||||
|
Some(input_stream),
|
||||||
|
&scope
|
||||||
|
).await;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(Some(v)) => {
|
||||||
|
let results: Vec<Value> = v.collect().await;
|
||||||
|
|
||||||
|
for result in results {
|
||||||
|
yield Ok(ReturnSuccess::Value(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None) => {
|
||||||
|
yield Err(ShellError::labeled_error(
|
||||||
|
"Expected a block",
|
||||||
|
"each needs a block",
|
||||||
|
tag,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
yield Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(stream.to_output_stream())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::commands::{UnevaluatedCallInfo, WholeStreamCommand};
|
use crate::commands::{UnevaluatedCallInfo, WholeStreamCommand};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
use nu_protocol::{Primitive, ReturnSuccess, Scope, Signature, SyntaxShape, UntaggedValue, Value};
|
||||||
use nu_source::Tagged;
|
use nu_source::Tagged;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
@ -235,6 +235,7 @@ fn save(
|
||||||
span: Span::unknown()
|
span: Span::unknown()
|
||||||
},
|
},
|
||||||
name_tag: raw_args.call_info.name_tag,
|
name_tag: raw_args.call_info.name_tag,
|
||||||
|
scope: Scope::empty(), // FIXME?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut result = converter.run(new_args.with_input(input), ®istry);
|
let mut result = converter.run(new_args.with_input(input), ®istry);
|
||||||
|
|
|
@ -68,6 +68,7 @@ impl PerItemCommand for Where {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//FIXME: should we use the scope that's brought in as well?
|
||||||
let condition = evaluate_baseline_expr(&condition, registry, &Scope::new(input.clone()))?;
|
let condition = evaluate_baseline_expr(&condition, registry, &Scope::new(input.clone()))?;
|
||||||
|
|
||||||
let stream = match condition.as_bool() {
|
let stream = match condition.as_bool() {
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::stream::{InputStream, OutputStream};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_parser::SignatureRegistry;
|
use nu_parser::SignatureRegistry;
|
||||||
use nu_protocol::{hir, Signature};
|
use nu_protocol::{hir, Scope, Signature};
|
||||||
use nu_source::{Tag, Text};
|
use nu_source::{Tag, Text};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
@ -196,22 +196,33 @@ impl Context {
|
||||||
command: Arc<Command>,
|
command: Arc<Command>,
|
||||||
name_tag: Tag,
|
name_tag: Tag,
|
||||||
args: hir::Call,
|
args: hir::Call,
|
||||||
|
scope: &Scope,
|
||||||
input: InputStream,
|
input: InputStream,
|
||||||
) -> OutputStream {
|
) -> OutputStream {
|
||||||
let command_args = self.command_args(args, input, name_tag);
|
let command_args = self.command_args(args, input, name_tag, scope);
|
||||||
command.run(command_args, self.registry())
|
command.run(command_args, self.registry())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_info(&self, args: hir::Call, name_tag: Tag) -> UnevaluatedCallInfo {
|
fn call_info(&self, args: hir::Call, name_tag: Tag, scope: &Scope) -> UnevaluatedCallInfo {
|
||||||
UnevaluatedCallInfo { args, name_tag }
|
UnevaluatedCallInfo {
|
||||||
|
args,
|
||||||
|
name_tag,
|
||||||
|
scope: scope.clone(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn command_args(&self, args: hir::Call, input: InputStream, name_tag: Tag) -> CommandArgs {
|
fn command_args(
|
||||||
|
&self,
|
||||||
|
args: hir::Call,
|
||||||
|
input: InputStream,
|
||||||
|
name_tag: Tag,
|
||||||
|
scope: &Scope,
|
||||||
|
) -> CommandArgs {
|
||||||
CommandArgs {
|
CommandArgs {
|
||||||
host: self.host.clone(),
|
host: self.host.clone(),
|
||||||
ctrl_c: self.ctrl_c.clone(),
|
ctrl_c: self.ctrl_c.clone(),
|
||||||
shell_manager: self.shell_manager.clone(),
|
shell_manager: self.shell_manager.clone(),
|
||||||
call_info: self.call_info(args, name_tag),
|
call_info: self.call_info(args, name_tag, scope),
|
||||||
input,
|
input,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
17
crates/nu-cli/tests/commands/alias.rs
Normal file
17
crates/nu-cli/tests/commands/alias.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
use nu_test_support::nu;
|
||||||
|
use nu_test_support::playground::Playground;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn alias_args_work() {
|
||||||
|
Playground::setup("append_test_1", |dirs, _| {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: dirs.root(),
|
||||||
|
r#"
|
||||||
|
alias double_echo [a b] {echo $a $b}
|
||||||
|
double_echo 1 2 | to-json
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(actual, "[1,2]");
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
mod alias;
|
||||||
mod append;
|
mod append;
|
||||||
mod calc;
|
mod calc;
|
||||||
mod cd;
|
mod cd;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::hir::Commands;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_source::{b, DebugDocBuilder, PrettyDebug};
|
use nu_source::{b, DebugDocBuilder, PrettyDebug};
|
||||||
|
@ -20,6 +21,8 @@ pub enum CommandAction {
|
||||||
EnterValueShell(Value),
|
EnterValueShell(Value),
|
||||||
/// Enter the help shell, which allows exploring the help system
|
/// Enter the help shell, which allows exploring the help system
|
||||||
EnterHelpShell(Value),
|
EnterHelpShell(Value),
|
||||||
|
/// Enter the help shell, which allows exploring the help system
|
||||||
|
AddAlias(String, Vec<String>, Commands),
|
||||||
/// Go to the previous shell in the shell ring buffer
|
/// Go to the previous shell in the shell ring buffer
|
||||||
PreviousShell,
|
PreviousShell,
|
||||||
/// Go to the next shell in the shell ring buffer
|
/// Go to the next shell in the shell ring buffer
|
||||||
|
@ -41,6 +44,7 @@ impl PrettyDebug for CommandAction {
|
||||||
CommandAction::EnterShell(s) => b::typed("enter shell", b::description(s)),
|
CommandAction::EnterShell(s) => b::typed("enter shell", b::description(s)),
|
||||||
CommandAction::EnterValueShell(v) => b::typed("enter value shell", v.pretty()),
|
CommandAction::EnterValueShell(v) => b::typed("enter value shell", v.pretty()),
|
||||||
CommandAction::EnterHelpShell(v) => b::typed("enter help shell", v.pretty()),
|
CommandAction::EnterHelpShell(v) => b::typed("enter help shell", v.pretty()),
|
||||||
|
CommandAction::AddAlias(..) => b::description("add alias"),
|
||||||
CommandAction::PreviousShell => b::description("previous shell"),
|
CommandAction::PreviousShell => b::description("previous shell"),
|
||||||
CommandAction::NextShell => b::description("next shell"),
|
CommandAction::NextShell => b::description("next shell"),
|
||||||
CommandAction::LeaveShell => b::description("leave shell"),
|
CommandAction::LeaveShell => b::description("leave shell"),
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use crate::value::{Primitive, UntaggedValue, Value};
|
use crate::value::{Primitive, UntaggedValue, Value};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
/// An evaluation scope. Scopes map variable names to Values and aid in evaluating blocks and expressions.
|
/// An evaluation scope. Scopes map variable names to Values and aid in evaluating blocks and expressions.
|
||||||
/// Additionally, holds the value for the special $it variable, a variable used to refer to the value passing
|
/// Additionally, holds the value for the special $it variable, a variable used to refer to the value passing
|
||||||
/// through the pipeline at that moment
|
/// through the pipeline at that moment
|
||||||
#[derive(Debug)]
|
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||||
pub struct Scope {
|
pub struct Scope {
|
||||||
pub it: Value,
|
pub it: Value,
|
||||||
pub vars: IndexMap<String, Value>,
|
pub vars: IndexMap<String, Value>,
|
||||||
|
@ -37,4 +38,20 @@ impl Scope {
|
||||||
vars: IndexMap::new(),
|
vars: IndexMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_it(self, value: Value) -> Scope {
|
||||||
|
Scope {
|
||||||
|
it: value,
|
||||||
|
vars: self.vars,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_var(self, name: String, value: Value) -> Scope {
|
||||||
|
let mut new_vars = self.vars.clone();
|
||||||
|
new_vars.insert(name, value);
|
||||||
|
Scope {
|
||||||
|
it: self.it,
|
||||||
|
vars: new_vars,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue