Tests pass!

This commit is contained in:
Yehuda Katz 2019-07-23 15:22:11 -07:00
parent 01223091ec
commit 5a8e041a48
61 changed files with 1111 additions and 402 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/target /target
**/*.rs.bk **/*.rs.bk
history.txt history.txt
tests/fixtures/nuplayground

View File

@ -9,13 +9,11 @@ use crate::commands::plugin::JsonRpc;
use crate::commands::plugin::{PluginCommand, PluginSink}; use crate::commands::plugin::{PluginCommand, PluginSink};
use crate::context::Context; use crate::context::Context;
crate use crate::errors::ShellError; crate use crate::errors::ShellError;
use crate::evaluate::Scope;
use crate::git::current_branch; use crate::git::current_branch;
use crate::object::Value; use crate::object::Value;
use crate::parser::parse::span::Spanned; use crate::parser::parse::span::Spanned;
use crate::parser::registry;
use crate::parser::registry::CommandConfig; use crate::parser::registry::CommandConfig;
use crate::parser::{Pipeline, PipelineElement, TokenNode}; use crate::parser::{hir, Pipeline, PipelineElement, TokenNode};
use crate::prelude::*; use crate::prelude::*;
use log::{debug, trace}; use log::{debug, trace};
@ -150,22 +148,22 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
use crate::commands::*; use crate::commands::*;
context.add_commands(vec![ context.add_commands(vec![
command("first", Box::new(first::first)),
command("pick", Box::new(pick::pick)),
command("from-ini", Box::new(from_ini::from_ini)),
command("from-csv", Box::new(from_csv::from_csv)),
command("from-json", Box::new(from_json::from_json)),
command("from-toml", Box::new(from_toml::from_toml)),
command("from-xml", Box::new(from_xml::from_xml)),
command("ps", Box::new(ps::ps)), command("ps", Box::new(ps::ps)),
command("ls", Box::new(ls::ls)), command("ls", Box::new(ls::ls)),
command("sysinfo", Box::new(sysinfo::sysinfo)), command("sysinfo", Box::new(sysinfo::sysinfo)),
command("cd", Box::new(cd::cd)), command("cd", Box::new(cd::cd)),
command("first", Box::new(first::first)),
command("size", Box::new(size::size)), command("size", Box::new(size::size)),
command("from-csv", Box::new(from_csv::from_csv)),
command("from-ini", Box::new(from_ini::from_ini)),
command("from-json", Box::new(from_json::from_json)),
command("from-toml", Box::new(from_toml::from_toml)),
command("from-xml", Box::new(from_xml::from_xml)),
command("from-yaml", Box::new(from_yaml::from_yaml)), command("from-yaml", Box::new(from_yaml::from_yaml)),
command("get", Box::new(get::get)), command("get", Box::new(get::get)),
command("exit", Box::new(exit::exit)), command("exit", Box::new(exit::exit)),
command("lines", Box::new(lines::lines)), command("lines", Box::new(lines::lines)),
command("pick", Box::new(pick::pick)),
command("split-column", Box::new(split_column::split_column)), command("split-column", Box::new(split_column::split_column)),
command("split-row", Box::new(split_row::split_row)), command("split-row", Box::new(split_row::split_row)),
command("lines", Box::new(lines::lines)), command("lines", Box::new(lines::lines)),
@ -348,10 +346,11 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
_ => pipeline.commands.push(ClassifiedCommand::Sink(SinkCommand { _ => pipeline.commands.push(ClassifiedCommand::Sink(SinkCommand {
command: sink("autoview", Box::new(autoview::autoview)), command: sink("autoview", Box::new(autoview::autoview)),
name_span: None, name_span: None,
args: registry::Args { args: hir::Call::new(
positional: None, Box::new(hir::Expression::synthetic_string("autoview")),
named: None, None,
}, None,
),
})), })),
} }
@ -386,7 +385,7 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
(Some(ClassifiedCommand::Sink(left)), None) => { (Some(ClassifiedCommand::Sink(left)), None) => {
let input_vec: Vec<Spanned<Value>> = input.objects.into_vec().await; let input_vec: Vec<Spanned<Value>> = input.objects.into_vec().await;
if let Err(err) = left.run(ctx, input_vec) { if let Err(err) = left.run(ctx, input_vec, &Text::from(line)) {
return LineResult::Error(line.clone(), err); return LineResult::Error(line.clone(), err);
} }
break; break;
@ -395,20 +394,20 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
( (
Some(ClassifiedCommand::Internal(left)), Some(ClassifiedCommand::Internal(left)),
Some(ClassifiedCommand::External(_)), Some(ClassifiedCommand::External(_)),
) => match left.run(ctx, input).await { ) => match left.run(ctx, input, Text::from(line)).await {
Ok(val) => ClassifiedInputStream::from_input_stream(val), Ok(val) => ClassifiedInputStream::from_input_stream(val),
Err(err) => return LineResult::Error(line.clone(), err), Err(err) => return LineResult::Error(line.clone(), err),
}, },
(Some(ClassifiedCommand::Internal(left)), Some(_)) => { (Some(ClassifiedCommand::Internal(left)), Some(_)) => {
match left.run(ctx, input).await { match left.run(ctx, input, Text::from(line)).await {
Ok(val) => ClassifiedInputStream::from_input_stream(val), Ok(val) => ClassifiedInputStream::from_input_stream(val),
Err(err) => return LineResult::Error(line.clone(), err), Err(err) => return LineResult::Error(line.clone(), err),
} }
} }
(Some(ClassifiedCommand::Internal(left)), None) => { (Some(ClassifiedCommand::Internal(left)), None) => {
match left.run(ctx, input).await { match left.run(ctx, input, Text::from(line)).await {
Ok(val) => ClassifiedInputStream::from_input_stream(val), Ok(val) => ClassifiedInputStream::from_input_stream(val),
Err(err) => return LineResult::Error(line.clone(), err), Err(err) => return LineResult::Error(line.clone(), err),
} }
@ -487,11 +486,10 @@ fn classify_command(
true => { true => {
let command = context.get_command(name); let command = context.get_command(name);
let config = command.config(); let config = command.config();
let scope = Scope::empty();
trace!(target: "nu::build_pipeline", "classifying {:?}", config); trace!(target: "nu::build_pipeline", "classifying {:?}", config);
let args = config.evaluate_args(call, context, &scope, source)?; let args: hir::Call = config.parse_args(call, context.registry(), source)?;
Ok(ClassifiedCommand::Internal(InternalCommand { Ok(ClassifiedCommand::Internal(InternalCommand {
command, command,
@ -504,9 +502,8 @@ fn classify_command(
true => { true => {
let command = context.get_sink(name); let command = context.get_sink(name);
let config = command.config(); let config = command.config();
let scope = Scope::empty();
let args = config.evaluate_args(call, context, &scope, source)?; let args = config.parse_args(call, context.registry(), source)?;
Ok(ClassifiedCommand::Sink(SinkCommand { Ok(ClassifiedCommand::Sink(SinkCommand {
command, command,

View File

@ -4,7 +4,6 @@ crate mod macros;
crate mod args; crate mod args;
crate mod autoview; crate mod autoview;
crate mod cd; crate mod cd;
crate mod rm;
crate mod classified; crate mod classified;
crate mod clip; crate mod clip;
crate mod command; crate mod command;
@ -25,6 +24,7 @@ crate mod pick;
crate mod plugin; crate mod plugin;
crate mod ps; crate mod ps;
crate mod reject; crate mod reject;
crate mod rm;
crate mod save; crate mod save;
crate mod size; crate mod size;
crate mod skip_while; crate mod skip_while;
@ -42,9 +42,9 @@ crate mod trim;
crate mod vtable; crate mod vtable;
crate mod where_; crate mod where_;
crate use command::command; crate use command::{command, filter, EvaluatedFilterCommandArgs, EvaluatedStaticCommandArgs};
crate use config::Config; crate use config::Config;
crate use rm::Remove;
crate use open::Open; crate use open::Open;
crate use rm::Remove;
crate use skip_while::SkipWhile; crate use skip_while::SkipWhile;
crate use where_::Where; crate use where_::Where;

View File

@ -2,8 +2,10 @@ use crate::errors::ShellError;
use crate::prelude::*; use crate::prelude::*;
use std::env; use std::env;
pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn cd(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let env = args.env.lock().unwrap(); let env = args.env.clone();
let env = env.lock().unwrap();
let args = args.evaluate_once(registry)?;
let cwd = env.path().to_path_buf(); let cwd = env.path().to_path_buf();
let path = match args.nth(0) { let path = match args.nth(0) {
@ -13,7 +15,7 @@ pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
return Err(ShellError::maybe_labeled_error( return Err(ShellError::maybe_labeled_error(
"Can not change to home directory", "Can not change to home directory",
"can not go to home", "can not go to home",
args.call_info.name_span, args.name_span(),
)) ))
} }
}, },

View File

@ -1,6 +1,7 @@
use crate::commands::command::Sink; use crate::commands::command::Sink;
use crate::context::SourceMap; use crate::context::SourceMap;
use crate::parser::{registry::Args, Span, Spanned, TokenNode}; use crate::evaluate::Scope;
use crate::parser::{hir, Span, Spanned, TokenNode};
use crate::prelude::*; use crate::prelude::*;
use bytes::{BufMut, BytesMut}; use bytes::{BufMut, BytesMut};
use futures::stream::StreamExt; use futures::stream::StreamExt;
@ -101,7 +102,7 @@ impl ClassifiedCommand {
crate struct SinkCommand { crate struct SinkCommand {
crate command: Arc<dyn Sink>, crate command: Arc<dyn Sink>,
crate name_span: Option<Span>, crate name_span: Option<Span>,
crate args: Args, crate args: hir::Call,
} }
impl SinkCommand { impl SinkCommand {
@ -109,8 +110,12 @@ impl SinkCommand {
self, self,
context: &mut Context, context: &mut Context,
input: Vec<Spanned<Value>>, input: Vec<Spanned<Value>>,
source: &Text,
) -> Result<(), ShellError> { ) -> Result<(), ShellError> {
context.run_sink(self.command, self.name_span.clone(), self.args, input) let args = self
.args
.evaluate(context.registry(), &Scope::empty(), source)?;
context.run_sink(self.command, self.name_span.clone(), args, input)
} }
} }
@ -118,7 +123,7 @@ crate struct InternalCommand {
crate command: Arc<dyn Command>, crate command: Arc<dyn Command>,
crate name_span: Option<Span>, crate name_span: Option<Span>,
crate source_map: SourceMap, crate source_map: SourceMap,
crate args: Args, crate args: hir::Call,
} }
impl InternalCommand { impl InternalCommand {
@ -126,11 +131,12 @@ impl InternalCommand {
self, self,
context: &mut Context, context: &mut Context,
input: ClassifiedInputStream, input: ClassifiedInputStream,
source: Text,
) -> Result<InputStream, ShellError> { ) -> Result<InputStream, ShellError> {
if log_enabled!(log::Level::Trace) { if log_enabled!(log::Level::Trace) {
trace!(target: "nu::run::internal", "->"); trace!(target: "nu::run::internal", "->");
trace!(target: "nu::run::internal", "{}", self.command.name()); trace!(target: "nu::run::internal", "{}", self.command.name());
trace!(target: "nu::run::internal", "{:?}", self.args.debug()); trace!(target: "nu::run::internal", "{}", self.args.debug(&source));
} }
let objects: InputStream = let objects: InputStream =
@ -141,6 +147,7 @@ impl InternalCommand {
self.name_span.clone(), self.name_span.clone(),
self.source_map, self.source_map,
self.args, self.args,
source,
objects, objects,
)?; )?;

View File

@ -16,7 +16,7 @@ pub fn clip(args: SinkCommandArgs) -> Result<(), ShellError> {
} }
let string = i.as_string().map_err(labelled( let string = i.as_string().map_err(labelled(
args.call_info.name_span, args.name_span(),
"Given non-string data", "Given non-string data",
"expected strings from pipeline", "expected strings from pipeline",
))?; ))?;

View File

@ -1,20 +1,62 @@
use crate::context::SourceMap; use crate::context::{SourceMap, SpanSource};
use crate::context::SpanSource;
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::evaluate::Scope;
use crate::object::Value; use crate::object::Value;
use crate::parser::{ use crate::parser::hir;
registry::{self, Args}, use crate::parser::{registry, Span, Spanned};
Span, Spanned,
};
use crate::prelude::*; use crate::prelude::*;
use getset::Getters; use getset::Getters;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt;
use std::ops::Deref;
use std::path::PathBuf; use std::path::PathBuf;
use uuid::Uuid; use uuid::Uuid;
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct UnevaluatedCallInfo {
pub args: hir::Call,
pub source: Text,
pub source_map: SourceMap,
pub name_span: Option<Span>,
}
impl ToDebug for UnevaluatedCallInfo {
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
self.args.fmt_debug(f, source)
}
}
impl UnevaluatedCallInfo {
fn name(&self) -> Result<&str, ShellError> {
let head = &self.args.head();
match head.item() {
hir::RawExpression::Literal(hir::Literal::Bare) => Ok(head.span.slice(&self.source)),
hir::RawExpression::Literal(hir::Literal::String(span)) => Ok(span.slice(&self.source)),
other => Err(ShellError::type_error(
"Command name",
head.type_name().spanned(head.span),
)),
}
}
fn evaluate(
self,
registry: &registry::CommandRegistry,
scope: &Scope,
) -> Result<CallInfo, ShellError> {
let args = self.args.evaluate(registry, scope, &self.source)?;
Ok(CallInfo {
args,
source_map: self.source_map,
name_span: self.name_span,
})
}
}
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug)]
pub struct CallInfo { pub struct CallInfo {
pub args: Args, pub args: registry::EvaluatedArgs,
pub source_map: SourceMap, pub source_map: SourceMap,
pub name_span: Option<Span>, pub name_span: Option<Span>,
} }
@ -22,13 +64,137 @@ pub struct CallInfo {
#[derive(Getters)] #[derive(Getters)]
#[get = "crate"] #[get = "crate"]
pub struct CommandArgs { pub struct CommandArgs {
pub host: Arc<Mutex<dyn Host + Send>>, pub host: Arc<Mutex<dyn Host>>,
pub env: Arc<Mutex<Environment>>, pub env: Arc<Mutex<Environment>>,
pub call_info: CallInfo, pub call_info: UnevaluatedCallInfo,
pub input: InputStream, pub input: InputStream,
} }
impl ToDebug for CommandArgs {
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
self.call_info.fmt_debug(f, source)
}
}
impl CommandArgs { impl CommandArgs {
pub fn evaluate_once(
self,
registry: &registry::CommandRegistry,
) -> Result<EvaluatedStaticCommandArgs, ShellError> {
let host = self.host.clone();
let env = self.env.clone();
let input = self.input;
let call_info = self.call_info.evaluate(registry, &Scope::empty())?;
Ok(EvaluatedStaticCommandArgs::new(host, env, call_info, input))
}
pub fn name_span(&self) -> Option<Span> {
self.call_info.name_span
}
}
pub enum EvaluatedInput {
Static(InputStream),
Filter(Spanned<Value>),
}
impl EvaluatedInput {
pub fn stream(self) -> InputStream {
match self {
EvaluatedInput::Static(stream) => stream,
EvaluatedInput::Filter(value) => vec![value].into(),
}
}
}
pub struct EvaluatedStaticCommandArgs {
pub args: EvaluatedCommandArgs,
pub input: InputStream,
}
impl Deref for EvaluatedStaticCommandArgs {
type Target = EvaluatedCommandArgs;
fn deref(&self) -> &Self::Target {
&self.args
}
}
impl EvaluatedStaticCommandArgs {
pub fn new(
host: Arc<Mutex<dyn Host>>,
env: Arc<Mutex<Environment>>,
call_info: CallInfo,
input: impl Into<InputStream>,
) -> EvaluatedStaticCommandArgs {
EvaluatedStaticCommandArgs {
args: EvaluatedCommandArgs {
host,
env,
call_info,
},
input: input.into(),
}
}
pub fn name_span(&self) -> Option<Span> {
self.args.call_info.name_span
}
pub fn parts(self) -> (InputStream, registry::EvaluatedArgs) {
let EvaluatedStaticCommandArgs { args, input } = self;
(input, args.call_info.args)
}
}
#[derive(Getters)]
#[get = "pub"]
pub struct EvaluatedFilterCommandArgs {
args: EvaluatedCommandArgs,
input: Spanned<Value>,
}
impl Deref for EvaluatedFilterCommandArgs {
type Target = EvaluatedCommandArgs;
fn deref(&self) -> &Self::Target {
&self.args
}
}
impl EvaluatedFilterCommandArgs {
pub fn new(
host: Arc<Mutex<dyn Host>>,
env: Arc<Mutex<Environment>>,
call_info: CallInfo,
input: Spanned<Value>,
) -> EvaluatedFilterCommandArgs {
EvaluatedFilterCommandArgs {
args: EvaluatedCommandArgs {
host,
env,
call_info,
},
input,
}
}
}
#[derive(Getters)]
#[get = "crate"]
pub struct EvaluatedCommandArgs {
pub host: Arc<Mutex<dyn Host>>,
pub env: Arc<Mutex<Environment>>,
pub call_info: CallInfo,
}
impl EvaluatedCommandArgs {
pub fn parts(self) -> () {}
pub fn call_args(&self) -> &registry::EvaluatedArgs {
&self.call_info.args
}
pub fn nth(&self, pos: usize) -> Option<&Spanned<Value>> { pub fn nth(&self, pos: usize) -> Option<&Spanned<Value>> {
self.call_info.args.nth(pos) self.call_info.args.nth(pos)
} }
@ -61,6 +227,12 @@ pub struct SinkCommandArgs {
pub input: Vec<Spanned<Value>>, pub input: Vec<Spanned<Value>>,
} }
impl SinkCommandArgs {
pub fn name_span(&self) -> Option<Span> {
self.call_info.name_span
}
}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub enum CommandAction { pub enum CommandAction {
ChangePath(PathBuf), ChangePath(PathBuf),
@ -100,8 +272,12 @@ impl ReturnSuccess {
} }
} }
pub trait Command { pub trait Command: Send + Sync {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError>; fn run(
&self,
args: CommandArgs,
registry: &registry::CommandRegistry,
) -> Result<OutputStream, ShellError>;
fn name(&self) -> &str; fn name(&self) -> &str;
fn config(&self) -> registry::CommandConfig { fn config(&self) -> registry::CommandConfig {
@ -132,14 +308,74 @@ pub trait Sink {
} }
} }
pub struct FnCommand { pub struct FnFilterCommand {
name: String, name: String,
func: Box<dyn Fn(CommandArgs) -> Result<OutputStream, ShellError>>, func: fn(EvaluatedFilterCommandArgs) -> Result<OutputStream, ShellError>,
} }
impl Command for FnCommand { impl Command for FnFilterCommand {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> { fn name(&self) -> &str {
(self.func)(args) &self.name
}
fn run(
&self,
args: CommandArgs,
registry: &registry::CommandRegistry,
) -> Result<OutputStream, ShellError> {
let CommandArgs {
host,
env,
call_info,
input,
} = args;
let host: Arc<Mutex<dyn Host>> = host.clone();
let env: Arc<Mutex<Environment>> = env.clone();
let registry: registry::CommandRegistry = registry.clone();
let func = self.func;
let result = input.values.map(move |it| {
let registry = registry.clone();
let call_info = match call_info
.clone()
.evaluate(&registry, &Scope::it_value(it.clone()))
{
Err(err) => return OutputStream::from(vec![Err(err)]).values,
Ok(args) => args,
};
let args = EvaluatedFilterCommandArgs::new(host.clone(), env.clone(), call_info, it);
match func(args) {
Err(err) => return OutputStream::from(vec![Err(err)]).values,
Ok(stream) => stream.values,
}
});
let result = result.flatten();
let result: BoxStream<ReturnValue> = result.boxed();
Ok(result.into())
}
}
pub struct FnRawCommand {
name: String,
func: Box<
dyn Fn(CommandArgs, &registry::CommandRegistry) -> Result<OutputStream, ShellError>
+ Send
+ Sync,
>,
}
impl Command for FnRawCommand {
fn run(
&self,
args: CommandArgs,
registry: &registry::CommandRegistry,
) -> Result<OutputStream, ShellError> {
(self.func)(args, registry)
} }
fn name(&self) -> &str { fn name(&self) -> &str {
@ -149,9 +385,23 @@ impl Command for FnCommand {
pub fn command( pub fn command(
name: &str, name: &str,
func: Box<dyn Fn(CommandArgs) -> Result<OutputStream, ShellError>>, func: Box<
dyn Fn(CommandArgs, &registry::CommandRegistry) -> Result<OutputStream, ShellError>
+ Send
+ Sync,
>,
) -> Arc<dyn Command> { ) -> Arc<dyn Command> {
Arc::new(FnCommand { Arc::new(FnRawCommand {
name: name.to_string(),
func,
})
}
pub fn filter(
name: &str,
func: fn(EvaluatedFilterCommandArgs) -> Result<OutputStream, ShellError>,
) -> Arc<dyn Command> {
Arc::new(FnFilterCommand {
name: name.to_string(), name: name.to_string(),
func, func,
}) })

View File

@ -1,10 +1,10 @@
use crate::prelude::*; use crate::prelude::*;
use crate::commands::EvaluatedStaticCommandArgs;
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::config; use crate::object::{config, Value};
use crate::object::Value;
use crate::parser::hir::SyntaxType; use crate::parser::hir::SyntaxType;
use crate::parser::registry::{CommandConfig, NamedType}; use crate::parser::registry::{self, CommandConfig, NamedType};
use indexmap::IndexMap; use indexmap::IndexMap;
use log::trace; use log::trace;
use std::iter::FromIterator; use std::iter::FromIterator;
@ -12,9 +12,15 @@ use std::iter::FromIterator;
pub struct Config; pub struct Config;
impl Command for Config { impl Command for Config {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> { fn run(
&self,
args: CommandArgs,
registry: &registry::CommandRegistry,
) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
config(args) config(args)
} }
fn name(&self) -> &str { fn name(&self) -> &str {
"config" "config"
} }
@ -38,11 +44,11 @@ impl Command for Config {
} }
} }
pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn config(args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
let mut result = crate::object::config::config(args.call_info.name_span)?; let mut result = crate::object::config::config(args.name_span())?;
trace!("{:#?}", args.call_info.args.positional); trace!("{:#?}", args.call_args().positional);
trace!("{:#?}", args.call_info.args.named); trace!("{:#?}", args.call_args().named);
if let Some(v) = args.get("get") { if let Some(v) = args.get("get") {
let key = v.as_string()?; let key = v.as_string()?;
@ -95,7 +101,7 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
} }
if args.len() == 0 { if args.len() == 0 {
return Ok(vec![Value::Object(result.into()).spanned(args.call_info.name_span)].into()); return Ok(vec![Value::Object(result.into()).spanned(args.name_span())].into());
} }
Err(ShellError::string(format!("Unimplemented"))) Err(ShellError::string(format!("Unimplemented")))

View File

@ -2,6 +2,6 @@ use crate::commands::command::CommandAction;
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::prelude::*; use crate::prelude::*;
pub fn exit(_args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn exit(_args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::Exit))].into()) Ok(vec![Ok(ReturnSuccess::Action(CommandAction::Exit))].into())
} }

View File

@ -1,14 +1,17 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::parser::CommandRegistry;
use crate::prelude::*; use crate::prelude::*;
// TODO: "Amount remaining" wrapper // TODO: "Amount remaining" wrapper
pub fn first(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn first(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
if args.len() == 0 { if args.len() == 0 {
return Err(ShellError::maybe_labeled_error( return Err(ShellError::maybe_labeled_error(
"First requires an amount", "First requires an amount",
"needs parameter", "needs parameter",
args.call_info.name_span, args.name_span(),
)); ));
} }
@ -25,7 +28,7 @@ pub fn first(args: CommandArgs) -> Result<OutputStream, ShellError> {
} }
}; };
let input = args.input; Ok(OutputStream::from_input(
args.input.values.take(amount as u64),
Ok(OutputStream::from_input(input.values.take(amount as u64))) ))
} }

View File

@ -6,7 +6,6 @@ pub fn from_csv_string_to_value(
s: String, s: String,
span: impl Into<Span>, span: impl Into<Span>,
) -> Result<Spanned<Value>, Box<dyn std::error::Error>> { ) -> Result<Spanned<Value>, Box<dyn std::error::Error>> {
let mut reader = ReaderBuilder::new() let mut reader = ReaderBuilder::new()
.has_headers(false) .has_headers(false)
.from_reader(s.as_bytes()); .from_reader(s.as_bytes());
@ -49,9 +48,10 @@ pub fn from_csv_string_to_value(
}) })
} }
pub fn from_csv(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn from_csv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let span = args.name_span();
let out = args.input; let out = args.input;
let span = args.call_info.name_span;
Ok(out Ok(out
.values .values

View File

@ -37,9 +37,11 @@ pub fn from_ini_string_to_value(
Ok(convert_ini_top_to_nu_value(&v, span)) Ok(convert_ini_top_to_nu_value(&v, span))
} }
pub fn from_ini(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn from_ini(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let span = args.name_span();
let out = args.input; let out = args.input;
let span = args.call_info.name_span;
Ok(out Ok(out
.values .values
.map(move |a| match a.item { .map(move |a| match a.item {

View File

@ -43,9 +43,14 @@ pub fn from_json_string_to_value(
Ok(convert_json_value_to_nu_value(&v, span)) Ok(convert_json_value_to_nu_value(&v, span))
} }
pub fn from_json(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn from_json(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let span = args.name_span();
let out = args.input; let out = args.input;
let span = args.call_info.name_span;
Ok(out Ok(out
.values .values
.map(move |a| match a.item { .map(move |a| match a.item {

View File

@ -41,9 +41,14 @@ pub fn from_toml_string_to_value(
Ok(convert_toml_value_to_nu_value(&v, span)) Ok(convert_toml_value_to_nu_value(&v, span))
} }
pub fn from_toml(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn from_toml(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let span = args.name_span();
let out = args.input; let out = args.input;
let span = args.call_info.name_span;
Ok(out Ok(out
.values .values
.map(move |a| match a.item { .map(move |a| match a.item {

View File

@ -59,9 +59,10 @@ pub fn from_xml_string_to_value(
Ok(from_document_to_value(&parsed, span)) Ok(from_document_to_value(&parsed, span))
} }
pub fn from_xml(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn from_xml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let span = args.name_span();
let out = args.input; let out = args.input;
let span = args.call_info.name_span;
Ok(out Ok(out
.values .values
.map(move |a| match a.item { .map(move |a| match a.item {

View File

@ -48,9 +48,13 @@ pub fn from_yaml_string_to_value(
Ok(convert_yaml_value_to_nu_value(&v, span)) Ok(convert_yaml_value_to_nu_value(&v, span))
} }
pub fn from_yaml(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn from_yaml(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let span = args.name_span();
let out = args.input; let out = args.input;
let span = args.call_info.name_span;
Ok(out Ok(out
.values .values
.map(move |a| match a.item { .map(move |a| match a.item {

View File

@ -21,36 +21,37 @@ fn get_member(path: &str, span: Span, obj: &Spanned<Value>) -> Result<Spanned<Va
Ok(current.clone()) Ok(current.clone())
} }
pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn get(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
if args.len() == 0 { let args = args.evaluate_once(registry)?;
let span = args.name_span();
let len = args.len();
if len == 0 {
return Err(ShellError::maybe_labeled_error( return Err(ShellError::maybe_labeled_error(
"Get requires a field or field path", "Get requires a field or field path",
"needs parameter", "needs parameter",
args.call_info.name_span, span,
)); ));
} }
let amount = args.expect_nth(0)?.as_i64(); let amount = args.expect_nth(0)?.as_i64();
let (input, args) = args.parts();
let positional = args.positional;
// If it's a number, get the row instead of the column // If it's a number, get the row instead of the column
if let Ok(amount) = amount { if let Ok(amount) = amount {
return Ok(args return Ok(input.values.skip(amount as u64).take(1).from_input_stream());
.input
.values
.skip(amount as u64)
.take(1)
.from_input_stream());
} }
let fields: Result<Vec<(String, Span)>, _> = args let fields: Result<Vec<(String, Span)>, _> = positional
.positional_iter() .iter()
.flatten()
.map(|a| (a.as_string().map(|x| (x, a.span)))) .map(|a| (a.as_string().map(|x| (x, a.span))))
.collect(); .collect();
let fields = fields?; let fields = fields?;
let stream = args let stream = input
.input
.values .values
.map(move |item| { .map(move |item| {
let mut result = VecDeque::new(); let mut result = VecDeque::new();

View File

@ -5,9 +5,12 @@ use log::trace;
// TODO: "Amount remaining" wrapper // TODO: "Amount remaining" wrapper
pub fn lines(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn lines(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let span = args.name_span();
let input = args.input; let input = args.input;
let span = args.call_info.name_span;
let input: InputStream = trace_stream!(target: "nu::trace_stream::lines", "input" = input);
let stream = input let stream = input
.values .values

View File

@ -4,8 +4,10 @@ use crate::parser::Spanned;
use crate::prelude::*; use crate::prelude::*;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn ls(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let env = args.env.lock().unwrap(); let env = args.env.clone();
let env = env.lock().unwrap();
let args = args.evaluate_once(registry)?;
let path = env.path.to_path_buf(); let path = env.path.to_path_buf();
let mut full_path = PathBuf::from(path); let mut full_path = PathBuf::from(path);
match &args.nth(0) { match &args.nth(0) {
@ -30,7 +32,7 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
return Err(ShellError::maybe_labeled_error( return Err(ShellError::maybe_labeled_error(
e.to_string(), e.to_string(),
e.to_string(), e.to_string(),
args.call_info.name_span, args.name_span(),
)); ));
} }
} }
@ -40,7 +42,7 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut shell_entries = VecDeque::new(); let mut shell_entries = VecDeque::new();
for entry in entries { for entry in entries {
let value = dir_entry_dict(&entry?, args.call_info.name_span)?; let value = dir_entry_dict(&entry?, args.name_span())?;
shell_entries.push_back(ReturnSuccess::value(value)) shell_entries.push_back(ReturnSuccess::value(value))
} }
Ok(shell_entries.to_output_stream()) Ok(shell_entries.to_output_stream())

View File

@ -36,13 +36,14 @@ macro_rules! command {
pub struct $export; pub struct $export;
impl Command for $export { impl Command for $export {
fn run(&self, $args: CommandArgs) -> Result<OutputStream, ShellError> { fn run(&self, $args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
fn command($args: CommandArgs, ( $($param_name),*, ): ( $($param_type),*, )) -> Result<OutputStream, ShellError> { fn command($args: EvaluatedCommandArgs, ( $($param_name),*, ): ( $($param_type),*, )) -> Result<OutputStream, ShellError> {
let output = $body; let output = $body;
Ok(output.boxed().to_output_stream()) Ok(output.boxed().to_output_stream())
} }
let $args = $args.evaluate_once(registry)?;
let tuple = ( $($extract ,)* ); let tuple = ( $($extract ,)* );
command( $args, tuple ) command( $args, tuple )
} }

View File

@ -1,68 +1,151 @@
use crate::context::SpanSource; use crate::context::SpanSource;
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::{Primitive, Switch, Value}; use crate::object::{Primitive, Switch, Value};
use crate::parser::hir::SyntaxType;
use crate::parser::parse::span::Span; use crate::parser::parse::span::Span;
use crate::parser::registry::{self, CommandConfig, NamedType, PositionalType};
use crate::prelude::*; use crate::prelude::*;
use indexmap::IndexMap;
use mime::Mime; use mime::Mime;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use uuid::Uuid; use uuid::Uuid;
command! { pub struct Open;
Open as open(args, path: Spanned<PathBuf>, --raw: Switch,) {
let span = args.call_info.name_span;
let cwd = args impl Command for Open {
.env fn run(
.lock() &self,
.unwrap() args: CommandArgs,
.path() registry: &registry::CommandRegistry,
.to_path_buf(); ) -> Result<OutputStream, ShellError> {
let env = args.env.clone();
let args = args.evaluate_once(registry)?;
let path = <Spanned<PathBuf>>::extract(args.expect_nth(0)?)?;
let raw = args.has("raw");
let span = args.name_span();
let cwd = env.lock().unwrap().path().to_path_buf();
let full_path = PathBuf::from(cwd); let full_path = PathBuf::from(cwd);
let path_str = path.to_str().ok_or(ShellError::type_error("Path", "invalid path".spanned(path.span)))?; let path_str = path.to_str().ok_or(ShellError::type_error(
"Path",
"invalid path".spanned(path.span),
))?;
let (file_extension, contents, contents_span, span_source) = fetch(&full_path, path_str, path.span)?; let (file_extension, contents, contents_span, span_source) =
fetch(&full_path, path_str, path.span)?;
let file_extension = if raw.is_present() { let file_extension = if raw { None } else { file_extension };
None
} else {
file_extension
};
let mut stream = VecDeque::new(); let mut stream = VecDeque::new();
if let Some(uuid) = contents_span.source { if let Some(uuid) = contents_span.source {
// If we have loaded something, track its source // If we have loaded something, track its source
stream.push_back(ReturnSuccess::action(CommandAction::AddSpanSource(uuid, span_source))) stream.push_back(ReturnSuccess::action(CommandAction::AddSpanSource(
uuid,
span_source,
)))
} }
match contents { match contents {
Value::Primitive(Primitive::String(string)) => { Value::Primitive(Primitive::String(string)) => {
let value = parse_as_value( let value = parse_as_value(file_extension, string, contents_span, span)?;
file_extension,
string,
contents_span,
span,
)?;
match value { match value {
Spanned { item: Value::List(list), .. } => { Spanned {
item: Value::List(list),
..
} => {
for elem in list { for elem in list {
stream.push_back(ReturnSuccess::value(elem)); stream.push_back(ReturnSuccess::value(elem));
} }
} }
x => stream.push_back(ReturnSuccess::value(x)) x => stream.push_back(ReturnSuccess::value(x)),
}
} }
},
other => stream.push_back(ReturnSuccess::value(other.spanned(contents_span))), other => stream.push_back(ReturnSuccess::value(other.spanned(contents_span))),
}; };
stream Ok(stream.boxed().to_output_stream())
}
fn name(&self) -> &str {
"open"
}
fn config(&self) -> CommandConfig {
let mut named = IndexMap::default();
named.insert("raw".to_string(), NamedType::Switch);
CommandConfig {
name: self.name().to_string(),
positional: vec![PositionalType::mandatory("path", SyntaxType::Block)],
rest_positional: false,
named,
is_sink: true,
is_filter: false,
} }
} }
}
// command! {
// Open as open(args, path: Spanned<PathBuf>, --raw: Switch,) {
// let span = args.name_span();
// let env = args.env.clone();
// let path = env
// .lock()
// .unwrap()
// .path()
// .to_path_buf();
// let full_path = PathBuf::from(cwd);
// let path_str = path.to_str().ok_or(ShellError::type_error("Path", "invalid path".spanned(path.span)))?;
// let (file_extension, contents, contents_span, span_source) = fetch(&full_path, path_str, path.span)?;
// let file_extension = if raw.is_present() {
// None
// } else {
// file_extension
// };
// let mut stream = VecDeque::new();
// if let Some(uuid) = contents_span.source {
// // If we have loaded something, track its source
// stream.push_back(ReturnSuccess::action(CommandAction::AddSpanSource(uuid, span_source)))
// }
// match contents {
// Value::Primitive(Primitive::String(string)) => {
// let value = parse_as_value(
// file_extension,
// string,
// contents_span,
// span,
// )?;
// match value {
// Spanned { item: Value::List(list), .. } => {
// for elem in list {
// stream.push_back(ReturnSuccess::value(elem));
// }
// }
// x => stream.push_back(ReturnSuccess::value(x))
// }
// },
// other => stream.push_back(ReturnSuccess::value(other.spanned(contents_span))),
// };
// stream
// }
// }
pub fn fetch( pub fn fetch(
cwd: &PathBuf, cwd: &PathBuf,

View File

@ -1,19 +1,30 @@
use crate::context::CommandRegistry;
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::base::select_fields; use crate::object::base::select_fields;
use crate::prelude::*; use crate::prelude::*;
pub fn pick(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn pick(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
if args.len() == 0 { let args = args.evaluate_once(registry)?;
let len = args.len();
let span = args.name_span();
let (input, args) = args.parts();
if len == 0 {
return Err(ShellError::maybe_labeled_error( return Err(ShellError::maybe_labeled_error(
"Pick requires fields", "Pick requires fields",
"needs parameter", "needs parameter",
args.call_info.name_span, span,
)); ));
} }
let fields: Result<Vec<String>, _> = args.positional_iter().map(|a| a.as_string()).collect(); let fields: Result<Vec<String>, _> = args
.positional
.iter()
.flatten()
.map(|a| a.as_string())
.collect();
let fields = fields?; let fields = fields?;
let input = args.input;
let objects = input let objects = input
.values .values

View File

@ -41,8 +41,12 @@ pub struct PluginCommand {
} }
impl Command for PluginCommand { impl Command for PluginCommand {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> { fn run(
filter_plugin(self.path.clone(), args) &self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
filter_plugin(self.path.clone(), args, registry)
} }
fn name(&self) -> &str { fn name(&self) -> &str {
&self.name &self.name
@ -71,7 +75,13 @@ impl Sink for PluginSink {
} }
} }
pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn filter_plugin(
path: String,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let mut child = std::process::Command::new(path) let mut child = std::process::Command::new(path)
.stdin(std::process::Stdio::piped()) .stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped())
@ -84,7 +94,7 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
let mut reader = BufReader::new(stdout); let mut reader = BufReader::new(stdout);
let request = JsonRpc::new("begin_filter", args.call_info); let request = JsonRpc::new("begin_filter", args.args.call_info);
let request_raw = serde_json::to_string(&request).unwrap(); let request_raw = serde_json::to_string(&request).unwrap();
stdin.write(format!("{}\n", request_raw).as_bytes())?; stdin.write(format!("{}\n", request_raw).as_bytes())?;
let mut input = String::new(); let mut input = String::new();

View File

@ -3,14 +3,14 @@ use crate::object::process::process_dict;
use crate::prelude::*; use crate::prelude::*;
use sysinfo::{RefreshKind, SystemExt}; use sysinfo::{RefreshKind, SystemExt};
pub fn ps(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn ps(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let mut system = sysinfo::System::new_with_specifics(RefreshKind::new().with_processes()); let mut system = sysinfo::System::new_with_specifics(RefreshKind::new().with_processes());
system.refresh_processes(); system.refresh_processes();
let list = system.get_process_list(); let list = system.get_process_list();
let list = list let list = list
.into_iter() .into_iter()
.map(|(_, process)| process_dict(process, args.call_info.name_span)) .map(|(_, process)| process_dict(process, args.name_span()))
.collect::<VecDeque<_>>(); .collect::<VecDeque<_>>();
Ok(list.from_input_stream()) Ok(list.from_input_stream())

View File

@ -2,21 +2,31 @@ use crate::errors::ShellError;
use crate::object::base::reject_fields; use crate::object::base::reject_fields;
use crate::prelude::*; use crate::prelude::*;
pub fn reject(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn reject(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let name_span = args.call_info.name_span; let name_span = args.name_span();
let args = args.evaluate_once(registry)?;
let len = args.len();
let span = args.name_span();
let (input, args) = args.parts();
if args.len() == 0 { if len == 0 {
return Err(ShellError::maybe_labeled_error( return Err(ShellError::maybe_labeled_error(
"Reject requires fields", "Reject requires fields",
"needs parameter", "needs parameter",
args.call_info.name_span, span,
)); ));
} }
let fields: Result<Vec<String>, _> = args.positional_iter().map(|a| a.as_string()).collect(); let fields: Result<Vec<String>, _> = args
.positional
.iter()
.flatten()
.map(|a| a.as_string())
.collect();
let fields = fields?; let fields = fields?;
let stream = args.input.values.map(move |item| { let stream = input.values.map(move |item| {
reject_fields(&item, &fields, item.span) reject_fields(&item, &fields, item.span)
.into_spanned_value() .into_spanned_value()
.spanned(name_span) .spanned(name_span)

View File

@ -1,3 +1,4 @@
use crate::commands::EvaluatedStaticCommandArgs;
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::parser::hir::SyntaxType; use crate::parser::hir::SyntaxType;
use crate::parser::registry::{CommandConfig, NamedType, PositionalType}; use crate::parser::registry::{CommandConfig, NamedType, PositionalType};
@ -7,8 +8,13 @@ use indexmap::IndexMap;
pub struct Remove; pub struct Remove;
impl Command for Remove { impl Command for Remove {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> { fn run(
rm(args) &self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let env = args.env.clone();
rm(args.evaluate_once(registry)?, env)
} }
fn name(&self) -> &str { fn name(&self) -> &str {
@ -30,8 +36,11 @@ impl Command for Remove {
} }
} }
pub fn rm(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn rm(
let mut full_path = args.env.lock().unwrap().path().to_path_buf(); args: EvaluatedStaticCommandArgs,
env: Arc<Mutex<Environment>>,
) -> Result<OutputStream, ShellError> {
let mut full_path = env.lock().unwrap().path().to_path_buf();
match args match args
.nth(0) .nth(0)
@ -48,7 +57,7 @@ pub fn rm(args: CommandArgs) -> Result<OutputStream, ShellError> {
return Err(ShellError::labeled_error( return Err(ShellError::labeled_error(
"is a directory", "is a directory",
"", "",
args.call_info.name_span.unwrap(), args.name_span().unwrap(),
)); ));
} }
std::fs::remove_dir_all(&full_path).expect("can not remove directory"); std::fs::remove_dir_all(&full_path).expect("can not remove directory");

View File

@ -13,7 +13,7 @@ pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> {
return Err(ShellError::maybe_labeled_error( return Err(ShellError::maybe_labeled_error(
"Save requires a filepath", "Save requires a filepath",
"needs path", "needs path",
args.call_info.name_span, args.name_span(),
)); ));
} }

View File

@ -2,7 +2,7 @@ use crate::errors::ShellError;
use crate::object::{SpannedDictBuilder, Value}; use crate::object::{SpannedDictBuilder, Value};
use crate::prelude::*; use crate::prelude::*;
pub fn size(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn size(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let input = args.input; let input = args.input;
Ok(input Ok(input
.values .values

View File

@ -6,8 +6,12 @@ use crate::prelude::*;
pub struct SkipWhile; pub struct SkipWhile;
impl Command for SkipWhile { impl Command for SkipWhile {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> { fn run(
skip_while(args) &self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
skip_while(args, registry)
} }
fn name(&self) -> &str { fn name(&self) -> &str {
"skip-while" "skip-while"
@ -25,18 +29,24 @@ impl Command for SkipWhile {
} }
} }
pub fn skip_while(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn skip_while(
if args.len() == 0 { args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let block = args.expect_nth(0)?.as_block()?;
let span = args.name_span();
let len = args.len();
let input = args.input;
if len == 0 {
return Err(ShellError::maybe_labeled_error( return Err(ShellError::maybe_labeled_error(
"Where requires a condition", "Where requires a condition",
"needs condition", "needs condition",
args.call_info.name_span, span,
)); ));
} }
let block = args.nth(0).unwrap().as_block()?;
let input = args.input;
let objects = input.values.skip_while(move |item| { let objects = input.values.skip_while(move |item| {
let result = block.invoke(&item); let result = block.invoke(&item);

View File

@ -1,11 +1,20 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::prelude::*; use crate::prelude::*;
pub fn sort_by(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn sort_by(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let fields: Result<Vec<_>, _> = args.positional_iter().map(|a| a.as_string()).collect(); let args = args.evaluate_once(registry)?;
let (input, args) = args.parts();
let fields: Result<Vec<_>, _> = args
.positional
.iter()
.flatten()
.map(|a| a.as_string())
.collect();
let fields = fields?; let fields = fields?;
let output = args.input.values.collect::<Vec<_>>(); let output = input.values.collect::<Vec<_>>();
let output = output.map(move |mut vec| { let output = output.map(move |mut vec| {
vec.sort_by_key(|item| { vec.sort_by_key(|item| {

View File

@ -3,20 +3,24 @@ use crate::object::{Primitive, SpannedDictBuilder, Value};
use crate::prelude::*; use crate::prelude::*;
use log::trace; use log::trace;
pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn split_column(
let positional: Vec<_> = args.positional_iter().cloned().collect(); args: CommandArgs,
let span = args.call_info.name_span; registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let span = args.name_span();
let (input, args) = args.parts();
let positional: Vec<_> = args.positional.iter().flatten().cloned().collect();
if positional.len() == 0 { if positional.len() == 0 {
return Err(ShellError::maybe_labeled_error( return Err(ShellError::maybe_labeled_error(
"Split-column needs more information", "Split-column needs more information",
"needs parameter (eg split-column \",\")", "needs parameter (eg split-column \",\")",
args.call_info.name_span, span,
)); ));
} }
let input = args.input;
Ok(input Ok(input
.values .values
.map(move |v| match v.item { .map(move |v| match v.item {

View File

@ -4,20 +4,25 @@ use crate::parser::Spanned;
use crate::prelude::*; use crate::prelude::*;
use log::trace; use log::trace;
pub fn split_row(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn split_row(
let positional: Vec<Spanned<Value>> = args.positional_iter().cloned().collect(); args: CommandArgs,
let span = args.call_info.name_span; registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let span = args.name_span();
let len = args.len();
let (input, args) = args.parts();
if positional.len() == 0 { let positional: Vec<Spanned<Value>> = args.positional.iter().flatten().cloned().collect();
if len == 0 {
return Err(ShellError::maybe_labeled_error( return Err(ShellError::maybe_labeled_error(
"Split-row needs more information", "Split-row needs more information",
"needs parameter (eg split-row \"\\n\")", "needs parameter (eg split-row \"\\n\")",
args.call_info.name_span, span,
)); ));
} }
let input = args.input;
let stream = input let stream = input
.values .values
.map(move |v| match v.item { .map(move |v| match v.item {

View File

@ -6,8 +6,8 @@ use crate::prelude::*;
use sys_info::*; use sys_info::*;
use sysinfo::{ComponentExt, DiskExt, NetworkExt, RefreshKind, SystemExt}; use sysinfo::{ComponentExt, DiskExt, NetworkExt, RefreshKind, SystemExt};
pub fn sysinfo(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn sysinfo(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let name_span = args.call_info.name_span; let name_span = args.name_span();
let mut idx = SpannedDictBuilder::new(name_span); let mut idx = SpannedDictBuilder::new(name_span);
if let (Ok(name), Ok(version)) = (os_type(), os_release()) { if let (Ok(name), Ok(version)) = (os_type(), os_release()) {

View File

@ -1,7 +1,7 @@
use crate::object::Value; use crate::object::Value;
use crate::prelude::*; use crate::prelude::*;
pub fn to_array(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn to_array(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let out = args.input.values.collect(); let out = args.input.values.collect();
Ok(out Ok(out

View File

@ -1,10 +1,9 @@
use crate::object::{Primitive, Value}; use crate::object::{Primitive, Value};
use crate::prelude::*; use crate::prelude::*;
use log::debug;
use csv::WriterBuilder; use csv::WriterBuilder;
use log::debug;
pub fn value_to_csv_value(v: &Value) -> Value { pub fn value_to_csv_value(v: &Value) -> Value {
debug!("value_to_csv_value(Value::Object(v)) where v = {:?}", v); debug!("value_to_csv_value(Value::Object(v)) where v = {:?}", v);
match v { match v {
@ -13,7 +12,7 @@ pub fn value_to_csv_value(v: &Value) -> Value {
Value::Object(o) => Value::Object(o.clone()), Value::Object(o) => Value::Object(o.clone()),
Value::List(l) => Value::List(l.clone()), Value::List(l) => Value::List(l.clone()),
Value::Block(_) => Value::Primitive(Primitive::Nothing), Value::Block(_) => Value::Primitive(Primitive::Nothing),
_ => Value::Primitive(Primitive::Nothing) _ => Value::Primitive(Primitive::Nothing),
} }
} }
@ -21,7 +20,6 @@ pub fn to_string(v: &Value) -> Result<String, Box<dyn std::error::Error>> {
match v { match v {
Value::List(_l) => return Ok(String::from("[list list]")), Value::List(_l) => return Ok(String::from("[list list]")),
Value::Object(o) => { Value::Object(o) => {
debug!("to_csv:to_string(Value::Object(v)) where v = {:?}", v); debug!("to_csv:to_string(Value::Object(v)) where v = {:?}", v);
let mut wtr = WriterBuilder::new().from_writer(vec![]); let mut wtr = WriterBuilder::new().from_writer(vec![]);
@ -36,21 +34,21 @@ pub fn to_string(v: &Value) -> Result<String, Box<dyn std::error::Error>> {
wtr.write_record(fields).expect("can not write."); wtr.write_record(fields).expect("can not write.");
wtr.write_record(values).expect("can not write."); wtr.write_record(values).expect("can not write.");
return Ok(String::from_utf8(wtr.into_inner()?)?) return Ok(String::from_utf8(wtr.into_inner()?)?);
}, }
Value::Primitive(Primitive::String(s)) => return Ok(s.to_string()), Value::Primitive(Primitive::String(s)) => return Ok(s.to_string()),
_ => return Err("Bad input".into()) _ => return Err("Bad input".into()),
} }
} }
pub fn to_csv(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn to_csv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let name_span = args.name_span();
let out = args.input; let out = args.input;
let name_span = args.call_info.name_span;
Ok(out Ok(out
.values .values
.map( .map(move |a| match to_string(&value_to_csv_value(&a.item)) {
move |a| match to_string(&value_to_csv_value(&a.item)) {
Ok(x) => { Ok(x) => {
ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span)) ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span))
} }
@ -59,7 +57,6 @@ pub fn to_csv(args: CommandArgs) -> Result<OutputStream, ShellError> {
"can not convert piped data to CSV string", "can not convert piped data to CSV string",
name_span, name_span,
)), )),
}, })
)
.to_output_stream()) .to_output_stream())
} }

View File

@ -40,9 +40,11 @@ pub fn value_to_json_value(v: &Value) -> serde_json::Value {
} }
} }
pub fn to_json(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn to_json(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let name_span = args.name_span();
let out = args.input; let out = args.input;
let name_span = args.call_info.name_span;
Ok(out Ok(out
.values .values
.map( .map(

View File

@ -30,9 +30,10 @@ pub fn value_to_toml_value(v: &Value) -> toml::Value {
} }
} }
pub fn to_toml(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn to_toml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let name_span = args.name_span();
let out = args.input; let out = args.input;
let name_span = args.call_info.name_span;
Ok(out Ok(out
.values .values

View File

@ -38,9 +38,10 @@ pub fn value_to_yaml_value(v: &Value) -> serde_yaml::Value {
} }
} }
pub fn to_yaml(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn to_yaml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let name_span = args.name_span();
let out = args.input; let out = args.input;
let name_span = args.call_info.name_span;
Ok(out Ok(out
.values .values
.map( .map(

View File

@ -2,7 +2,7 @@ use crate::errors::ShellError;
use crate::object::Value; use crate::object::Value;
use crate::prelude::*; use crate::prelude::*;
pub fn trim(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn trim(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let input = args.input; let input = args.input;
Ok(input Ok(input

View File

@ -1,14 +1,31 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::Block; use crate::object::base as value;
use crate::object::{types, Value};
use crate::parser::hir::SyntaxType;
use crate::parser::registry::{self, CommandConfig, PositionalType};
use crate::prelude::*; use crate::prelude::*;
use futures::future::ready; use futures::future::ready;
use indexmap::IndexMap;
use log::trace; use log::trace;
command! { pub struct Where;
Where as where(args, condition: Block,) {
let input: InputStream = trace_stream!(target: "nu::trace_stream::where", "where input" = args.input);
input.values.filter_map(move |item| { impl Command for Where {
fn run(
&self,
args: CommandArgs,
registry: &registry::CommandRegistry,
) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let condition = value::Block::extract(args.expect_nth(0)?)?;
let input = args.input;
let input: InputStream =
trace_stream!(target: "nu::trace_stream::where", "where input" = input);
Ok(input
.values
.filter_map(move |item| {
let result = condition.invoke(&item); let result = condition.invoke(&item);
let return_value = match result { let return_value = match result {
@ -19,5 +36,41 @@ command! {
ready(return_value) ready(return_value)
}) })
.boxed()
.to_output_stream())
}
fn name(&self) -> &str {
"where"
}
fn config(&self) -> CommandConfig {
CommandConfig {
name: self.name().to_string(),
positional: vec![PositionalType::mandatory("condition", SyntaxType::Block)],
rest_positional: false,
named: IndexMap::default(),
is_sink: true,
is_filter: false,
} }
} }
}
// command! {
// Where as where(args, condition: Block,) {
// let input = args.input;
// let input: InputStream = trace_stream!(target: "nu::trace_stream::where", "where input" = input);
// input.values.filter_map(move |item| {
// let result = condition.invoke(&item);
// let return_value = match result {
// Err(err) => Some(Err(err)),
// Ok(v) if v.is_true() => Some(Ok(ReturnSuccess::Value(item.clone()))),
// _ => None,
// };
// ready(return_value)
// })
// }
// }

View File

@ -1,21 +1,24 @@
use crate::commands::command::{CallInfo, Sink, SinkCommandArgs}; use crate::commands::command::{CallInfo, Sink, SinkCommandArgs, UnevaluatedCallInfo};
use crate::parser::{ use crate::parser::{
registry::{Args, CommandConfig, CommandRegistry}, hir,
registry::{self, CommandConfig},
Span, Span,
}; };
use crate::prelude::*; use crate::prelude::*;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use derive_new::new;
use indexmap::IndexMap; use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error; use std::error::Error;
use std::sync::Arc; use std::sync::Arc;
use uuid::Uuid;
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum SpanSource { pub enum SpanSource {
Url(String), Url(String),
File(String), File(String),
Source(Text),
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
@ -35,9 +38,51 @@ impl SourceMap {
} }
} }
#[derive(Clone, new)]
pub struct CommandRegistry {
#[new(value = "Arc::new(Mutex::new(IndexMap::default()))")]
registry: Arc<Mutex<IndexMap<String, Arc<dyn Command>>>>,
}
impl CommandRegistry {
crate fn empty() -> CommandRegistry {
CommandRegistry {
registry: Arc::new(Mutex::new(IndexMap::default())),
}
}
fn get_config(&self, name: &str) -> Option<CommandConfig> {
let registry = self.registry.lock().unwrap();
registry.get(name).map(|c| c.config())
}
fn get_command(&self, name: &str) -> Option<Arc<dyn Command>> {
let registry = self.registry.lock().unwrap();
registry.get(name).map(|c| c.clone())
}
fn has(&self, name: &str) -> bool {
let registry = self.registry.lock().unwrap();
registry.contains_key(name)
}
fn insert(&mut self, name: impl Into<String>, command: Arc<dyn Command>) {
let mut registry = self.registry.lock().unwrap();
registry.insert(name.into(), command);
}
crate fn names(&self) -> Vec<String> {
let mut registry = self.registry.lock().unwrap();
registry.keys().cloned().collect()
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct Context { pub struct Context {
commands: IndexMap<String, Arc<dyn Command>>, registry: CommandRegistry,
sinks: IndexMap<String, Arc<dyn Sink>>, sinks: IndexMap<String, Arc<dyn Sink>>,
crate source_map: SourceMap, crate source_map: SourceMap,
crate host: Arc<Mutex<dyn Host + Send>>, crate host: Arc<Mutex<dyn Host + Send>>,
@ -45,9 +90,13 @@ pub struct Context {
} }
impl Context { impl Context {
crate fn registry(&self) -> &CommandRegistry {
&self.registry
}
crate fn basic() -> Result<Context, Box<dyn Error>> { crate fn basic() -> Result<Context, Box<dyn Error>> {
Ok(Context { Ok(Context {
commands: indexmap::IndexMap::new(), registry: CommandRegistry::new(),
sinks: indexmap::IndexMap::new(), sinks: indexmap::IndexMap::new(),
source_map: SourceMap::new(), source_map: SourceMap::new(),
host: Arc::new(Mutex::new(crate::env::host::BasicHost)), host: Arc::new(Mutex::new(crate::env::host::BasicHost)),
@ -57,7 +106,7 @@ impl Context {
pub fn add_commands(&mut self, commands: Vec<Arc<dyn Command>>) { pub fn add_commands(&mut self, commands: Vec<Arc<dyn Command>>) {
for command in commands { for command in commands {
self.commands.insert(command.name().to_string(), command); self.registry.insert(command.name().to_string(), command);
} }
} }
@ -83,7 +132,7 @@ impl Context {
&mut self, &mut self,
command: Arc<dyn Sink>, command: Arc<dyn Sink>,
name_span: Option<Span>, name_span: Option<Span>,
args: Args, args: registry::EvaluatedArgs,
input: Vec<Spanned<Value>>, input: Vec<Spanned<Value>>,
) -> Result<(), ShellError> { ) -> Result<(), ShellError> {
let command_args = SinkCommandArgs { let command_args = SinkCommandArgs {
@ -99,16 +148,16 @@ impl Context {
command.run(command_args) command.run(command_args)
} }
pub fn clone_commands(&self) -> indexmap::IndexMap<String, Arc<dyn Command>> { pub fn clone_commands(&self) -> CommandRegistry {
self.commands.clone() self.registry.clone()
} }
crate fn has_command(&self, name: &str) -> bool { crate fn has_command(&self, name: &str) -> bool {
self.commands.contains_key(name) self.registry.has(name)
} }
crate fn get_command(&self, name: &str) -> Arc<dyn Command> { crate fn get_command(&self, name: &str) -> Arc<dyn Command> {
self.commands.get(name).unwrap().clone() self.registry.get_command(name).unwrap()
} }
crate fn run_command( crate fn run_command(
@ -116,26 +165,43 @@ impl Context {
command: Arc<dyn Command>, command: Arc<dyn Command>,
name_span: Option<Span>, name_span: Option<Span>,
source_map: SourceMap, source_map: SourceMap,
args: Args, args: hir::Call,
source: Text,
input: InputStream, input: InputStream,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let command_args = CommandArgs { let command_args = self.command_args(args, input, source, source_map, name_span);
command.run(command_args, self.registry())
}
fn call_info(
&self,
args: hir::Call,
source: Text,
source_map: SourceMap,
name_span: Option<Span>,
) -> UnevaluatedCallInfo {
UnevaluatedCallInfo {
args,
source,
source_map,
name_span,
}
}
fn command_args(
&self,
args: hir::Call,
input: InputStream,
source: Text,
source_map: SourceMap,
name_span: Option<Span>,
) -> CommandArgs {
CommandArgs {
host: self.host.clone(), host: self.host.clone(),
env: self.env.clone(), env: self.env.clone(),
call_info: CallInfo { call_info: self.call_info(args, source, source_map, name_span),
name_span,
source_map,
args,
},
input, input,
};
command.run(command_args)
} }
} }
impl CommandRegistry for Context {
fn get(&self, name: &str) -> Option<CommandConfig> {
self.commands.get(name).map(|c| c.config())
}
} }

2
src/env/host.rs vendored
View File

@ -2,7 +2,7 @@ use crate::prelude::*;
use language_reporting::termcolor; use language_reporting::termcolor;
use std::fmt::Debug; use std::fmt::Debug;
pub trait Host: Debug { pub trait Host: Debug + Send {
fn out_terminal(&self) -> Box<term::StdoutTerminal>; fn out_terminal(&self) -> Box<term::StdoutTerminal>;
fn err_terminal(&self) -> Box<term::StderrTerminal>; fn err_terminal(&self) -> Box<term::StderrTerminal>;

View File

@ -9,7 +9,7 @@ use derive_new::new;
use indexmap::IndexMap; use indexmap::IndexMap;
#[derive(new)] #[derive(new)]
crate struct Scope { pub struct Scope {
it: Spanned<Value>, it: Spanned<Value>,
#[new(default)] #[new(default)]
vars: IndexMap<String, Spanned<Value>>, vars: IndexMap<String, Spanned<Value>>,
@ -22,16 +22,26 @@ impl Scope {
vars: IndexMap::new(), vars: IndexMap::new(),
} }
} }
crate fn it_value(value: Spanned<Value>) -> Scope {
Scope {
it: value,
vars: IndexMap::new(),
}
}
} }
crate fn evaluate_baseline_expr( crate fn evaluate_baseline_expr(
expr: &Expression, expr: &Expression,
registry: &dyn CommandRegistry, registry: &CommandRegistry,
scope: &Scope, scope: &Scope,
source: &Text, source: &Text,
) -> Result<Spanned<Value>, ShellError> { ) -> Result<Spanned<Value>, ShellError> {
match &expr.item { match &expr.item {
RawExpression::Literal(literal) => Ok(evaluate_literal(expr.copy_span(*literal), source)), RawExpression::Literal(literal) => Ok(evaluate_literal(expr.copy_span(*literal), source)),
RawExpression::Synthetic(hir::Synthetic::String(s)) => {
Ok(Value::string(s).spanned_unknown())
}
RawExpression::Variable(var) => evaluate_reference(var, scope, source), RawExpression::Variable(var) => evaluate_reference(var, scope, source),
RawExpression::Binary(binary) => { RawExpression::Binary(binary) => {
let left = evaluate_baseline_expr(binary.left(), registry, scope, source)?; let left = evaluate_baseline_expr(binary.left(), registry, scope, source)?;

View File

@ -23,6 +23,7 @@ mod parser;
mod plugin; mod plugin;
mod shell; mod shell;
mod stream; mod stream;
mod traits;
pub use crate::commands::command::{CallInfo, ReturnSuccess, ReturnValue}; pub use crate::commands::command::{CallInfo, ReturnSuccess, ReturnValue};
pub use crate::context::SpanSource; pub use crate::context::SpanSource;
@ -34,4 +35,4 @@ pub use cli::cli;
pub use errors::ShellError; pub use errors::ShellError;
pub use object::base::{Primitive, Value}; pub use object::base::{Primitive, Value};
pub use parser::parse::text::Text; pub use parser::parse::text::Text;
pub use parser::registry::{Args, CommandConfig, NamedType, PositionalType}; pub use parser::registry::{CommandConfig, EvaluatedArgs, NamedType, PositionalType};

View File

@ -1,3 +1,4 @@
use crate::context::CommandRegistry;
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::evaluate::{evaluate_baseline_expr, Scope}; use crate::evaluate::{evaluate_baseline_expr, Scope};
use crate::object::SpannedDictBuilder; use crate::object::SpannedDictBuilder;
@ -169,7 +170,12 @@ impl Block {
let mut last = None; let mut last = None;
for expr in self.expressions.iter() { for expr in self.expressions.iter() {
last = Some(evaluate_baseline_expr(&expr, &(), &scope, &self.source)?) last = Some(evaluate_baseline_expr(
&expr,
&CommandRegistry::empty(),
&scope,
&self.source,
)?)
} }
Ok(last.unwrap()) Ok(last.unwrap())

View File

@ -4,9 +4,13 @@ crate mod binary;
crate mod named; crate mod named;
crate mod path; crate mod path;
use crate::parser::{Span, Spanned, Unit}; use crate::evaluate::Scope;
use crate::parser::{registry, Span, Spanned, Unit};
use crate::prelude::*;
use derive_new::new; use derive_new::new;
use getset::Getters; use getset::Getters;
use serde_derive::{Deserialize, Serialize};
use std::fmt;
crate use baseline_parse::{baseline_parse_single_token, baseline_parse_token_as_string}; crate use baseline_parse::{baseline_parse_single_token, baseline_parse_token_as_string};
crate use baseline_parse_tokens::{baseline_parse_next_expr, SyntaxType, TokensIterator}; crate use baseline_parse_tokens::{baseline_parse_next_expr, SyntaxType, TokensIterator};
@ -23,7 +27,7 @@ pub fn path(head: impl Into<Expression>, tail: Vec<Spanned<impl Into<String>>>)
) )
} }
#[derive(Debug, Clone, Eq, PartialEq, Getters, new)] #[derive(Debug, Clone, Eq, PartialEq, Getters, Serialize, Deserialize, new)]
pub struct Call { pub struct Call {
#[get = "crate"] #[get = "crate"]
head: Box<Expression>, head: Box<Expression>,
@ -33,9 +37,42 @@ pub struct Call {
named: Option<NamedArguments>, named: Option<NamedArguments>,
} }
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] impl Call {
pub fn evaluate(
&self,
registry: &registry::CommandRegistry,
scope: &Scope,
source: &Text,
) -> Result<registry::EvaluatedArgs, ShellError> {
registry::evaluate_args(self, registry, scope, source)
}
}
impl ToDebug for Call {
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
write!(f, "({}", self.head.debug(source))?;
if let Some(positional) = &self.positional {
write!(f, " ")?;
write!(
f,
"{}",
&itertools::join(positional.iter().map(|p| p.debug(source)), " ")
)?;
}
if let Some(named) = &self.named {
write!(f, "{}", named.debug(source))?;
}
Ok(())
}
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum RawExpression { pub enum RawExpression {
Literal(Literal), Literal(Literal),
Synthetic(Synthetic),
Variable(Variable), Variable(Variable),
Binary(Box<Binary>), Binary(Box<Binary>),
Block(Vec<Expression>), Block(Vec<Expression>),
@ -45,10 +82,24 @@ pub enum RawExpression {
Boolean(bool), Boolean(bool),
} }
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum Synthetic {
String(String),
}
impl Synthetic {
pub fn type_name(&self) -> &'static str {
match self {
Synthetic::String(_) => "string",
}
}
}
impl RawExpression { impl RawExpression {
pub fn type_name(&self) -> &'static str { pub fn type_name(&self) -> &'static str {
match self { match self {
RawExpression::Literal(literal) => literal.type_name(), RawExpression::Literal(literal) => literal.type_name(),
RawExpression::Synthetic(synthetic) => synthetic.type_name(),
RawExpression::Variable(..) => "variable", RawExpression::Variable(..) => "variable",
RawExpression::Binary(..) => "binary", RawExpression::Binary(..) => "binary",
RawExpression::Block(..) => "block", RawExpression::Block(..) => "block",
@ -61,36 +112,40 @@ impl RawExpression {
pub type Expression = Spanned<RawExpression>; pub type Expression = Spanned<RawExpression>;
impl Expression { impl Expression {
fn int(i: impl Into<i64>, span: impl Into<Span>) -> Expression { crate fn int(i: impl Into<i64>, span: impl Into<Span>) -> Expression {
Spanned::from_item(RawExpression::Literal(Literal::Integer(i.into())), span) Spanned::from_item(RawExpression::Literal(Literal::Integer(i.into())), span)
} }
fn size(i: impl Into<i64>, unit: impl Into<Unit>, span: impl Into<Span>) -> Expression { crate fn size(i: impl Into<i64>, unit: impl Into<Unit>, span: impl Into<Span>) -> Expression {
Spanned::from_item( Spanned::from_item(
RawExpression::Literal(Literal::Size(i.into(), unit.into())), RawExpression::Literal(Literal::Size(i.into(), unit.into())),
span, span,
) )
} }
fn string(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression { crate fn synthetic_string(s: impl Into<String>) -> Expression {
RawExpression::Synthetic(Synthetic::String(s.into())).spanned_unknown()
}
crate fn string(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
Spanned::from_item( Spanned::from_item(
RawExpression::Literal(Literal::String(inner.into())), RawExpression::Literal(Literal::String(inner.into())),
outer.into(), outer.into(),
) )
} }
fn bare(span: impl Into<Span>) -> Expression { crate fn bare(span: impl Into<Span>) -> Expression {
Spanned::from_item(RawExpression::Literal(Literal::Bare), span.into()) Spanned::from_item(RawExpression::Literal(Literal::Bare), span.into())
} }
fn variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression { crate fn variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
Spanned::from_item( Spanned::from_item(
RawExpression::Variable(Variable::Other(inner.into())), RawExpression::Variable(Variable::Other(inner.into())),
outer.into(), outer.into(),
) )
} }
fn it_variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression { crate fn it_variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
Spanned::from_item( Spanned::from_item(
RawExpression::Variable(Variable::It(inner.into())), RawExpression::Variable(Variable::It(inner.into())),
outer.into(), outer.into(),
@ -98,13 +153,37 @@ impl Expression {
} }
} }
impl ToDebug for Expression {
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
match self.item() {
RawExpression::Literal(l) => write!(f, "{}", l.spanned(self.span()).debug(source)),
RawExpression::Synthetic(Synthetic::String(s)) => write!(f, "{:?}", s),
RawExpression::Variable(Variable::It(_)) => write!(f, "$it"),
RawExpression::Variable(Variable::Other(s)) => write!(f, "${}", s.slice(source)),
RawExpression::Binary(b) => write!(f, "{}", b.debug(source)),
RawExpression::Block(exprs) => {
write!(f, "{{ ")?;
for expr in exprs {
write!(f, "{} ", expr.debug(source))?;
}
write!(f, "}}")
}
RawExpression::Path(p) => write!(f, "{}", p.debug(source)),
RawExpression::Boolean(true) => write!(f, "$yes"),
RawExpression::Boolean(false) => write!(f, "$no"),
}
}
}
impl From<Spanned<Path>> for Expression { impl From<Spanned<Path>> for Expression {
fn from(path: Spanned<Path>) -> Expression { fn from(path: Spanned<Path>) -> Expression {
path.map(|p| RawExpression::Path(Box::new(p))) path.map(|p| RawExpression::Path(Box::new(p)))
} }
} }
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum Literal { pub enum Literal {
Integer(i64), Integer(i64),
Size(i64, Unit), Size(i64, Unit),
@ -112,6 +191,17 @@ pub enum Literal {
Bare, Bare,
} }
impl ToDebug for Spanned<&Literal> {
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
match self.item() {
Literal::Integer(int) => write!(f, "{}", *int),
Literal::Size(int, unit) => write!(f, "{}{:?}", *int, unit),
Literal::String(span) => write!(f, "{}", span.slice(source)),
Literal::Bare => write!(f, "{}", self.span().slice(source)),
}
}
}
impl Literal { impl Literal {
fn type_name(&self) -> &'static str { fn type_name(&self) -> &'static str {
match self { match self {
@ -123,7 +213,7 @@ impl Literal {
} }
} }
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum Variable { pub enum Variable {
It(Span), It(Span),
Other(Span), Other(Span),

View File

@ -12,7 +12,7 @@ use serde_derive::{Deserialize, Serialize};
pub fn baseline_parse_tokens( pub fn baseline_parse_tokens(
token_nodes: &mut TokensIterator<'_>, token_nodes: &mut TokensIterator<'_>,
registry: &dyn CommandRegistry, registry: &CommandRegistry,
source: &Text, source: &Text,
) -> Result<Vec<hir::Expression>, ShellError> { ) -> Result<Vec<hir::Expression>, ShellError> {
let mut exprs: Vec<hir::Expression> = vec![]; let mut exprs: Vec<hir::Expression> = vec![];
@ -43,7 +43,7 @@ pub enum SyntaxType {
pub fn baseline_parse_next_expr( pub fn baseline_parse_next_expr(
tokens: &mut TokensIterator, tokens: &mut TokensIterator,
registry: &dyn CommandRegistry, registry: &CommandRegistry,
source: &Text, source: &Text,
syntax_type: SyntaxType, syntax_type: SyntaxType,
) -> Result<hir::Expression, ShellError> { ) -> Result<hir::Expression, ShellError> {
@ -176,7 +176,7 @@ pub fn baseline_parse_next_expr(
pub fn baseline_parse_semantic_token( pub fn baseline_parse_semantic_token(
token: &TokenNode, token: &TokenNode,
registry: &dyn CommandRegistry, registry: &CommandRegistry,
source: &Text, source: &Text,
) -> Result<hir::Expression, ShellError> { ) -> Result<hir::Expression, ShellError> {
match token { match token {
@ -197,7 +197,7 @@ pub fn baseline_parse_semantic_token(
pub fn baseline_parse_delimited( pub fn baseline_parse_delimited(
token: &Spanned<DelimitedNode>, token: &Spanned<DelimitedNode>,
registry: &dyn CommandRegistry, registry: &CommandRegistry,
source: &Text, source: &Text,
) -> Result<hir::Expression, ShellError> { ) -> Result<hir::Expression, ShellError> {
match token.delimiter() { match token.delimiter() {
@ -216,7 +216,7 @@ pub fn baseline_parse_delimited(
pub fn baseline_parse_path( pub fn baseline_parse_path(
token: &Spanned<PathNode>, token: &Spanned<PathNode>,
registry: &dyn CommandRegistry, registry: &CommandRegistry,
source: &Text, source: &Text,
) -> Result<hir::Expression, ShellError> { ) -> Result<hir::Expression, ShellError> {
let head = baseline_parse_semantic_token(token.head(), registry, source)?; let head = baseline_parse_semantic_token(token.head(), registry, source)?;

View File

@ -1,11 +1,26 @@
use crate::parser::{hir::Expression, Operator, Spanned}; use crate::parser::{hir::Expression, Operator, Spanned};
use crate::prelude::*;
use derive_new::new; use derive_new::new;
use getset::Getters; use getset::Getters;
use serde_derive::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Getters, new)] #[derive(
Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Getters, Serialize, Deserialize, new,
)]
#[get = "crate"] #[get = "crate"]
pub struct Binary { pub struct Binary {
left: Expression, left: Expression,
op: Spanned<Operator>, op: Spanned<Operator>,
right: Expression, right: Expression,
} }
impl ToDebug for Binary {
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
write!(f, "{}", self.left.debug(source))?;
write!(f, " {} ", self.op.debug(source))?;
write!(f, "{}", self.right.debug(source))?;
Ok(())
}
}

View File

@ -1,10 +1,13 @@
use crate::parser::hir::Expression; use crate::parser::hir::Expression;
use crate::parser::{Flag, Span}; use crate::parser::{Flag, Span};
use crate::prelude::*;
use derive_new::new; use derive_new::new;
use indexmap::IndexMap; use indexmap::IndexMap;
use log::trace; use log::trace;
use serde_derive::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub enum NamedValue { pub enum NamedValue {
AbsentSwitch, AbsentSwitch,
PresentSwitch(Span), PresentSwitch(Span),
@ -12,12 +15,27 @@ pub enum NamedValue {
Value(Expression), Value(Expression),
} }
#[derive(Debug, Clone, Eq, PartialEq, new)] #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, new)]
pub struct NamedArguments { pub struct NamedArguments {
#[new(default)] #[new(default)]
crate named: IndexMap<String, NamedValue>, crate named: IndexMap<String, NamedValue>,
} }
impl ToDebug for NamedArguments {
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
for (name, value) in &self.named {
match value {
NamedValue::AbsentSwitch => continue,
NamedValue::PresentSwitch(span) => write!(f, " {}", span.slice(source))?,
NamedValue::AbsentValue => continue,
NamedValue::Value(expr) => write!(f, " --{} {}", name, expr.debug(source))?,
}
}
Ok(())
}
}
impl NamedArguments { impl NamedArguments {
pub fn insert_switch(&mut self, name: impl Into<String>, switch: Option<Flag>) { pub fn insert_switch(&mut self, name: impl Into<String>, switch: Option<Flag>) {
let name = name.into(); let name = name.into();

View File

@ -1,10 +1,27 @@
use crate::parser::{hir::Expression, Spanned}; use crate::parser::{hir::Expression, Spanned};
use crate::prelude::*;
use derive_new::new; use derive_new::new;
use getset::Getters; use getset::Getters;
use serde_derive::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Getters, new)] #[derive(
Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Getters, Serialize, Deserialize, new,
)]
#[get = "crate"] #[get = "crate"]
pub struct Path { pub struct Path {
head: Expression, head: Expression,
tail: Vec<Spanned<String>>, tail: Vec<Spanned<String>>,
} }
impl ToDebug for Path {
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
write!(f, "{}", self.head.debug(source))?;
for part in &self.tail {
write!(f, ".{}", part.item())?;
}
Ok(())
}
}

View File

@ -1,4 +1,6 @@
use crate::prelude::*;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::fmt;
use std::str::FromStr; use std::str::FromStr;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
@ -11,6 +13,12 @@ pub enum Operator {
GreaterThanOrEqual, GreaterThanOrEqual,
} }
impl ToDebug for Operator {
fn fmt_debug(&self, f: &mut fmt::Formatter, _source: &str) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl Operator { impl Operator {
#[allow(unused)] #[allow(unused)]
pub fn print(&self) -> String { pub fn print(&self) -> String {

View File

@ -1,3 +1,4 @@
use crate::prelude::*;
use crate::Text; use crate::Text;
use derive_new::new; use derive_new::new;
use getset::Getters; use getset::Getters;
@ -14,6 +15,12 @@ pub struct Spanned<T> {
pub item: T, pub item: T,
} }
impl<T> HasSpan for Spanned<T> {
fn span(&self) -> Span {
self.span
}
}
impl<T> Spanned<T> { impl<T> Spanned<T> {
pub fn spanned(self, span: impl Into<Span>) -> Spanned<T> { pub fn spanned(self, span: impl Into<Span>) -> Spanned<T> {
Spanned::from_item(self.item, span.into()) Spanned::from_item(self.item, span.into())

View File

@ -1,3 +1,4 @@
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::hash::Hash; use std::hash::Hash;
use std::hash::Hasher; use std::hash::Hasher;
@ -202,3 +203,21 @@ where
self.partial_cmp(*other) self.partial_cmp(*other)
} }
} }
impl Serialize for Text {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.as_ref().serialize(serializer)
}
}
impl Deserialize<'de> for Text {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(Text::from(String::deserialize(deserializer)?))
}
}

View File

@ -10,7 +10,7 @@ use log::trace;
pub fn parse_command( pub fn parse_command(
config: &CommandConfig, config: &CommandConfig,
registry: &dyn CommandRegistry, registry: &CommandRegistry,
call: &Spanned<CallNode>, call: &Spanned<CallNode>,
source: &Text, source: &Text,
) -> Result<hir::Call, ShellError> { ) -> Result<hir::Call, ShellError> {
@ -63,7 +63,7 @@ fn parse_command_head(head: &TokenNode) -> Result<hir::Expression, ShellError> {
fn parse_command_tail( fn parse_command_tail(
config: &CommandConfig, config: &CommandConfig,
registry: &dyn CommandRegistry, registry: &CommandRegistry,
tail: Option<Vec<TokenNode>>, tail: Option<Vec<TokenNode>>,
source: &Text, source: &Text,
command_span: Span, command_span: Span,

View File

@ -1,3 +1,5 @@
// TODO: Temporary redirect
crate use crate::context::CommandRegistry;
use crate::evaluate::{evaluate_baseline_expr, Scope}; use crate::evaluate::{evaluate_baseline_expr, Scope};
use crate::parser::{hir, hir::SyntaxType, parse_command, CallNode, Spanned}; use crate::parser::{hir, hir::SyntaxType, parse_command, CallNode, Spanned};
use crate::prelude::*; use crate::prelude::*;
@ -80,17 +82,17 @@ pub struct CommandConfig {
} }
#[derive(Debug, Default, new, Serialize, Deserialize)] #[derive(Debug, Default, new, Serialize, Deserialize)]
pub struct Args { pub struct EvaluatedArgs {
pub positional: Option<Vec<Spanned<Value>>>, pub positional: Option<Vec<Spanned<Value>>>,
pub named: Option<IndexMap<String, Spanned<Value>>>, pub named: Option<IndexMap<String, Spanned<Value>>>,
} }
#[derive(new)] #[derive(new)]
pub struct DebugPositional<'a> { pub struct DebugEvaluatedPositional<'a> {
positional: &'a Option<Vec<Spanned<Value>>>, positional: &'a Option<Vec<Spanned<Value>>>,
} }
impl fmt::Debug for DebugPositional<'a> { impl fmt::Debug for DebugEvaluatedPositional<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.positional { match &self.positional {
None => write!(f, "None"), None => write!(f, "None"),
@ -103,11 +105,11 @@ impl fmt::Debug for DebugPositional<'a> {
} }
#[derive(new)] #[derive(new)]
pub struct DebugNamed<'a> { pub struct DebugEvaluatedNamed<'a> {
named: &'a Option<IndexMap<String, Spanned<Value>>>, named: &'a Option<IndexMap<String, Spanned<Value>>>,
} }
impl fmt::Debug for DebugNamed<'a> { impl fmt::Debug for DebugEvaluatedNamed<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.named { match &self.named {
None => write!(f, "None"), None => write!(f, "None"),
@ -119,24 +121,27 @@ impl fmt::Debug for DebugNamed<'a> {
} }
} }
pub struct DebugArgs<'a> { pub struct DebugEvaluatedArgs<'a> {
args: &'a Args, args: &'a EvaluatedArgs,
} }
impl fmt::Debug for DebugArgs<'a> { impl fmt::Debug for DebugEvaluatedArgs<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut s = f.debug_struct("Args"); let mut s = f.debug_struct("Args");
s.field("positional", &DebugPositional::new(&self.args.positional)); s.field(
s.field("named", &DebugNamed::new(&self.args.named)); "positional",
&DebugEvaluatedPositional::new(&self.args.positional),
);
s.field("named", &DebugEvaluatedNamed::new(&self.args.named));
s.finish() s.finish()
} }
} }
impl Args { impl EvaluatedArgs {
pub fn debug(&'a self) -> DebugArgs<'a> { pub fn debug(&'a self) -> DebugEvaluatedArgs<'a> {
DebugArgs { args: self } DebugEvaluatedArgs { args: self }
} }
pub fn nth(&self, pos: usize) -> Option<&Spanned<Value>> { pub fn nth(&self, pos: usize) -> Option<&Spanned<Value>> {
@ -205,92 +210,17 @@ impl Iterator for PositionalIter<'a> {
} }
impl CommandConfig { impl CommandConfig {
crate fn evaluate_args( crate fn parse_args(
&self, &self,
call: &Spanned<CallNode>, call: &Spanned<CallNode>,
registry: &dyn CommandRegistry, registry: &CommandRegistry,
scope: &Scope,
source: &Text, source: &Text,
) -> Result<Args, ShellError> { ) -> Result<hir::Call, ShellError> {
let args = parse_command(self, registry, call, source)?; let args = parse_command(self, registry, call, source)?;
trace!("parsed args: {:?}", args); trace!("parsed args: {:?}", args);
evaluate_args(args, registry, scope, source) Ok(args)
// let mut positional: Vec<Spanned<Value>> = vec![];
// let mut named: IndexMap<String, Value> = IndexMap::default();
// let mut args: Vec<TokenNode> = args.cloned().collect();
// for (key, ty) in self.named.iter() {
// let index = args.iter().position(|a| a.is_flag(&key, source));
// match (index, ty) {
// (Some(i), NamedType::Switch) => {
// args.remove(i);
// named.insert(key.clone(), Value::boolean(true));
// }
// (None, NamedType::Switch) => {}
// (Some(i), NamedType::Optional(v)) => {
// args.remove(i);
// named.insert(key.clone(), extract_named(&mut args, i, v)?);
// }
// (None, NamedType::Optional(_)) => {}
// (Some(i), NamedType::Mandatory(v)) => {
// args.remove(i);
// named.insert(key.clone(), extract_named(&mut args, i, v)?);
// }
// (None, NamedType::Mandatory(_)) => {
// return Err(ShellError::string(&format!(
// "Expected mandatory argument {}, but it was missing",
// key
// )))
// }
// }
// }
// let mut args = args.into_iter();
// for param in &self.mandatory_positional {
// let arg = args.next();
// let value = match arg {
// None => {
// return Err(ShellError::string(format!(
// "expected mandatory positional argument {}",
// param.name()
// )))
// }
// Some(arg) => param.evaluate(arg.clone(), scope, source)?,
// };
// positional.push(value);
// }
// if self.rest_positional {
// let rest: Result<Vec<Spanned<Value>>, _> = args
// .map(|i| evaluate_baseline_expr(&i, &Scope::empty(), source))
// .collect();
// positional.extend(rest?);
// } else {
// let rest: Vec<TokenNode> = args.collect();
// if rest.len() > 0 {
// return Err(ShellError::string(&format!(
// "Too many arguments, extras: {:?}",
// rest
// )));
// }
// }
// Ok(Args { positional, named })
} }
#[allow(unused)] #[allow(unused)]
@ -299,25 +229,25 @@ impl CommandConfig {
} }
} }
fn evaluate_args( crate fn evaluate_args(
args: hir::Call, call: &hir::Call,
registry: &dyn CommandRegistry, registry: &CommandRegistry,
scope: &Scope, scope: &Scope,
source: &Text, source: &Text,
) -> Result<Args, ShellError> { ) -> Result<EvaluatedArgs, ShellError> {
let positional: Result<Option<Vec<_>>, _> = args let positional: Result<Option<Vec<_>>, _> = call
.positional() .positional()
.as_ref() .as_ref()
.map(|p| { .map(|p| {
p.iter() p.iter()
.map(|e| evaluate_baseline_expr(e, &(), scope, source)) .map(|e| evaluate_baseline_expr(e, &CommandRegistry::empty(), scope, source))
.collect() .collect()
}) })
.transpose(); .transpose();
let positional = positional?; let positional = positional?;
let named: Result<Option<IndexMap<String, Spanned<Value>>>, ShellError> = args let named: Result<Option<IndexMap<String, Spanned<Value>>>, ShellError> = call
.named() .named()
.as_ref() .as_ref()
.map(|n| { .map(|n| {
@ -348,15 +278,5 @@ fn evaluate_args(
let named = named?; let named = named?;
Ok(Args::new(positional, named)) Ok(EvaluatedArgs::new(positional, named))
}
pub trait CommandRegistry {
fn get(&self, name: &str) -> Option<CommandConfig>;
}
impl CommandRegistry for () {
fn get(&self, _name: &str) -> Option<CommandConfig> {
None
}
} }

View File

@ -34,9 +34,10 @@ macro_rules! trace_stream {
crate use crate::cli::MaybeOwned; crate use crate::cli::MaybeOwned;
crate use crate::commands::command::{ crate use crate::commands::command::{
Command, CommandAction, CommandArgs, ReturnSuccess, ReturnValue, Sink, SinkCommandArgs, Command, CommandAction, CommandArgs, EvaluatedCommandArgs, ReturnSuccess, ReturnValue, Sink,
SinkCommandArgs,
}; };
crate use crate::context::Context; crate use crate::context::{CommandRegistry, Context};
crate use crate::env::host::handle_unexpected; crate use crate::env::host::handle_unexpected;
crate use crate::env::{Environment, Host}; crate use crate::env::{Environment, Host};
crate use crate::errors::ShellError; crate use crate::errors::ShellError;
@ -44,10 +45,10 @@ crate use crate::object::types::ExtractType;
crate use crate::object::{Primitive, Value}; crate use crate::object::{Primitive, Value};
crate use crate::parser::{Span, Spanned, SpannedItem}; crate use crate::parser::{Span, Spanned, SpannedItem};
crate use crate::stream::{InputStream, OutputStream}; crate use crate::stream::{InputStream, OutputStream};
crate use crate::traits::{HasSpan, ToDebug};
crate use crate::Text; crate use crate::Text;
crate use futures::stream::BoxStream; crate use futures::stream::BoxStream;
crate use futures::Stream; crate use futures::{FutureExt, Stream, StreamExt};
crate use futures::{FutureExt, StreamExt};
crate use std::collections::VecDeque; crate use std::collections::VecDeque;
crate use std::future::Future; crate use std::future::Future;
crate use std::sync::{Arc, Mutex}; crate use std::sync::{Arc, Mutex};

View File

@ -1,4 +1,6 @@
use crate::context::CommandRegistry;
use crate::prelude::*; use crate::prelude::*;
use derive_new::new; use derive_new::new;
use rustyline::completion::Completer; use rustyline::completion::Completer;
use rustyline::completion::{self, FilenameCompleter}; use rustyline::completion::{self, FilenameCompleter};
@ -7,7 +9,7 @@ use rustyline::line_buffer::LineBuffer;
#[derive(new)] #[derive(new)]
crate struct NuCompleter { crate struct NuCompleter {
pub file_completer: FilenameCompleter, pub file_completer: FilenameCompleter,
pub commands: indexmap::IndexMap<String, Arc<dyn Command>>, pub commands: CommandRegistry,
} }
impl Completer for NuCompleter { impl Completer for NuCompleter {
@ -19,7 +21,7 @@ impl Completer for NuCompleter {
pos: usize, pos: usize,
context: &rustyline::Context, context: &rustyline::Context,
) -> rustyline::Result<(usize, Vec<completion::Pair>)> { ) -> rustyline::Result<(usize, Vec<completion::Pair>)> {
let commands: Vec<String> = self.commands.keys().cloned().collect(); let commands: Vec<String> = self.commands.names();
let mut completions = self.file_completer.complete(line, pos, context)?.1; let mut completions = self.file_completer.complete(line, pos, context)?.1;

View File

@ -18,7 +18,7 @@ crate struct Helper {
} }
impl Helper { impl Helper {
crate fn new(commands: indexmap::IndexMap<String, Arc<dyn Command>>) -> Helper { crate fn new(commands: CommandRegistry) -> Helper {
Helper { Helper {
completer: NuCompleter { completer: NuCompleter {
file_completer: FilenameCompleter::new(), file_completer: FilenameCompleter::new(),

28
src/traits.rs Normal file
View File

@ -0,0 +1,28 @@
use crate::prelude::*;
use std::fmt;
pub struct Debuggable<'a, T: ToDebug> {
inner: &'a T,
source: &'a str,
}
impl<T: ToDebug> fmt::Display for Debuggable<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.inner.fmt_debug(f, self.source)
}
}
pub trait HasSpan {
fn span(&self) -> Span;
}
pub trait ToDebug: Sized {
fn debug(&'a self, source: &'a str) -> Debuggable<'a, Self> {
Debuggable {
inner: self,
source,
}
}
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result;
}

View File

@ -1,2 +0,0 @@
*_test
*.txt

View File

@ -7,9 +7,9 @@ use std::io::Read;
#[macro_export] #[macro_export]
macro_rules! nu { macro_rules! nu {
($out:ident, $cwd:expr, $commands:expr) => { ($out:ident, $cwd:expr, $commands:expr) => {
pub use std::error::Error;
pub use std::io::prelude::*; pub use std::io::prelude::*;
pub use std::process::{Command, Stdio}; pub use std::process::{Command, Stdio};
pub use std::error::Error;
let commands = &*format!( let commands = &*format!(
" "
@ -95,7 +95,8 @@ pub fn setup_playground_for(topic: &str) -> (String, String) {
pub fn file_contents(full_path: &str) -> String { pub fn file_contents(full_path: &str) -> String {
let mut file = std::fs::File::open(full_path).expect("can not open file"); let mut file = std::fs::File::open(full_path).expect("can not open file");
let mut contents = String::new(); let mut contents = String::new();
file.read_to_string(&mut contents).expect("can not read file"); file.read_to_string(&mut contents)
.expect("can not read file");
contents contents
} }
@ -112,7 +113,14 @@ pub fn delete_directory_at(full_path: &str) {
} }
pub fn create_directory_at(full_path: &str) { pub fn create_directory_at(full_path: &str) {
std::fs::create_dir(PathBuf::from(full_path)).expect("can not create directory"); let path = PathBuf::from(full_path);
println!("{:?} - is_dir: {:?}", path, path.is_dir());
if !path.is_dir() {
std::fs::create_dir_all(PathBuf::from(full_path))
.expect(&format!("can not create directory {:?}", full_path));
}
} }
pub fn executable_path() -> PathBuf { pub fn executable_path() -> PathBuf {