forked from extern/nushell
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
@ -11,7 +11,7 @@ use futures_codec::FramedRead;
|
||||
|
||||
use nu_errors::ShellError;
|
||||
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 rustyline::error::ReadlineError;
|
||||
@ -258,6 +258,7 @@ pub fn create_default_context(
|
||||
whole_stream_command(What),
|
||||
whole_stream_command(Which),
|
||||
whole_stream_command(Debug),
|
||||
per_item_command(Alias),
|
||||
// Statistics
|
||||
whole_stream_command(Size),
|
||||
whole_stream_command(Count),
|
||||
@ -442,6 +443,29 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
})
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
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 {
|
||||
if context.ctrl_c.load(Ordering::SeqCst) {
|
||||
context.ctrl_c.store(false, Ordering::SeqCst);
|
||||
@ -712,7 +736,7 @@ async fn process_line(
|
||||
None
|
||||
};
|
||||
|
||||
match run_pipeline(pipeline, ctx, input_stream).await {
|
||||
match run_pipeline(pipeline, ctx, input_stream, &Scope::empty()).await {
|
||||
Ok(Some(input)) => {
|
||||
// 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
|
||||
|
@ -4,6 +4,7 @@ pub(crate) mod macros;
|
||||
mod from_delimited_data;
|
||||
mod to_delimited_data;
|
||||
|
||||
pub(crate) mod alias;
|
||||
pub(crate) mod append;
|
||||
pub(crate) mod args;
|
||||
pub(crate) mod autoview;
|
||||
@ -75,6 +76,7 @@ pub(crate) mod reject;
|
||||
pub(crate) mod rename;
|
||||
pub(crate) mod reverse;
|
||||
pub(crate) mod rm;
|
||||
pub(crate) mod run_alias;
|
||||
pub(crate) mod save;
|
||||
pub(crate) mod shells;
|
||||
pub(crate) mod shuffle;
|
||||
@ -115,6 +117,7 @@ pub(crate) use command::{
|
||||
WholeStreamCommand,
|
||||
};
|
||||
|
||||
pub(crate) use alias::Alias;
|
||||
pub(crate) use append::Append;
|
||||
pub(crate) use calc::Calc;
|
||||
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 nu_errors::ShellError;
|
||||
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::Ordering;
|
||||
|
||||
@ -287,6 +287,7 @@ fn create_default_command_args(context: &RunnableContextWithoutInput) -> RawComm
|
||||
span,
|
||||
},
|
||||
name_tag: context.name.clone(),
|
||||
scope: Scope::empty(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,9 @@ pub(crate) fn run_expression_block(
|
||||
expr: SpannedExpression,
|
||||
context: &mut Context,
|
||||
input: Option<InputStream>,
|
||||
scope: &Scope,
|
||||
) -> Result<Option<InputStream>, ShellError> {
|
||||
let scope = scope.clone();
|
||||
if log_enabled!(log::Level::Trace) {
|
||||
trace!(target: "nu::run::expr", "->");
|
||||
trace!(target: "nu::run::expr", "{:?}", expr);
|
||||
@ -25,10 +27,11 @@ pub(crate) fn run_expression_block(
|
||||
pin_mut!(values);
|
||||
|
||||
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 {
|
||||
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 nu_errors::ShellError;
|
||||
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_value_ext::as_column_path;
|
||||
use std::io::Write;
|
||||
@ -97,6 +97,7 @@ pub(crate) async fn run_external_command(
|
||||
command: ExternalCommand,
|
||||
context: &mut Context,
|
||||
input: Option<InputStream>,
|
||||
_scope: &Scope,
|
||||
is_last: bool,
|
||||
) -> Result<Option<InputStream>, ShellError> {
|
||||
trace!(target: "nu::run::external", "-> {}", command.name);
|
||||
@ -718,6 +719,7 @@ mod tests {
|
||||
};
|
||||
use futures::executor::block_on;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::Scope;
|
||||
use nu_test_support::commands::ExternalBuilder;
|
||||
|
||||
// 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.");
|
||||
|
||||
assert!(run_external_command(cmd, &mut ctx, None, false)
|
||||
assert!(
|
||||
run_external_command(cmd, &mut ctx, None, &Scope::empty(), false)
|
||||
.await
|
||||
.is_err());
|
||||
.is_err()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,14 +1,17 @@
|
||||
use crate::commands::command::per_item_command;
|
||||
use crate::commands::run_alias::AliasCommand;
|
||||
use crate::commands::UnevaluatedCallInfo;
|
||||
use crate::prelude::*;
|
||||
use log::{log_enabled, trace};
|
||||
use nu_errors::ShellError;
|
||||
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(
|
||||
command: InternalCommand,
|
||||
context: &mut Context,
|
||||
input: Option<InputStream>,
|
||||
scope: &Scope,
|
||||
) -> Result<Option<InputStream>, ShellError> {
|
||||
if log_enabled!(log::Level::Trace) {
|
||||
trace!(target: "nu::run::internal", "->");
|
||||
@ -28,6 +31,7 @@ pub(crate) fn run_internal_command(
|
||||
internal_command?,
|
||||
Tag::unknown_anchor(command.name_span),
|
||||
command.args.clone(),
|
||||
scope,
|
||||
objects,
|
||||
)
|
||||
};
|
||||
@ -68,6 +72,7 @@ pub(crate) fn run_internal_command(
|
||||
span: Span::unknown()
|
||||
},
|
||||
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);
|
||||
@ -120,6 +125,15 @@ pub(crate) fn run_internal_command(
|
||||
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 => {
|
||||
context.shell_manager.prev();
|
||||
}
|
||||
|
@ -5,11 +5,13 @@ use crate::context::Context;
|
||||
use crate::stream::InputStream;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::hir::{ClassifiedCommand, ClassifiedPipeline};
|
||||
use nu_protocol::Scope;
|
||||
|
||||
pub(crate) async fn run_pipeline(
|
||||
pipeline: ClassifiedPipeline,
|
||||
ctx: &mut Context,
|
||||
mut input: Option<InputStream>,
|
||||
scope: &Scope,
|
||||
) -> Result<Option<InputStream>, ShellError> {
|
||||
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"))
|
||||
}
|
||||
|
||||
(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.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) => {
|
||||
run_external_command(left, ctx, input, true).await?
|
||||
run_external_command(left, ctx, input, scope, true).await?
|
||||
}
|
||||
|
||||
(Some(ClassifiedCommand::External(left)), _) => {
|
||||
run_external_command(left, ctx, input, false).await?
|
||||
run_external_command(left, ctx, input, scope, false).await?
|
||||
}
|
||||
|
||||
(None, _) => break,
|
||||
|
@ -16,15 +16,27 @@ use std::sync::atomic::AtomicBool;
|
||||
pub struct UnevaluatedCallInfo {
|
||||
pub args: hir::Call,
|
||||
pub name_tag: Tag,
|
||||
pub scope: Scope,
|
||||
}
|
||||
|
||||
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,
|
||||
registry: &CommandRegistry,
|
||||
scope: &Scope,
|
||||
it: &Value,
|
||||
) -> 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 {
|
||||
args,
|
||||
@ -113,7 +125,7 @@ impl CommandArgs {
|
||||
let ctrl_c = self.ctrl_c.clone();
|
||||
let shell_manager = self.shell_manager.clone();
|
||||
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(
|
||||
host,
|
||||
@ -133,7 +145,12 @@ impl CommandArgs {
|
||||
let ctrl_c = self.ctrl_c.clone();
|
||||
let shell_manager = self.shell_manager.clone();
|
||||
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(
|
||||
host,
|
||||
@ -515,10 +532,16 @@ impl Command {
|
||||
.input
|
||||
.values
|
||||
.map(move |x| {
|
||||
let call_info = raw_args
|
||||
.clone()
|
||||
.call_info
|
||||
.evaluate(®istry, &Scope::it_value(x.clone()));
|
||||
let call_info = UnevaluatedCallInfo {
|
||||
args: raw_args.call_info.args.clone(),
|
||||
name_tag: raw_args.call_info.name_tag.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 {
|
||||
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 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,
|
||||
Ok(args) => args,
|
||||
};
|
||||
|
@ -5,7 +5,8 @@ use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
hir::ClassifiedPipeline, CallInfo, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
hir::ClassifiedPipeline, CallInfo, ReturnSuccess, Scope, Signature, SyntaxShape, UntaggedValue,
|
||||
Value,
|
||||
};
|
||||
|
||||
pub struct Each;
|
||||
@ -52,6 +53,7 @@ impl PerItemCommand for Each {
|
||||
ClassifiedPipeline::new(block.clone(), None),
|
||||
&mut context,
|
||||
Some(input_stream),
|
||||
&Scope::empty(),
|
||||
).await;
|
||||
|
||||
match result {
|
||||
|
@ -104,6 +104,7 @@ impl PerItemCommand for Enter {
|
||||
span: Span::unknown()
|
||||
},
|
||||
name_tag: raw_args.call_info.name_tag,
|
||||
scope: raw_args.call_info.scope.clone()
|
||||
},
|
||||
};
|
||||
let mut result = converter.run(
|
||||
|
@ -3,7 +3,7 @@ use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use log::trace;
|
||||
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 std::io::prelude::*;
|
||||
use std::io::BufReader;
|
||||
@ -71,10 +71,13 @@ pub fn filter_plugin(
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
trace!("filter_plugin :: {}", path);
|
||||
|
||||
let args = args.evaluate_once_with_scope(
|
||||
registry,
|
||||
&Scope::it_value(UntaggedValue::string("$it").into_untagged_value()),
|
||||
)?;
|
||||
let scope = &args
|
||||
.call_info
|
||||
.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)
|
||||
.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::prelude::*;
|
||||
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 std::path::{Path, PathBuf};
|
||||
|
||||
@ -235,6 +235,7 @@ fn save(
|
||||
span: Span::unknown()
|
||||
},
|
||||
name_tag: raw_args.call_info.name_tag,
|
||||
scope: Scope::empty(), // FIXME?
|
||||
}
|
||||
};
|
||||
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 stream = match condition.as_bool() {
|
||||
|
@ -7,7 +7,7 @@ use crate::stream::{InputStream, OutputStream};
|
||||
use indexmap::IndexMap;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::SignatureRegistry;
|
||||
use nu_protocol::{hir, Signature};
|
||||
use nu_protocol::{hir, Scope, Signature};
|
||||
use nu_source::{Tag, Text};
|
||||
use parking_lot::Mutex;
|
||||
use std::error::Error;
|
||||
@ -196,22 +196,33 @@ impl Context {
|
||||
command: Arc<Command>,
|
||||
name_tag: Tag,
|
||||
args: hir::Call,
|
||||
scope: &Scope,
|
||||
input: InputStream,
|
||||
) -> 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())
|
||||
}
|
||||
|
||||
fn call_info(&self, args: hir::Call, name_tag: Tag) -> UnevaluatedCallInfo {
|
||||
UnevaluatedCallInfo { args, name_tag }
|
||||
fn call_info(&self, args: hir::Call, name_tag: Tag, scope: &Scope) -> UnevaluatedCallInfo {
|
||||
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 {
|
||||
host: self.host.clone(),
|
||||
ctrl_c: self.ctrl_c.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,
|
||||
}
|
||||
}
|
||||
|
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 calc;
|
||||
mod cd;
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::hir::Commands;
|
||||
use crate::value::Value;
|
||||
use nu_errors::ShellError;
|
||||
use nu_source::{b, DebugDocBuilder, PrettyDebug};
|
||||
@ -20,6 +21,8 @@ pub enum CommandAction {
|
||||
EnterValueShell(Value),
|
||||
/// Enter the help shell, which allows exploring the help system
|
||||
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
|
||||
PreviousShell,
|
||||
/// 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::EnterValueShell(v) => b::typed("enter value 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::NextShell => b::description("next shell"),
|
||||
CommandAction::LeaveShell => b::description("leave shell"),
|
||||
|
@ -1,11 +1,12 @@
|
||||
use crate::value::{Primitive, UntaggedValue, Value};
|
||||
use indexmap::IndexMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// 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
|
||||
/// through the pipeline at that moment
|
||||
#[derive(Debug)]
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
pub struct Scope {
|
||||
pub it: Value,
|
||||
pub vars: IndexMap<String, Value>,
|
||||
@ -37,4 +38,20 @@ impl Scope {
|
||||
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 New Issue
Block a user