forked from extern/nushell
It expansion (#1668)
* First step in it-expansion * Fix tests * fix clippy warnings
This commit is contained in:
parent
6f2ef05195
commit
8bd3cedce1
@ -238,28 +238,28 @@ pub fn create_default_context(
|
||||
context.add_commands(vec![
|
||||
// System/file operations
|
||||
whole_stream_command(Pwd),
|
||||
per_item_command(Ls),
|
||||
per_item_command(Du),
|
||||
whole_stream_command(Ls),
|
||||
whole_stream_command(Du),
|
||||
whole_stream_command(Cd),
|
||||
per_item_command(Remove),
|
||||
per_item_command(Open),
|
||||
whole_stream_command(Remove),
|
||||
whole_stream_command(Open),
|
||||
whole_stream_command(Config),
|
||||
per_item_command(Help),
|
||||
per_item_command(History),
|
||||
whole_stream_command(Help),
|
||||
whole_stream_command(History),
|
||||
whole_stream_command(Save),
|
||||
per_item_command(Touch),
|
||||
per_item_command(Cpy),
|
||||
whole_stream_command(Touch),
|
||||
whole_stream_command(Cpy),
|
||||
whole_stream_command(Date),
|
||||
per_item_command(Calc),
|
||||
per_item_command(Mkdir),
|
||||
per_item_command(Move),
|
||||
per_item_command(Kill),
|
||||
whole_stream_command(Calc),
|
||||
whole_stream_command(Mkdir),
|
||||
whole_stream_command(Move),
|
||||
whole_stream_command(Kill),
|
||||
whole_stream_command(Version),
|
||||
whole_stream_command(Clear),
|
||||
whole_stream_command(What),
|
||||
whole_stream_command(Which),
|
||||
whole_stream_command(Debug),
|
||||
per_item_command(Alias),
|
||||
whole_stream_command(Alias),
|
||||
// Statistics
|
||||
whole_stream_command(Size),
|
||||
whole_stream_command(Count),
|
||||
@ -269,7 +269,7 @@ pub fn create_default_context(
|
||||
whole_stream_command(Next),
|
||||
whole_stream_command(Previous),
|
||||
whole_stream_command(Shells),
|
||||
per_item_command(Enter),
|
||||
whole_stream_command(Enter),
|
||||
whole_stream_command(Exit),
|
||||
// Viewers
|
||||
whole_stream_command(Autoview),
|
||||
@ -279,14 +279,14 @@ pub fn create_default_context(
|
||||
whole_stream_command(SplitRow),
|
||||
whole_stream_command(Lines),
|
||||
whole_stream_command(Trim),
|
||||
per_item_command(Echo),
|
||||
per_item_command(Parse),
|
||||
whole_stream_command(Echo),
|
||||
whole_stream_command(Parse),
|
||||
// Column manipulation
|
||||
whole_stream_command(Reject),
|
||||
whole_stream_command(Pick),
|
||||
whole_stream_command(Get),
|
||||
per_item_command(Edit),
|
||||
per_item_command(Insert),
|
||||
whole_stream_command(Edit),
|
||||
whole_stream_command(Insert),
|
||||
whole_stream_command(SplitBy),
|
||||
// Row manipulation
|
||||
whole_stream_command(Reverse),
|
||||
@ -299,16 +299,16 @@ pub fn create_default_context(
|
||||
whole_stream_command(Skip),
|
||||
whole_stream_command(Nth),
|
||||
whole_stream_command(Drop),
|
||||
per_item_command(Format),
|
||||
per_item_command(Where),
|
||||
whole_stream_command(Format),
|
||||
whole_stream_command(Where),
|
||||
whole_stream_command(Compact),
|
||||
whole_stream_command(Default),
|
||||
whole_stream_command(SkipWhile),
|
||||
whole_stream_command(Range),
|
||||
whole_stream_command(Rename),
|
||||
whole_stream_command(Uniq),
|
||||
per_item_command(Each),
|
||||
per_item_command(IsEmpty),
|
||||
whole_stream_command(Each),
|
||||
whole_stream_command(IsEmpty),
|
||||
// Table manipulation
|
||||
whole_stream_command(Shuffle),
|
||||
whole_stream_command(Wrap),
|
||||
@ -726,7 +726,7 @@ async fn process_line(
|
||||
debug!("=== Parsed ===");
|
||||
debug!("{:#?}", result);
|
||||
|
||||
let classified_block = nu_parser::classify_block(&result, ctx.registry());
|
||||
let mut classified_block = nu_parser::classify_block(&result, ctx.registry());
|
||||
|
||||
debug!("{:#?}", classified_block);
|
||||
//println!("{:#?}", pipeline);
|
||||
@ -845,6 +845,8 @@ async fn process_line(
|
||||
InputStream::empty()
|
||||
};
|
||||
|
||||
classified_block.block.expand_it_usage();
|
||||
|
||||
match run_block(&classified_block.block, ctx, input_stream, &Scope::empty()).await {
|
||||
Ok(input) => {
|
||||
// Running a pipeline gives us back a stream that we can then
|
||||
|
@ -116,10 +116,7 @@ pub(crate) mod wrap;
|
||||
|
||||
pub(crate) use autoview::Autoview;
|
||||
pub(crate) use cd::Cd;
|
||||
pub(crate) use command::{
|
||||
per_item_command, whole_stream_command, Command, PerItemCommand, UnevaluatedCallInfo,
|
||||
WholeStreamCommand,
|
||||
};
|
||||
pub(crate) use command::{whole_stream_command, Command, UnevaluatedCallInfo, WholeStreamCommand};
|
||||
|
||||
pub(crate) use alias::Alias;
|
||||
pub(crate) use append::Append;
|
||||
|
@ -1,14 +1,20 @@
|
||||
use crate::commands::PerItemCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
CallInfo, CommandAction, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use nu_protocol::{hir::Block, CommandAction, ReturnSuccess, Signature, SyntaxShape, Value};
|
||||
use nu_source::Tagged;
|
||||
|
||||
pub struct Alias;
|
||||
|
||||
impl PerItemCommand for Alias {
|
||||
#[derive(Deserialize)]
|
||||
pub struct AliasArgs {
|
||||
pub name: Tagged<String>,
|
||||
pub args: Vec<Value>,
|
||||
pub block: Block,
|
||||
}
|
||||
|
||||
impl WholeStreamCommand for Alias {
|
||||
fn name(&self) -> &str {
|
||||
"alias"
|
||||
}
|
||||
@ -26,40 +32,32 @@ impl PerItemCommand for Alias {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
_raw_args: &RawCommandArgs,
|
||||
_input: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> 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())
|
||||
args.process(registry, alias)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alias(
|
||||
AliasArgs {
|
||||
name,
|
||||
args: list,
|
||||
block,
|
||||
}: AliasArgs,
|
||||
_: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let stream = async_stream! {
|
||||
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()))
|
||||
};
|
||||
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
use crate::commands::PerItemCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{CallInfo, Primitive, ReturnSuccess, UntaggedValue, Value};
|
||||
use nu_protocol::{Primitive, ReturnSuccess, UntaggedValue, Value};
|
||||
|
||||
pub struct Calc;
|
||||
|
||||
impl PerItemCommand for Calc {
|
||||
#[derive(Deserialize)]
|
||||
pub struct CalcArgs {}
|
||||
|
||||
impl WholeStreamCommand for Calc {
|
||||
fn name(&self) -> &str {
|
||||
"calc"
|
||||
}
|
||||
@ -16,36 +19,37 @@ impl PerItemCommand for Calc {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
raw_args: &RawCommandArgs,
|
||||
input: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
calc(input, raw_args)
|
||||
args.process(registry, calc)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
fn calc(input: Value, args: &RawCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_span = &args.call_info.name_tag.span;
|
||||
|
||||
let output = if let Ok(string) = input.as_string() {
|
||||
match parse(&string, &input.tag) {
|
||||
Ok(value) => ReturnSuccess::value(value),
|
||||
Err(err) => Err(ShellError::labeled_error(
|
||||
"Calculation error",
|
||||
err,
|
||||
&input.tag.span,
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"Expected a string from pipeline",
|
||||
"requires string input",
|
||||
name_span,
|
||||
))
|
||||
};
|
||||
|
||||
Ok(vec![output].into())
|
||||
pub fn calc(
|
||||
_: CalcArgs,
|
||||
RunnableContext { input, name, .. }: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
Ok(input
|
||||
.map(move |input| {
|
||||
if let Ok(string) = input.as_string() {
|
||||
match parse(&string, &input.tag) {
|
||||
Ok(value) => ReturnSuccess::value(value),
|
||||
Err(err) => Err(ShellError::labeled_error(
|
||||
"Calculation error",
|
||||
err,
|
||||
&input.tag.span,
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"Expected a string from pipeline",
|
||||
"requires string input",
|
||||
name.clone(),
|
||||
))
|
||||
}
|
||||
})
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
pub fn parse(math_expression: &str, tag: impl Into<Tag>) -> Result<Value, String> {
|
||||
|
@ -1,5 +1,4 @@
|
||||
use crate::commands::classified::expr::run_expression_block;
|
||||
//use crate::commands::classified::external::run_external_command;
|
||||
use crate::commands::classified::internal::run_internal_command;
|
||||
use crate::context::Context;
|
||||
use crate::prelude::*;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::commands::command::per_item_command;
|
||||
use crate::commands::command::whole_stream_command;
|
||||
use crate::commands::run_alias::AliasCommand;
|
||||
use crate::commands::UnevaluatedCallInfo;
|
||||
use crate::prelude::*;
|
||||
@ -122,7 +122,7 @@ pub(crate) fn run_internal_command(
|
||||
}
|
||||
CommandAction::AddAlias(name, args, block) => {
|
||||
context.add_commands(vec![
|
||||
per_item_command(AliasCommand::new(
|
||||
whole_stream_command(AliasCommand::new(
|
||||
name,
|
||||
args,
|
||||
block,
|
||||
|
@ -49,36 +49,6 @@ impl UnevaluatedCallInfo {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CallInfoExt {
|
||||
fn process<'de, T: Deserialize<'de>>(
|
||||
&self,
|
||||
shell_manager: &ShellManager,
|
||||
ctrl_c: Arc<AtomicBool>,
|
||||
callback: fn(T, &RunnablePerItemContext) -> Result<OutputStream, ShellError>,
|
||||
) -> Result<RunnablePerItemArgs<T>, ShellError>;
|
||||
}
|
||||
|
||||
impl CallInfoExt for CallInfo {
|
||||
fn process<'de, T: Deserialize<'de>>(
|
||||
&self,
|
||||
shell_manager: &ShellManager,
|
||||
ctrl_c: Arc<AtomicBool>,
|
||||
callback: fn(T, &RunnablePerItemContext) -> Result<OutputStream, ShellError>,
|
||||
) -> Result<RunnablePerItemArgs<T>, ShellError> {
|
||||
let mut deserializer = ConfigDeserializer::from_call_info(self.clone());
|
||||
|
||||
Ok(RunnablePerItemArgs {
|
||||
args: T::deserialize(&mut deserializer)?,
|
||||
context: RunnablePerItemContext {
|
||||
shell_manager: shell_manager.clone(),
|
||||
name: self.name_tag.clone(),
|
||||
ctrl_c,
|
||||
},
|
||||
callback,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Getters)]
|
||||
#[get = "pub(crate)"]
|
||||
pub struct CommandArgs {
|
||||
@ -227,12 +197,6 @@ impl CommandArgs {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RunnablePerItemContext {
|
||||
pub shell_manager: ShellManager,
|
||||
pub name: Tag,
|
||||
pub ctrl_c: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
pub struct RunnableContext {
|
||||
pub input: InputStream,
|
||||
pub shell_manager: ShellManager,
|
||||
@ -248,18 +212,6 @@ impl RunnableContext {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RunnablePerItemArgs<T> {
|
||||
args: T,
|
||||
context: RunnablePerItemContext,
|
||||
callback: fn(T, &RunnablePerItemContext) -> Result<OutputStream, ShellError>,
|
||||
}
|
||||
|
||||
impl<T> RunnablePerItemArgs<T> {
|
||||
pub fn run(self) -> Result<OutputStream, ShellError> {
|
||||
(self.callback)(self.args, &self.context)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RunnableArgs<T, O: ToOutputStream> {
|
||||
args: T,
|
||||
context: RunnableContext,
|
||||
@ -626,7 +578,3 @@ impl WholeStreamCommand for FnFilterCommand {
|
||||
pub fn whole_stream_command(command: impl WholeStreamCommand + 'static) -> Arc<Command> {
|
||||
Arc::new(Command::WholeStream(Arc::new(command)))
|
||||
}
|
||||
|
||||
pub fn per_item_command(command: impl PerItemCommand + 'static) -> Arc<Command> {
|
||||
Arc::new(Command::PerItem(Arc::new(command)))
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::commands::command::RunnablePerItemContext;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{CallInfo, Signature, SyntaxShape, Value};
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -15,7 +15,7 @@ pub struct CopyArgs {
|
||||
pub recursive: Tagged<bool>,
|
||||
}
|
||||
|
||||
impl PerItemCommand for Cpy {
|
||||
impl WholeStreamCommand for Cpy {
|
||||
fn name(&self) -> &str {
|
||||
"cp"
|
||||
}
|
||||
@ -37,18 +37,14 @@ impl PerItemCommand for Cpy {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
raw_args: &RawCommandArgs,
|
||||
_input: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
call_info
|
||||
.process(&raw_args.shell_manager, raw_args.ctrl_c.clone(), cp)?
|
||||
.run()
|
||||
args.process(registry, cp)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
fn cp(args: CopyArgs, context: &RunnablePerItemContext) -> Result<OutputStream, ShellError> {
|
||||
pub fn cp(args: CopyArgs, context: RunnableContext) -> Result<OutputStream, ShellError> {
|
||||
let shell_manager = context.shell_manager.clone();
|
||||
shell_manager.cp(args, context)
|
||||
shell_manager.cp(args, &context)
|
||||
}
|
||||
|
@ -1,12 +1,10 @@
|
||||
extern crate filesize;
|
||||
|
||||
use crate::commands::command::RunnablePerItemContext;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use filesize::file_real_size_fast;
|
||||
use glob::*;
|
||||
use indexmap::map::IndexMap;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{CallInfo, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -31,7 +29,7 @@ pub struct DuArgs {
|
||||
min_size: Option<Tagged<u64>>,
|
||||
}
|
||||
|
||||
impl PerItemCommand for Du {
|
||||
impl WholeStreamCommand for Du {
|
||||
fn name(&self) -> &str {
|
||||
NAME
|
||||
}
|
||||
@ -75,18 +73,14 @@ impl PerItemCommand for Du {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
raw_args: &RawCommandArgs,
|
||||
_input: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
call_info
|
||||
.process(&raw_args.shell_manager, raw_args.ctrl_c.clone(), du)?
|
||||
.run()
|
||||
args.process(registry, du)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
fn du(args: DuArgs, ctx: &RunnablePerItemContext) -> Result<OutputStream, ShellError> {
|
||||
fn du(args: DuArgs, ctx: RunnableContext) -> Result<OutputStream, ShellError> {
|
||||
let tag = ctx.name.clone();
|
||||
|
||||
let exclude = args.exclude.map_or(Ok(None), move |x| {
|
||||
@ -117,7 +111,7 @@ fn du(args: DuArgs, ctx: &RunnablePerItemContext) -> Result<OutputStream, ShellE
|
||||
})
|
||||
.map(|v| v.map_err(glob_err_into));
|
||||
|
||||
let ctrl_c = ctx.ctrl_c.clone();
|
||||
let ctrl_c = ctx.ctrl_c;
|
||||
let all = args.all;
|
||||
let deref = args.deref;
|
||||
let max_depth = args.max_depth.map(|f| f.item);
|
||||
|
@ -1,16 +1,21 @@
|
||||
use crate::commands::classified::block::run_block;
|
||||
use crate::commands::PerItemCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
|
||||
use futures::stream::once;
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{CallInfo, ReturnSuccess, Scope, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_protocol::{hir::Block, ReturnSuccess, Scope, Signature, SyntaxShape};
|
||||
|
||||
pub struct Each;
|
||||
|
||||
impl PerItemCommand for Each {
|
||||
#[derive(Deserialize)]
|
||||
pub struct EachArgs {
|
||||
block: Block,
|
||||
}
|
||||
|
||||
impl WholeStreamCommand for Each {
|
||||
fn name(&self) -> &str {
|
||||
"each"
|
||||
}
|
||||
@ -29,58 +34,51 @@ impl PerItemCommand for Each {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
raw_args: &RawCommandArgs,
|
||||
input: Value,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let call_info = call_info.clone();
|
||||
let registry = registry.clone();
|
||||
let raw_args = raw_args.clone();
|
||||
let stream = async_stream! {
|
||||
match call_info.args.expect_nth(0)? {
|
||||
Value {
|
||||
value: UntaggedValue::Block(block),
|
||||
tag
|
||||
} => {
|
||||
let mut context = Context::from_raw(&raw_args, ®istry);
|
||||
let input_clone = input.clone();
|
||||
let input_stream = once(async { Ok(input) }).to_input_stream();
|
||||
|
||||
let result = run_block(
|
||||
block,
|
||||
&mut context,
|
||||
input_stream,
|
||||
&Scope::new(input_clone),
|
||||
).await;
|
||||
|
||||
match result {
|
||||
Ok(mut stream) => {
|
||||
let errors = context.get_errors();
|
||||
if let Some(error) = errors.first() {
|
||||
yield Err(error.clone());
|
||||
return;
|
||||
}
|
||||
|
||||
while let Some(result) = stream.next().await {
|
||||
yield Ok(ReturnSuccess::Value(result));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
yield Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Value { tag, .. } => {
|
||||
yield Err(ShellError::labeled_error(
|
||||
"Expected a block",
|
||||
"each needs a block",
|
||||
tag,
|
||||
))
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Ok(stream.to_output_stream())
|
||||
Ok(args.process_raw(registry, each)?.run())
|
||||
}
|
||||
}
|
||||
|
||||
fn each(
|
||||
each_args: EachArgs,
|
||||
context: RunnableContext,
|
||||
raw_args: RawCommandArgs,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let block = each_args.block;
|
||||
let registry = context.registry.clone();
|
||||
let mut input_stream = context.input;
|
||||
let stream = async_stream! {
|
||||
while let Some(input) = input_stream.next().await {
|
||||
let mut context = Context::from_raw(&raw_args, ®istry);
|
||||
let input_clone = input.clone();
|
||||
let input_stream = once(async { Ok(input) }).to_input_stream();
|
||||
|
||||
let result = run_block(
|
||||
&block,
|
||||
&mut context,
|
||||
input_stream,
|
||||
&Scope::new(input_clone),
|
||||
).await;
|
||||
|
||||
match result {
|
||||
Ok(mut stream) => {
|
||||
let errors = context.get_errors();
|
||||
if let Some(error) = errors.first() {
|
||||
yield Err(error.clone());
|
||||
}
|
||||
|
||||
while let Some(result) = stream.next().await {
|
||||
yield Ok(ReturnSuccess::Value(result));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
yield Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
|
@ -1,10 +1,16 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{CallInfo, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
||||
pub struct Echo;
|
||||
|
||||
impl PerItemCommand for Echo {
|
||||
#[derive(Deserialize)]
|
||||
pub struct EchoArgs {
|
||||
pub rest: Vec<Value>,
|
||||
}
|
||||
|
||||
impl WholeStreamCommand for Echo {
|
||||
fn name(&self) -> &str {
|
||||
"echo"
|
||||
}
|
||||
@ -19,44 +25,36 @@ impl PerItemCommand for Echo {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
raw_args: &RawCommandArgs,
|
||||
_input: Value,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
run(call_info, registry, raw_args)
|
||||
args.process(registry, echo)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
fn run(
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
_raw_args: &RawCommandArgs,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
fn echo(args: EchoArgs, _: RunnableContext) -> Result<OutputStream, ShellError> {
|
||||
let mut output = vec![];
|
||||
|
||||
if let Some(ref positional) = call_info.args.positional {
|
||||
for i in positional {
|
||||
match i.as_string() {
|
||||
Ok(s) => {
|
||||
output.push(Ok(ReturnSuccess::Value(
|
||||
UntaggedValue::string(s).into_value(i.tag.clone()),
|
||||
)));
|
||||
}
|
||||
_ => match i {
|
||||
Value {
|
||||
value: UntaggedValue::Table(table),
|
||||
..
|
||||
} => {
|
||||
for value in table {
|
||||
output.push(Ok(ReturnSuccess::Value(value.clone())));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
output.push(Ok(ReturnSuccess::Value(i.clone())));
|
||||
}
|
||||
},
|
||||
for i in args.rest {
|
||||
match i.as_string() {
|
||||
Ok(s) => {
|
||||
output.push(Ok(ReturnSuccess::Value(
|
||||
UntaggedValue::string(s).into_value(i.tag.clone()),
|
||||
)));
|
||||
}
|
||||
_ => match i {
|
||||
Value {
|
||||
value: UntaggedValue::Table(table),
|
||||
..
|
||||
} => {
|
||||
for value in table {
|
||||
output.push(Ok(ReturnSuccess::Value(value.clone())));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
output.push(Ok(ReturnSuccess::Value(i.clone())));
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,19 @@
|
||||
use crate::commands::PerItemCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{CallInfo, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_value_ext::ValueExt;
|
||||
|
||||
pub struct Edit;
|
||||
|
||||
impl PerItemCommand for Edit {
|
||||
#[derive(Deserialize)]
|
||||
pub struct EditArgs {
|
||||
field: ColumnPath,
|
||||
replacement: Value,
|
||||
}
|
||||
|
||||
impl WholeStreamCommand for Edit {
|
||||
fn name(&self) -> &str {
|
||||
"edit"
|
||||
}
|
||||
@ -15,13 +21,13 @@ impl PerItemCommand for Edit {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("edit")
|
||||
.required(
|
||||
"Field",
|
||||
"field",
|
||||
SyntaxShape::ColumnPath,
|
||||
"the name of the column to edit",
|
||||
)
|
||||
.required(
|
||||
"Value",
|
||||
SyntaxShape::String,
|
||||
"replacement value",
|
||||
SyntaxShape::Any,
|
||||
"the new value to give the cell(s)",
|
||||
)
|
||||
}
|
||||
@ -32,41 +38,45 @@ impl PerItemCommand for Edit {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
_raw_args: &RawCommandArgs,
|
||||
value: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let value_tag = value.tag();
|
||||
let field = call_info.args.expect_nth(0)?.as_column_path()?;
|
||||
let replacement = call_info.args.expect_nth(1)?.tagged_unknown();
|
||||
args.process(registry, edit)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
let stream = match value {
|
||||
obj
|
||||
@
|
||||
Value {
|
||||
fn edit(
|
||||
EditArgs { field, replacement }: EditArgs,
|
||||
RunnableContext { input, .. }: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let mut input = input;
|
||||
|
||||
let stream = async_stream! {
|
||||
match input.next().await {
|
||||
Some(obj @ Value {
|
||||
value: UntaggedValue::Row(_),
|
||||
..
|
||||
} => match obj.replace_data_at_column_path(&field, replacement.item.clone()) {
|
||||
Some(v) => futures::stream::iter(vec![Ok(ReturnSuccess::Value(v))]),
|
||||
}) => match obj.replace_data_at_column_path(&field, replacement.clone()) {
|
||||
Some(v) => yield Ok(ReturnSuccess::Value(v)),
|
||||
None => {
|
||||
return Err(ShellError::labeled_error(
|
||||
yield Err(ShellError::labeled_error(
|
||||
"edit could not find place to insert column",
|
||||
"column name",
|
||||
&field.tag,
|
||||
obj.tag,
|
||||
))
|
||||
}
|
||||
},
|
||||
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
Some(Value { tag, ..}) => {
|
||||
yield Err(ShellError::labeled_error(
|
||||
"Unrecognized type in stream",
|
||||
"original value",
|
||||
value_tag,
|
||||
tag,
|
||||
))
|
||||
}
|
||||
};
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
|
@ -1,15 +1,22 @@
|
||||
use crate::commands::PerItemCommand;
|
||||
use crate::commands::UnevaluatedCallInfo;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
CallInfo, CommandAction, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
CommandAction, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::Tagged;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct Enter;
|
||||
|
||||
impl PerItemCommand for Enter {
|
||||
#[derive(Deserialize)]
|
||||
pub struct EnterArgs {
|
||||
location: Tagged<PathBuf>,
|
||||
}
|
||||
|
||||
impl WholeStreamCommand for Enter {
|
||||
fn name(&self) -> &str {
|
||||
"enter"
|
||||
}
|
||||
@ -28,130 +35,121 @@ impl PerItemCommand for Enter {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
raw_args: &RawCommandArgs,
|
||||
_input: Value,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let raw_args = raw_args.clone();
|
||||
match call_info.args.expect_nth(0)? {
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Path(location)),
|
||||
tag,
|
||||
..
|
||||
} => {
|
||||
let location_string = location.display().to_string();
|
||||
let location_clone = location_string.clone();
|
||||
let tag_clone = tag.clone();
|
||||
|
||||
if location_string.starts_with("help") {
|
||||
let spec = location_string.split(':').collect::<Vec<&str>>();
|
||||
|
||||
if spec.len() == 2 {
|
||||
let (_, command) = (spec[0], spec[1]);
|
||||
|
||||
if registry.has(command) {
|
||||
return Ok(vec![Ok(ReturnSuccess::Action(
|
||||
CommandAction::EnterHelpShell(
|
||||
UntaggedValue::string(command).into_value(Tag::unknown()),
|
||||
),
|
||||
))]
|
||||
.into());
|
||||
}
|
||||
}
|
||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell(
|
||||
UntaggedValue::nothing().into_value(Tag::unknown()),
|
||||
)))]
|
||||
.into())
|
||||
} else if location.is_dir() {
|
||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterShell(
|
||||
location_clone,
|
||||
)))]
|
||||
.into())
|
||||
} else {
|
||||
let stream = async_stream! {
|
||||
// If it's a file, attempt to open the file as a value and enter it
|
||||
let cwd = raw_args.shell_manager.path();
|
||||
|
||||
let full_path = std::path::PathBuf::from(cwd);
|
||||
|
||||
let (file_extension, contents, contents_tag) =
|
||||
crate::commands::open::fetch(
|
||||
&full_path,
|
||||
&location_clone,
|
||||
tag_clone.span,
|
||||
).await?;
|
||||
|
||||
match contents {
|
||||
UntaggedValue::Primitive(Primitive::String(_)) => {
|
||||
let tagged_contents = contents.into_value(&contents_tag);
|
||||
|
||||
if let Some(extension) = file_extension {
|
||||
let command_name = format!("from-{}", extension);
|
||||
if let Some(converter) =
|
||||
registry.get_command(&command_name)
|
||||
{
|
||||
let new_args = RawCommandArgs {
|
||||
host: raw_args.host,
|
||||
ctrl_c: raw_args.ctrl_c,
|
||||
shell_manager: raw_args.shell_manager,
|
||||
call_info: UnevaluatedCallInfo {
|
||||
args: nu_protocol::hir::Call {
|
||||
head: raw_args.call_info.args.head,
|
||||
positional: None,
|
||||
named: None,
|
||||
span: Span::unknown(),
|
||||
is_last: false,
|
||||
},
|
||||
name_tag: raw_args.call_info.name_tag,
|
||||
scope: raw_args.call_info.scope.clone()
|
||||
},
|
||||
};
|
||||
let mut result = converter.run(
|
||||
new_args.with_input(vec![tagged_contents]),
|
||||
®istry,
|
||||
);
|
||||
let result_vec: Vec<Result<ReturnSuccess, ShellError>> =
|
||||
result.drain_vec().await;
|
||||
for res in result_vec {
|
||||
match res {
|
||||
Ok(ReturnSuccess::Value(Value {
|
||||
value,
|
||||
..
|
||||
})) => {
|
||||
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(
|
||||
Value {
|
||||
value,
|
||||
tag: contents_tag.clone(),
|
||||
})));
|
||||
}
|
||||
x => yield x,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(tagged_contents)));
|
||||
}
|
||||
} else {
|
||||
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(tagged_contents)));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let tagged_contents = contents.into_value(contents_tag);
|
||||
|
||||
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(tagged_contents)));
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
}
|
||||
x => Ok(
|
||||
vec![Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(
|
||||
x.clone(),
|
||||
)))]
|
||||
.into(),
|
||||
),
|
||||
}
|
||||
Ok(args.process_raw(registry, enter)?.run())
|
||||
}
|
||||
}
|
||||
|
||||
fn enter(
|
||||
EnterArgs { location }: EnterArgs,
|
||||
RunnableContext {
|
||||
registry,
|
||||
name: tag,
|
||||
..
|
||||
}: RunnableContext,
|
||||
raw_args: RawCommandArgs,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let location_string = location.display().to_string();
|
||||
let location_clone = location_string.clone();
|
||||
|
||||
if location_string.starts_with("help") {
|
||||
let spec = location_string.split(':').collect::<Vec<&str>>();
|
||||
|
||||
if spec.len() == 2 {
|
||||
let (_, command) = (spec[0], spec[1]);
|
||||
|
||||
if registry.has(command) {
|
||||
return Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell(
|
||||
UntaggedValue::string(command).into_value(Tag::unknown()),
|
||||
)))]
|
||||
.into());
|
||||
}
|
||||
}
|
||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell(
|
||||
UntaggedValue::nothing().into_value(Tag::unknown()),
|
||||
)))]
|
||||
.into())
|
||||
} else if location.is_dir() {
|
||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterShell(
|
||||
location_clone,
|
||||
)))]
|
||||
.into())
|
||||
} else {
|
||||
let stream = async_stream! {
|
||||
// If it's a file, attempt to open the file as a value and enter it
|
||||
let cwd = raw_args.shell_manager.path();
|
||||
|
||||
let full_path = std::path::PathBuf::from(cwd);
|
||||
|
||||
let (file_extension, contents, contents_tag) =
|
||||
crate::commands::open::fetch(
|
||||
&full_path,
|
||||
&PathBuf::from(location_clone),
|
||||
tag.span,
|
||||
).await?;
|
||||
|
||||
match contents {
|
||||
UntaggedValue::Primitive(Primitive::String(_)) => {
|
||||
let tagged_contents = contents.into_value(&contents_tag);
|
||||
|
||||
if let Some(extension) = file_extension {
|
||||
let command_name = format!("from-{}", extension);
|
||||
if let Some(converter) =
|
||||
registry.get_command(&command_name)
|
||||
{
|
||||
let new_args = RawCommandArgs {
|
||||
host: raw_args.host,
|
||||
ctrl_c: raw_args.ctrl_c,
|
||||
shell_manager: raw_args.shell_manager,
|
||||
call_info: UnevaluatedCallInfo {
|
||||
args: nu_protocol::hir::Call {
|
||||
head: raw_args.call_info.args.head,
|
||||
positional: None,
|
||||
named: None,
|
||||
span: Span::unknown(),
|
||||
is_last: false,
|
||||
},
|
||||
name_tag: raw_args.call_info.name_tag,
|
||||
scope: raw_args.call_info.scope.clone()
|
||||
},
|
||||
};
|
||||
let mut result = converter.run(
|
||||
new_args.with_input(vec![tagged_contents]),
|
||||
®istry,
|
||||
);
|
||||
let result_vec: Vec<Result<ReturnSuccess, ShellError>> =
|
||||
result.drain_vec().await;
|
||||
for res in result_vec {
|
||||
match res {
|
||||
Ok(ReturnSuccess::Value(Value {
|
||||
value,
|
||||
..
|
||||
})) => {
|
||||
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(
|
||||
Value {
|
||||
value,
|
||||
tag: contents_tag.clone(),
|
||||
})));
|
||||
}
|
||||
x => yield x,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(tagged_contents)));
|
||||
}
|
||||
} else {
|
||||
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(tagged_contents)));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let tagged_contents = contents.into_value(contents_tag);
|
||||
|
||||
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(tagged_contents)));
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,20 @@
|
||||
use crate::commands::PerItemCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
CallInfo, ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
use nu_value_ext::{as_column_path, get_data_by_column_path};
|
||||
use std::borrow::Borrow;
|
||||
|
||||
pub struct Format;
|
||||
|
||||
impl PerItemCommand for Format {
|
||||
#[derive(Deserialize)]
|
||||
pub struct FormatArgs {
|
||||
pattern: Tagged<String>,
|
||||
}
|
||||
|
||||
impl WholeStreamCommand for Format {
|
||||
fn name(&self) -> &str {
|
||||
"format"
|
||||
}
|
||||
@ -19,7 +22,7 @@ impl PerItemCommand for Format {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("format").required(
|
||||
"pattern",
|
||||
SyntaxShape::Any,
|
||||
SyntaxShape::String,
|
||||
"the pattern to output. Eg) \"{foo}: {bar}\"",
|
||||
)
|
||||
}
|
||||
@ -30,61 +33,67 @@ impl PerItemCommand for Format {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
_raw_args: &RawCommandArgs,
|
||||
value: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
//let value_tag = value.tag();
|
||||
let pattern = call_info.args.expect_nth(0)?;
|
||||
let pattern_tag = pattern.tag.clone();
|
||||
let pattern = pattern.as_string()?;
|
||||
args.process(registry, format_command)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
let format_pattern = format(&pattern);
|
||||
let commands = format_pattern;
|
||||
fn format_command(
|
||||
FormatArgs { pattern }: FormatArgs,
|
||||
RunnableContext { input, .. }: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let pattern_tag = pattern.tag.clone();
|
||||
|
||||
let output = match value {
|
||||
value
|
||||
@
|
||||
Value {
|
||||
value: UntaggedValue::Row(_),
|
||||
..
|
||||
} => {
|
||||
let mut output = String::new();
|
||||
let format_pattern = format(&pattern);
|
||||
let commands = format_pattern;
|
||||
let mut input = input;
|
||||
|
||||
for command in &commands {
|
||||
match command {
|
||||
FormatCommand::Text(s) => {
|
||||
output.push_str(&s);
|
||||
}
|
||||
FormatCommand::Column(c) => {
|
||||
let key = to_column_path(&c, &pattern_tag)?;
|
||||
let stream = async_stream! {
|
||||
while let Some(value) = input.next().await {
|
||||
match value {
|
||||
value
|
||||
@
|
||||
Value {
|
||||
value: UntaggedValue::Row(_),
|
||||
..
|
||||
} => {
|
||||
let mut output = String::new();
|
||||
|
||||
let fetcher = get_data_by_column_path(
|
||||
&value,
|
||||
&key,
|
||||
Box::new(move |(_, _, error)| error),
|
||||
);
|
||||
|
||||
if let Ok(c) = fetcher {
|
||||
output
|
||||
.push_str(&value::format_leaf(c.borrow()).plain_string(100_000))
|
||||
for command in &commands {
|
||||
match command {
|
||||
FormatCommand::Text(s) => {
|
||||
output.push_str(&s);
|
||||
}
|
||||
FormatCommand::Column(c) => {
|
||||
let key = to_column_path(&c, &pattern_tag)?;
|
||||
|
||||
let fetcher = get_data_by_column_path(
|
||||
&value,
|
||||
&key,
|
||||
Box::new(move |(_, _, error)| error),
|
||||
);
|
||||
|
||||
if let Ok(c) = fetcher {
|
||||
output
|
||||
.push_str(&value::format_leaf(c.borrow()).plain_string(100_000))
|
||||
}
|
||||
// That column doesn't match, so don't emit anything
|
||||
}
|
||||
// That column doesn't match, so don't emit anything
|
||||
}
|
||||
}
|
||||
|
||||
yield ReturnSuccess::value(
|
||||
UntaggedValue::string(output).into_untagged_value())
|
||||
}
|
||||
_ => yield ReturnSuccess::value(
|
||||
UntaggedValue::string(String::new()).into_untagged_value()),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
output
|
||||
}
|
||||
_ => String::new(),
|
||||
};
|
||||
|
||||
Ok(futures::stream::iter(vec![ReturnSuccess::value(
|
||||
UntaggedValue::string(output).into_untagged_value(),
|
||||
)])
|
||||
.to_output_stream())
|
||||
}
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -1,24 +1,33 @@
|
||||
use crate::commands::PerItemCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::data::command_dict;
|
||||
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
CallInfo, NamedType, PositionalType, Primitive, ReturnSuccess, Signature, SyntaxShape,
|
||||
TaggedDictBuilder, UntaggedValue, Value,
|
||||
NamedType, PositionalType, ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder,
|
||||
UntaggedValue,
|
||||
};
|
||||
use nu_source::SpannedItem;
|
||||
use nu_source::{SpannedItem, Tagged};
|
||||
use nu_value_ext::get_data_by_key;
|
||||
|
||||
pub struct Help;
|
||||
|
||||
impl PerItemCommand for Help {
|
||||
#[derive(Deserialize)]
|
||||
pub struct HelpArgs {
|
||||
command: Option<Tagged<String>>,
|
||||
}
|
||||
|
||||
impl WholeStreamCommand for Help {
|
||||
fn name(&self) -> &str {
|
||||
"help"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("help").rest(SyntaxShape::Any, "the name of command(s) to get help on")
|
||||
Signature::build("help").optional(
|
||||
"command",
|
||||
SyntaxShape::String,
|
||||
"the name of command(s) to get help on",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
@ -27,67 +36,65 @@ impl PerItemCommand for Help {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
_raw_args: &RawCommandArgs,
|
||||
_input: Value,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let tag = &call_info.name_tag;
|
||||
args.process(registry, help)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
match call_info.args.nth(0) {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::String(document)),
|
||||
tag,
|
||||
}) => {
|
||||
let mut help = VecDeque::new();
|
||||
if document == "commands" {
|
||||
let mut sorted_names = registry.names();
|
||||
sorted_names.sort();
|
||||
for cmd in sorted_names {
|
||||
let mut short_desc = TaggedDictBuilder::new(tag.clone());
|
||||
let value = command_dict(
|
||||
registry.get_command(&cmd).ok_or_else(|| {
|
||||
ShellError::labeled_error(
|
||||
format!("Could not load {}", cmd),
|
||||
"could not load command",
|
||||
tag,
|
||||
)
|
||||
})?,
|
||||
tag.clone(),
|
||||
);
|
||||
fn help(
|
||||
HelpArgs { command }: HelpArgs,
|
||||
RunnableContext { registry, name, .. }: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
if let Some(document) = command {
|
||||
let mut help = VecDeque::new();
|
||||
if document.item == "commands" {
|
||||
let mut sorted_names = registry.names();
|
||||
sorted_names.sort();
|
||||
for cmd in sorted_names {
|
||||
let mut short_desc = TaggedDictBuilder::new(name.clone());
|
||||
let document_tag = document.tag.clone();
|
||||
let value = command_dict(
|
||||
registry.get_command(&cmd).ok_or_else(|| {
|
||||
ShellError::labeled_error(
|
||||
format!("Could not load {}", cmd),
|
||||
"could not load command",
|
||||
document_tag,
|
||||
)
|
||||
})?,
|
||||
name.clone(),
|
||||
);
|
||||
|
||||
short_desc.insert_untagged("name", cmd);
|
||||
short_desc.insert_untagged(
|
||||
"description",
|
||||
get_data_by_key(&value, "usage".spanned_unknown())
|
||||
.ok_or_else(|| {
|
||||
ShellError::labeled_error(
|
||||
"Expected a usage key",
|
||||
"expected a 'usage' key",
|
||||
&value.tag,
|
||||
)
|
||||
})?
|
||||
.as_string()?,
|
||||
);
|
||||
short_desc.insert_untagged("name", cmd);
|
||||
short_desc.insert_untagged(
|
||||
"description",
|
||||
get_data_by_key(&value, "usage".spanned_unknown())
|
||||
.ok_or_else(|| {
|
||||
ShellError::labeled_error(
|
||||
"Expected a usage key",
|
||||
"expected a 'usage' key",
|
||||
&value.tag,
|
||||
)
|
||||
})?
|
||||
.as_string()?,
|
||||
);
|
||||
|
||||
help.push_back(ReturnSuccess::value(short_desc.into_value()));
|
||||
}
|
||||
} else if let Some(command) = registry.get_command(document) {
|
||||
return Ok(
|
||||
get_help(&command.name(), &command.usage(), command.signature()).into(),
|
||||
);
|
||||
} else {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Can't find command (use 'help commands' for full list)",
|
||||
"can't find command",
|
||||
tag,
|
||||
));
|
||||
}
|
||||
let help = futures::stream::iter(help);
|
||||
Ok(help.to_output_stream())
|
||||
help.push_back(ReturnSuccess::value(short_desc.into_value()));
|
||||
}
|
||||
_ => {
|
||||
let msg = r#"Welcome to Nushell.
|
||||
} else if let Some(command) = registry.get_command(&document.item) {
|
||||
return Ok(get_help(&command.name(), &command.usage(), command.signature()).into());
|
||||
} else {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Can't find command (use 'help commands' for full list)",
|
||||
"can't find command",
|
||||
document.tag,
|
||||
));
|
||||
}
|
||||
let help = futures::stream::iter(help);
|
||||
Ok(help.to_output_stream())
|
||||
} else {
|
||||
let msg = r#"Welcome to Nushell.
|
||||
|
||||
Here are some tips to help you get started.
|
||||
* help commands - list all available commands
|
||||
@ -109,13 +116,11 @@ Get the processes on your system actively using CPU:
|
||||
|
||||
You can also learn more at https://www.nushell.sh/book/"#;
|
||||
|
||||
let output_stream = futures::stream::iter(vec![ReturnSuccess::value(
|
||||
UntaggedValue::string(msg).into_value(tag),
|
||||
)]);
|
||||
let output_stream = futures::stream::iter(vec![ReturnSuccess::value(
|
||||
UntaggedValue::string(msg).into_value(name),
|
||||
)]);
|
||||
|
||||
Ok(output_stream.to_output_stream())
|
||||
}
|
||||
}
|
||||
Ok(output_stream.to_output_stream())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,17 @@
|
||||
use crate::cli::History as HistoryFile;
|
||||
use crate::commands::PerItemCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{CallInfo, ReturnSuccess, Signature, UntaggedValue, Value};
|
||||
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader};
|
||||
|
||||
pub struct History;
|
||||
|
||||
impl PerItemCommand for History {
|
||||
#[derive(Deserialize)]
|
||||
pub struct HistoryArgs;
|
||||
|
||||
impl WholeStreamCommand for History {
|
||||
fn name(&self) -> &str {
|
||||
"history"
|
||||
}
|
||||
@ -23,27 +26,30 @@ impl PerItemCommand for History {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
_raw_args: &RawCommandArgs,
|
||||
_input: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let tag = call_info.name_tag.clone();
|
||||
|
||||
let stream = async_stream! {
|
||||
let history_path = HistoryFile::path();
|
||||
let file = File::open(history_path);
|
||||
if let Ok(file) = file {
|
||||
let reader = BufReader::new(file);
|
||||
for line in reader.lines() {
|
||||
if let Ok(line) = line {
|
||||
yield ReturnSuccess::value(UntaggedValue::string(line).into_value(tag.clone()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
yield Err(ShellError::labeled_error("Could not open history", "history file could not be opened", tag.clone()));
|
||||
}
|
||||
};
|
||||
Ok(stream.to_output_stream())
|
||||
args.process(registry, history)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
fn history(
|
||||
_: HistoryArgs,
|
||||
RunnableContext { name: tag, .. }: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let stream = async_stream! {
|
||||
let history_path = HistoryFile::path();
|
||||
let file = File::open(history_path);
|
||||
if let Ok(file) = file {
|
||||
let reader = BufReader::new(file);
|
||||
for line in reader.lines() {
|
||||
if let Ok(line) = line {
|
||||
yield ReturnSuccess::value(UntaggedValue::string(line).into_value(tag.clone()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
yield Err(ShellError::labeled_error("Could not open history", "history file could not be opened", tag.clone()));
|
||||
}
|
||||
};
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
|
@ -1,13 +1,19 @@
|
||||
use crate::commands::PerItemCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{CallInfo, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_value_ext::ValueExt;
|
||||
|
||||
pub struct Insert;
|
||||
|
||||
impl PerItemCommand for Insert {
|
||||
#[derive(Deserialize)]
|
||||
pub struct InsertArgs {
|
||||
column: ColumnPath,
|
||||
value: Value,
|
||||
}
|
||||
|
||||
impl WholeStreamCommand for Insert {
|
||||
fn name(&self) -> &str {
|
||||
"insert"
|
||||
}
|
||||
@ -27,40 +33,45 @@ impl PerItemCommand for Insert {
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Edit an existing column to have a new value."
|
||||
"Insert a new column with a given value."
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
_raw_args: &RawCommandArgs,
|
||||
value: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let value_tag = value.tag();
|
||||
let field = call_info.args.expect_nth(0)?.as_column_path()?;
|
||||
let replacement = call_info.args.expect_nth(1)?.tagged_unknown();
|
||||
|
||||
let stream = match value {
|
||||
obj
|
||||
@
|
||||
Value {
|
||||
value: UntaggedValue::Row(_),
|
||||
..
|
||||
} => match obj.insert_data_at_column_path(&field, replacement.item.clone()) {
|
||||
Ok(v) => futures::stream::iter(vec![Ok(ReturnSuccess::Value(v))]),
|
||||
Err(err) => return Err(err),
|
||||
},
|
||||
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Unrecognized type in stream",
|
||||
"original value",
|
||||
value_tag,
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(stream.to_output_stream())
|
||||
args.process(registry, insert)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
fn insert(
|
||||
InsertArgs { column, value }: InsertArgs,
|
||||
RunnableContext { input, .. }: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let mut input = input;
|
||||
|
||||
let stream = async_stream! {
|
||||
match input.next().await {
|
||||
Some(obj @ Value {
|
||||
value: UntaggedValue::Row(_),
|
||||
..
|
||||
}) => match obj.insert_data_at_column_path(&column, value.clone()) {
|
||||
Ok(v) => yield Ok(ReturnSuccess::Value(v)),
|
||||
Err(err) => yield Err(err),
|
||||
},
|
||||
|
||||
Some(Value { tag, ..}) => {
|
||||
yield Err(ShellError::labeled_error(
|
||||
"Unrecognized type in stream",
|
||||
"original value",
|
||||
tag,
|
||||
));
|
||||
}
|
||||
|
||||
None => {}
|
||||
};
|
||||
|
||||
};
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
use crate::commands::PerItemCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
CallInfo, ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
use nu_value_ext::ValueExt;
|
||||
|
||||
@ -17,7 +15,12 @@ enum IsEmptyFor {
|
||||
|
||||
pub struct IsEmpty;
|
||||
|
||||
impl PerItemCommand for IsEmpty {
|
||||
#[derive(Deserialize)]
|
||||
pub struct IsEmptyArgs {
|
||||
rest: Vec<Value>,
|
||||
}
|
||||
|
||||
impl WholeStreamCommand for IsEmpty {
|
||||
fn name(&self) -> &str {
|
||||
"empty?"
|
||||
}
|
||||
@ -35,61 +38,100 @@ impl PerItemCommand for IsEmpty {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
_raw_args: &RawCommandArgs,
|
||||
value: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let value_tag = value.tag();
|
||||
args.process(registry, is_empty)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
let action = if call_info.args.len() <= 2 {
|
||||
let field = call_info.args.expect_nth(0);
|
||||
let replacement_if_true = call_info.args.expect_nth(1);
|
||||
fn is_empty(
|
||||
IsEmptyArgs { rest }: IsEmptyArgs,
|
||||
RunnableContext { input, .. }: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
Ok(input
|
||||
.map(move |value| {
|
||||
let value_tag = value.tag();
|
||||
|
||||
match (field, replacement_if_true) {
|
||||
(Ok(field), Ok(replacement_if_true)) => IsEmptyFor::RowWithFieldAndFallback(
|
||||
Box::new(field.as_column_path()?),
|
||||
replacement_if_true.clone(),
|
||||
),
|
||||
(Ok(field), Err(_)) => IsEmptyFor::RowWithField(field.as_column_path()?),
|
||||
(_, _) => IsEmptyFor::Value,
|
||||
}
|
||||
} else {
|
||||
let no_args = vec![];
|
||||
let mut arguments = call_info
|
||||
.args
|
||||
.positional
|
||||
.as_ref()
|
||||
.unwrap_or_else(|| &no_args)
|
||||
.iter()
|
||||
.rev();
|
||||
let replacement_if_true = match arguments.next() {
|
||||
Some(arg) => arg.clone(),
|
||||
None => UntaggedValue::boolean(value.is_empty()).into_value(&value_tag),
|
||||
let action = if rest.len() <= 2 {
|
||||
let field = rest.get(0);
|
||||
let replacement_if_true = rest.get(1);
|
||||
|
||||
match (field, replacement_if_true) {
|
||||
(Some(field), Some(replacement_if_true)) => {
|
||||
IsEmptyFor::RowWithFieldAndFallback(
|
||||
Box::new(field.as_column_path()?),
|
||||
replacement_if_true.clone(),
|
||||
)
|
||||
}
|
||||
(Some(field), None) => IsEmptyFor::RowWithField(field.as_column_path()?),
|
||||
(_, _) => IsEmptyFor::Value,
|
||||
}
|
||||
} else {
|
||||
// let no_args = vec![];
|
||||
let mut arguments = rest.iter().rev();
|
||||
let replacement_if_true = match arguments.next() {
|
||||
Some(arg) => arg.clone(),
|
||||
None => UntaggedValue::boolean(value.is_empty()).into_value(&value_tag),
|
||||
};
|
||||
|
||||
IsEmptyFor::RowWithFieldsAndFallback(
|
||||
arguments
|
||||
.map(|a| a.as_column_path())
|
||||
.filter_map(Result::ok)
|
||||
.collect(),
|
||||
replacement_if_true,
|
||||
)
|
||||
};
|
||||
|
||||
IsEmptyFor::RowWithFieldsAndFallback(
|
||||
arguments
|
||||
.map(|a| a.as_column_path())
|
||||
.filter_map(Result::ok)
|
||||
.collect(),
|
||||
replacement_if_true,
|
||||
)
|
||||
};
|
||||
match action {
|
||||
IsEmptyFor::Value => Ok(ReturnSuccess::Value(
|
||||
UntaggedValue::boolean(value.is_empty()).into_value(value_tag),
|
||||
)),
|
||||
IsEmptyFor::RowWithFieldsAndFallback(fields, default) => {
|
||||
let mut out = value;
|
||||
|
||||
match action {
|
||||
IsEmptyFor::Value => Ok(futures::stream::iter(vec![Ok(ReturnSuccess::Value(
|
||||
UntaggedValue::boolean(value.is_empty()).into_value(value_tag),
|
||||
))])
|
||||
.to_output_stream()),
|
||||
IsEmptyFor::RowWithFieldsAndFallback(fields, default) => {
|
||||
let mut out = value;
|
||||
for field in fields.iter() {
|
||||
let val =
|
||||
out.get_data_by_column_path(&field, Box::new(move |(_, _, err)| err))?;
|
||||
|
||||
for field in fields.iter() {
|
||||
let emptiness_value = match out {
|
||||
obj
|
||||
@
|
||||
Value {
|
||||
value: UntaggedValue::Row(_),
|
||||
..
|
||||
} => {
|
||||
if val.is_empty() {
|
||||
match obj.replace_data_at_column_path(&field, default.clone()) {
|
||||
Some(v) => Ok(v),
|
||||
None => Err(ShellError::labeled_error(
|
||||
"empty? could not find place to check emptiness",
|
||||
"column name",
|
||||
&field.tag,
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
Ok(obj)
|
||||
}
|
||||
}
|
||||
_ => Err(ShellError::labeled_error(
|
||||
"Unrecognized type in stream",
|
||||
"original value",
|
||||
&value_tag,
|
||||
)),
|
||||
};
|
||||
|
||||
out = emptiness_value?;
|
||||
}
|
||||
|
||||
Ok(ReturnSuccess::Value(out))
|
||||
}
|
||||
IsEmptyFor::RowWithField(field) => {
|
||||
let val =
|
||||
out.get_data_by_column_path(&field, Box::new(move |(_, _, err)| err))?;
|
||||
value.get_data_by_column_path(&field, Box::new(move |(_, _, err)| err))?;
|
||||
|
||||
let emptiness_value = match out {
|
||||
match &value {
|
||||
obj
|
||||
@
|
||||
Value {
|
||||
@ -97,8 +139,11 @@ impl PerItemCommand for IsEmpty {
|
||||
..
|
||||
} => {
|
||||
if val.is_empty() {
|
||||
match obj.replace_data_at_column_path(&field, default.clone()) {
|
||||
Some(v) => Ok(v),
|
||||
match obj.replace_data_at_column_path(
|
||||
&field,
|
||||
UntaggedValue::boolean(true).into_value(&value_tag),
|
||||
) {
|
||||
Some(v) => Ok(ReturnSuccess::Value(v)),
|
||||
None => Err(ShellError::labeled_error(
|
||||
"empty? could not find place to check emptiness",
|
||||
"column name",
|
||||
@ -106,7 +151,7 @@ impl PerItemCommand for IsEmpty {
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
Ok(obj)
|
||||
Ok(ReturnSuccess::Value(value))
|
||||
}
|
||||
}
|
||||
_ => Err(ShellError::labeled_error(
|
||||
@ -114,90 +159,40 @@ impl PerItemCommand for IsEmpty {
|
||||
"original value",
|
||||
&value_tag,
|
||||
)),
|
||||
};
|
||||
|
||||
out = emptiness_value?;
|
||||
}
|
||||
}
|
||||
IsEmptyFor::RowWithFieldAndFallback(field, default) => {
|
||||
let val =
|
||||
value.get_data_by_column_path(&field, Box::new(move |(_, _, err)| err))?;
|
||||
|
||||
Ok(futures::stream::iter(vec![Ok(ReturnSuccess::Value(out))]).to_output_stream())
|
||||
}
|
||||
IsEmptyFor::RowWithField(field) => {
|
||||
let val =
|
||||
value.get_data_by_column_path(&field, Box::new(move |(_, _, err)| err))?;
|
||||
|
||||
let stream = match &value {
|
||||
obj
|
||||
@
|
||||
Value {
|
||||
value: UntaggedValue::Row(_),
|
||||
..
|
||||
} => {
|
||||
if val.is_empty() {
|
||||
match obj.replace_data_at_column_path(
|
||||
&field,
|
||||
UntaggedValue::boolean(true).into_value(&value_tag),
|
||||
) {
|
||||
Some(v) => futures::stream::iter(vec![Ok(ReturnSuccess::Value(v))]),
|
||||
None => {
|
||||
return Err(ShellError::labeled_error(
|
||||
match &value {
|
||||
obj
|
||||
@
|
||||
Value {
|
||||
value: UntaggedValue::Row(_),
|
||||
..
|
||||
} => {
|
||||
if val.is_empty() {
|
||||
match obj.replace_data_at_column_path(&field, default) {
|
||||
Some(v) => Ok(ReturnSuccess::Value(v)),
|
||||
None => Err(ShellError::labeled_error(
|
||||
"empty? could not find place to check emptiness",
|
||||
"column name",
|
||||
&field.tag,
|
||||
))
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
Ok(ReturnSuccess::Value(value))
|
||||
}
|
||||
} else {
|
||||
futures::stream::iter(vec![Ok(ReturnSuccess::Value(value))])
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
_ => Err(ShellError::labeled_error(
|
||||
"Unrecognized type in stream",
|
||||
"original value",
|
||||
&value_tag,
|
||||
))
|
||||
)),
|
||||
}
|
||||
};
|
||||
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
}
|
||||
IsEmptyFor::RowWithFieldAndFallback(field, default) => {
|
||||
let val =
|
||||
value.get_data_by_column_path(&field, Box::new(move |(_, _, err)| err))?;
|
||||
|
||||
let stream = match &value {
|
||||
obj
|
||||
@
|
||||
Value {
|
||||
value: UntaggedValue::Row(_),
|
||||
..
|
||||
} => {
|
||||
if val.is_empty() {
|
||||
match obj.replace_data_at_column_path(&field, default) {
|
||||
Some(v) => futures::stream::iter(vec![Ok(ReturnSuccess::Value(v))]),
|
||||
None => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"empty? could not find place to check emptiness",
|
||||
"column name",
|
||||
&field.tag,
|
||||
))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
futures::stream::iter(vec![Ok(ReturnSuccess::Value(value))])
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Unrecognized type in stream",
|
||||
"original value",
|
||||
&value_tag,
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.to_output_stream())
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::commands::command::RunnablePerItemContext;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{CallInfo, Signature, SyntaxShape, Value};
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
@ -16,7 +16,7 @@ pub struct KillArgs {
|
||||
pub quiet: Tagged<bool>,
|
||||
}
|
||||
|
||||
impl PerItemCommand for Kill {
|
||||
impl WholeStreamCommand for Kill {
|
||||
fn name(&self) -> &str {
|
||||
"kill"
|
||||
}
|
||||
@ -39,14 +39,10 @@ impl PerItemCommand for Kill {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
raw_args: &RawCommandArgs,
|
||||
_input: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
call_info
|
||||
.process(&raw_args.shell_manager, raw_args.ctrl_c.clone(), kill)?
|
||||
.run()
|
||||
args.process(registry, kill)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,7 +53,7 @@ fn kill(
|
||||
force,
|
||||
quiet,
|
||||
}: KillArgs,
|
||||
_context: &RunnablePerItemContext,
|
||||
_context: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let mut cmd = if cfg!(windows) {
|
||||
let mut cmd = Command::new("taskkill");
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::commands::command::RunnablePerItemContext;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{CallInfo, Signature, SyntaxShape, Value};
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -18,7 +18,7 @@ pub struct LsArgs {
|
||||
pub with_symlink_targets: bool,
|
||||
}
|
||||
|
||||
impl PerItemCommand for Ls {
|
||||
impl WholeStreamCommand for Ls {
|
||||
fn name(&self) -> &str {
|
||||
"ls"
|
||||
}
|
||||
@ -54,17 +54,13 @@ impl PerItemCommand for Ls {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
raw_args: &RawCommandArgs,
|
||||
_input: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
call_info
|
||||
.process(&raw_args.shell_manager, raw_args.ctrl_c.clone(), ls)?
|
||||
.run()
|
||||
args.process(registry, ls)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
fn ls(args: LsArgs, context: &RunnablePerItemContext) -> Result<OutputStream, ShellError> {
|
||||
context.shell_manager.ls(args, context)
|
||||
fn ls(args: LsArgs, context: RunnableContext) -> Result<OutputStream, ShellError> {
|
||||
context.shell_manager.ls(args, &context)
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::commands::command::RunnablePerItemContext;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{CallInfo, Signature, SyntaxShape, Value};
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -13,7 +13,7 @@ pub struct MkdirArgs {
|
||||
pub rest: Vec<Tagged<PathBuf>>,
|
||||
}
|
||||
|
||||
impl PerItemCommand for Mkdir {
|
||||
impl WholeStreamCommand for Mkdir {
|
||||
fn name(&self) -> &str {
|
||||
"mkdir"
|
||||
}
|
||||
@ -28,18 +28,14 @@ impl PerItemCommand for Mkdir {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
raw_args: &RawCommandArgs,
|
||||
_input: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
call_info
|
||||
.process(&raw_args.shell_manager, raw_args.ctrl_c.clone(), mkdir)?
|
||||
.run()
|
||||
args.process(registry, mkdir)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
fn mkdir(args: MkdirArgs, context: &RunnablePerItemContext) -> Result<OutputStream, ShellError> {
|
||||
fn mkdir(args: MkdirArgs, context: RunnableContext) -> Result<OutputStream, ShellError> {
|
||||
let shell_manager = context.shell_manager.clone();
|
||||
shell_manager.mkdir(args, context)
|
||||
shell_manager.mkdir(args, &context)
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::commands::command::RunnablePerItemContext;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{CallInfo, Signature, SyntaxShape, Value};
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -14,7 +14,7 @@ pub struct MoveArgs {
|
||||
pub dst: Tagged<PathBuf>,
|
||||
}
|
||||
|
||||
impl PerItemCommand for Move {
|
||||
impl WholeStreamCommand for Move {
|
||||
fn name(&self) -> &str {
|
||||
"mv"
|
||||
}
|
||||
@ -39,18 +39,14 @@ impl PerItemCommand for Move {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
raw_args: &RawCommandArgs,
|
||||
_input: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
call_info
|
||||
.process(&raw_args.shell_manager, raw_args.ctrl_c.clone(), mv)?
|
||||
.run()
|
||||
args.process(registry, mv)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
fn mv(args: MoveArgs, context: &RunnablePerItemContext) -> Result<OutputStream, ShellError> {
|
||||
fn mv(args: MoveArgs, context: RunnableContext) -> Result<OutputStream, ShellError> {
|
||||
let shell_manager = context.shell_manager.clone();
|
||||
shell_manager.mv(args, context)
|
||||
shell_manager.mv(args, &context)
|
||||
}
|
||||
|
@ -1,14 +1,19 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
CallInfo, CommandAction, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::{AnchorLocation, Span};
|
||||
use nu_protocol::{CommandAction, ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_source::{AnchorLocation, Span, Tagged};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub struct Open;
|
||||
|
||||
impl PerItemCommand for Open {
|
||||
#[derive(Deserialize)]
|
||||
pub struct OpenArgs {
|
||||
path: Tagged<PathBuf>,
|
||||
raw: Tagged<bool>,
|
||||
}
|
||||
|
||||
impl WholeStreamCommand for Open {
|
||||
fn name(&self) -> &str {
|
||||
"open"
|
||||
}
|
||||
@ -33,36 +38,23 @@ impl PerItemCommand for Open {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
raw_args: &RawCommandArgs,
|
||||
_input: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
run(call_info, raw_args)
|
||||
args.process(registry, open)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
fn run(call_info: &CallInfo, raw_args: &RawCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let shell_manager = &raw_args.shell_manager;
|
||||
fn open(
|
||||
OpenArgs { path, raw }: OpenArgs,
|
||||
RunnableContext { shell_manager, .. }: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let cwd = PathBuf::from(shell_manager.path());
|
||||
let full_path = cwd;
|
||||
|
||||
let path = call_info.args.nth(0).ok_or_else(|| {
|
||||
ShellError::labeled_error(
|
||||
"No file or directory specified",
|
||||
"for command",
|
||||
&call_info.name_tag,
|
||||
)
|
||||
})?;
|
||||
|
||||
let path_buf = path.as_path()?;
|
||||
let path_str = path_buf.display().to_string();
|
||||
let path_span = path.tag.span;
|
||||
let has_raw = call_info.args.has("raw");
|
||||
|
||||
let stream = async_stream! {
|
||||
|
||||
let result = fetch(&full_path, &path_str, path_span).await;
|
||||
let result = fetch(&full_path, &path.item, path.tag.span).await;
|
||||
|
||||
if let Err(e) = result {
|
||||
yield Err(e);
|
||||
@ -70,12 +62,12 @@ fn run(call_info: &CallInfo, raw_args: &RawCommandArgs) -> Result<OutputStream,
|
||||
}
|
||||
let (file_extension, contents, contents_tag) = result?;
|
||||
|
||||
let file_extension = if has_raw {
|
||||
let file_extension = if raw.item {
|
||||
None
|
||||
} else {
|
||||
// If the extension could not be determined via mimetype, try to use the path
|
||||
// extension. Some file types do not declare their mimetypes (such as bson files).
|
||||
file_extension.or(path_str.split('.').last().map(String::from))
|
||||
file_extension.or(path.extension().map(|x| x.to_string_lossy().to_string()))
|
||||
};
|
||||
|
||||
let tagged_contents = contents.into_value(&contents_tag);
|
||||
@ -92,7 +84,7 @@ fn run(call_info: &CallInfo, raw_args: &RawCommandArgs) -> Result<OutputStream,
|
||||
|
||||
pub async fn fetch(
|
||||
cwd: &PathBuf,
|
||||
location: &str,
|
||||
location: &PathBuf,
|
||||
span: Span,
|
||||
) -> Result<(Option<String>, UntaggedValue, Tag), ShellError> {
|
||||
let mut cwd = cwd.clone();
|
||||
|
@ -1,11 +1,9 @@
|
||||
use crate::commands::PerItemCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
CallInfo, ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value,
|
||||
};
|
||||
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue};
|
||||
use nu_source::Tagged;
|
||||
use regex::Regex;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -84,7 +82,12 @@ fn build_regex(commands: &[ParseCommand]) -> String {
|
||||
}
|
||||
pub struct Parse;
|
||||
|
||||
impl PerItemCommand for Parse {
|
||||
#[derive(Deserialize)]
|
||||
pub struct ParseArgs {
|
||||
pattern: Tagged<String>,
|
||||
}
|
||||
|
||||
impl WholeStreamCommand for Parse {
|
||||
fn name(&self) -> &str {
|
||||
"parse"
|
||||
}
|
||||
@ -92,7 +95,7 @@ impl PerItemCommand for Parse {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("parse").required(
|
||||
"pattern",
|
||||
SyntaxShape::Any,
|
||||
SyntaxShape::String,
|
||||
"the pattern to match. Eg) \"{foo}: {bar}\"",
|
||||
)
|
||||
}
|
||||
@ -103,41 +106,55 @@ impl PerItemCommand for Parse {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
_raw_args: &RawCommandArgs,
|
||||
value: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
//let value_tag = value.tag();
|
||||
let pattern = call_info.args.expect_nth(0)?.as_string()?;
|
||||
|
||||
let parse_pattern = parse(&pattern);
|
||||
let parse_regex = build_regex(&parse_pattern);
|
||||
|
||||
let column_names = column_names(&parse_pattern);
|
||||
let regex = Regex::new(&parse_regex).map_err(|_| {
|
||||
ShellError::labeled_error("Could not parse regex", "could not parse regex", &value.tag)
|
||||
})?;
|
||||
|
||||
let output = if let Ok(s) = value.as_string() {
|
||||
let mut results = vec![];
|
||||
for cap in regex.captures_iter(&s) {
|
||||
let mut dict = TaggedDictBuilder::new(value.tag());
|
||||
|
||||
for (idx, column_name) in column_names.iter().enumerate() {
|
||||
dict.insert_untagged(
|
||||
column_name,
|
||||
UntaggedValue::string(&cap[idx + 1].to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
results.push(ReturnSuccess::value(dict.into_value()));
|
||||
}
|
||||
|
||||
VecDeque::from(results)
|
||||
} else {
|
||||
VecDeque::new()
|
||||
};
|
||||
Ok(output.into())
|
||||
args.process(registry, parse_command)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_command(
|
||||
ParseArgs { pattern }: ParseArgs,
|
||||
RunnableContext { name, input, .. }: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let parse_pattern = parse(&pattern.item);
|
||||
let parse_regex = build_regex(&parse_pattern);
|
||||
let column_names = column_names(&parse_pattern);
|
||||
let name = name.span;
|
||||
let regex = Regex::new(&parse_regex).map_err(|_| {
|
||||
ShellError::labeled_error(
|
||||
"Could not parse regex",
|
||||
"could not parse regex",
|
||||
&pattern.tag,
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(input
|
||||
.map(move |value| {
|
||||
if let Ok(s) = value.as_string() {
|
||||
let mut output = vec![];
|
||||
for cap in regex.captures_iter(&s) {
|
||||
let mut dict = TaggedDictBuilder::new(value.tag());
|
||||
for (idx, column_name) in column_names.iter().enumerate() {
|
||||
dict.insert_untagged(
|
||||
column_name,
|
||||
UntaggedValue::string(cap[idx + 1].to_string()),
|
||||
);
|
||||
}
|
||||
output.push(Ok(ReturnSuccess::Value(dict.into_value())));
|
||||
}
|
||||
output
|
||||
} else {
|
||||
vec![Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected string input",
|
||||
"expected string input",
|
||||
name,
|
||||
"value originated here",
|
||||
value.tag,
|
||||
))]
|
||||
}
|
||||
})
|
||||
.map(futures::stream::iter)
|
||||
.flatten()
|
||||
.to_output_stream())
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::commands::command::RunnablePerItemContext;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{CallInfo, Signature, SyntaxShape, Value};
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -16,7 +16,7 @@ pub struct RemoveArgs {
|
||||
pub trash: Tagged<bool>,
|
||||
}
|
||||
|
||||
impl PerItemCommand for Remove {
|
||||
impl WholeStreamCommand for Remove {
|
||||
fn name(&self) -> &str {
|
||||
"rm"
|
||||
}
|
||||
@ -38,18 +38,14 @@ impl PerItemCommand for Remove {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
raw_args: &RawCommandArgs,
|
||||
_input: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
call_info
|
||||
.process(&raw_args.shell_manager, raw_args.ctrl_c.clone(), rm)?
|
||||
.run()
|
||||
args.process(registry, rm)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
fn rm(args: RemoveArgs, context: &RunnablePerItemContext) -> Result<OutputStream, ShellError> {
|
||||
fn rm(args: RemoveArgs, context: RunnableContext) -> Result<OutputStream, ShellError> {
|
||||
let shell_manager = context.shell_manager.clone();
|
||||
shell_manager.rm(args, context)
|
||||
shell_manager.rm(args, &context)
|
||||
}
|
||||
|
@ -1,18 +1,19 @@
|
||||
use crate::commands::classified::block::run_block;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
|
||||
use derive_new::new;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{hir::Block, CallInfo, ReturnSuccess, Scope, Signature, SyntaxShape, Value};
|
||||
use nu_protocol::{hir::Block, ReturnSuccess, Scope, Signature, SyntaxShape};
|
||||
|
||||
#[derive(new)]
|
||||
#[derive(new, Clone)]
|
||||
pub struct AliasCommand {
|
||||
name: String,
|
||||
args: Vec<String>,
|
||||
block: Block,
|
||||
}
|
||||
|
||||
impl PerItemCommand for AliasCommand {
|
||||
impl WholeStreamCommand for AliasCommand {
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
@ -33,73 +34,76 @@ impl PerItemCommand for AliasCommand {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
raw_args: &RawCommandArgs,
|
||||
input: Value,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let tag = call_info.name_tag.clone();
|
||||
let call_info = call_info.clone();
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let call_info = args.call_info.clone();
|
||||
let registry = registry.clone();
|
||||
let raw_args = raw_args.clone();
|
||||
let block = self.block.clone();
|
||||
|
||||
let mut scope = Scope::it_value(input.clone());
|
||||
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 alias_command = self.clone();
|
||||
let mut context = Context::from_args(&args, ®istry);
|
||||
let mut input = args.input;
|
||||
|
||||
let stream = async_stream! {
|
||||
let mut context = Context::from_raw(&raw_args, ®istry);
|
||||
|
||||
let input_clone = Ok(input.clone());
|
||||
let input_stream = futures::stream::once(async { input_clone }).boxed().to_input_stream();
|
||||
|
||||
let result = run_block(
|
||||
&block,
|
||||
&mut context,
|
||||
input_stream,
|
||||
&scope
|
||||
).await;
|
||||
|
||||
match result {
|
||||
Ok(stream) if stream.is_empty() => {
|
||||
yield Err(ShellError::labeled_error(
|
||||
"Expected a block",
|
||||
"alias needs a block",
|
||||
tag,
|
||||
));
|
||||
}
|
||||
Ok(mut stream) => {
|
||||
// We collect first to ensure errors are put into the context
|
||||
while let Some(result) = stream.next().await {
|
||||
yield Ok(ReturnSuccess::Value(result));
|
||||
while let Some(input) = input.next().await {
|
||||
let call_info = call_info.clone();
|
||||
let tag = tag.clone();
|
||||
let evaluated = call_info.evaluate_with_new_it(®istry, &input)?;
|
||||
let mut scope = Scope::it_value(input.clone());
|
||||
if let Some(positional) = &evaluated.args.positional {
|
||||
for (pos, arg) in positional.iter().enumerate() {
|
||||
scope = scope.set_var(alias_command.args[pos].to_string(), arg.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let errors = context.get_errors();
|
||||
if let Some(x) = errors.first() {
|
||||
//yield Err(error.clone());
|
||||
let input_clone = Ok(input.clone());
|
||||
let input_stream = futures::stream::once(async { input_clone }).boxed().to_input_stream();
|
||||
|
||||
let result = run_block(
|
||||
&block,
|
||||
&mut context,
|
||||
input_stream,
|
||||
&scope
|
||||
).await;
|
||||
|
||||
match result {
|
||||
Ok(stream) if stream.is_empty() => {
|
||||
yield Err(ShellError::labeled_error(
|
||||
"Expected a block",
|
||||
"alias needs a block",
|
||||
tag,
|
||||
));
|
||||
}
|
||||
Ok(mut stream) => {
|
||||
// We collect first to ensure errors are put into the context
|
||||
while let Some(result) = stream.next().await {
|
||||
yield Ok(ReturnSuccess::Value(result));
|
||||
}
|
||||
|
||||
let errors = context.get_errors();
|
||||
if let Some(x) = errors.first() {
|
||||
//yield Err(error.clone());
|
||||
yield Err(ShellError::labeled_error_with_secondary(
|
||||
"Alias failed to run",
|
||||
"alias failed to run",
|
||||
tag.clone(),
|
||||
x.to_string(),
|
||||
tag
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
//yield Err(e);
|
||||
yield Err(ShellError::labeled_error_with_secondary(
|
||||
"Alias failed to run",
|
||||
"alias failed to run",
|
||||
tag.clone(),
|
||||
x.to_string(),
|
||||
e.to_string(),
|
||||
tag
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
//yield Err(e);
|
||||
yield Err(ShellError::labeled_error_with_secondary(
|
||||
"Alias failed to run",
|
||||
"alias failed to run",
|
||||
tag.clone(),
|
||||
e.to_string(),
|
||||
tag
|
||||
));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{CallInfo, Signature, SyntaxShape, Value};
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
use std::fs::OpenOptions;
|
||||
use std::path::PathBuf;
|
||||
@ -12,7 +13,7 @@ pub struct TouchArgs {
|
||||
pub target: Tagged<PathBuf>,
|
||||
}
|
||||
|
||||
impl PerItemCommand for Touch {
|
||||
impl WholeStreamCommand for Touch {
|
||||
fn name(&self) -> &str {
|
||||
"touch"
|
||||
}
|
||||
@ -28,27 +29,19 @@ impl PerItemCommand for Touch {
|
||||
}
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
raw_args: &RawCommandArgs,
|
||||
_input: Value,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
call_info
|
||||
.process(&raw_args.shell_manager, raw_args.ctrl_c.clone(), touch)?
|
||||
.run()
|
||||
args.process(registry, touch)?.run()
|
||||
}
|
||||
}
|
||||
fn touch(args: TouchArgs, _context: &RunnablePerItemContext) -> Result<OutputStream, ShellError> {
|
||||
match OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(&args.target)
|
||||
{
|
||||
fn touch(TouchArgs { target }: TouchArgs, _: RunnableContext) -> Result<OutputStream, ShellError> {
|
||||
match OpenOptions::new().write(true).create(true).open(&target) {
|
||||
Ok(_) => Ok(OutputStream::empty()),
|
||||
Err(err) => Err(ShellError::labeled_error(
|
||||
"File Error",
|
||||
err.to_string(),
|
||||
&args.target.tag,
|
||||
&target.tag,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,20 @@
|
||||
use crate::commands::PerItemCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::evaluate::evaluate_baseline_expr;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
hir::ClassifiedCommand, CallInfo, ReturnSuccess, Scope, Signature, SyntaxShape, UntaggedValue,
|
||||
Value,
|
||||
hir::Block, hir::ClassifiedCommand, ReturnSuccess, Scope, Signature, SyntaxShape,
|
||||
};
|
||||
|
||||
pub struct Where;
|
||||
|
||||
impl PerItemCommand for Where {
|
||||
#[derive(Deserialize)]
|
||||
pub struct WhereArgs {
|
||||
block: Block,
|
||||
}
|
||||
|
||||
impl WholeStreamCommand for Where {
|
||||
fn name(&self) -> &str {
|
||||
"where"
|
||||
}
|
||||
@ -29,68 +33,68 @@ impl PerItemCommand for Where {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
call_info: &CallInfo,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
_raw_args: &RawCommandArgs,
|
||||
input: Value,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let block = call_info.args.expect_nth(0)?.clone();
|
||||
|
||||
let condition = match block {
|
||||
Value {
|
||||
value: UntaggedValue::Block(block),
|
||||
args.process(registry, where_command)?.run()
|
||||
}
|
||||
}
|
||||
fn where_command(
|
||||
WhereArgs { block }: WhereArgs,
|
||||
RunnableContext {
|
||||
name: tag,
|
||||
registry,
|
||||
input,
|
||||
..
|
||||
}: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let condition = {
|
||||
if block.block.len() != 1 {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Expected a condition",
|
||||
"expected a condition",
|
||||
tag,
|
||||
} => {
|
||||
if block.block.len() != 1 {
|
||||
));
|
||||
}
|
||||
match block.block[0].list.get(0) {
|
||||
Some(item) => match item {
|
||||
ClassifiedCommand::Expr(expr) => expr.clone(),
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Expected a condition",
|
||||
"expected a condition",
|
||||
tag,
|
||||
));
|
||||
))
|
||||
}
|
||||
match block.block[0].list.get(0) {
|
||||
Some(item) => match item {
|
||||
ClassifiedCommand::Expr(expr) => expr.clone(),
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Expected a condition",
|
||||
"expected a condition",
|
||||
tag,
|
||||
))
|
||||
}
|
||||
},
|
||||
None => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Expected a condition",
|
||||
"expected a condition",
|
||||
tag,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Value { tag, .. } => {
|
||||
},
|
||||
None => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Expected a condition",
|
||||
"expected a condition",
|
||||
tag,
|
||||
));
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
//FIXME: should we use the scope that's brought in as well?
|
||||
let condition = evaluate_baseline_expr(&condition, registry, &Scope::new(input.clone()))?;
|
||||
let mut input = input;
|
||||
|
||||
let stream = match condition.as_bool() {
|
||||
Ok(b) => {
|
||||
if b {
|
||||
VecDeque::from(vec![Ok(ReturnSuccess::Value(input))])
|
||||
} else {
|
||||
VecDeque::new()
|
||||
let stream = async_stream! {
|
||||
while let Some(input) = input.next().await {
|
||||
|
||||
//FIXME: should we use the scope that's brought in as well?
|
||||
let condition = evaluate_baseline_expr(&condition, ®istry, &Scope::new(input.clone()))?;
|
||||
|
||||
match condition.as_bool() {
|
||||
Ok(b) => {
|
||||
if b {
|
||||
yield Ok(ReturnSuccess::Value(input));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
Err(e) => yield Err(e),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
Ok(stream.into())
|
||||
}
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
|
@ -112,6 +112,30 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_args(args: &CommandArgs, registry: &CommandRegistry) -> Context {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
Context {
|
||||
registry: registry.clone(),
|
||||
host: args.host.clone(),
|
||||
current_errors: Arc::new(Mutex::new(vec![])),
|
||||
ctrl_c: args.ctrl_c.clone(),
|
||||
shell_manager: args.shell_manager.clone(),
|
||||
windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())),
|
||||
}
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
Context {
|
||||
registry: registry.clone(),
|
||||
host: args.host.clone(),
|
||||
current_errors: Arc::new(Mutex::new(vec![])),
|
||||
ctrl_c: args.ctrl_c.clone(),
|
||||
shell_manager: args.shell_manager.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn basic() -> Result<Context, Box<dyn Error>> {
|
||||
let registry = CommandRegistry::new();
|
||||
|
||||
|
@ -356,7 +356,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut ConfigDeserializer<'de> {
|
||||
return visit::<Value, _>(value.val, name, fields, visitor);
|
||||
}
|
||||
|
||||
if name == "Evaluate" {
|
||||
if name == "Block" {
|
||||
let block = match value.val {
|
||||
Value {
|
||||
value: UntaggedValue::Block(block),
|
||||
|
@ -71,10 +71,7 @@ macro_rules! trace_out_stream {
|
||||
pub(crate) use nu_protocol::{errln, out, outln};
|
||||
use nu_source::HasFallibleSpan;
|
||||
|
||||
pub(crate) use crate::commands::command::{
|
||||
CallInfoExt, CommandArgs, PerItemCommand, RawCommandArgs, RunnableContext,
|
||||
RunnablePerItemContext,
|
||||
};
|
||||
pub(crate) use crate::commands::command::{CommandArgs, RawCommandArgs, RunnableContext};
|
||||
pub(crate) use crate::context::CommandRegistry;
|
||||
pub(crate) use crate::context::Context;
|
||||
pub(crate) use crate::data::config;
|
||||
|
@ -102,7 +102,7 @@ impl Shell for FilesystemShell {
|
||||
short_names,
|
||||
with_symlink_targets,
|
||||
}: LsArgs,
|
||||
context: &RunnablePerItemContext,
|
||||
context: &RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let ctrl_c = context.ctrl_c.clone();
|
||||
let name_tag = context.name.clone();
|
||||
|
@ -140,11 +140,7 @@ impl Shell for HelpShell {
|
||||
self.path = path;
|
||||
}
|
||||
|
||||
fn ls(
|
||||
&self,
|
||||
_args: LsArgs,
|
||||
_context: &RunnablePerItemContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
fn ls(&self, _args: LsArgs, _context: &RunnableContext) -> Result<OutputStream, ShellError> {
|
||||
let output = self
|
||||
.commands()
|
||||
.into_iter()
|
||||
|
@ -14,11 +14,7 @@ pub trait Shell: std::fmt::Debug {
|
||||
fn name(&self) -> String;
|
||||
fn homedir(&self) -> Option<PathBuf>;
|
||||
|
||||
fn ls(
|
||||
&self,
|
||||
args: LsArgs,
|
||||
context: &RunnablePerItemContext,
|
||||
) -> Result<OutputStream, ShellError>;
|
||||
fn ls(&self, args: LsArgs, context: &RunnableContext) -> Result<OutputStream, ShellError>;
|
||||
fn cd(&self, args: CdArgs, name: Tag) -> Result<OutputStream, ShellError>;
|
||||
fn cp(&self, args: CopyArgs, name: Tag, path: &str) -> Result<OutputStream, ShellError>;
|
||||
fn mkdir(&self, args: MkdirArgs, name: Tag, path: &str) -> Result<OutputStream, ShellError>;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::commands::cd::CdArgs;
|
||||
use crate::commands::command::{EvaluatedWholeStreamCommandArgs, RunnablePerItemContext};
|
||||
use crate::commands::command::EvaluatedWholeStreamCommandArgs;
|
||||
use crate::commands::cp::CopyArgs;
|
||||
use crate::commands::ls::LsArgs;
|
||||
use crate::commands::mkdir::MkdirArgs;
|
||||
@ -132,11 +132,7 @@ impl ShellManager {
|
||||
env[self.current_shell()].homedir()
|
||||
}
|
||||
|
||||
pub fn ls(
|
||||
&self,
|
||||
args: LsArgs,
|
||||
context: &RunnablePerItemContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
pub fn ls(&self, args: LsArgs, context: &RunnableContext) -> Result<OutputStream, ShellError> {
|
||||
let env = self.shells.lock();
|
||||
|
||||
env[self.current_shell()].ls(args, context)
|
||||
@ -151,7 +147,7 @@ impl ShellManager {
|
||||
pub fn cp(
|
||||
&self,
|
||||
args: CopyArgs,
|
||||
context: &RunnablePerItemContext,
|
||||
context: &RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let shells = self.shells.lock();
|
||||
|
||||
@ -162,7 +158,7 @@ impl ShellManager {
|
||||
pub fn rm(
|
||||
&self,
|
||||
args: RemoveArgs,
|
||||
context: &RunnablePerItemContext,
|
||||
context: &RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let shells = self.shells.lock();
|
||||
|
||||
@ -173,7 +169,7 @@ impl ShellManager {
|
||||
pub fn mkdir(
|
||||
&self,
|
||||
args: MkdirArgs,
|
||||
context: &RunnablePerItemContext,
|
||||
context: &RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let shells = self.shells.lock();
|
||||
|
||||
@ -184,7 +180,7 @@ impl ShellManager {
|
||||
pub fn mv(
|
||||
&self,
|
||||
args: MoveArgs,
|
||||
context: &RunnablePerItemContext,
|
||||
context: &RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let shells = self.shells.lock();
|
||||
|
||||
|
@ -95,7 +95,7 @@ impl Shell for ValueShell {
|
||||
fn ls(
|
||||
&self,
|
||||
LsArgs { path, .. }: LsArgs,
|
||||
context: &RunnablePerItemContext,
|
||||
context: &RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let mut full_path = PathBuf::from(self.path());
|
||||
let name_tag = context.name.clone();
|
||||
|
@ -77,6 +77,36 @@ pub enum ClassifiedCommand {
|
||||
Error(ParseError),
|
||||
}
|
||||
|
||||
impl ClassifiedCommand {
|
||||
pub fn has_it_iteration(&self) -> bool {
|
||||
match self {
|
||||
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();
|
||||
|
||||
if let Some(positionals) = &command.args.positional {
|
||||
for arg in positionals {
|
||||
result = result || arg.has_shallow_it_usage();
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
ClassifiedCommand::Expr(expr) => expr.has_shallow_it_usage(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
||||
pub struct Commands {
|
||||
pub list: Vec<ClassifiedCommand>,
|
||||
@ -91,6 +121,37 @@ impl Commands {
|
||||
pub fn push(&mut self, command: ClassifiedCommand) {
|
||||
self.list.push(command);
|
||||
}
|
||||
|
||||
/// Convert all shallow uses of $it to `each { use of $it }`, converting each to a per-row command
|
||||
pub fn expand_it_usage(&mut self) {
|
||||
for idx in 0..self.list.len() {
|
||||
if self.list[idx].has_it_iteration() {
|
||||
self.list[idx] = ClassifiedCommand::Internal(InternalCommand {
|
||||
name: "each".to_string(),
|
||||
name_span: self.span,
|
||||
args: hir::Call {
|
||||
head: Box::new(SpannedExpression {
|
||||
expr: Expression::Synthetic(Synthetic::String("each".to_string())),
|
||||
span: self.span,
|
||||
}),
|
||||
named: None,
|
||||
span: self.span,
|
||||
positional: Some(vec![SpannedExpression {
|
||||
expr: Expression::Block(Block {
|
||||
block: vec![Commands {
|
||||
list: vec![self.list[idx].clone()],
|
||||
span: self.span,
|
||||
}],
|
||||
span: self.span,
|
||||
}),
|
||||
span: self.span,
|
||||
}]),
|
||||
is_last: false, // FIXME
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
||||
@ -110,6 +171,13 @@ impl Block {
|
||||
pub fn push(&mut self, commands: Commands) {
|
||||
self.block.push(commands);
|
||||
}
|
||||
|
||||
/// Convert all shallow uses of $it to `each { use of $it }`, converting each to a per-row command
|
||||
pub fn expand_it_usage(&mut self) {
|
||||
for commands in &mut self.block {
|
||||
commands.expand_it_usage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Hash, Deserialize, Serialize)]
|
||||
@ -201,14 +269,6 @@ pub enum Member {
|
||||
}
|
||||
|
||||
impl Member {
|
||||
// pub fn int(span: Span, source: &Text) -> Member {
|
||||
// if let Ok(big_int) = BigInt::from_str(span.slice(source)) {
|
||||
// Member::Int(big_int, span)
|
||||
// } else {
|
||||
// unreachable!("Internal error: could not convert text to BigInt as expected")
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn to_path_member(&self) -> PathMember {
|
||||
match self {
|
||||
//Member::String(outer, inner) => PathMember::string(inner.slice(source), *outer),
|
||||
@ -459,6 +519,17 @@ impl SpannedExpression {
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_shallow_it_usage(&self) -> bool {
|
||||
match &self.expr {
|
||||
Expression::Binary(binary) => {
|
||||
binary.left.has_shallow_it_usage() || binary.right.has_shallow_it_usage()
|
||||
}
|
||||
Expression::Variable(Variable::It(_)) => true,
|
||||
Expression::Path(path) => path.head.has_shallow_it_usage(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for SpannedExpression {
|
||||
|
Loading…
Reference in New Issue
Block a user