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
**/*.rs.bk
history.txt
tests/fixtures/nuplayground

View File

@ -9,13 +9,11 @@ use crate::commands::plugin::JsonRpc;
use crate::commands::plugin::{PluginCommand, PluginSink};
use crate::context::Context;
crate use crate::errors::ShellError;
use crate::evaluate::Scope;
use crate::git::current_branch;
use crate::object::Value;
use crate::parser::parse::span::Spanned;
use crate::parser::registry;
use crate::parser::registry::CommandConfig;
use crate::parser::{Pipeline, PipelineElement, TokenNode};
use crate::parser::{hir, Pipeline, PipelineElement, TokenNode};
use crate::prelude::*;
use log::{debug, trace};
@ -150,22 +148,22 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
use crate::commands::*;
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("ls", Box::new(ls::ls)),
command("sysinfo", Box::new(sysinfo::sysinfo)),
command("cd", Box::new(cd::cd)),
command("first", Box::new(first::first)),
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("get", Box::new(get::get)),
command("exit", Box::new(exit::exit)),
command("lines", Box::new(lines::lines)),
command("pick", Box::new(pick::pick)),
command("split-column", Box::new(split_column::split_column)),
command("split-row", Box::new(split_row::split_row)),
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 {
command: sink("autoview", Box::new(autoview::autoview)),
name_span: None,
args: registry::Args {
positional: None,
named: None,
},
args: hir::Call::new(
Box::new(hir::Expression::synthetic_string("autoview")),
None,
None,
),
})),
}
@ -386,7 +385,7 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
(Some(ClassifiedCommand::Sink(left)), None) => {
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);
}
break;
@ -395,20 +394,20 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
(
Some(ClassifiedCommand::Internal(left)),
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),
Err(err) => return LineResult::Error(line.clone(), err),
},
(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),
Err(err) => return LineResult::Error(line.clone(), err),
}
}
(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),
Err(err) => return LineResult::Error(line.clone(), err),
}
@ -487,11 +486,10 @@ fn classify_command(
true => {
let command = context.get_command(name);
let config = command.config();
let scope = Scope::empty();
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 {
command,
@ -504,9 +502,8 @@ fn classify_command(
true => {
let command = context.get_sink(name);
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 {
command,

View File

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

View File

@ -2,8 +2,10 @@ use crate::errors::ShellError;
use crate::prelude::*;
use std::env;
pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
let env = args.env.lock().unwrap();
pub fn cd(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let env = args.env.clone();
let env = env.lock().unwrap();
let args = args.evaluate_once(registry)?;
let cwd = env.path().to_path_buf();
let path = match args.nth(0) {
@ -13,7 +15,7 @@ pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
return Err(ShellError::maybe_labeled_error(
"Can not change to home directory",
"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::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 bytes::{BufMut, BytesMut};
use futures::stream::StreamExt;
@ -101,7 +102,7 @@ impl ClassifiedCommand {
crate struct SinkCommand {
crate command: Arc<dyn Sink>,
crate name_span: Option<Span>,
crate args: Args,
crate args: hir::Call,
}
impl SinkCommand {
@ -109,8 +110,12 @@ impl SinkCommand {
self,
context: &mut Context,
input: Vec<Spanned<Value>>,
source: &Text,
) -> 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 name_span: Option<Span>,
crate source_map: SourceMap,
crate args: Args,
crate args: hir::Call,
}
impl InternalCommand {
@ -126,11 +131,12 @@ impl InternalCommand {
self,
context: &mut Context,
input: ClassifiedInputStream,
source: Text,
) -> Result<InputStream, ShellError> {
if log_enabled!(log::Level::Trace) {
trace!(target: "nu::run::internal", "->");
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 =
@ -141,6 +147,7 @@ impl InternalCommand {
self.name_span.clone(),
self.source_map,
self.args,
source,
objects,
)?;

View File

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

View File

@ -1,20 +1,62 @@
use crate::context::SourceMap;
use crate::context::SpanSource;
use crate::context::{SourceMap, SpanSource};
use crate::errors::ShellError;
use crate::evaluate::Scope;
use crate::object::Value;
use crate::parser::{
registry::{self, Args},
Span, Spanned,
};
use crate::parser::hir;
use crate::parser::{registry, Span, Spanned};
use crate::prelude::*;
use getset::Getters;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::ops::Deref;
use std::path::PathBuf;
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)]
pub struct CallInfo {
pub args: Args,
pub args: registry::EvaluatedArgs,
pub source_map: SourceMap,
pub name_span: Option<Span>,
}
@ -22,13 +64,137 @@ pub struct CallInfo {
#[derive(Getters)]
#[get = "crate"]
pub struct CommandArgs {
pub host: Arc<Mutex<dyn Host + Send>>,
pub host: Arc<Mutex<dyn Host>>,
pub env: Arc<Mutex<Environment>>,
pub call_info: CallInfo,
pub call_info: UnevaluatedCallInfo,
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 {
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>> {
self.call_info.args.nth(pos)
}
@ -61,6 +227,12 @@ pub struct SinkCommandArgs {
pub input: Vec<Spanned<Value>>,
}
impl SinkCommandArgs {
pub fn name_span(&self) -> Option<Span> {
self.call_info.name_span
}
}
#[derive(Debug, Serialize, Deserialize)]
pub enum CommandAction {
ChangePath(PathBuf),
@ -100,8 +272,12 @@ impl ReturnSuccess {
}
}
pub trait Command {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError>;
pub trait Command: Send + Sync {
fn run(
&self,
args: CommandArgs,
registry: &registry::CommandRegistry,
) -> Result<OutputStream, ShellError>;
fn name(&self) -> &str;
fn config(&self) -> registry::CommandConfig {
@ -132,14 +308,74 @@ pub trait Sink {
}
}
pub struct FnCommand {
pub struct FnFilterCommand {
name: String,
func: Box<dyn Fn(CommandArgs) -> Result<OutputStream, ShellError>>,
func: fn(EvaluatedFilterCommandArgs) -> Result<OutputStream, ShellError>,
}
impl Command for FnCommand {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
(self.func)(args)
impl Command for FnFilterCommand {
fn name(&self) -> &str {
&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 {
@ -149,9 +385,23 @@ impl Command for FnCommand {
pub fn command(
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::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(),
func,
})

View File

@ -1,10 +1,10 @@
use crate::prelude::*;
use crate::commands::EvaluatedStaticCommandArgs;
use crate::errors::ShellError;
use crate::object::config;
use crate::object::Value;
use crate::object::{config, Value};
use crate::parser::hir::SyntaxType;
use crate::parser::registry::{CommandConfig, NamedType};
use crate::parser::registry::{self, CommandConfig, NamedType};
use indexmap::IndexMap;
use log::trace;
use std::iter::FromIterator;
@ -12,9 +12,15 @@ use std::iter::FromIterator;
pub struct 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)
}
fn name(&self) -> &str {
"config"
}
@ -38,11 +44,11 @@ impl Command for Config {
}
}
pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut result = crate::object::config::config(args.call_info.name_span)?;
pub fn config(args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
let mut result = crate::object::config::config(args.name_span())?;
trace!("{:#?}", args.call_info.args.positional);
trace!("{:#?}", args.call_info.args.named);
trace!("{:#?}", args.call_args().positional);
trace!("{:#?}", args.call_args().named);
if let Some(v) = args.get("get") {
let key = v.as_string()?;
@ -95,7 +101,7 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
}
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")))

View File

@ -2,6 +2,6 @@ use crate::commands::command::CommandAction;
use crate::errors::ShellError;
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())
}

View File

@ -1,14 +1,17 @@
use crate::errors::ShellError;
use crate::parser::CommandRegistry;
use crate::prelude::*;
// 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 {
return Err(ShellError::maybe_labeled_error(
"First requires an amount",
"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(input.values.take(amount as u64)))
Ok(OutputStream::from_input(
args.input.values.take(amount as u64),
))
}

View File

@ -6,7 +6,6 @@ pub fn from_csv_string_to_value(
s: String,
span: impl Into<Span>,
) -> Result<Spanned<Value>, Box<dyn std::error::Error>> {
let mut reader = ReaderBuilder::new()
.has_headers(false)
.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 span = args.call_info.name_span;
Ok(out
.values

View File

@ -37,9 +37,11 @@ pub fn from_ini_string_to_value(
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 span = args.call_info.name_span;
Ok(out
.values
.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))
}
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 span = args.call_info.name_span;
Ok(out
.values
.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))
}
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 span = args.call_info.name_span;
Ok(out
.values
.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))
}
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 span = args.call_info.name_span;
Ok(out
.values
.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))
}
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 span = args.call_info.name_span;
Ok(out
.values
.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())
}
pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
if args.len() == 0 {
pub fn get(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let span = args.name_span();
let len = args.len();
if len == 0 {
return Err(ShellError::maybe_labeled_error(
"Get requires a field or field path",
"needs parameter",
args.call_info.name_span,
span,
));
}
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 let Ok(amount) = amount {
return Ok(args
.input
.values
.skip(amount as u64)
.take(1)
.from_input_stream());
return Ok(input.values.skip(amount as u64).take(1).from_input_stream());
}
let fields: Result<Vec<(String, Span)>, _> = args
.positional_iter()
let fields: Result<Vec<(String, Span)>, _> = positional
.iter()
.flatten()
.map(|a| (a.as_string().map(|x| (x, a.span))))
.collect();
let fields = fields?;
let stream = args
.input
let stream = input
.values
.map(move |item| {
let mut result = VecDeque::new();

View File

@ -5,9 +5,12 @@ use log::trace;
// 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 span = args.call_info.name_span;
let input: InputStream = trace_stream!(target: "nu::trace_stream::lines", "input" = input);
let stream = input
.values

View File

@ -4,8 +4,10 @@ use crate::parser::Spanned;
use crate::prelude::*;
use std::path::{Path, PathBuf};
pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
let env = args.env.lock().unwrap();
pub fn ls(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let env = args.env.clone();
let env = env.lock().unwrap();
let args = args.evaluate_once(registry)?;
let path = env.path.to_path_buf();
let mut full_path = PathBuf::from(path);
match &args.nth(0) {
@ -30,7 +32,7 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
return Err(ShellError::maybe_labeled_error(
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();
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))
}
Ok(shell_entries.to_output_stream())

View File

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

View File

@ -1,69 +1,152 @@
use crate::context::SpanSource;
use crate::errors::ShellError;
use crate::object::{Primitive, Switch, Value};
use crate::parser::hir::SyntaxType;
use crate::parser::parse::span::Span;
use crate::parser::registry::{self, CommandConfig, NamedType, PositionalType};
use crate::prelude::*;
use indexmap::IndexMap;
use mime::Mime;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use uuid::Uuid;
command! {
Open as open(args, path: Spanned<PathBuf>, --raw: Switch,) {
let span = args.call_info.name_span;
pub struct Open;
let cwd = args
.env
.lock()
.unwrap()
.path()
.to_path_buf();
impl Command for Open {
fn run(
&self,
args: CommandArgs,
registry: &registry::CommandRegistry,
) -> 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 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() {
None
} else {
file_extension
};
let file_extension = if raw { 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)))
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,
)?;
let value = parse_as_value(file_extension, string, contents_span, span)?;
match value {
Spanned { item: Value::List(list), .. } => {
Spanned {
item: Value::List(list),
..
} => {
for elem in list {
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))),
};
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(
cwd: &PathBuf,
location: &str,

View File

@ -1,19 +1,30 @@
use crate::context::CommandRegistry;
use crate::errors::ShellError;
use crate::object::base::select_fields;
use crate::prelude::*;
pub fn pick(args: CommandArgs) -> Result<OutputStream, ShellError> {
if args.len() == 0 {
pub fn pick(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
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(
"Pick requires fields",
"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 input = args.input;
let objects = input
.values

View File

@ -41,8 +41,12 @@ pub struct PluginCommand {
}
impl Command for PluginCommand {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
filter_plugin(self.path.clone(), args)
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
filter_plugin(self.path.clone(), args, registry)
}
fn name(&self) -> &str {
&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)
.stdin(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 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();
stdin.write(format!("{}\n", request_raw).as_bytes())?;
let mut input = String::new();

View File

@ -3,14 +3,14 @@ use crate::object::process::process_dict;
use crate::prelude::*;
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());
system.refresh_processes();
let list = system.get_process_list();
let list = list
.into_iter()
.map(|(_, process)| process_dict(process, args.call_info.name_span))
.map(|(_, process)| process_dict(process, args.name_span()))
.collect::<VecDeque<_>>();
Ok(list.from_input_stream())

View File

@ -2,21 +2,31 @@ use crate::errors::ShellError;
use crate::object::base::reject_fields;
use crate::prelude::*;
pub fn reject(args: CommandArgs) -> Result<OutputStream, ShellError> {
let name_span = args.call_info.name_span;
pub fn reject(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
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(
"Reject requires fields",
"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 stream = args.input.values.map(move |item| {
let stream = input.values.map(move |item| {
reject_fields(&item, &fields, item.span)
.into_spanned_value()
.spanned(name_span)

View File

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

View File

@ -13,7 +13,7 @@ pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> {
return Err(ShellError::maybe_labeled_error(
"Save requires a filepath",
"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::prelude::*;
pub fn size(args: CommandArgs) -> Result<OutputStream, ShellError> {
pub fn size(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let input = args.input;
Ok(input
.values

View File

@ -6,8 +6,12 @@ use crate::prelude::*;
pub struct SkipWhile;
impl Command for SkipWhile {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
skip_while(args)
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
skip_while(args, registry)
}
fn name(&self) -> &str {
"skip-while"
@ -25,18 +29,24 @@ impl Command for SkipWhile {
}
}
pub fn skip_while(args: CommandArgs) -> Result<OutputStream, ShellError> {
if args.len() == 0 {
pub fn skip_while(
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(
"Where requires a 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 result = block.invoke(&item);

View File

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

View File

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

View File

@ -4,20 +4,25 @@ use crate::parser::Spanned;
use crate::prelude::*;
use log::trace;
pub fn split_row(args: CommandArgs) -> Result<OutputStream, ShellError> {
let positional: Vec<Spanned<Value>> = args.positional_iter().cloned().collect();
let span = args.call_info.name_span;
pub fn split_row(
args: CommandArgs,
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(
"Split-row needs more information",
"needs parameter (eg split-row \"\\n\")",
args.call_info.name_span,
span,
));
}
let input = args.input;
let stream = input
.values
.map(move |v| match v.item {

View File

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

View File

@ -1,7 +1,7 @@
use crate::object::Value;
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();
Ok(out

View File

@ -1,10 +1,9 @@
use crate::object::{Primitive, Value};
use crate::prelude::*;
use log::debug;
use csv::WriterBuilder;
use log::debug;
pub fn value_to_csv_value(v: &Value) -> Value {
debug!("value_to_csv_value(Value::Object(v)) where v = {:?}", v);
match v {
@ -13,7 +12,7 @@ pub fn value_to_csv_value(v: &Value) -> Value {
Value::Object(o) => Value::Object(o.clone()),
Value::List(l) => Value::List(l.clone()),
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 {
Value::List(_l) => return Ok(String::from("[list list]")),
Value::Object(o) => {
debug!("to_csv:to_string(Value::Object(v)) where v = {:?}", v);
let mut wtr = WriterBuilder::new().from_writer(vec![]);
@ -32,34 +30,33 @@ pub fn to_string(v: &Value) -> Result<String, Box<dyn std::error::Error>> {
fields.push_back(k.clone());
values.push_back(to_string(&v)?);
}
wtr.write_record(fields).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()),
_ => 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 name_span = args.call_info.name_span;
Ok(out
.values
.map(
move |a| match to_string(&value_to_csv_value(&a.item)) {
Ok(x) => {
ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span))
}
Err(_) => Err(ShellError::maybe_labeled_error(
"Can not convert to CSV string",
"can not convert piped data to CSV string",
name_span,
)),
},
)
.map(move |a| match to_string(&value_to_csv_value(&a.item)) {
Ok(x) => {
ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span))
}
Err(_) => Err(ShellError::maybe_labeled_error(
"Can not convert to CSV string",
"can not convert piped data to CSV string",
name_span,
)),
})
.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 name_span = args.call_info.name_span;
Ok(out
.values
.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 name_span = args.call_info.name_span;
Ok(out
.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 name_span = args.call_info.name_span;
Ok(out
.values
.map(

View File

@ -2,7 +2,7 @@ use crate::errors::ShellError;
use crate::object::Value;
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;
Ok(input

View File

@ -1,23 +1,76 @@
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 futures::future::ready;
use indexmap::IndexMap;
use log::trace;
command! {
Where as where(args, condition: Block,) {
let input: InputStream = trace_stream!(target: "nu::trace_stream::where", "where input" = args.input);
pub struct Where;
input.values.filter_map(move |item| {
let result = condition.invoke(&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);
let return_value = match result {
Err(err) => Some(Err(err)),
Ok(v) if v.is_true() => Some(Ok(ReturnSuccess::Value(item.clone()))),
_ => None,
};
Ok(input
.values
.filter_map(move |item| {
let result = condition.invoke(&item);
ready(return_value)
})
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)
})
.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::{
registry::{Args, CommandConfig, CommandRegistry},
hir,
registry::{self, CommandConfig},
Span,
};
use crate::prelude::*;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use derive_new::new;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::error::Error;
use std::sync::Arc;
use uuid::Uuid;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum SpanSource {
Url(String),
File(String),
Source(Text),
}
#[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)]
pub struct Context {
commands: IndexMap<String, Arc<dyn Command>>,
registry: CommandRegistry,
sinks: IndexMap<String, Arc<dyn Sink>>,
crate source_map: SourceMap,
crate host: Arc<Mutex<dyn Host + Send>>,
@ -45,9 +90,13 @@ pub struct Context {
}
impl Context {
crate fn registry(&self) -> &CommandRegistry {
&self.registry
}
crate fn basic() -> Result<Context, Box<dyn Error>> {
Ok(Context {
commands: indexmap::IndexMap::new(),
registry: CommandRegistry::new(),
sinks: indexmap::IndexMap::new(),
source_map: SourceMap::new(),
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>>) {
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,
command: Arc<dyn Sink>,
name_span: Option<Span>,
args: Args,
args: registry::EvaluatedArgs,
input: Vec<Spanned<Value>>,
) -> Result<(), ShellError> {
let command_args = SinkCommandArgs {
@ -99,16 +148,16 @@ impl Context {
command.run(command_args)
}
pub fn clone_commands(&self) -> indexmap::IndexMap<String, Arc<dyn Command>> {
self.commands.clone()
pub fn clone_commands(&self) -> CommandRegistry {
self.registry.clone()
}
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> {
self.commands.get(name).unwrap().clone()
self.registry.get_command(name).unwrap()
}
crate fn run_command(
@ -116,26 +165,43 @@ impl Context {
command: Arc<dyn Command>,
name_span: Option<Span>,
source_map: SourceMap,
args: Args,
args: hir::Call,
source: Text,
input: InputStream,
) -> 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(),
env: self.env.clone(),
call_info: CallInfo {
name_span,
source_map,
args,
},
call_info: self.call_info(args, source, source_map, name_span),
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 std::fmt::Debug;
pub trait Host: Debug {
pub trait Host: Debug + Send {
fn out_terminal(&self) -> Box<term::StdoutTerminal>;
fn err_terminal(&self) -> Box<term::StderrTerminal>;

View File

@ -9,7 +9,7 @@ use derive_new::new;
use indexmap::IndexMap;
#[derive(new)]
crate struct Scope {
pub struct Scope {
it: Spanned<Value>,
#[new(default)]
vars: IndexMap<String, Spanned<Value>>,
@ -22,16 +22,26 @@ impl Scope {
vars: IndexMap::new(),
}
}
crate fn it_value(value: Spanned<Value>) -> Scope {
Scope {
it: value,
vars: IndexMap::new(),
}
}
}
crate fn evaluate_baseline_expr(
expr: &Expression,
registry: &dyn CommandRegistry,
registry: &CommandRegistry,
scope: &Scope,
source: &Text,
) -> Result<Spanned<Value>, ShellError> {
match &expr.item {
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::Binary(binary) => {
let left = evaluate_baseline_expr(binary.left(), registry, scope, source)?;

View File

@ -23,6 +23,7 @@ mod parser;
mod plugin;
mod shell;
mod stream;
mod traits;
pub use crate::commands::command::{CallInfo, ReturnSuccess, ReturnValue};
pub use crate::context::SpanSource;
@ -34,4 +35,4 @@ pub use cli::cli;
pub use errors::ShellError;
pub use object::base::{Primitive, Value};
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::evaluate::{evaluate_baseline_expr, Scope};
use crate::object::SpannedDictBuilder;
@ -169,7 +170,12 @@ impl Block {
let mut last = None;
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())

View File

@ -4,9 +4,13 @@ crate mod binary;
crate mod named;
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 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_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 {
#[get = "crate"]
head: Box<Expression>,
@ -33,9 +37,42 @@ pub struct Call {
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 {
Literal(Literal),
Synthetic(Synthetic),
Variable(Variable),
Binary(Box<Binary>),
Block(Vec<Expression>),
@ -45,10 +82,24 @@ pub enum RawExpression {
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 {
pub fn type_name(&self) -> &'static str {
match self {
RawExpression::Literal(literal) => literal.type_name(),
RawExpression::Synthetic(synthetic) => synthetic.type_name(),
RawExpression::Variable(..) => "variable",
RawExpression::Binary(..) => "binary",
RawExpression::Block(..) => "block",
@ -61,36 +112,40 @@ impl RawExpression {
pub type Expression = Spanned<RawExpression>;
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)
}
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(
RawExpression::Literal(Literal::Size(i.into(), unit.into())),
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(
RawExpression::Literal(Literal::String(inner.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())
}
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(
RawExpression::Variable(Variable::Other(inner.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(
RawExpression::Variable(Variable::It(inner.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 {
fn from(path: Spanned<Path>) -> Expression {
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 {
Integer(i64),
Size(i64, Unit),
@ -112,6 +191,17 @@ pub enum Literal {
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 {
fn type_name(&self) -> &'static str {
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 {
It(Span),
Other(Span),

View File

@ -12,7 +12,7 @@ use serde_derive::{Deserialize, Serialize};
pub fn baseline_parse_tokens(
token_nodes: &mut TokensIterator<'_>,
registry: &dyn CommandRegistry,
registry: &CommandRegistry,
source: &Text,
) -> Result<Vec<hir::Expression>, ShellError> {
let mut exprs: Vec<hir::Expression> = vec![];
@ -43,7 +43,7 @@ pub enum SyntaxType {
pub fn baseline_parse_next_expr(
tokens: &mut TokensIterator,
registry: &dyn CommandRegistry,
registry: &CommandRegistry,
source: &Text,
syntax_type: SyntaxType,
) -> Result<hir::Expression, ShellError> {
@ -176,7 +176,7 @@ pub fn baseline_parse_next_expr(
pub fn baseline_parse_semantic_token(
token: &TokenNode,
registry: &dyn CommandRegistry,
registry: &CommandRegistry,
source: &Text,
) -> Result<hir::Expression, ShellError> {
match token {
@ -197,7 +197,7 @@ pub fn baseline_parse_semantic_token(
pub fn baseline_parse_delimited(
token: &Spanned<DelimitedNode>,
registry: &dyn CommandRegistry,
registry: &CommandRegistry,
source: &Text,
) -> Result<hir::Expression, ShellError> {
match token.delimiter() {
@ -216,7 +216,7 @@ pub fn baseline_parse_delimited(
pub fn baseline_parse_path(
token: &Spanned<PathNode>,
registry: &dyn CommandRegistry,
registry: &CommandRegistry,
source: &Text,
) -> Result<hir::Expression, ShellError> {
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::prelude::*;
use derive_new::new;
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"]
pub struct Binary {
left: Expression,
op: Spanned<Operator>,
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::{Flag, Span};
use crate::prelude::*;
use derive_new::new;
use indexmap::IndexMap;
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 {
AbsentSwitch,
PresentSwitch(Span),
@ -12,12 +15,27 @@ pub enum NamedValue {
Value(Expression),
}
#[derive(Debug, Clone, Eq, PartialEq, new)]
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, new)]
pub struct NamedArguments {
#[new(default)]
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 {
pub fn insert_switch(&mut self, name: impl Into<String>, switch: Option<Flag>) {
let name = name.into();

View File

@ -1,10 +1,27 @@
use crate::parser::{hir::Expression, Spanned};
use crate::prelude::*;
use derive_new::new;
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"]
pub struct Path {
head: Expression,
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 std::fmt;
use std::str::FromStr;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
@ -11,6 +13,12 @@ pub enum Operator {
GreaterThanOrEqual,
}
impl ToDebug for Operator {
fn fmt_debug(&self, f: &mut fmt::Formatter, _source: &str) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl Operator {
#[allow(unused)]
pub fn print(&self) -> String {

View File

@ -1,3 +1,4 @@
use crate::prelude::*;
use crate::Text;
use derive_new::new;
use getset::Getters;
@ -14,6 +15,12 @@ pub struct Spanned<T> {
pub item: T,
}
impl<T> HasSpan for Spanned<T> {
fn span(&self) -> Span {
self.span
}
}
impl<T> Spanned<T> {
pub fn spanned(self, span: impl Into<Span>) -> Spanned<T> {
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::hash::Hash;
use std::hash::Hasher;
@ -202,3 +203,21 @@ where
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(
config: &CommandConfig,
registry: &dyn CommandRegistry,
registry: &CommandRegistry,
call: &Spanned<CallNode>,
source: &Text,
) -> Result<hir::Call, ShellError> {
@ -63,7 +63,7 @@ fn parse_command_head(head: &TokenNode) -> Result<hir::Expression, ShellError> {
fn parse_command_tail(
config: &CommandConfig,
registry: &dyn CommandRegistry,
registry: &CommandRegistry,
tail: Option<Vec<TokenNode>>,
source: &Text,
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::parser::{hir, hir::SyntaxType, parse_command, CallNode, Spanned};
use crate::prelude::*;
@ -80,17 +82,17 @@ pub struct CommandConfig {
}
#[derive(Debug, Default, new, Serialize, Deserialize)]
pub struct Args {
pub struct EvaluatedArgs {
pub positional: Option<Vec<Spanned<Value>>>,
pub named: Option<IndexMap<String, Spanned<Value>>>,
}
#[derive(new)]
pub struct DebugPositional<'a> {
pub struct DebugEvaluatedPositional<'a> {
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 {
match &self.positional {
None => write!(f, "None"),
@ -103,11 +105,11 @@ impl fmt::Debug for DebugPositional<'a> {
}
#[derive(new)]
pub struct DebugNamed<'a> {
pub struct DebugEvaluatedNamed<'a> {
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 {
match &self.named {
None => write!(f, "None"),
@ -119,24 +121,27 @@ impl fmt::Debug for DebugNamed<'a> {
}
}
pub struct DebugArgs<'a> {
args: &'a Args,
pub struct DebugEvaluatedArgs<'a> {
args: &'a EvaluatedArgs,
}
impl fmt::Debug for DebugArgs<'a> {
impl fmt::Debug for DebugEvaluatedArgs<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut s = f.debug_struct("Args");
s.field("positional", &DebugPositional::new(&self.args.positional));
s.field("named", &DebugNamed::new(&self.args.named));
s.field(
"positional",
&DebugEvaluatedPositional::new(&self.args.positional),
);
s.field("named", &DebugEvaluatedNamed::new(&self.args.named));
s.finish()
}
}
impl Args {
pub fn debug(&'a self) -> DebugArgs<'a> {
DebugArgs { args: self }
impl EvaluatedArgs {
pub fn debug(&'a self) -> DebugEvaluatedArgs<'a> {
DebugEvaluatedArgs { args: self }
}
pub fn nth(&self, pos: usize) -> Option<&Spanned<Value>> {
@ -205,92 +210,17 @@ impl Iterator for PositionalIter<'a> {
}
impl CommandConfig {
crate fn evaluate_args(
crate fn parse_args(
&self,
call: &Spanned<CallNode>,
registry: &dyn CommandRegistry,
scope: &Scope,
registry: &CommandRegistry,
source: &Text,
) -> Result<Args, ShellError> {
) -> Result<hir::Call, ShellError> {
let args = parse_command(self, registry, call, source)?;
trace!("parsed args: {:?}", args);
evaluate_args(args, registry, scope, source)
// 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 })
Ok(args)
}
#[allow(unused)]
@ -299,25 +229,25 @@ impl CommandConfig {
}
}
fn evaluate_args(
args: hir::Call,
registry: &dyn CommandRegistry,
crate fn evaluate_args(
call: &hir::Call,
registry: &CommandRegistry,
scope: &Scope,
source: &Text,
) -> Result<Args, ShellError> {
let positional: Result<Option<Vec<_>>, _> = args
) -> Result<EvaluatedArgs, ShellError> {
let positional: Result<Option<Vec<_>>, _> = call
.positional()
.as_ref()
.map(|p| {
p.iter()
.map(|e| evaluate_baseline_expr(e, &(), scope, source))
.map(|e| evaluate_baseline_expr(e, &CommandRegistry::empty(), scope, source))
.collect()
})
.transpose();
let positional = positional?;
let named: Result<Option<IndexMap<String, Spanned<Value>>>, ShellError> = args
let named: Result<Option<IndexMap<String, Spanned<Value>>>, ShellError> = call
.named()
.as_ref()
.map(|n| {
@ -348,15 +278,5 @@ fn evaluate_args(
let named = named?;
Ok(Args::new(positional, named))
}
pub trait CommandRegistry {
fn get(&self, name: &str) -> Option<CommandConfig>;
}
impl CommandRegistry for () {
fn get(&self, _name: &str) -> Option<CommandConfig> {
None
}
Ok(EvaluatedArgs::new(positional, named))
}

View File

@ -34,9 +34,10 @@ macro_rules! trace_stream {
crate use crate::cli::MaybeOwned;
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::{Environment, Host};
crate use crate::errors::ShellError;
@ -44,10 +45,10 @@ crate use crate::object::types::ExtractType;
crate use crate::object::{Primitive, Value};
crate use crate::parser::{Span, Spanned, SpannedItem};
crate use crate::stream::{InputStream, OutputStream};
crate use crate::traits::{HasSpan, ToDebug};
crate use crate::Text;
crate use futures::stream::BoxStream;
crate use futures::Stream;
crate use futures::{FutureExt, StreamExt};
crate use futures::{FutureExt, Stream, StreamExt};
crate use std::collections::VecDeque;
crate use std::future::Future;
crate use std::sync::{Arc, Mutex};

View File

@ -1,4 +1,6 @@
use crate::context::CommandRegistry;
use crate::prelude::*;
use derive_new::new;
use rustyline::completion::Completer;
use rustyline::completion::{self, FilenameCompleter};
@ -7,7 +9,7 @@ use rustyline::line_buffer::LineBuffer;
#[derive(new)]
crate struct NuCompleter {
pub file_completer: FilenameCompleter,
pub commands: indexmap::IndexMap<String, Arc<dyn Command>>,
pub commands: CommandRegistry,
}
impl Completer for NuCompleter {
@ -19,7 +21,7 @@ impl Completer for NuCompleter {
pos: usize,
context: &rustyline::Context,
) -> 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;

View File

@ -18,7 +18,7 @@ crate struct Helper {
}
impl Helper {
crate fn new(commands: indexmap::IndexMap<String, Arc<dyn Command>>) -> Helper {
crate fn new(commands: CommandRegistry) -> Helper {
Helper {
completer: NuCompleter {
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_rules! nu {
($out:ident, $cwd:expr, $commands:expr) => {
pub use std::error::Error;
pub use std::io::prelude::*;
pub use std::process::{Command, Stdio};
pub use std::error::Error;
let commands = &*format!(
"
@ -93,10 +93,11 @@ pub fn setup_playground_for(topic: &str) -> (String, 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 contents = String::new();
file.read_to_string(&mut contents).expect("can not read file");
contents
let mut file = std::fs::File::open(full_path).expect("can not open file");
let mut contents = String::new();
file.read_to_string(&mut contents)
.expect("can not read file");
contents
}
pub fn create_file_at(full_path: &str) {
@ -112,7 +113,14 @@ pub fn delete_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 {