From 34033afce414cb919b69a82640c96304960a0c76 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Wed, 3 Jul 2019 13:31:15 -0700 Subject: [PATCH 01/10] WIP improve error infrastructure Also simplify commands and reduce papercuts --- src/cli.rs | 10 +- src/commands.rs | 5 + src/commands/cd.rs | 10 +- src/commands/classified.rs | 69 +++++--- src/commands/clip.rs | 22 +-- src/commands/command.rs | 28 ++- src/commands/config.rs | 40 ++--- src/commands/enter.rs | 37 ++-- src/commands/exit.rs | 4 +- src/commands/first.rs | 5 +- src/commands/from_ini.rs | 21 ++- src/commands/from_json.rs | 21 ++- src/commands/from_toml.rs | 21 ++- src/commands/from_xml.rs | 21 ++- src/commands/from_yaml.rs | 21 ++- src/commands/get.rs | 23 +-- src/commands/lines.rs | 17 +- src/commands/ls.rs | 16 +- src/commands/macros.rs | 326 +++++++++++++++++++++++++++++++++++ src/commands/open.rs | 159 +++++++---------- src/commands/pick.rs | 7 +- src/commands/plugin.rs | 15 +- src/commands/ps.rs | 4 +- src/commands/reject.rs | 6 +- src/commands/size.rs | 4 +- src/commands/skip_while.rs | 7 +- src/commands/sort_by.rs | 9 +- src/commands/split_column.rs | 15 +- src/commands/split_row.rs | 17 +- src/commands/sysinfo.rs | 4 +- src/commands/to_array.rs | 7 +- src/commands/to_json.rs | 14 +- src/commands/to_toml.rs | 11 +- src/commands/trim.rs | 9 +- src/commands/view.rs | 2 +- src/commands/where_.rs | 64 ++----- src/errors.rs | 37 +++- src/format/tree.rs | 1 - src/lib.rs | 7 +- src/object/base.rs | 74 ++++++-- src/parser/parse/files.rs | 2 +- src/parser/parse_command.rs | 91 +++++----- src/parser/registry.rs | 31 +++- src/plugins/inc.rs | 100 +++++++---- src/prelude.rs | 75 +++++++- src/stream.rs | 118 ++++++++++++- 46 files changed, 1087 insertions(+), 520 deletions(-) create mode 100644 src/commands/macros.rs diff --git a/src/cli.rs b/src/cli.rs index 864462cd8b..d54abc8c9e 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -159,6 +159,7 @@ pub async fn cli() -> Result<(), Box> { command("sysinfo", Box::new(sysinfo::sysinfo)), command("cd", Box::new(cd::cd)), command("view", Box::new(view::view)), + // command("skip", skip::Skip), command("first", Box::new(first::first)), command("size", Box::new(size::size)), command("from-ini", Box::new(from_ini::from_ini)), @@ -167,7 +168,6 @@ pub async fn cli() -> Result<(), Box> { 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("enter", Box::new(enter::enter)), command("exit", Box::new(exit::exit)), command("lines", Box::new(lines::lines)), command("pick", Box::new(pick::pick)), @@ -180,11 +180,15 @@ pub async fn cli() -> Result<(), Box> { command("to-json", Box::new(to_json::to_json)), command("to-toml", Box::new(to_toml::to_toml)), command("sort-by", Box::new(sort_by::sort_by)), + command("sort-by", Box::new(sort_by::sort_by)), + command("inc", |x| plugin::plugin("inc".into(), x)), + command("sum", |x| plugin::plugin("sum".into(), x)), Arc::new(Open), Arc::new(Where), Arc::new(Config), Arc::new(SkipWhile), - command("sort-by", Box::new(sort_by::sort_by)), + Arc::new(Enter), + Arc::new(Skip), ]); context.add_sinks(vec![ @@ -392,7 +396,7 @@ async fn process_line(readline: Result, ctx: &mut Context } (Some(ClassifiedCommand::Sink(left)), None) => { - let input_vec: Vec = input.objects.collect().await; + let input_vec: Vec = input.objects.into_vec().await; if let Err(err) = left.run(ctx, input_vec) { return LineResult::Error(line.clone(), err); } diff --git a/src/commands.rs b/src/commands.rs index 551291fcfb..20121eb3f8 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,3 +1,6 @@ +#[macro_use] +crate mod macros; + crate mod args; crate mod autoview; crate mod cd; @@ -39,6 +42,8 @@ crate mod where_; crate use command::command; crate use config::Config; +crate use enter::Enter; crate use open::Open; +crate use skip::Skip; crate use skip_while::SkipWhile; crate use where_::Where; diff --git a/src/commands/cd.rs b/src/commands/cd.rs index 3472e2a54c..7df0f9b3be 100644 --- a/src/commands/cd.rs +++ b/src/commands/cd.rs @@ -52,14 +52,14 @@ pub fn cd(args: CommandArgs) -> Result { } } } - stream.push_back(ReturnValue::change_cwd(path)); - Ok(stream.boxed()) + stream.push_back(ReturnSuccess::change_cwd(path)); + Ok(stream.into()) } _ => { let mut stream = VecDeque::new(); match args.nth(0) { None => { - stream.push_back(ReturnValue::change_cwd(PathBuf::from("/"))); + stream.push_back(ReturnSuccess::change_cwd(PathBuf::from("/"))); } Some(v) => { let mut cwd = latest.path().to_path_buf(); @@ -75,10 +75,10 @@ pub fn cd(args: CommandArgs) -> Result { } }, } - stream.push_back(ReturnValue::change_cwd(cwd)); + stream.push_back(ReturnSuccess::change_cwd(cwd)); } }; - Ok(stream.boxed()) + Ok(stream.into()) } } } diff --git a/src/commands/classified.rs b/src/commands/classified.rs index 8ebb1b0cca..8ac0f5fe10 100644 --- a/src/commands/classified.rs +++ b/src/commands/classified.rs @@ -54,21 +54,39 @@ crate struct ClassifiedInputStream { impl ClassifiedInputStream { crate fn new() -> ClassifiedInputStream { ClassifiedInputStream { - objects: VecDeque::new().boxed(), + objects: VecDeque::new().into(), stdin: None, } } - crate fn from_input_stream(stream: InputStream) -> ClassifiedInputStream { + pub fn into_vec(self) -> impl std::future::Future> { + self.objects.into_vec() + } + + crate fn from_vec(stream: VecDeque) -> ClassifiedInputStream { ClassifiedInputStream { - objects: stream, + objects: stream.into(), + stdin: None, + } + } + + crate fn from_list(stream: Vec) -> ClassifiedInputStream { + ClassifiedInputStream { + objects: stream.into(), + stdin: None, + } + } + + crate fn from_input_stream(stream: impl Into) -> ClassifiedInputStream { + ClassifiedInputStream { + objects: stream.into(), stdin: None, } } crate fn from_stdout(stdout: std::fs::File) -> ClassifiedInputStream { ClassifiedInputStream { - objects: VecDeque::new().boxed(), + objects: VecDeque::new().into(), stdin: Some(stdout), } } @@ -110,31 +128,23 @@ impl InternalCommand { context: &mut Context, input: ClassifiedInputStream, ) -> Result { - let objects = if log_enabled!(log::Level::Trace) { + if log_enabled!(log::Level::Trace) { trace!("->"); trace!("{}", self.command.name()); trace!("{:?}", self.args.debug()); - let objects: Vec<_> = input.objects.collect().await; - trace!( - "input = {:#?}", - objects.iter().map(|o| o.debug()).collect::>(), - ); - VecDeque::from(objects).boxed() - } else { - input.objects - }; + } - let mut result = + let objects: InputStream = trace_stream!("input" = input.objects); + + let result = context.run_command(self.command, self.name_span.clone(), self.args, objects)?; + let mut result = result.values; + let mut stream = VecDeque::new(); while let Some(item) = result.next().await { - match item { - ReturnValue::Value(Value::Error(err)) => { - return Err(*err); - } - - ReturnValue::Action(action) => match action { + match item? { + ReturnSuccess::Action(action) => match action { CommandAction::ChangePath(path) => { context.env.lock().unwrap().back_mut().map(|x| { x.path = path; @@ -158,12 +168,13 @@ impl InternalCommand { }, }, - ReturnValue::Value(v) => { + ReturnSuccess::Value(v) => { stream.push_back(v); } } } - Ok(stream.boxed() as InputStream) + + Ok(stream.into()) } } @@ -187,9 +198,11 @@ impl ExternalCommand { input: ClassifiedInputStream, stream_next: StreamNext, ) -> Result { - let inputs: Vec = input.objects.collect().await; + let stdin = input.stdin; + let inputs: Vec = input.objects.into_vec().await; - trace!("{:?} -> {}", inputs, self.name); + trace!("-> {}", self.name); + trace!("inputs = {:?}", inputs); let mut arg_string = format!("{}", self.name); for arg in &self.args { @@ -298,7 +311,7 @@ impl ExternalCommand { } }; - if let Some(stdin) = input.stdin { + if let Some(stdin) = stdin { process = process.stdin(stdin); } @@ -318,7 +331,9 @@ impl ExternalCommand { let file = futures::io::AllowStdIo::new(stdout); let stream = Framed::new(file, LinesCodec {}); let stream = stream.map(|line| Value::string(line.unwrap())); - Ok(ClassifiedInputStream::from_input_stream(stream.boxed())) + Ok(ClassifiedInputStream::from_input_stream( + stream.boxed() as BoxStream<'static, Value> + )) } } } diff --git a/src/commands/clip.rs b/src/commands/clip.rs index a55e7119b1..96b6b7081e 100644 --- a/src/commands/clip.rs +++ b/src/commands/clip.rs @@ -1,10 +1,11 @@ use crate::commands::command::SinkCommandArgs; -use crate::errors::ShellError; +use crate::errors::{labelled, ShellError}; use clipboard::{ClipboardContext, ClipboardProvider}; pub fn clip(args: SinkCommandArgs) -> Result<(), ShellError> { let mut clip_context: ClipboardContext = ClipboardProvider::new().unwrap(); let mut new_copy_data = String::new(); + if args.input.len() > 0 { let mut first = true; for i in args.input.iter() { @@ -13,18 +14,17 @@ pub fn clip(args: SinkCommandArgs) -> Result<(), ShellError> { } else { first = false; } - match i.as_string() { - Ok(s) => new_copy_data.push_str(&s), - Err(_) => { - return Err(ShellError::maybe_labeled_error( - "Given non-string data", - "expected strings from pipeline", - args.name_span, - )) - } - } + + let string = i.as_string().map_err(labelled( + args.name_span, + "Given non-string data", + "expected strings from pipeline", + ))?; + + new_copy_data.push_str(&string); } } + clip_context.set_contents(new_copy_data).unwrap(); Ok(()) diff --git a/src/commands/command.rs b/src/commands/command.rs index 31d5723284..7d51cd38f2 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -7,7 +7,7 @@ use crate::parser::{ use crate::prelude::*; use getset::Getters; use serde::{Deserialize, Serialize}; -use std::path::PathBuf; +use std::{ops::Try, path::PathBuf}; #[derive(Getters)] #[get = "crate"] @@ -60,14 +60,26 @@ pub enum CommandAction { } #[derive(Debug, Serialize, Deserialize)] -pub enum ReturnValue { +pub enum ReturnSuccess { Value(Value), Action(CommandAction), } -impl ReturnValue { - crate fn change_cwd(path: PathBuf) -> ReturnValue { - ReturnValue::Action(CommandAction::ChangePath(path)) +pub type ReturnValue = Result; + +impl From for ReturnValue { + fn from(input: Value) -> ReturnValue { + Ok(ReturnSuccess::Value(input)) + } +} + +impl ReturnSuccess { + pub fn change_cwd(path: PathBuf) -> ReturnValue { + Ok(ReturnSuccess::Action(CommandAction::ChangePath(path))) + } + + pub fn value(input: Value) -> ReturnValue { + Ok(ReturnSuccess::Value(input)) } } @@ -78,8 +90,7 @@ pub trait Command { fn config(&self) -> registry::CommandConfig { registry::CommandConfig { name: self.name().to_string(), - mandatory_positional: vec![], - optional_positional: vec![], + positional: vec![], rest_positional: true, named: indexmap::IndexMap::new(), is_filter: true, @@ -97,8 +108,7 @@ pub trait Sink { fn config(&self) -> registry::CommandConfig { registry::CommandConfig { name: self.name().to_string(), - mandatory_positional: vec![], - optional_positional: vec![], + positional: vec![], rest_positional: true, named: indexmap::IndexMap::new(), is_filter: false, diff --git a/src/commands/config.rs b/src/commands/config.rs index d4c793e7ca..313d2f93be 100644 --- a/src/commands/config.rs +++ b/src/commands/config.rs @@ -1,10 +1,13 @@ +#[macro_use] +use crate::prelude::*; + use crate::errors::ShellError; use crate::object::config; use crate::object::Value; use crate::parser::registry::{CommandConfig, NamedType, NamedValue}; -use crate::prelude::*; use indexmap::IndexMap; use log::trace; +use std::iter::FromIterator; pub struct Config; @@ -29,8 +32,7 @@ impl Command for Config { CommandConfig { name: self.name().to_string(), - mandatory_positional: vec![], - optional_positional: vec![], + positional: vec![], rest_positional: false, named, is_sink: true, @@ -54,8 +56,7 @@ pub fn config(args: CommandArgs) -> Result { .ok_or_else(|| ShellError::string(&format!("Missing key {} in config", key)))?; return Ok( - futures::stream::once(futures::future::ready(ReturnValue::Value(value.clone()))) - .boxed(), + vec![value.clone()].into(), // futures::stream::once(futures::future::ready(ReturnSuccess::Value(value.clone()))).into(), ); } @@ -65,12 +66,7 @@ pub fn config(args: CommandArgs) -> Result { config::write_config(&result)?; - return Ok( - futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object( - result.into(), - )))) - .boxed(), - ); + return Ok(stream![Value::Object(result.into())].from_input_stream()); } } @@ -79,12 +75,7 @@ pub fn config(args: CommandArgs) -> Result { config::write_config(&result)?; - return Ok( - futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object( - result.into(), - )))) - .boxed(), - ); + return Ok(stream![Value::Object(result.into())].from_input_stream()); } if let Some(v) = args.get("remove") { @@ -99,21 +90,12 @@ pub fn config(args: CommandArgs) -> Result { ))); } - return Ok( - futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object( - result.into(), - )))) - .boxed(), - ); + let obj = VecDeque::from_iter(vec![Value::Object(result.into())]); + return Ok(obj.from_input_stream()); } if args.len() == 0 { - return Ok( - futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object( - result.into(), - )))) - .boxed(), - ); + return Ok(vec![Value::Object(result.into())].into()); } Err(ShellError::string(format!("Unimplemented"))) diff --git a/src/commands/enter.rs b/src/commands/enter.rs index d8eba93c9a..8b6f547e6b 100644 --- a/src/commands/enter.rs +++ b/src/commands/enter.rs @@ -2,9 +2,31 @@ use crate::commands::command::CommandAction; use crate::commands::open::{fetch, parse_as_value}; use crate::errors::ShellError; use crate::object::{Primitive, Value}; +use crate::parser::registry::{CommandConfig, PositionalType}; use crate::prelude::*; use std::path::PathBuf; +pub struct Enter; + +impl Command for Enter { + fn config(&self) -> CommandConfig { + CommandConfig { + name: self.name().to_string(), + positional: vec![PositionalType::mandatory("path", "Block")], + rest_positional: false, + named: indexmap::IndexMap::new(), + } + } + + fn name(&self) -> &str { + "enter" + } + + fn run(&self, args: CommandArgs) -> Result { + enter(args) + } +} + pub fn enter(args: CommandArgs) -> Result { if args.len() == 0 { return Err(ShellError::maybe_labeled_error( @@ -67,16 +89,9 @@ pub fn enter(args: CommandArgs) -> Result { } }; - match contents { - Value::Primitive(Primitive::String(x)) => { - stream.push_back(ReturnValue::Action(CommandAction::Enter(parse_as_value( - file_extension, - x, - span, - )?))); - } - x => stream.push_back(ReturnValue::Action(CommandAction::Enter(x))), - } + stream.push_back(Ok(ReturnSuccess::Action(CommandAction::Enter( + parse_as_value(file_extension, contents, span)?, + )))); - Ok(stream.boxed()) + Ok(stream.into()) } diff --git a/src/commands/exit.rs b/src/commands/exit.rs index 27438f6654..64cddfcfb9 100644 --- a/src/commands/exit.rs +++ b/src/commands/exit.rs @@ -3,7 +3,5 @@ use crate::errors::ShellError; use crate::prelude::*; pub fn exit(_args: CommandArgs) -> Result { - let mut stream = VecDeque::new(); - stream.push_back(ReturnValue::Action(CommandAction::Exit)); - Ok(stream.boxed()) + Ok(vec![Ok(ReturnSuccess::Action(CommandAction::Exit))].into()) } diff --git a/src/commands/first.rs b/src/commands/first.rs index 68831eeaea..5a466a8cd5 100644 --- a/src/commands/first.rs +++ b/src/commands/first.rs @@ -27,8 +27,5 @@ pub fn first(args: CommandArgs) -> Result { let input = args.input; - Ok(input - .take(amount as u64) - .map(|v| ReturnValue::Value(v)) - .boxed()) + Ok(OutputStream::from_input(input.values.take(amount as u64))) } diff --git a/src/commands/from_ini.rs b/src/commands/from_ini.rs index 4e8701d98e..7fa5dc3a59 100644 --- a/src/commands/from_ini.rs +++ b/src/commands/from_ini.rs @@ -30,22 +30,21 @@ pub fn from_ini(args: CommandArgs) -> Result { let out = args.input; let span = args.name_span; Ok(out + .values .map(move |a| match a { Value::Primitive(Primitive::String(s)) => match from_ini_string_to_value(s) { - Ok(x) => ReturnValue::Value(x), - Err(e) => { - ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( - "Could not parse as INI", - format!("{:#?}", e), - span, - )))) - } + Ok(x) => Ok(ReturnSuccess::Value(x)), + Err(e) => Err(ShellError::maybe_labeled_error( + "Could not parse as INI", + format!("{:#?}", e), + span, + )), }, - _ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( + _ => Err(ShellError::maybe_labeled_error( "Expected string values from pipeline", "expects strings from pipeline", span, - )))), + )), }) - .boxed()) + .to_output_stream()) } diff --git a/src/commands/from_json.rs b/src/commands/from_json.rs index e85d19d684..cb1610b769 100644 --- a/src/commands/from_json.rs +++ b/src/commands/from_json.rs @@ -34,22 +34,21 @@ pub fn from_json(args: CommandArgs) -> Result { let out = args.input; let span = args.name_span; Ok(out + .values .map(move |a| match a { Value::Primitive(Primitive::String(s)) => match from_json_string_to_value(s) { - Ok(x) => ReturnValue::Value(x), - Err(_) => { - ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( - "Could not parse as JSON", - "piped data failed JSON parse", - span, - )))) - } + Ok(x) => ReturnSuccess::value(x), + Err(_) => Err(ShellError::maybe_labeled_error( + "Could not parse as JSON", + "piped data failed JSON parse", + span, + )), }, - _ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( + _ => Err(ShellError::maybe_labeled_error( "Expected string values from pipeline", "expects strings from pipeline", span, - )))), + )), }) - .boxed()) + .to_output_stream()) } diff --git a/src/commands/from_toml.rs b/src/commands/from_toml.rs index 5d1bb9a0c0..b50b09da39 100644 --- a/src/commands/from_toml.rs +++ b/src/commands/from_toml.rs @@ -33,22 +33,21 @@ pub fn from_toml(args: CommandArgs) -> Result { let out = args.input; let span = args.name_span; Ok(out + .values .map(move |a| match a { Value::Primitive(Primitive::String(s)) => match from_toml_string_to_value(s) { - Ok(x) => ReturnValue::Value(x), - Err(_) => { - ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( - "Could not parse as TOML", - "piped data failed TOML parse", - span, - )))) - } + Ok(x) => ReturnSuccess::value(x), + Err(_) => Err(ShellError::maybe_labeled_error( + "Could not parse as TOML", + "piped data failed TOML parse", + span, + )), }, - _ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( + _ => Err(ShellError::maybe_labeled_error( "Expected string values from pipeline", "expects strings from pipeline", span, - )))), + )), }) - .boxed()) + .to_output_stream()) } diff --git a/src/commands/from_xml.rs b/src/commands/from_xml.rs index d7c8091f8e..a1b1a14d76 100644 --- a/src/commands/from_xml.rs +++ b/src/commands/from_xml.rs @@ -52,22 +52,21 @@ pub fn from_xml(args: CommandArgs) -> Result { let out = args.input; let span = args.name_span; Ok(out + .values .map(move |a| match a { Value::Primitive(Primitive::String(s)) => match from_xml_string_to_value(s) { - Ok(x) => ReturnValue::Value(x), - Err(_) => { - ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( - "Could not parse as XML", - "piped data failed XML parse", - span, - )))) - } + Ok(x) => ReturnSuccess::value(x), + Err(_) => Err(ShellError::maybe_labeled_error( + "Could not parse as XML", + "piped data failed XML parse", + span, + )), }, - _ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( + _ => Err(ShellError::maybe_labeled_error( "Expected string values from pipeline", "expects strings from pipeline", span, - )))), + )), }) - .boxed()) + .to_output_stream()) } diff --git a/src/commands/from_yaml.rs b/src/commands/from_yaml.rs index 2a07d47d1f..8647f79904 100644 --- a/src/commands/from_yaml.rs +++ b/src/commands/from_yaml.rs @@ -43,22 +43,21 @@ pub fn from_yaml(args: CommandArgs) -> Result { let out = args.input; let span = args.name_span; Ok(out + .values .map(move |a| match a { Value::Primitive(Primitive::String(s)) => match from_yaml_string_to_value(s) { - Ok(x) => ReturnValue::Value(x), - Err(_) => { - ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( - "Could not parse as YAML", - "piped data failed YAML parse", - span, - )))) - } + Ok(x) => ReturnSuccess::value(x), + Err(_) => Err(ShellError::maybe_labeled_error( + "Could not parse as YAML", + "piped data failed YAML parse", + span, + )), }, - _ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( + _ => Err(ShellError::maybe_labeled_error( "Expected string values from pipeline", "expects strings from pipeline", span, - )))), + )), }) - .boxed()) + .to_output_stream()) } diff --git a/src/commands/get.rs b/src/commands/get.rs index 8173b02ef7..f022f8e930 100644 --- a/src/commands/get.rs +++ b/src/commands/get.rs @@ -3,22 +3,22 @@ use crate::object::Value; use crate::parser::Span; use crate::prelude::*; -fn get_member(path: &str, span: Span, obj: &Value) -> Option { +fn get_member(path: &str, span: Span, obj: &Value) -> Result { let mut current = obj; for p in path.split(".") { match current.get_data_by_key(p) { Some(v) => current = v, None => { - return Some(Value::Error(Box::new(ShellError::labeled_error( + return Err(ShellError::labeled_error( "Unknown field", "object missing field", span, - )))); + )); } } } - Some(current.copy()) + Ok(current.copy()) } pub fn get(args: CommandArgs) -> Result { @@ -36,10 +36,10 @@ pub fn get(args: CommandArgs) -> Result { if let Ok(amount) = amount { return Ok(args .input + .values .skip(amount as u64) .take(1) - .map(|v| ReturnValue::Value(v)) - .boxed()); + .from_input_stream()); } let fields: Result, _> = args @@ -51,17 +51,18 @@ pub fn get(args: CommandArgs) -> Result { let stream = args .input + .values .map(move |item| { let mut result = VecDeque::new(); for field in &fields { match get_member(&field.0, field.1, &item) { - Some(Value::List(l)) => { + Ok(Value::List(l)) => { for item in l { - result.push_back(ReturnValue::Value(item.copy())); + result.push_back(ReturnSuccess::value(item.copy())); } } - Some(x) => result.push_back(ReturnValue::Value(x.copy())), - None => {} + Ok(x) => result.push_back(ReturnSuccess::value(x.copy())), + Err(_) => {} } } @@ -69,5 +70,5 @@ pub fn get(args: CommandArgs) -> Result { }) .flatten(); - Ok(stream.boxed()) + Ok(stream.to_output_stream()) } diff --git a/src/commands/lines.rs b/src/commands/lines.rs index 933268758a..7f1ae850f2 100644 --- a/src/commands/lines.rs +++ b/src/commands/lines.rs @@ -10,6 +10,7 @@ pub fn lines(args: CommandArgs) -> Result { let span = args.name_span; let stream = input + .values .map(move |v| match v { Value::Primitive(Primitive::String(s)) => { let split_result: Vec<_> = s.lines().filter(|s| s.trim() != "").collect(); @@ -18,7 +19,7 @@ pub fn lines(args: CommandArgs) -> Result { let mut result = VecDeque::new(); for s in split_result { - result.push_back(ReturnValue::Value(Value::Primitive(Primitive::String( + result.push_back(ReturnSuccess::value(Value::Primitive(Primitive::String( s.into(), )))); } @@ -26,17 +27,15 @@ pub fn lines(args: CommandArgs) -> Result { } _ => { let mut result = VecDeque::new(); - result.push_back(ReturnValue::Value(Value::Error(Box::new( - ShellError::maybe_labeled_error( - "Expected string values from pipeline", - "expects strings from pipeline", - span, - ), - )))); + result.push_back(Err(ShellError::maybe_labeled_error( + "Expected string values from pipeline", + "expects strings from pipeline", + span, + ))); result } }) .flatten(); - Ok(stream.boxed()) + Ok(stream.to_output_stream()) } diff --git a/src/commands/ls.rs b/src/commands/ls.rs index a0ff1f5f6e..e23080ae8d 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -45,9 +45,9 @@ pub fn ls(args: CommandArgs) -> Result { for entry in entries { let value = Value::Object(dir_entry_dict(&entry?)?); - shell_entries.push_back(ReturnValue::Value(value)) + shell_entries.push_back(ReturnSuccess::value(value)) } - Ok(shell_entries.boxed()) + Ok(shell_entries.to_output_stream()) } _ => { let mut entries = VecDeque::new(); @@ -97,7 +97,11 @@ pub fn ls(args: CommandArgs) -> Result { return Err(ShellError::maybe_labeled_error( "Index not closed", format!("path missing closing ']'"), - if args.len() > 0 { Some(args.nth(0).unwrap().span) } else { args.name_span }, + if args.len() > 0 { + Some(args.nth(0).unwrap().span) + } else { + args.name_span + }, )) } } @@ -123,14 +127,14 @@ pub fn ls(args: CommandArgs) -> Result { match viewed { Value::List(l) => { for item in l { - entries.push_back(ReturnValue::Value(item.copy())); + entries.push_back(ReturnSuccess::value(item.copy())); } } x => { - entries.push_back(ReturnValue::Value(x.clone())); + entries.push_back(ReturnSuccess::value(x.clone())); } } - Ok(entries.boxed()) + Ok(entries.to_output_stream()) } } } diff --git a/src/commands/macros.rs b/src/commands/macros.rs new file mode 100644 index 0000000000..bb5e96d057 --- /dev/null +++ b/src/commands/macros.rs @@ -0,0 +1,326 @@ +#[macro_export] +macro_rules! command { + ( + Named { $export:tt $args:ident $body:block } + Positional { $($number:tt)* } + Rest {} + CommandConfig { + name: $config_name:tt, + mandatory_positional: vec![ $($mandatory_positional:tt)* ], + optional_positional: vec![ $($optional_positional:tt)* ], + rest_positional: $rest_positional:tt, + named: { + $( + ($named_param:tt : $named_type:tt) + )* + } + } + + Function { + $( ( $param_name:tt : $param_type:tt ) )* + } + + Extract { + $($extract:tt)* + } + ) => { + #[allow(non_camel_case_types)] + pub struct $export; + + impl Command for $export { + fn run(&self, $args: CommandArgs) -> Result { + fn command($args: CommandArgs, ( $($param_name),*, ): ( $($param_type),*, )) -> Result { + let output = $body; + + Ok(output.boxed().to_output_stream()) + } + + let tuple = ( $($extract),*, ); + command( $args, tuple ) + } + + fn name(&self) -> &str { + stringify!($config_name) + } + + fn config(&self) -> $crate::parser::registry::CommandConfig { + $crate::parser::registry::CommandConfig { + name: self.name().to_string(), + positional: vec![$($mandatory_positional)*], + rest_positional: false, + named: { + use $crate::parser::registry::{NamedType, NamedValue}; + + #[allow(unused_mut)] + let mut named: indexmap::IndexMap = indexmap::IndexMap::new(); + + $( + named.insert(stringify!($named_param).to_string(), NamedType::$named_type); + )* + + named + } + } + } + } + }; + + // switch + ( + Named { $export:tt $args:ident $body:block } + Positional { $($positional_count:tt)* } + Rest { , -- $param_name:ident : Switch $($rest:tt)* } + CommandConfig { + name: $config_name:tt, + mandatory_positional: vec![ $($mandatory_positional:tt)* ], + optional_positional: vec![ $($optional_positional:tt)* ], + rest_positional: $rest_positional:tt, + named: { + $($config_named:tt)* + } + } + Function { + $($function:tt)* + } + Extract { + $($extract:tt)* + } + ) => { + command!( + Named { $export $args $body } + Positional { $($positional_count)* + 1 } + Rest { $($rest)* } + CommandConfig { + name: $config_name, + mandatory_positional: vec![ $($mandatory_positional)* ], + optional_positional: vec![ $($optional_positional)* ], + rest_positional: $rest_positional, + named: { + $($config_named)* + ($param_name : Switch) + } + } + + Function { + $($function)* ($param_name : Switch) + } + + Extract { + ($($extract)* { + use std::convert::TryInto; + + $args.get(stringify!($param_name)).clone().try_into()? + }) + } + ); + }; + + // mandatory named arguments + ( + Named { $export:tt $args:ident $body:block } + Positional { $($positional_count:tt)* } + Rest { , -- $param_name:ident : $param_kind:tt $($rest:tt)* } + CommandConfig { + name: $config_name:tt, + mandatory_positional: vec![ $($mandatory_positional:tt)* ], + optional_positional: vec![ $($optional_positional:tt)* ], + rest_positional: $rest_positional:tt, + named: { + $($config_named:tt)* + } + } + Function { + $($function:tt)* + } + Extract { + $($extract:tt)* + } + ) => { + command!( + Named { $export $args $body } + Positional { $($positional_count)* + 1 } + Rest { $($rest)* } + CommandConfig { + name: $config_name, + mandatory_positional: vec![ $($mandatory_positional)* ], + optional_positional: vec![ $($optional_positional)* ], + rest_positional: $rest_positional, + named: { + $($config_named)* + ($param_name : Mandatory(NamedValue::Single)) + } + } + + Function { + $($function)* ($param_name : $param_kind) + } + + Extract { + ($($extract)* { + use std::convert::TryInto; + + $args.get(stringify!($param_name)).clone().try_into()? + }) + } + ); + }; + + // optional named arguments + ( + Named { $export:tt $args:ident $body:block } + Positional { $($positional_count:tt)* } + Rest { , -- $param_name:ident ? : $param_kind:tt $($rest:tt)* } + CommandConfig { + name: $config_name:tt, + mandatory_positional: vec![ $($mandatory_positional:tt)* ], + optional_positional: vec![ $($optional_positional:tt)* ], + rest_positional: $rest_positional:tt, + named: { + $($config_named:tt)* + } + } + Function { + $($function:tt)* + } + Extract { + $($extract:tt)* + } + ) => { + command!( + Named { $export $args $body } + Positional { $($positional_count)* + 1 } + Rest { $($rest)* } + CommandConfig { + name: $config_name, + mandatory_positional: vec![ $($mandatory_positional)* ], + optional_positional: vec![ $($optional_positional)* ], + rest_positional: $rest_positional, + named: { + $($config_named)* + ($param_name : Optional(NamedValue::Single)) + } + } + + Function { + $($function)* ($param_name : $param_kind) + } + + Extract { + ($($extract)* { + use std::convert::TryInto; + + $args.get(stringify!($param_name)).clone().try_into()? + }) + } + ); + }; + + // mandatory positional argument + ( + Named { $export:ident $args:ident $body:block } + Positional { $($positional_count:tt)* } + Rest { , $param_name:ident : $param_kind:tt $($rest:tt)* } + CommandConfig { + name: $config_name:tt, + mandatory_positional: vec![ $($mandatory_positional:tt)* ], + optional_positional: vec![ $($optional_positional:tt)* ], + rest_positional: $rest_positional:tt, + named: { + $($config_named:tt)* + } + } + + Function { + $($function:tt)* + } + + Extract { + $($extract:tt)* + } + + ) => { + command!( + Named { $export $args $body } + Positional { $($positional_count)* + 1 } + Rest { $($rest)* } + CommandConfig { + name: $config_name, + mandatory_positional: vec![ $($mandatory_positional)* $crate::parser::registry::PositionalType::mandatory( + stringify!($param_name), stringify!($param_kind) + ), ], + optional_positional: vec![ $($optional_positional)* ], + rest_positional: $rest_positional, + named: { + $($config_named)* + } + } + + Function { + $($function)* ($param_name : $param_kind) + } + + Extract { + $($extract:tt)* { + use std::convert::TryInto; + $args.expect_nth($($positional_count)*)?.try_into()? + } + } + ); + }; + + ($export:ident as $config_name:tt ( $args:ident $($command_rest:tt)* ) $body:block) => { + command!( + Named { $export $args $body } + Positional { 0 } + Rest { $($command_rest)* } + CommandConfig { + name: $config_name, + mandatory_positional: vec![], + optional_positional: vec![], + rest_positional: false, + named: {} + } + + Function { + } + + Extract { + } + ); + }; + + // ($export:ident as $name:tt ( $args:ident, -- $param:ident : $kind:ident ) $body:block) => { + // #[allow(non_camel_case_types)] + // pub struct $export; + + // impl Command for $export { + // fn run(&self, $args: CommandArgs) -> Result { + // fn command($args: CommandArgs, $param: $kind) -> Result { + // $body + // } + + // use std::convert::TryInto; + + // let param = $args.get(stringify!($param)).try_into()?; + // command($args, param) + // } + + // fn name(&self) -> &str { + // stringify!($name) + // } + + // fn config(&self) -> CommandConfig { + // let mut named: IndexMap = IndexMap::new(); + // named.insert(stringify!($param).to_string(), NamedType::$kind); + + // CommandConfig { + // name: self.name().to_string(), + // mandatory_positional: vec![], + // optional_positional: vec![], + // rest_positional: false, + // named, + // } + // } + // } + // }; +} diff --git a/src/commands/open.rs b/src/commands/open.rs index 39227b0662..a37f5f37ef 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -1,38 +1,74 @@ use crate::errors::ShellError; -use crate::object::{Primitive, Value}; +use crate::object::{Primitive, Switch, Value}; use crate::parser::parse::span::Span; -use crate::parser::registry::{CommandConfig, NamedType}; +use crate::parser::registry::NamedType; use crate::prelude::*; -use indexmap::IndexMap; use mime::Mime; use std::path::{Path, PathBuf}; use std::str::FromStr; -pub struct Open; +command! { + Open as open(args, --raw: Switch) { + let span = args.name_span; -impl Command for Open { - fn run(&self, args: CommandArgs) -> Result { - open(args) - } - fn name(&self) -> &str { - "open" - } + let cwd = args + .env + .lock() + .unwrap() + .front() + .unwrap() + .path() + .to_path_buf(); - fn config(&self) -> CommandConfig { - let mut named: IndexMap = IndexMap::new(); - named.insert("raw".to_string(), NamedType::Switch); + let full_path = PathBuf::from(cwd); - CommandConfig { - name: self.name().to_string(), - mandatory_positional: vec![], - optional_positional: vec![], - rest_positional: false, - named, - is_filter: true, - is_sink: false, - can_load: vec![], - can_save: vec![], - } + let (file_extension, contents) = match &args.expect_nth(0)?.item { + Value::Primitive(Primitive::String(s)) => fetch(&full_path, s, args.expect_nth(0)?.span)?, + _ => { + return Err(ShellError::labeled_error( + "Expected string value for filename", + "expected filename", + args.expect_nth(0)?.span, + )); + } + }; + + let mut stream = VecDeque::new(); + + let file_extension = if raw.is_present() { + None + } else if args.has("json") { + Some("json".to_string()) + } else if args.has("xml") { + Some("xml".to_string()) + } else if args.has("ini") { + Some("ini".to_string()) + } else if args.has("yaml") { + Some("yaml".to_string()) + } else if args.has("toml") { + Some("toml".to_string()) + } else { + if let Some(ref named_args) = args.args.named { + for named in named_args.iter() { + return Err(ShellError::labeled_error( + "Unknown flag for open", + "unknown flag", + named.1.span.clone(), + )); + } + file_extension + } else { + file_extension + } + }; + + stream.push_back(ReturnSuccess::value(parse_as_value( + file_extension, + contents, + span, + )?)); + + stream } } @@ -40,7 +76,7 @@ pub fn fetch( cwd: &PathBuf, location: &str, span: Span, -) -> Result<(Option, Value), ShellError> { +) -> Result<(Option, String), ShellError> { let mut cwd = cwd.clone(); if location.starts_with("http:") || location.starts_with("https:") { let response = reqwest::get(location); @@ -168,74 +204,3 @@ pub fn parse_as_value( _ => Ok(Value::string(contents)), } } - -fn open(args: CommandArgs) -> Result { - if args.len() == 0 { - return Err(ShellError::maybe_labeled_error( - "Open requires a path or url", - "needs path or url", - args.name_span, - )); - } - - let span = args.name_span; - - let cwd = args - .env - .lock() - .unwrap() - .front() - .unwrap() - .path() - .to_path_buf(); - let full_path = PathBuf::from(cwd); - - let (file_extension, contents) = match &args.expect_nth(0)?.item { - Value::Primitive(Primitive::String(s)) => fetch(&full_path, s, args.expect_nth(0)?.span)?, - _ => { - return Err(ShellError::labeled_error( - "Expected string value for filename", - "expected filename", - args.expect_nth(0)?.span, - )); - } - }; - - let mut stream = VecDeque::new(); - - let file_extension = if args.has("raw") { - None - } else if args.has("json") { - Some("json".to_string()) - } else if args.has("xml") { - Some("xml".to_string()) - } else if args.has("ini") { - Some("ini".to_string()) - } else if args.has("yaml") { - Some("yaml".to_string()) - } else if args.has("toml") { - Some("toml".to_string()) - } else { - if let Some(ref named_args) = args.args.named { - for named in named_args.iter() { - return Err(ShellError::labeled_error( - "Unknown flag for open", - "unknown flag", - named.1.span.clone(), - )); - } - file_extension - } else { - file_extension - } - }; - - match contents { - Value::Primitive(Primitive::String(x)) => { - stream.push_back(ReturnValue::Value(parse_as_value(file_extension, x, span)?)); - } - x => stream.push_back(ReturnValue::Value(x)), - } - - Ok(stream.boxed()) -} diff --git a/src/commands/pick.rs b/src/commands/pick.rs index 12d2a271a4..0a1e209f20 100644 --- a/src/commands/pick.rs +++ b/src/commands/pick.rs @@ -17,9 +17,8 @@ pub fn pick(args: CommandArgs) -> Result { let objects = args .input - .map(move |item| Value::Object(select_fields(&item, &fields))) - .map(|item| ReturnValue::Value(item)); + .values + .map(move |item| Value::Object(select_fields(&item, &fields))); - let stream = Pin::new(Box::new(objects)); - Ok(stream) + Ok(objects.from_input_stream()) } diff --git a/src/commands/plugin.rs b/src/commands/plugin.rs index d7fa3f92d9..1ae9e989e3 100644 --- a/src/commands/plugin.rs +++ b/src/commands/plugin.rs @@ -93,11 +93,9 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result { let mut result = VecDeque::new(); - result.push_back(ReturnValue::Value(Value::Error(Box::new( - ShellError::string(format!( - "Error while processing input: {:?} {}", - e, input - )), + result.push_back(Err(ShellError::string(format!( + "Error while processing input: {:?} {}", + e, input )))); result } @@ -105,8 +103,9 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result { let mut result = VecDeque::new(); - result.push_back(ReturnValue::Value(Value::Error(Box::new( - ShellError::string(format!("Error while processing input: {:?}", e)), + result.push_back(Err(ShellError::string(format!( + "Error while processing input: {:?}", + e )))); result } @@ -115,7 +114,7 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result Result<(), ShellError> { diff --git a/src/commands/ps.rs b/src/commands/ps.rs index 04bd45433c..3a69618fe8 100644 --- a/src/commands/ps.rs +++ b/src/commands/ps.rs @@ -11,8 +11,8 @@ pub fn ps(_args: CommandArgs) -> Result { let list = list .into_iter() - .map(|(_, process)| ReturnValue::Value(Value::Object(process_dict(process)))) + .map(|(_, process)| Value::Object(process_dict(process))) .collect::>(); - Ok(list.boxed()) + Ok(list.from_input_stream()) } diff --git a/src/commands/reject.rs b/src/commands/reject.rs index 50bce3d724..ad8cd51f89 100644 --- a/src/commands/reject.rs +++ b/src/commands/reject.rs @@ -17,8 +17,8 @@ pub fn reject(args: CommandArgs) -> Result { let stream = args .input - .map(move |item| Value::Object(reject_fields(&item, &fields))) - .map(|item| ReturnValue::Value(item)); + .values + .map(move |item| Value::Object(reject_fields(&item, &fields))); - Ok(stream.boxed()) + Ok(stream.from_input_stream()) } diff --git a/src/commands/size.rs b/src/commands/size.rs index 39c16412dd..094e48005d 100644 --- a/src/commands/size.rs +++ b/src/commands/size.rs @@ -34,7 +34,7 @@ pub fn size(args: CommandArgs) -> Result { contents.clear(); } - Ok(list.boxed()) + Ok(list.to_output_stream()) } fn count(name: &str, contents: &str) -> ReturnValue { @@ -69,5 +69,5 @@ fn count(name: &str, contents: &str) -> ReturnValue { dict.add("chars", Value::int(chars)); dict.add("max length", Value::int(bytes)); - ReturnValue::Value(Value::Object(dict)) + ReturnSuccess::value(Value::Object(dict)) } diff --git a/src/commands/skip_while.rs b/src/commands/skip_while.rs index 466f8d9569..ce671eb2a2 100644 --- a/src/commands/skip_while.rs +++ b/src/commands/skip_while.rs @@ -16,8 +16,7 @@ impl Command for SkipWhile { fn config(&self) -> CommandConfig { CommandConfig { name: self.name().to_string(), - mandatory_positional: vec![PositionalType::Block("condition".to_string())], - optional_positional: vec![], + positional: vec![PositionalType::mandatory("condition", "Block")], rest_positional: false, named: indexmap::IndexMap::new(), is_filter: true, @@ -40,7 +39,7 @@ pub fn skip_while(args: CommandArgs) -> Result { let block = args.nth(0).unwrap().as_block()?; let input = args.input; - let objects = input.skip_while(move |item| { + let objects = input.values.skip_while(move |item| { let result = block.invoke(&item); let return_value = match result { @@ -51,5 +50,5 @@ pub fn skip_while(args: CommandArgs) -> Result { futures::future::ready(return_value) }); - Ok(objects.map(|x| ReturnValue::Value(x)).boxed()) + Ok(objects.from_input_stream()) } diff --git a/src/commands/sort_by.rs b/src/commands/sort_by.rs index 9793e9b1b9..26d22372bc 100644 --- a/src/commands/sort_by.rs +++ b/src/commands/sort_by.rs @@ -5,7 +5,7 @@ pub fn sort_by(args: CommandArgs) -> Result { let fields: Result, _> = args.positional_iter().map(|a| a.as_string()).collect(); let fields = fields?; - let output = args.input.collect::>(); + let output = args.input.values.collect::>(); let output = output.map(move |mut vec| { vec.sort_by_key(|item| { @@ -15,11 +15,8 @@ pub fn sort_by(args: CommandArgs) -> Result { .collect::>>() }); - vec.into_iter() - .map(|v| ReturnValue::Value(v.copy())) - .collect::>() - .boxed() + vec.into_iter().collect::>() }); - Ok(output.flatten_stream().boxed()) + Ok(output.flatten_stream().from_input_stream()) } diff --git a/src/commands/split_column.rs b/src/commands/split_column.rs index dcf1b11695..0a1cac8142 100644 --- a/src/commands/split_column.rs +++ b/src/commands/split_column.rs @@ -8,7 +8,7 @@ use log::trace; pub fn split_column(args: CommandArgs) -> Result { let positional: Vec<_> = args.positional_iter().cloned().collect(); let span = args.name_span; - + if positional.len() == 0 { return Err(ShellError::maybe_labeled_error( "Split-column needs more information", @@ -20,6 +20,7 @@ pub fn split_column(args: CommandArgs) -> Result { let input = args.input; Ok(input + .values .map(move |v| match v { Value::Primitive(Primitive::String(s)) => { let splitter = positional[0].as_string().unwrap().replace("\\n", "\n"); @@ -39,7 +40,7 @@ pub fn split_column(args: CommandArgs) -> Result { for (&k, v) in split_result.iter().zip(gen_columns.iter()) { dict.add(v.clone(), Value::Primitive(Primitive::String(k.into()))); } - ReturnValue::Value(Value::Object(dict)) + ReturnSuccess::value(Value::Object(dict)) } else if split_result.len() == (positional.len() - 1) { let mut dict = crate::object::Dictionary::default(); for (&k, v) in split_result.iter().zip(positional.iter().skip(1)) { @@ -48,7 +49,7 @@ pub fn split_column(args: CommandArgs) -> Result { Value::Primitive(Primitive::String(k.into())), ); } - ReturnValue::Value(Value::Object(dict)) + ReturnSuccess::value(Value::Object(dict)) } else { let mut dict = crate::object::Dictionary::default(); for k in positional.iter().skip(1) { @@ -57,14 +58,14 @@ pub fn split_column(args: CommandArgs) -> Result { Value::Primitive(Primitive::String("".into())), ); } - ReturnValue::Value(Value::Object(dict)) + ReturnSuccess::value(Value::Object(dict)) } } - _ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( + _ => Err(ShellError::maybe_labeled_error( "Expected string values from pipeline", "expects strings from pipeline", span, - )))), + )), }) - .boxed()) + .to_output_stream()) } diff --git a/src/commands/split_row.rs b/src/commands/split_row.rs index d0553d242e..380c9ca193 100644 --- a/src/commands/split_row.rs +++ b/src/commands/split_row.rs @@ -21,6 +21,7 @@ pub fn split_row(args: CommandArgs) -> Result { let input = args.input; let stream = input + .values .map(move |v| match v { Value::Primitive(Primitive::String(s)) => { let splitter = positional[0].as_string().unwrap().replace("\\n", "\n"); @@ -31,7 +32,7 @@ pub fn split_row(args: CommandArgs) -> Result { let mut result = VecDeque::new(); for s in split_result { - result.push_back(ReturnValue::Value(Value::Primitive(Primitive::String( + result.push_back(ReturnSuccess::value(Value::Primitive(Primitive::String( s.into(), )))); } @@ -39,17 +40,15 @@ pub fn split_row(args: CommandArgs) -> Result { } _ => { let mut result = VecDeque::new(); - result.push_back(ReturnValue::Value(Value::Error(Box::new( - ShellError::maybe_labeled_error( - "Expected string values from pipeline", - "expects strings from pipeline", - span, - ), - )))); + result.push_back(Err(ShellError::maybe_labeled_error( + "Expected string values from pipeline", + "expects strings from pipeline", + span, + ))); result } }) .flatten(); - Ok(stream.boxed()) + Ok(stream.to_output_stream()) } diff --git a/src/commands/sysinfo.rs b/src/commands/sysinfo.rs index 2c1c4c88cb..e6b60840ff 100644 --- a/src/commands/sysinfo.rs +++ b/src/commands/sysinfo.rs @@ -196,7 +196,7 @@ pub fn sysinfo(_args: CommandArgs) -> Result { // println!("{:#?}", system.get_network()); let mut stream = VecDeque::new(); - stream.push_back(ReturnValue::Value(Value::Object(Dictionary::from(idx)))); + stream.push_back(Value::Object(Dictionary::from(idx))); - Ok(stream.boxed()) + Ok(stream.from_input_stream()) } diff --git a/src/commands/to_array.rs b/src/commands/to_array.rs index 1f7e67d24f..9e2f4c33d9 100644 --- a/src/commands/to_array.rs +++ b/src/commands/to_array.rs @@ -2,9 +2,10 @@ use crate::object::Value; use crate::prelude::*; pub fn to_array(args: CommandArgs) -> Result { - let out = args.input.collect(); + let out = args.input.values.collect(); + Ok(out - .map(|vec: Vec<_>| single_output(Value::List(vec))) + .map(|vec: Vec<_>| stream![Value::List(vec)]) .flatten_stream() - .boxed()) + .from_input_stream()) } diff --git a/src/commands/to_json.rs b/src/commands/to_json.rs index 497b0310cb..2244604929 100644 --- a/src/commands/to_json.rs +++ b/src/commands/to_json.rs @@ -47,14 +47,12 @@ pub fn to_json(args: CommandArgs) -> Result { Ok(out .map( move |a| match serde_json::to_string(&value_to_json_value(&a)) { - Ok(x) => ReturnValue::Value(Value::Primitive(Primitive::String(x))), - Err(_) => { - ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( - "Can not convert to JSON string", - "can not convert piped data to JSON string", - span, - )))) - } + Ok(x) => Ok(ReturnValue::Value(Value::Primitive(Primitive::String(x)))), + Err(_) => Err(ShellError::maybe_labeled_error( + "Can not convert to JSON string", + "can not convert piped data to JSON string", + span, + )), }, ) .boxed()) diff --git a/src/commands/to_toml.rs b/src/commands/to_toml.rs index 2e90b99fa9..ca3edcf936 100644 --- a/src/commands/to_toml.rs +++ b/src/commands/to_toml.rs @@ -35,13 +35,14 @@ pub fn to_toml(args: CommandArgs) -> Result { let out = args.input; let span = args.name_span; Ok(out - .map(move |a| match toml::to_string(&value_to_toml_value(&a)) { - Ok(x) => ReturnValue::Value(Value::Primitive(Primitive::String(x))), - Err(_) => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( + .values + .map(move |a| match toml::to_string(&a) { + Ok(x) => ReturnSuccess::value(Value::Primitive(Primitive::String(x))), + Err(_) => Err(ShellError::maybe_labeled_error( "Can not convert to TOML string", "can not convert piped data to TOML string", span, - )))), + )), }) - .boxed()) + .to_output_stream()) } diff --git a/src/commands/trim.rs b/src/commands/trim.rs index b4ebc8ed22..92466d9f34 100644 --- a/src/commands/trim.rs +++ b/src/commands/trim.rs @@ -9,15 +9,16 @@ pub fn trim(args: CommandArgs) -> Result { let span = args.name_span; Ok(input + .values .map(move |v| match v { Value::Primitive(Primitive::String(s)) => { - ReturnValue::Value(Value::Primitive(Primitive::String(s.trim().into()))) + ReturnSuccess::value(Value::Primitive(Primitive::String(s.trim().into()))) } - _ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error( + _ => Err(ShellError::maybe_labeled_error( "Expected string values from pipeline", "expects strings from pipeline", span, - )))), + )), }) - .boxed()) + .to_output_stream()) } diff --git a/src/commands/view.rs b/src/commands/view.rs index 565dcccb0d..3522b82fe7 100644 --- a/src/commands/view.rs +++ b/src/commands/view.rs @@ -46,5 +46,5 @@ pub fn view(args: CommandArgs) -> Result { let _ = printer.file(file.display().to_string()); - Ok(VecDeque::new().boxed()) + Ok(VecDeque::new().into()) } diff --git a/src/commands/where_.rs b/src/commands/where_.rs index afc0d901c4..dca4816a90 100644 --- a/src/commands/where_.rs +++ b/src/commands/where_.rs @@ -1,55 +1,23 @@ use crate::errors::ShellError; -use crate::parser::registry::{CommandConfig, PositionalType}; +use crate::object::Block; use crate::prelude::*; +use futures::future::ready; +use log::trace; -pub struct Where; +command! { + Where as where(args, condition: Block) { + let input: InputStream = trace_stream!("where input" = args.input); -impl Command for Where { - fn run(&self, args: CommandArgs) -> Result { - r#where(args) - } - fn name(&self) -> &str { - "where" - } + input.values.filter_map(move |item| { + let result = condition.invoke(&item); - fn config(&self) -> CommandConfig { - CommandConfig { - name: self.name().to_string(), - mandatory_positional: vec![PositionalType::Block("condition".to_string())], - optional_positional: vec![], - rest_positional: false, - named: indexmap::IndexMap::new(), - is_filter: true, - is_sink: false, - can_load: vec![], - can_save: vec![], - } + let return_value = match result { + Err(err) => Some(Err(err)), + Ok(v) if v.is_true() => Some(Ok(ReturnSuccess::Value(item.copy()))), + _ => None, + }; + + ready(return_value) + }) } } - -pub fn r#where(args: CommandArgs) -> Result { - if args.len() == 0 { - return Err(ShellError::maybe_labeled_error( - "Where requires a condition", - "needs condition", - args.name_span, - )); - } - - let block = args.expect_nth(0)?.as_block()?; - let input = args.input; - - let objects = input.filter_map(move |item| { - let result = block.invoke(&item); - - let return_value = match result { - Err(err) => Some(ReturnValue::Value(Value::Error(Box::new(err)))), - Ok(v) if v.is_true() => Some(ReturnValue::Value(item.copy())), - _ => None, - }; - - futures::future::ready(return_value) - }); - - Ok(objects.boxed()) -} diff --git a/src/errors.rs b/src/errors.rs index 0279068ac4..a87edd5ce8 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -41,6 +41,16 @@ pub enum ArgumentError { MissingValueForName(String), } +pub fn labelled( + span: impl Into>, + heading: &'a str, + span_message: &'a str, +) -> impl FnOnce(ShellError) -> ShellError + 'a { + let span = span.into(); + + move |error| ShellError::maybe_labeled_error(heading, span_message, span) +} + #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)] pub enum ShellError { String(StringError), @@ -53,6 +63,7 @@ pub enum ShellError { expr: Description, }, ArgumentError { + command: String, error: ArgumentError, span: Span, }, @@ -119,28 +130,38 @@ impl ShellError { ShellError::String(StringError { title, .. }) => { Diagnostic::new(Severity::Error, title) } - ShellError::ArgumentError { error, span } => match error { + ShellError::ArgumentError { + command, + error, + span, + } => match error { ArgumentError::MissingMandatoryFlag(name) => Diagnostic::new( Severity::Error, format!( - "Command requires {}{}", - Color::Cyan.paint("--"), - Color::Cyan.paint(name) + "{} requires {}{}", + Color::Cyan.paint(command), + Color::Black.bold().paint("--"), + Color::Black.bold().paint(name) ), ) .with_label(Label::new_primary(span)), ArgumentError::MissingMandatoryPositional(name) => Diagnostic::new( Severity::Error, - format!("Command requires {}", Color::Cyan.paint(name)), + format!( + "{} requires {}", + Color::Cyan.paint(command), + Color::Green.bold().paint(name) + ), ) .with_label(Label::new_primary(span)), ArgumentError::MissingValueForName(name) => Diagnostic::new( Severity::Error, format!( - "Missing value for flag {}{}", - Color::Cyan.paint("--"), - Color::Cyan.paint(name) + "{} is missing value for flag {}{}", + Color::Cyan.paint(command), + Color::Black.bold().paint("--"), + Color::Black.bold().paint(name) ), ) .with_label(Label::new_primary(span)), diff --git a/src/format/tree.rs b/src/format/tree.rs index 5492adf15d..d124ea5cfd 100644 --- a/src/format/tree.rs +++ b/src/format/tree.rs @@ -31,7 +31,6 @@ impl TreeView { } } Value::Block(_) => {} - Value::Error(_) => {} Value::Filesystem => {} Value::Binary(_) => {} } diff --git a/src/lib.rs b/src/lib.rs index fe30296c8f..4528be06b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,10 @@ #![feature(try_trait)] #![feature(bind_by_move_pattern_guards)] #![feature(box_syntax)] +#![feature(type_ascription)] + +#[macro_use] +mod prelude; mod cli; mod commands; @@ -16,11 +20,10 @@ mod git; mod object; mod parser; mod plugin; -mod prelude; mod shell; mod stream; -pub use crate::commands::command::ReturnValue; +pub use crate::commands::command::{ReturnSuccess, ReturnValue}; pub use crate::env::host::BasicHost; pub use crate::parser::parse::span::SpannedItem; pub use crate::parser::Spanned; diff --git a/src/object/base.rs b/src/object/base.rs index 9e616049e7..1125cc5a8b 100644 --- a/src/object/base.rs +++ b/src/object/base.rs @@ -185,9 +185,6 @@ pub enum Value { #[allow(unused)] Block(Block), Filesystem, - - #[allow(unused)] - Error(Box), } pub fn debug_list(values: &'a Vec) -> ValuesDebug<'a> { @@ -217,7 +214,6 @@ impl fmt::Debug for ValueDebug<'a> { Value::Object(o) => o.debug(f), Value::List(l) => debug_list(l).fmt(f), Value::Block(_) => write!(f, "[[block]]"), - Value::Error(err) => write!(f, "[[error :: {} ]]", err), Value::Filesystem => write!(f, "[[filesystem]]"), Value::Binary(_) => write!(f, "[[binary]]"), } @@ -231,6 +227,65 @@ impl Spanned { } } +impl std::convert::TryFrom<&'a Spanned> for Block { + type Error = ShellError; + + fn try_from(value: &'a Spanned) -> Result { + match value.item() { + Value::Block(block) => Ok(block.clone()), + v => Err(ShellError::type_error( + "Block", + value.copy_span(v.type_name()), + )), + } + } +} + +impl std::convert::TryFrom<&'a Spanned> for i64 { + type Error = ShellError; + + fn try_from(value: &'a Spanned) -> Result { + match value.item() { + Value::Primitive(Primitive::Int(int)) => Ok(*int), + v => Err(ShellError::type_error( + "Integer", + value.copy_span(v.type_name()), + )), + } + } +} + +pub enum Switch { + Present, + Absent, +} + +impl Switch { + pub fn is_present(&self) -> bool { + match self { + Switch::Present => true, + Switch::Absent => false, + } + } +} + +impl std::convert::TryFrom>> for Switch { + type Error = ShellError; + + fn try_from(value: Option<&'a Spanned>) -> Result { + match value { + None => Ok(Switch::Absent), + Some(value) => match value.item() { + Value::Primitive(Primitive::Boolean(true)) => Ok(Switch::Present), + v => Err(ShellError::type_error( + "Boolean", + value.copy_span(v.type_name()), + )), + }, + } + } +} + impl Value { crate fn type_name(&self) -> String { match self { @@ -238,7 +293,6 @@ impl Value { Value::Object(_) => format!("object"), Value::List(_) => format!("list"), Value::Block(_) => format!("block"), - Value::Error(_) => format!("error"), Value::Filesystem => format!("filesystem"), Value::Binary(_) => format!("binary"), } @@ -312,7 +366,6 @@ impl Value { let list = l.iter().map(|i| i.copy()).collect(); Value::List(list) } - Value::Error(e) => Value::Error(Box::new(e.copy_error())), Value::Filesystem => Value::Filesystem, Value::Binary(b) => Value::Binary(b.clone()), } @@ -329,7 +382,6 @@ impl Value { ), Value::Object(_) => format!("[object Object]"), Value::List(_) => format!("[list List]"), - Value::Error(e) => format!("{}", e), Value::Filesystem => format!(""), Value::Binary(_) => format!(""), } @@ -459,14 +511,6 @@ impl Value { Ok(Value::Primitive(Primitive::Date(date))) } - #[allow(unused)] - pub fn system_date_result(s: Result) -> Value { - match s { - Ok(time) => Value::Primitive(Primitive::Date(time.into())), - Err(err) => Value::Error(Box::new(ShellError::string(format!("{}", err)))), - } - } - pub fn nothing() -> Value { Value::Primitive(Primitive::Nothing) } diff --git a/src/parser/parse/files.rs b/src/parser/parse/files.rs index 2b02c51c65..2743b95975 100644 --- a/src/parser/parse/files.rs +++ b/src/parser/parse/files.rs @@ -23,7 +23,7 @@ impl language_reporting::ReportingFiles for Files { 0 } fn file_name(&self, _file: Self::FileId) -> FileName { - FileName::Verbatim(format!("")) + FileName::Verbatim(format!("shell")) } fn byte_index(&self, _file: Self::FileId, _line: usize, _column: usize) -> Option { unimplemented!("byte_index") diff --git a/src/parser/parse_command.rs b/src/parser/parse_command.rs index a216de2928..ff407231c1 100644 --- a/src/parser/parse_command.rs +++ b/src/parser/parse_command.rs @@ -1,5 +1,5 @@ use crate::errors::{ArgumentError, ShellError}; -use crate::parser::registry::{CommandConfig, CommandRegistry, NamedType}; +use crate::parser::registry::{CommandConfig, CommandRegistry, NamedType, PositionalType}; use crate::parser::{baseline_parse_tokens, CallNode, Span, Spanned}; use crate::parser::{ hir::{self, NamedArguments}, @@ -86,30 +86,32 @@ fn parse_command_tail( named.insert_switch(name, flag); } - NamedType::Mandatory(kind) => match extract_mandatory(name, tail, source, command_span) - { - Err(err) => return Err(err), // produce a correct diagnostic - Ok((pos, flag)) => { - tail.move_to(pos); + NamedType::Mandatory(kind) => { + match extract_mandatory(config, name, tail, source, command_span) { + Err(err) => return Err(err), // produce a correct diagnostic + Ok((pos, flag)) => { + tail.move_to(pos); - if tail.at_end() { - return Err(ShellError::ArgumentError { - error: ArgumentError::MissingValueForName(name.to_string()), - span: flag.span, - }); + if tail.at_end() { + return Err(ShellError::ArgumentError { + command: config.name().clone(), + error: ArgumentError::MissingValueForName(name.to_string()), + span: flag.span, + }); + } + + let expr = hir::baseline_parse_next_expr( + tail, + registry, + source, + kind.to_coerce_hint(), + )?; + + tail.restart(); + named.insert_mandatory(name, expr); } - - let expr = hir::baseline_parse_next_expr( - tail, - registry, - source, - kind.to_coerce_hint(), - )?; - - tail.restart(); - named.insert_mandatory(name, expr); } - }, + } NamedType::Optional(kind) => match extract_optional(name, tail, source) { Err(err) => return Err(err), // produce a correct diagnostic Ok(Some((pos, flag))) => { @@ -117,6 +119,7 @@ fn parse_command_tail( if tail.at_end() { return Err(ShellError::ArgumentError { + command: config.name().clone(), error: ArgumentError::MissingValueForName(name.to_string()), span: flag.span, }); @@ -144,16 +147,26 @@ fn parse_command_tail( trace_remaining("after named", tail.clone(), source); let mut positional = vec![]; - let mandatory = config.mandatory_positional(); - for arg in mandatory { - trace!("Processing mandatory {:?}", arg); + for arg in config.positional() { + trace!("Processing positional {:?}", arg); - if tail.len() == 0 { - return Err(ShellError::ArgumentError { - error: ArgumentError::MissingMandatoryPositional(arg.name().to_string()), - span: command_span, - }); + match arg { + PositionalType::Mandatory(..) => { + if tail.len() == 0 { + return Err(ShellError::ArgumentError { + command: config.name().clone(), + error: ArgumentError::MissingMandatoryPositional(arg.name().to_string()), + span: command_span, + }); + } + } + + PositionalType::Optional(..) => { + if tail.len() == 0 { + break; + } + } } let result = hir::baseline_parse_next_expr(tail, registry, source, arg.to_coerce_hint())?; @@ -161,21 +174,7 @@ fn parse_command_tail( positional.push(result); } - trace_remaining("after mandatory", tail.clone(), source); - - let optional = config.optional_positional(); - - for arg in optional { - if tail.len() == 0 { - break; - } - - let result = hir::baseline_parse_next_expr(tail, registry, source, arg.to_coerce_hint())?; - - positional.push(result); - } - - trace_remaining("after optional", tail.clone(), source); + trace_remaining("after positional", tail.clone(), source); // TODO: Only do this if rest params are specified let remainder = baseline_parse_tokens(tail, registry, source)?; @@ -207,6 +206,7 @@ fn extract_switch(name: &str, tokens: &mut hir::TokensIterator<'_>, source: &Tex } fn extract_mandatory( + config: &CommandConfig, name: &str, tokens: &mut hir::TokensIterator<'a>, source: &Text, @@ -216,6 +216,7 @@ fn extract_mandatory( match flag { None => Err(ShellError::ArgumentError { + command: config.name().clone(), error: ArgumentError::MissingMandatoryFlag(name.to_string()), span, }), diff --git a/src/parser/registry.rs b/src/parser/registry.rs index 52cc9f0497..b753cb9aed 100644 --- a/src/parser/registry.rs +++ b/src/parser/registry.rs @@ -36,22 +36,38 @@ impl NamedValue { #[allow(unused)] #[derive(Debug, Clone, Serialize, Deserialize)] pub enum PositionalType { - Value(String), - Block(String), + Mandatory(String, PositionalValue), + Optional(String, PositionalValue), +} + +#[derive(Debug, Clone)] +pub enum PositionalValue { + Value, + Block, } impl PositionalType { + crate fn mandatory(name: &str, kind: &str) -> PositionalType { + match kind { + "Block" => PositionalType::Mandatory(name.to_string(), PositionalValue::Block), + _ => PositionalType::Mandatory(name.to_string(), PositionalValue::Value), + } + } + crate fn to_coerce_hint(&self) -> Option { match self { - PositionalType::Value(_) => None, - PositionalType::Block(_) => Some(ExpressionKindHint::Block), + PositionalType::Mandatory(_, PositionalValue::Block) + | PositionalType::Optional(_, PositionalValue::Block) => { + Some(ExpressionKindHint::Block) + } + _ => None, } } crate fn name(&self) -> &str { match self { - PositionalType::Value(s) => s, - PositionalType::Block(s) => s, + PositionalType::Mandatory(s, _) => s, + PositionalType::Optional(s, _) => s, } } } @@ -60,8 +76,7 @@ impl PositionalType { #[get = "crate"] pub struct CommandConfig { pub name: String, - pub mandatory_positional: Vec, - pub optional_positional: Vec, + crate positional: Vec, pub rest_positional: bool, pub named: IndexMap, pub is_filter: bool, diff --git a/src/plugins/inc.rs b/src/plugins/inc.rs index a55c3d34f1..dbaeaa1d82 100644 --- a/src/plugins/inc.rs +++ b/src/plugins/inc.rs @@ -3,6 +3,9 @@ use nu::{ serve_plugin, Args, CommandConfig, Plugin, PositionalType, Primitive, ReturnValue, ShellError, Spanned, Value, }; +use nu::{Primitive, ReturnSuccess, ReturnValue, ShellError, Spanned, Value}; +use serde::{Deserialize, Serialize}; +use std::io; struct Inc { inc_by: i64, @@ -13,42 +16,75 @@ impl Inc { } } -impl Plugin for Inc { - fn config(&mut self) -> Result { - Ok(CommandConfig { - name: "inc".to_string(), - mandatory_positional: vec![], - optional_positional: vec![PositionalType::Value("Increment".into())], - can_load: vec![], - can_save: vec![], - is_filter: true, - is_sink: false, - named: IndexMap::new(), - rest_positional: true, - }) - } - fn begin_filter(&mut self, args: Args) -> Result<(), ShellError> { - if let Some(args) = args.positional { - for arg in args { - match arg { - Spanned { - item: Value::Primitive(Primitive::Int(i)), - .. - } => { - self.inc_by = i; +fn send_response(result: Vec) { + let response = JsonRpc::new("response", result); + let response_raw = serde_json::to_string(&response).unwrap(); + println!("{}", response_raw); +} + +fn send_error(error: ShellError) { + let message: ReturnValue = Err(error); + send_response(vec![message]) +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(tag = "method")] +#[allow(non_camel_case_types)] +pub enum NuCommand { + init { params: Vec> }, + filter { params: Value }, + quit, +} + +fn main() -> Result<(), Box> { + let mut inc_by = 1; + + loop { + let mut input = String::new(); + match io::stdin().read_line(&mut input) { + Ok(_) => { + let command = serde_json::from_str::(&input); + + match command { + Ok(NuCommand::init { params }) => { + for param in params { + match param { + Spanned { + item: Value::Primitive(Primitive::Int(i)), + .. + } => { + inc_by = i; + } + _ => { + send_error(ShellError::string("Unrecognized type in params")); + } + } + } + } + Ok(NuCommand::filter { params }) => match params { + Value::Primitive(Primitive::Int(i)) => { + send_response(vec![ReturnSuccess::value(Value::int(i + inc_by))]); + } + Value::Primitive(Primitive::Bytes(b)) => { + send_response(vec![ReturnSuccess::value(Value::bytes( + b + inc_by as u128, + ))]); + } + _ => { + send_error(ShellError::string("Unrecognized type in stream")); + } + }, + Ok(NuCommand::quit) => { + break; + } + Err(_) => { + send_error(ShellError::string("Unrecognized type in stream")); } _ => return Err(ShellError::string("Unrecognized type in params")), } } - } - - Ok(()) - } - - fn filter(&mut self, input: Value) -> Result, ShellError> { - match input { - Value::Primitive(Primitive::Int(i)) => { - Ok(vec![ReturnValue::Value(Value::int(i + self.inc_by))]) + Err(_) => { + send_error(ShellError::string("Unrecognized type in stream")); } Value::Primitive(Primitive::Bytes(b)) => Ok(vec![ReturnValue::Value(Value::bytes( b + self.inc_by as u64, diff --git a/src/prelude.rs b/src/prelude.rs index 90b7945cb1..7a9db241af 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,13 +1,82 @@ +#[macro_export] +macro_rules! stream { + ($($expr:expr),*) => {{ + let mut v = VecDeque::new(); + + $( + v.push_back($expr); + )* + + v + }} +} + +#[macro_export] +macro_rules! trace_stream { + ($desc:tt = $expr:expr) => {{ + if log::log_enabled!(target: "nu::trace_stream", log::Level::Trace) { + use futures::stream::StreamExt; + // Blocking is generally quite bad, but this is for debugging + // let mut local = futures::executor::LocalPool::new(); + // let objects = local.run_until($expr.into_vec()); + // let objects: Vec<_> = futures::executor::block_on($expr.into_vec()); + + let objects = $expr.values.inspect(|o| { + trace!(target: "nu::trace_stream", "{} = {:#?}", $desc, o.debug()); + }); + + $crate::stream::InputStream::from_stream(objects.boxed()) + } else { + $expr + } + }}; +} + crate use crate::cli::MaybeOwned; -crate use crate::commands::command::{Command, CommandAction, CommandArgs, ReturnValue}; +crate use crate::commands::command::{ + Command, CommandAction, CommandArgs, ReturnSuccess, ReturnValue, +}; crate use crate::context::Context; crate use crate::env::host::handle_unexpected; crate use crate::env::{Environment, Host}; crate use crate::errors::ShellError; crate use crate::object::{Primitive, Value}; -crate use crate::stream::{single_output, InputStream, OutputStream}; +crate use crate::stream::{InputStream, OutputStream}; crate use crate::Text; +crate use futures::stream::BoxStream; +crate use futures::Stream; crate use futures::{FutureExt, StreamExt}; crate use std::collections::VecDeque; -crate use std::pin::Pin; +crate use std::future::Future; crate use std::sync::{Arc, Mutex}; + +pub trait FromInputStream { + fn from_input_stream(self) -> OutputStream; +} + +impl FromInputStream for T +where + T: Stream + Send + 'static, +{ + fn from_input_stream(self) -> OutputStream { + OutputStream { + values: self.map(ReturnSuccess::value).boxed(), + } + } +} + +pub trait ToOutputStream { + fn to_output_stream(self) -> OutputStream; +} + +impl ToOutputStream for T +where + T: Stream + Send + 'static, + U: Into, +{ + fn to_output_stream(self) -> OutputStream { + OutputStream { + values: self.map(|item| item.into()).boxed(), + } + } +} diff --git a/src/stream.rs b/src/stream.rs index 8a536950fb..a7ca6e0486 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -1,12 +1,112 @@ use crate::prelude::*; -use futures::stream::BoxStream; -pub type InputStream = BoxStream<'static, Value>; -pub type OutputStream = BoxStream<'static, ReturnValue>; - -crate fn single_output(item: Value) -> OutputStream { - let value = ReturnValue::Value(item); - let mut vec = VecDeque::new(); - vec.push_back(value); - vec.boxed() +pub struct InputStream { + crate values: BoxStream<'static, Value>, +} + +impl InputStream { + pub fn into_vec(self) -> impl Future> { + self.values.collect() + } + + pub fn from_stream(input: impl Stream + Send + 'static) -> InputStream { + InputStream { + values: input.boxed(), + } + } +} + +impl From> for InputStream { + fn from(input: BoxStream<'static, Value>) -> InputStream { + InputStream { values: input } + } +} + +impl From> for InputStream { + fn from(input: VecDeque) -> InputStream { + InputStream { + values: input.boxed(), + } + } +} + +impl From> for InputStream { + fn from(input: Vec) -> InputStream { + let mut list = VecDeque::default(); + list.extend(input); + + InputStream { + values: list.boxed(), + } + } +} + +pub struct OutputStream { + crate values: BoxStream<'static, ReturnValue>, +} + +impl OutputStream { + pub fn from_stream(input: impl Stream + Send + 'static) -> OutputStream { + OutputStream { + values: input.boxed(), + } + } + + pub fn from_input(input: impl Stream + Send + 'static) -> OutputStream { + OutputStream { + values: input.map(ReturnSuccess::value).boxed(), + } + } +} + +impl From for OutputStream { + fn from(input: InputStream) -> OutputStream { + OutputStream { + values: input.values.map(ReturnSuccess::value).boxed(), + } + } +} + +impl From> for OutputStream { + fn from(input: BoxStream<'static, Value>) -> OutputStream { + OutputStream { + values: input.map(ReturnSuccess::value).boxed(), + } + } +} + +impl From> for OutputStream { + fn from(input: BoxStream<'static, ReturnValue>) -> OutputStream { + OutputStream { values: input } + } +} + +impl From> for OutputStream { + fn from(input: VecDeque) -> OutputStream { + OutputStream { + values: input.boxed(), + } + } +} + +impl From> for OutputStream { + fn from(input: Vec) -> OutputStream { + let mut list = VecDeque::default(); + list.extend(input); + + OutputStream { + values: list.boxed(), + } + } +} + +impl From> for OutputStream { + fn from(input: Vec) -> OutputStream { + let mut list = VecDeque::default(); + list.extend(input.into_iter().map(ReturnSuccess::value)); + + OutputStream { + values: list.boxed(), + } + } } From 71adfb4cdc76d69912102bec610072371fdff06b Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Fri, 5 Jul 2019 15:08:58 -0700 Subject: [PATCH 02/10] WIP --- src/commands/macros.rs | 4 +- src/commands/open.rs | 1 - src/commands/where_.rs | 2 +- src/object/base.rs | 5 --- src/object/types.rs | 85 ++++++++++++++++++++++++++++++++++++++++-- src/prelude.rs | 2 + 6 files changed, 88 insertions(+), 11 deletions(-) diff --git a/src/commands/macros.rs b/src/commands/macros.rs index bb5e96d057..5a47ffe0cc 100644 --- a/src/commands/macros.rs +++ b/src/commands/macros.rs @@ -262,7 +262,9 @@ macro_rules! command { Extract { $($extract:tt)* { use std::convert::TryInto; - $args.expect_nth($($positional_count)*)?.try_into()? + let value = $args.expect_nth($($positional_count)*)?; + let value = $param_kind.check(value)?; + value.extract() } } ); diff --git a/src/commands/open.rs b/src/commands/open.rs index a37f5f37ef..34a6490df0 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -1,7 +1,6 @@ use crate::errors::ShellError; use crate::object::{Primitive, Switch, Value}; use crate::parser::parse::span::Span; -use crate::parser::registry::NamedType; use crate::prelude::*; use mime::Mime; use std::path::{Path, PathBuf}; diff --git a/src/commands/where_.rs b/src/commands/where_.rs index dca4816a90..9ea08b4f11 100644 --- a/src/commands/where_.rs +++ b/src/commands/where_.rs @@ -1,5 +1,5 @@ use crate::errors::ShellError; -use crate::object::Block; +use crate::object::types::*; use crate::prelude::*; use futures::future::ready; use log::trace; diff --git a/src/object/base.rs b/src/object/base.rs index 1125cc5a8b..54693314a5 100644 --- a/src/object/base.rs +++ b/src/object/base.rs @@ -149,11 +149,6 @@ impl Deserialize<'de> for Block { D: Deserializer<'de>, { unimplemented!("deserialize block") - // let s = "\"unimplemented deserialize block\""; - // Ok(Block::new( - // TokenTreeBuilder::spanned_string((1, s.len() - 1), (0, s.len())), - // Text::from(s), - // )) } } diff --git a/src/object/types.rs b/src/object/types.rs index 34055e0b0d..3d026772e3 100644 --- a/src/object/types.rs +++ b/src/object/types.rs @@ -1,7 +1,86 @@ +use crate::object::base as value; +use crate::parser::hir; +use crate::prelude::*; use derive_new::new; use serde_derive::{Deserialize, Serialize}; -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)] -pub enum Type { - Any, +pub trait Type: std::fmt::Debug + Send { + fn name(&self) -> &'static str; + fn check(&self, value: Spanned) -> Result, ShellError>; + fn coerce(&self) -> Option { + None + } +} + +pub trait ExtractType: Type { + fn extract(value: Value) -> T; +} + +#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)] +pub struct Any; + +impl Type for Any { + fn name(&self) -> &'static str { + "Any" + } + + fn check(&self, value: Spanned) -> Result, ShellError> { + Ok(value) + } +} + +#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)] +pub struct Integer; + +impl Type for Integer { + fn name(&self) -> &'static str { + "Integer" + } + + fn check(&self, value: Spanned) -> Result, ShellError> { + match value { + v @ Spanned { + item: Value::Primitive(Primitive::Int(_)), + .. + } => Ok(v), + other => Err(ShellError::type_error("Integer", other.spanned_type_name())), + } + } +} + +impl ExtractType for Integer { + fn extract(value: Value) -> i64 { + match value { + Value::Primitive(Primitive::Int(int)) => int, + _ => unreachable!("invariant: must check before extract"), + } + } +} + +#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)] +pub struct Block; + +impl Type for Block { + fn name(&self) -> &'static str { + "Block" + } + + fn check(&self, value: Spanned) -> Result, ShellError> { + match value { + v @ Spanned { + item: Value::Block(_), + .. + } => Ok(v), + other => Err(ShellError::type_error("Block", other.spanned_type_name())), + } + } +} + +impl ExtractType for Block { + fn extract(value: Value) -> value::Block { + match value { + Value::Block(block) => block, + _ => unreachable!("invariant: must check before extract"), + } + } } diff --git a/src/prelude.rs b/src/prelude.rs index 7a9db241af..9c79787cf9 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -40,7 +40,9 @@ crate use crate::context::Context; crate use crate::env::host::handle_unexpected; crate use crate::env::{Environment, Host}; crate use crate::errors::ShellError; +crate use crate::object::types::{ExtractType, Type}; crate use crate::object::{Primitive, Value}; +crate use crate::parser::{Span, Spanned}; crate use crate::stream::{InputStream, OutputStream}; crate use crate::Text; crate use futures::stream::BoxStream; From 7b68739b52e53288ebccabbe0eace8fbe8961b52 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Mon, 8 Jul 2019 09:44:53 -0700 Subject: [PATCH 03/10] WIP --- src/cli.rs | 4 +- src/commands/autoview.rs | 2 +- src/commands/cd.rs | 3 +- src/commands/classified.rs | 32 +++---- src/commands/command.rs | 20 ++-- src/commands/config.rs | 18 ++-- src/commands/enter.rs | 4 +- src/commands/from_ini.rs | 4 +- src/commands/from_json.rs | 6 +- src/commands/from_toml.rs | 6 +- src/commands/from_xml.rs | 7 +- src/commands/from_yaml.rs | 6 +- src/commands/get.rs | 13 ++- src/commands/lines.rs | 8 +- src/commands/ls.rs | 11 ++- src/commands/macros.rs | 8 +- src/commands/open.rs | 21 ++-- src/commands/pick.rs | 6 +- src/commands/plugin.rs | 9 +- src/commands/ps.rs | 4 +- src/commands/reject.rs | 2 +- src/commands/size.rs | 12 +-- src/commands/sort_by.rs | 4 +- src/commands/split_column.rs | 8 +- src/commands/split_row.rs | 8 +- src/commands/sysinfo.rs | 179 +++++++++++------------------------ src/commands/to_array.rs | 2 +- src/commands/to_json.rs | 23 ++--- src/commands/to_toml.rs | 4 +- src/commands/trim.rs | 19 ++-- src/commands/where_.rs | 4 +- src/context.rs | 2 +- src/env/environment.rs | 7 +- src/errors.rs | 6 +- src/evaluate/evaluator.rs | 27 +++--- src/format/table.rs | 4 +- src/format/vtable.rs | 2 +- src/object.rs | 5 +- src/object/base.rs | 59 +++++------- src/object/config.rs | 17 +++- src/object/dict.rs | 46 ++++++++- src/object/into.rs | 23 +++++ src/object/types.rs | 118 ++++++++++++++++++++--- src/parser.rs | 2 +- src/parser/parse/span.rs | 24 +++++ src/prelude.rs | 4 +- src/stream.rs | 18 ++-- 47 files changed, 467 insertions(+), 354 deletions(-) create mode 100644 src/object/into.rs diff --git a/src/cli.rs b/src/cli.rs index d54abc8c9e..4b5d5c6813 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -231,7 +231,7 @@ pub async fn cli() -> Result<(), Box> { let last = env.back().unwrap(); (last.obj().clone(), last.path().display().to_string()) }; - let readline = match obj { + let readline = match obj.item { Value::Filesystem => rl.readline(&format!( "{}{}> ", cwd, @@ -396,7 +396,7 @@ async fn process_line(readline: Result, ctx: &mut Context } (Some(ClassifiedCommand::Sink(left)), None) => { - let input_vec: Vec = input.objects.into_vec().await; + let input_vec: Vec> = input.objects.into_vec().await; if let Err(err) = left.run(ctx, input_vec) { return LineResult::Error(line.clone(), err); } diff --git a/src/commands/autoview.rs b/src/commands/autoview.rs index be49c25e07..55b4b42923 100644 --- a/src/commands/autoview.rs +++ b/src/commands/autoview.rs @@ -22,7 +22,7 @@ pub fn autoview(args: SinkCommandArgs) -> Result<(), ShellError> { Ok(()) } -fn equal_shapes(input: &Vec) -> bool { +fn equal_shapes(input: &Vec>) -> bool { let mut items = input.iter(); let item = match items.next() { diff --git a/src/commands/cd.rs b/src/commands/cd.rs index 7df0f9b3be..8d76b5cbd0 100644 --- a/src/commands/cd.rs +++ b/src/commands/cd.rs @@ -6,8 +6,9 @@ use std::path::PathBuf; pub fn cd(args: CommandArgs) -> Result { let env = args.env.lock().unwrap(); let latest = env.back().unwrap(); + let obj = latest.obj; - match latest.obj { + match obj.item { Value::Filesystem => { let cwd = latest.path().to_path_buf(); diff --git a/src/commands/classified.rs b/src/commands/classified.rs index 8ac0f5fe10..d29715c779 100644 --- a/src/commands/classified.rs +++ b/src/commands/classified.rs @@ -59,24 +59,6 @@ impl ClassifiedInputStream { } } - pub fn into_vec(self) -> impl std::future::Future> { - self.objects.into_vec() - } - - crate fn from_vec(stream: VecDeque) -> ClassifiedInputStream { - ClassifiedInputStream { - objects: stream.into(), - stdin: None, - } - } - - crate fn from_list(stream: Vec) -> ClassifiedInputStream { - ClassifiedInputStream { - objects: stream.into(), - stdin: None, - } - } - crate fn from_input_stream(stream: impl Into) -> ClassifiedInputStream { ClassifiedInputStream { objects: stream.into(), @@ -111,7 +93,11 @@ crate struct SinkCommand { } impl SinkCommand { - crate fn run(self, context: &mut Context, input: Vec) -> Result<(), ShellError> { + crate fn run( + self, + context: &mut Context, + input: Vec>, + ) -> Result<(), ShellError> { context.run_sink(self.command, self.name_span.clone(), self.args, input) } } @@ -160,7 +146,11 @@ impl InternalCommand { } CommandAction::Exit => match context.env.lock().unwrap().pop_back() { Some(Environment { - obj: Value::Filesystem, + obj: + Spanned { + item: Value::Filesystem, + .. + }, .. }) => std::process::exit(0), None => std::process::exit(-1), @@ -199,7 +189,7 @@ impl ExternalCommand { stream_next: StreamNext, ) -> Result { let stdin = input.stdin; - let inputs: Vec = input.objects.into_vec().await; + let inputs: Vec> = input.objects.into_vec().await; trace!("-> {}", self.name); trace!("inputs = {:?}", inputs); diff --git a/src/commands/command.rs b/src/commands/command.rs index 7d51cd38f2..92b0dc3b82 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -7,7 +7,7 @@ use crate::parser::{ use crate::prelude::*; use getset::Getters; use serde::{Deserialize, Serialize}; -use std::{ops::Try, path::PathBuf}; +use std::path::PathBuf; #[derive(Getters)] #[get = "crate"] @@ -49,26 +49,26 @@ pub struct SinkCommandArgs { pub ctx: Context, pub name_span: Option, pub args: Args, - pub input: Vec, + pub input: Vec>, } #[derive(Debug, Serialize, Deserialize)] pub enum CommandAction { ChangePath(PathBuf), - Enter(Value), + Enter(Spanned), Exit, } #[derive(Debug, Serialize, Deserialize)] pub enum ReturnSuccess { - Value(Value), + Value(Spanned), Action(CommandAction), } pub type ReturnValue = Result; -impl From for ReturnValue { - fn from(input: Value) -> ReturnValue { +impl From> for ReturnValue { + fn from(input: Spanned) -> ReturnValue { Ok(ReturnSuccess::Value(input)) } } @@ -78,8 +78,12 @@ impl ReturnSuccess { Ok(ReturnSuccess::Action(CommandAction::ChangePath(path))) } - pub fn value(input: Value) -> ReturnValue { - Ok(ReturnSuccess::Value(input)) + pub fn value(input: impl Into>) -> ReturnValue { + Ok(ReturnSuccess::Value(input.into())) + } + + pub fn spanned_value(input: Value, span: Span) -> ReturnValue { + Ok(ReturnSuccess::Value(Spanned::from_item(input, span))) } } diff --git a/src/commands/config.rs b/src/commands/config.rs index 313d2f93be..839fe9c275 100644 --- a/src/commands/config.rs +++ b/src/commands/config.rs @@ -1,4 +1,3 @@ -#[macro_use] use crate::prelude::*; use crate::errors::ShellError; @@ -44,7 +43,7 @@ impl Command for Config { } pub fn config(args: CommandArgs) -> Result { - let mut result = crate::object::config::config()?; + let mut result = crate::object::config::config(args.name_span)?; trace!("{:#?}", args.args.positional); trace!("{:#?}", args.args.named); @@ -56,7 +55,7 @@ pub fn config(args: CommandArgs) -> Result { .ok_or_else(|| ShellError::string(&format!("Missing key {} in config", key)))?; return Ok( - vec![value.clone()].into(), // futures::stream::once(futures::future::ready(ReturnSuccess::Value(value.clone()))).into(), + stream![value.clone()], // futures::stream::once(futures::future::ready(ReturnSuccess::Value(value.clone()))).into(), ); } @@ -66,16 +65,21 @@ pub fn config(args: CommandArgs) -> Result { config::write_config(&result)?; - return Ok(stream![Value::Object(result.into())].from_input_stream()); + return Ok( + stream![Spanned::from_item(Value::Object(result.into()), v.span())] + .from_input_stream(), + ); } } - if let Some(_) = args.get("clear") { + if let Some(c) = args.get("clear") { result.clear(); config::write_config(&result)?; - return Ok(stream![Value::Object(result.into())].from_input_stream()); + return Ok( + stream![Spanned::from_item(Value::Object(result.into()), c.span())].from_input_stream(), + ); } if let Some(v) = args.get("remove") { @@ -90,7 +94,7 @@ pub fn config(args: CommandArgs) -> Result { ))); } - let obj = VecDeque::from_iter(vec![Value::Object(result.into())]); + let obj = VecDeque::from_iter(vec![Value::Object(result.into()).spanned(v)]); return Ok(obj.from_input_stream()); } diff --git a/src/commands/enter.rs b/src/commands/enter.rs index 8b6f547e6b..7fd557f6dc 100644 --- a/src/commands/enter.rs +++ b/src/commands/enter.rs @@ -49,7 +49,7 @@ pub fn enter(args: CommandArgs) -> Result { let full_path = PathBuf::from(cwd); - let (file_extension, contents) = match &args.expect_nth(0)?.item { + let (file_extension, contents, contents_span) = match &args.expect_nth(0)?.item { Value::Primitive(Primitive::String(s)) => fetch(&full_path, s, args.expect_nth(0)?.span)?, _ => { return Err(ShellError::labeled_error( @@ -90,7 +90,7 @@ pub fn enter(args: CommandArgs) -> Result { }; stream.push_back(Ok(ReturnSuccess::Action(CommandAction::Enter( - parse_as_value(file_extension, contents, span)?, + parse_as_value(file_extension, contents, contents_span, span)?, )))); Ok(stream.into()) diff --git a/src/commands/from_ini.rs b/src/commands/from_ini.rs index 7fa5dc3a59..d4697d0acc 100644 --- a/src/commands/from_ini.rs +++ b/src/commands/from_ini.rs @@ -31,9 +31,9 @@ pub fn from_ini(args: CommandArgs) -> Result { let span = args.name_span; Ok(out .values - .map(move |a| match a { + .map(move |a| match a.item { Value::Primitive(Primitive::String(s)) => match from_ini_string_to_value(s) { - Ok(x) => Ok(ReturnSuccess::Value(x)), + Ok(x) => ReturnSuccess::value(x.spanned(a.span)), Err(e) => Err(ShellError::maybe_labeled_error( "Could not parse as INI", format!("{:#?}", e), diff --git a/src/commands/from_json.rs b/src/commands/from_json.rs index cb1610b769..edf8c1f29b 100644 --- a/src/commands/from_json.rs +++ b/src/commands/from_json.rs @@ -12,7 +12,7 @@ fn convert_json_value_to_nu_value(v: &serde_hjson::Value) -> Value { serde_hjson::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))), serde_hjson::Value::Array(a) => Value::List( a.iter() - .map(|x| convert_json_value_to_nu_value(x)) + .map(|x| convert_json_value_to_nu_value(x).spanned_unknown()) .collect(), ), serde_hjson::Value::Object(o) => { @@ -35,9 +35,9 @@ pub fn from_json(args: CommandArgs) -> Result { let span = args.name_span; Ok(out .values - .map(move |a| match a { + .map(move |a| match a.item { Value::Primitive(Primitive::String(s)) => match from_json_string_to_value(s) { - Ok(x) => ReturnSuccess::value(x), + Ok(x) => ReturnSuccess::value(x.spanned(a.span)), Err(_) => Err(ShellError::maybe_labeled_error( "Could not parse as JSON", "piped data failed JSON parse", diff --git a/src/commands/from_toml.rs b/src/commands/from_toml.rs index b50b09da39..a91c591726 100644 --- a/src/commands/from_toml.rs +++ b/src/commands/from_toml.rs @@ -10,7 +10,7 @@ fn convert_toml_value_to_nu_value(v: &toml::Value) -> Value { toml::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))), toml::Value::Array(a) => Value::List( a.iter() - .map(|x| convert_toml_value_to_nu_value(x)) + .map(|x| convert_toml_value_to_nu_value(x).spanned_unknown()) .collect(), ), toml::Value::Datetime(dt) => Value::Primitive(Primitive::String(dt.to_string())), @@ -34,9 +34,9 @@ pub fn from_toml(args: CommandArgs) -> Result { let span = args.name_span; Ok(out .values - .map(move |a| match a { + .map(move |a| match a.item { Value::Primitive(Primitive::String(s)) => match from_toml_string_to_value(s) { - Ok(x) => ReturnSuccess::value(x), + Ok(x) => ReturnSuccess::value(x.spanned(a.span)), Err(_) => Err(ShellError::maybe_labeled_error( "Could not parse as TOML", "piped data failed TOML parse", diff --git a/src/commands/from_xml.rs b/src/commands/from_xml.rs index a1b1a14d76..8a722ea3fc 100644 --- a/src/commands/from_xml.rs +++ b/src/commands/from_xml.rs @@ -10,7 +10,7 @@ fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>) -> Value { children_values.push(from_node_to_value(&c)); } - let children_values: Vec = children_values + let children_values: Vec> = children_values .into_iter() .filter(|x| match x { Value::Primitive(Primitive::String(f)) => { @@ -22,6 +22,7 @@ fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>) -> Value { } _ => true, }) + .map(|v| v.spanned_unknown()) .collect(); let mut collected = Dictionary::default(); @@ -53,9 +54,9 @@ pub fn from_xml(args: CommandArgs) -> Result { let span = args.name_span; Ok(out .values - .map(move |a| match a { + .map(move |a| match a.item { Value::Primitive(Primitive::String(s)) => match from_xml_string_to_value(s) { - Ok(x) => ReturnSuccess::value(x), + Ok(x) => ReturnSuccess::value(x.spanned(a.span)), Err(_) => Err(ShellError::maybe_labeled_error( "Could not parse as XML", "piped data failed XML parse", diff --git a/src/commands/from_yaml.rs b/src/commands/from_yaml.rs index 8647f79904..b4679fdb78 100644 --- a/src/commands/from_yaml.rs +++ b/src/commands/from_yaml.rs @@ -14,7 +14,7 @@ fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value) -> Value { serde_yaml::Value::String(s) => Value::string(s), serde_yaml::Value::Sequence(a) => Value::List( a.iter() - .map(|x| convert_yaml_value_to_nu_value(x)) + .map(|x| convert_yaml_value_to_nu_value(x).spanned_unknown()) .collect(), ), serde_yaml::Value::Mapping(t) => { @@ -44,9 +44,9 @@ pub fn from_yaml(args: CommandArgs) -> Result { let span = args.name_span; Ok(out .values - .map(move |a| match a { + .map(move |a| match a.item { Value::Primitive(Primitive::String(s)) => match from_yaml_string_to_value(s) { - Ok(x) => ReturnSuccess::value(x), + Ok(x) => ReturnSuccess::value(x.spanned(a.span)), Err(_) => Err(ShellError::maybe_labeled_error( "Could not parse as YAML", "piped data failed YAML parse", diff --git a/src/commands/get.rs b/src/commands/get.rs index f022f8e930..fea58ed0a9 100644 --- a/src/commands/get.rs +++ b/src/commands/get.rs @@ -3,7 +3,7 @@ use crate::object::Value; use crate::parser::Span; use crate::prelude::*; -fn get_member(path: &str, span: Span, obj: &Value) -> Result { +fn get_member(path: &str, span: Span, obj: &Spanned) -> Result, ShellError> { let mut current = obj; for p in path.split(".") { match current.get_data_by_key(p) { @@ -18,7 +18,7 @@ fn get_member(path: &str, span: Span, obj: &Value) -> Result } } - Ok(current.copy()) + Ok(current.clone()) } pub fn get(args: CommandArgs) -> Result { @@ -56,12 +56,15 @@ pub fn get(args: CommandArgs) -> Result { let mut result = VecDeque::new(); for field in &fields { match get_member(&field.0, field.1, &item) { - Ok(Value::List(l)) => { + Ok(Spanned { + item: Value::List(l), + .. + }) => { for item in l { - result.push_back(ReturnSuccess::value(item.copy())); + result.push_back(ReturnSuccess::value(item.clone())); } } - Ok(x) => result.push_back(ReturnSuccess::value(x.copy())), + Ok(x) => result.push_back(ReturnSuccess::value(x.clone())), Err(_) => {} } } diff --git a/src/commands/lines.rs b/src/commands/lines.rs index 7f1ae850f2..12cd0c020e 100644 --- a/src/commands/lines.rs +++ b/src/commands/lines.rs @@ -11,7 +11,7 @@ pub fn lines(args: CommandArgs) -> Result { let stream = input .values - .map(move |v| match v { + .map(move |v| match v.item { Value::Primitive(Primitive::String(s)) => { let split_result: Vec<_> = s.lines().filter(|s| s.trim() != "").collect(); @@ -19,9 +19,9 @@ pub fn lines(args: CommandArgs) -> Result { let mut result = VecDeque::new(); for s in split_result { - result.push_back(ReturnSuccess::value(Value::Primitive(Primitive::String( - s.into(), - )))); + result.push_back(ReturnSuccess::value( + Value::Primitive(Primitive::String(s.into())).spanned_unknown(), + )); } result } diff --git a/src/commands/ls.rs b/src/commands/ls.rs index e23080ae8d..8181e9cea3 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -18,7 +18,7 @@ pub fn ls(args: CommandArgs) -> Result { _ => {} } - match obj { + match obj.item { Value::Filesystem => { let entries = std::fs::read_dir(&full_path); @@ -45,7 +45,7 @@ pub fn ls(args: CommandArgs) -> Result { for entry in entries { let value = Value::Object(dir_entry_dict(&entry?)?); - shell_entries.push_back(ReturnSuccess::value(value)) + shell_entries.push_back(ReturnSuccess::value(value.spanned_unknown())) } Ok(shell_entries.to_output_stream()) } @@ -125,9 +125,12 @@ pub fn ls(args: CommandArgs) -> Result { } } match viewed { - Value::List(l) => { + Spanned { + item: Value::List(l), + .. + } => { for item in l { - entries.push_back(ReturnSuccess::value(item.copy())); + entries.push_back(ReturnSuccess::value(item.clone())); } } x => { diff --git a/src/commands/macros.rs b/src/commands/macros.rs index 5a47ffe0cc..5a4e9e2d14 100644 --- a/src/commands/macros.rs +++ b/src/commands/macros.rs @@ -49,7 +49,7 @@ macro_rules! command { positional: vec![$($mandatory_positional)*], rest_positional: false, named: { - use $crate::parser::registry::{NamedType, NamedValue}; + use $crate::parser::registry::NamedType; #[allow(unused_mut)] let mut named: indexmap::IndexMap = indexmap::IndexMap::new(); @@ -261,10 +261,10 @@ macro_rules! command { Extract { $($extract:tt)* { - use std::convert::TryInto; + use $crate::object::types::ExtractType; let value = $args.expect_nth($($positional_count)*)?; - let value = $param_kind.check(value)?; - value.extract() + // let value = $param_kind.check(value)?; + $param_kind::extract(value)? } } ); diff --git a/src/commands/open.rs b/src/commands/open.rs index 34a6490df0..72440bea79 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -21,7 +21,7 @@ command! { let full_path = PathBuf::from(cwd); - let (file_extension, contents) = match &args.expect_nth(0)?.item { + let (file_extension, contents, contents_span) = match &args.expect_nth(0)?.item { Value::Primitive(Primitive::String(s)) => fetch(&full_path, s, args.expect_nth(0)?.span)?, _ => { return Err(ShellError::labeled_error( @@ -64,6 +64,7 @@ command! { stream.push_back(ReturnSuccess::value(parse_as_value( file_extension, contents, + contents_span, span, )?)); @@ -75,7 +76,7 @@ pub fn fetch( cwd: &PathBuf, location: &str, span: Span, -) -> Result<(Option, String), ShellError> { +) -> Result<(Option, String, Span), ShellError> { let mut cwd = cwd.clone(); if location.starts_with("http:") || location.starts_with("https:") { let response = reqwest::get(location); @@ -106,7 +107,7 @@ pub fn fetch( None => path_extension, }; - Ok((extension, Value::string(s))) + Ok((extension, s, span)) } Err(_) => { return Err(ShellError::labeled_error( @@ -131,7 +132,8 @@ pub fn fetch( Ok(s) => Ok(( cwd.extension() .map(|name| name.to_string_lossy().to_string()), - Value::string(s), + s, + span, )), Err(_) => Ok((None, Value::Binary(bytes))), }, @@ -149,10 +151,12 @@ pub fn fetch( pub fn parse_as_value( extension: Option, contents: String, + contents_span: Span, name_span: Option, -) -> Result { +) -> Result, ShellError> { match extension { Some(x) if x == "toml" => crate::commands::from_toml::from_toml_string_to_value(contents) + .map(|c| c.spanned(contents_span)) .map_err(move |_| { ShellError::maybe_labeled_error( "Could not open as TOML", @@ -161,6 +165,7 @@ pub fn parse_as_value( ) }), Some(x) if x == "json" => crate::commands::from_json::from_json_string_to_value(contents) + .map(|c| c.spanned(contents_span)) .map_err(move |_| { ShellError::maybe_labeled_error( "Could not open as JSON", @@ -169,6 +174,7 @@ pub fn parse_as_value( ) }), Some(x) if x == "ini" => crate::commands::from_ini::from_ini_string_to_value(contents) + .map(|c| c.spanned(contents_span)) .map_err(move |_| { ShellError::maybe_labeled_error( "Could not open as INI", @@ -177,6 +183,7 @@ pub fn parse_as_value( ) }), Some(x) if x == "xml" => crate::commands::from_xml::from_xml_string_to_value(contents) + .map(|c| c.spanned(contents_span)) .map_err(move |_| { ShellError::maybe_labeled_error( "Could not open as XML", @@ -185,6 +192,7 @@ pub fn parse_as_value( ) }), Some(x) if x == "yml" => crate::commands::from_yaml::from_yaml_string_to_value(contents) + .map(|c| c.spanned(contents_span)) .map_err(move |_| { ShellError::maybe_labeled_error( "Could not open as YAML", @@ -193,6 +201,7 @@ pub fn parse_as_value( ) }), Some(x) if x == "yaml" => crate::commands::from_yaml::from_yaml_string_to_value(contents) + .map(|c| c.spanned(contents_span)) .map_err(move |_| { ShellError::maybe_labeled_error( "Could not open as YAML", @@ -200,6 +209,6 @@ pub fn parse_as_value( name_span, ) }), - _ => Ok(Value::string(contents)), + _ => Ok(Value::string(contents).spanned(contents_span)), } } diff --git a/src/commands/pick.rs b/src/commands/pick.rs index 0a1e209f20..e4b2c35b72 100644 --- a/src/commands/pick.rs +++ b/src/commands/pick.rs @@ -14,11 +14,11 @@ pub fn pick(args: CommandArgs) -> Result { let fields: Result, _> = args.positional_iter().map(|a| a.as_string()).collect(); let fields = fields?; + let input = args.input; - let objects = args - .input + let objects = input .values - .map(move |item| Value::Object(select_fields(&item, &fields))); + .map(move |value| Value::Object(select_fields(&value.item, &fields)).spanned(value.span)); Ok(objects.from_input_stream()) } diff --git a/src/commands/plugin.rs b/src/commands/plugin.rs index 1ae9e989e3..06cd27a453 100644 --- a/src/commands/plugin.rs +++ b/src/commands/plugin.rs @@ -50,14 +50,17 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result> = VecDeque::new(); + eos.push_back(Value::Primitive(Primitive::EndOfStream).spanned_unknown()); let stream = args .input .chain(eos) .map(move |v| match v { - Value::Primitive(Primitive::EndOfStream) => { + Spanned { + item: Value::Primitive(Primitive::EndOfStream), + .. + } => { let stdin = child.stdin.as_mut().expect("Failed to open stdin"); let stdout = child.stdout.as_mut().expect("Failed to open stdout"); diff --git a/src/commands/ps.rs b/src/commands/ps.rs index 3a69618fe8..d2be9c0ddc 100644 --- a/src/commands/ps.rs +++ b/src/commands/ps.rs @@ -4,14 +4,14 @@ use crate::object::Value; use crate::prelude::*; use sysinfo::{RefreshKind, SystemExt}; -pub fn ps(_args: CommandArgs) -> Result { +pub fn ps(args: CommandArgs) -> Result { 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)| Value::Object(process_dict(process))) + .map(|(item, process)| Value::Object(process_dict(process)).spanned(args.name_span)) .collect::>(); Ok(list.from_input_stream()) diff --git a/src/commands/reject.rs b/src/commands/reject.rs index ad8cd51f89..7fb0161c64 100644 --- a/src/commands/reject.rs +++ b/src/commands/reject.rs @@ -18,7 +18,7 @@ pub fn reject(args: CommandArgs) -> Result { let stream = args .input .values - .map(move |item| Value::Object(reject_fields(&item, &fields))); + .map(move |item| Value::Object(reject_fields(&item, &fields)).spanned(args.name_span)); Ok(stream.from_input_stream()) } diff --git a/src/commands/size.rs b/src/commands/size.rs index 094e48005d..041e8181a8 100644 --- a/src/commands/size.rs +++ b/src/commands/size.rs @@ -24,20 +24,20 @@ pub fn size(args: CommandArgs) -> Result { let mut contents = String::new(); - let mut list = VecDeque::new(); - for name in args.positional_iter() { - let name = name.as_string()?; + let mut list: VecDeque = VecDeque::new(); + for spanned_name in args.positional_iter() { + let name = spanned_name.as_string()?; let path = cwd.join(&name); let mut file = File::open(path)?; file.read_to_string(&mut contents)?; - list.push_back(count(&name, &contents)); + list.push_back(count(&name, &contents).spanned(spanned_name).into()); contents.clear(); } Ok(list.to_output_stream()) } -fn count(name: &str, contents: &str) -> ReturnValue { +fn count(name: &str, contents: &str) -> Value { let mut lines: i64 = 0; let mut words: i64 = 0; let mut chars: i64 = 0; @@ -69,5 +69,5 @@ fn count(name: &str, contents: &str) -> ReturnValue { dict.add("chars", Value::int(chars)); dict.add("max length", Value::int(bytes)); - ReturnSuccess::value(Value::Object(dict)) + Value::Object(dict) } diff --git a/src/commands/sort_by.rs b/src/commands/sort_by.rs index 26d22372bc..e7e69d6da9 100644 --- a/src/commands/sort_by.rs +++ b/src/commands/sort_by.rs @@ -11,8 +11,8 @@ pub fn sort_by(args: CommandArgs) -> Result { vec.sort_by_key(|item| { fields .iter() - .map(|f| item.get_data_by_key(f).map(|i| i.copy())) - .collect::>>() + .map(|f| item.get_data_by_key(f).map(|i| i.clone())) + .collect::>>>() }); vec.into_iter().collect::>() diff --git a/src/commands/split_column.rs b/src/commands/split_column.rs index 0a1cac8142..037e34b7cb 100644 --- a/src/commands/split_column.rs +++ b/src/commands/split_column.rs @@ -21,7 +21,7 @@ pub fn split_column(args: CommandArgs) -> Result { Ok(input .values - .map(move |v| match v { + .map(move |v| match v.item { Value::Primitive(Primitive::String(s)) => { let splitter = positional[0].as_string().unwrap().replace("\\n", "\n"); trace!("splitting with {:?}", splitter); @@ -40,7 +40,7 @@ pub fn split_column(args: CommandArgs) -> Result { for (&k, v) in split_result.iter().zip(gen_columns.iter()) { dict.add(v.clone(), Value::Primitive(Primitive::String(k.into()))); } - ReturnSuccess::value(Value::Object(dict)) + ReturnSuccess::value(Value::Object(dict).spanned(v.span)) } else if split_result.len() == (positional.len() - 1) { let mut dict = crate::object::Dictionary::default(); for (&k, v) in split_result.iter().zip(positional.iter().skip(1)) { @@ -49,7 +49,7 @@ pub fn split_column(args: CommandArgs) -> Result { Value::Primitive(Primitive::String(k.into())), ); } - ReturnSuccess::value(Value::Object(dict)) + ReturnSuccess::value(Value::Object(dict).spanned(v.span)) } else { let mut dict = crate::object::Dictionary::default(); for k in positional.iter().skip(1) { @@ -58,7 +58,7 @@ pub fn split_column(args: CommandArgs) -> Result { Value::Primitive(Primitive::String("".into())), ); } - ReturnSuccess::value(Value::Object(dict)) + ReturnSuccess::value(Value::Object(dict).spanned(v.span)) } } _ => Err(ShellError::maybe_labeled_error( diff --git a/src/commands/split_row.rs b/src/commands/split_row.rs index 380c9ca193..b65f13ba71 100644 --- a/src/commands/split_row.rs +++ b/src/commands/split_row.rs @@ -22,7 +22,7 @@ pub fn split_row(args: CommandArgs) -> Result { let stream = input .values - .map(move |v| match v { + .map(move |v| match v.item { Value::Primitive(Primitive::String(s)) => { let splitter = positional[0].as_string().unwrap().replace("\\n", "\n"); trace!("splitting with {:?}", splitter); @@ -32,9 +32,9 @@ pub fn split_row(args: CommandArgs) -> Result { let mut result = VecDeque::new(); for s in split_result { - result.push_back(ReturnSuccess::value(Value::Primitive(Primitive::String( - s.into(), - )))); + result.push_back(ReturnSuccess::value( + Value::Primitive(Primitive::String(s.into())).spanned(v.span), + )); } result } diff --git a/src/commands/sysinfo.rs b/src/commands/sysinfo.rs index e6b60840ff..3a7cd5646c 100644 --- a/src/commands/sysinfo.rs +++ b/src/commands/sysinfo.rs @@ -1,95 +1,53 @@ use crate::errors::ShellError; use crate::object::base::OF64; -use crate::object::Dictionary; +use crate::object::SpannedDictBuilder; use crate::object::{Primitive, Value}; use crate::prelude::*; +use log::trace; use sys_info::*; use sysinfo::{ComponentExt, DiskExt, NetworkExt, RefreshKind, SystemExt}; -pub fn sysinfo(_args: CommandArgs) -> Result { - let mut idx = indexmap::IndexMap::new(); +pub fn sysinfo(args: CommandArgs) -> Result { + let mut idx = SpannedDictBuilder::new(args.name_span); if let (Ok(name), Ok(version)) = (os_type(), os_release()) { - let mut os_idx = indexmap::IndexMap::new(); - os_idx.insert( - "name".to_string(), - Value::Primitive(Primitive::String(name)), - ); - os_idx.insert( - "version".to_string(), - Value::Primitive(Primitive::String(version)), - ); + let mut os_idx = SpannedDictBuilder::new(args.name_span); + os_idx.insert("name", Primitive::String(name)); + os_idx.insert("version", Primitive::String(version)); - idx.insert("os".to_string(), Value::Object(Dictionary::from(os_idx))); + idx.insert_spanned("os", os_idx.into_spanned_value()); } if let (Ok(num_cpu), Ok(cpu_speed)) = (cpu_num(), cpu_speed()) { - let mut cpu_idx = indexmap::IndexMap::new(); - cpu_idx.insert( - "num".to_string(), - Value::Primitive(Primitive::Int(num_cpu as i64)), - ); - cpu_idx.insert( - "speed".to_string(), - Value::Primitive(Primitive::Int(cpu_speed as i64)), - ); + let mut cpu_idx = SpannedDictBuilder::new(args.name_span); + cpu_idx.insert("num", Primitive::Int(num_cpu as i64)); + cpu_idx.insert("speed", Primitive::Int(cpu_speed as i64)); - idx.insert("cpu".to_string(), Value::Object(Dictionary::from(cpu_idx))); + idx.insert_spanned("cpu", cpu_idx); } if let Ok(x) = loadavg() { - let mut load_idx = indexmap::IndexMap::new(); - load_idx.insert( - "1min".to_string(), - Value::Primitive(Primitive::Float(OF64::from(x.one))), - ); - load_idx.insert( - "5min".to_string(), - Value::Primitive(Primitive::Float(OF64::from(x.five))), - ); - load_idx.insert( - "15min".to_string(), - Value::Primitive(Primitive::Float(OF64::from(x.fifteen))), - ); + let mut load_idx = SpannedDictBuilder::new(args.name_span); - idx.insert( - "load avg".to_string(), - Value::Object(Dictionary::from(load_idx)), - ); + load_idx.insert("1min", Primitive::Float(OF64::from(x.one))); + load_idx.insert("5min", Primitive::Float(OF64::from(x.five))); + load_idx.insert("15min", Primitive::Float(OF64::from(x.fifteen))); + + idx.insert_spanned("load avg", load_idx); } if let Ok(x) = mem_info() { - let mut mem_idx = indexmap::IndexMap::new(); - mem_idx.insert( - "total".to_string(), - Value::Primitive(Primitive::Bytes(x.total as u64 * 1024)), - ); - mem_idx.insert( - "free".to_string(), - Value::Primitive(Primitive::Bytes(x.free as u64 * 1024)), - ); - mem_idx.insert( - "avail".to_string(), - Value::Primitive(Primitive::Bytes(x.avail as u64 * 1024)), - ); - mem_idx.insert( - "buffers".to_string(), - Value::Primitive(Primitive::Bytes(x.buffers as u64 * 1024)), - ); - mem_idx.insert( - "cached".to_string(), - Value::Primitive(Primitive::Bytes(x.cached as u64 * 1024)), - ); - mem_idx.insert( - "swap total".to_string(), - Value::Primitive(Primitive::Bytes(x.swap_total as u64 * 1024)), - ); - mem_idx.insert( - "swap free".to_string(), - Value::Primitive(Primitive::Bytes(x.swap_free as u64 * 1024)), - ); + let mut mem_idx = SpannedDictBuilder::new(args.name_span); - idx.insert("mem".to_string(), Value::Object(Dictionary::from(mem_idx))); + mem_idx.insert("total", Primitive::Bytes(x.total as u64 * 1024)); + mem_idx.insert("free", Primitive::Bytes(x.free as u64 * 1024)); + mem_idx.insert("avail", Primitive::Bytes(x.avail as u64 * 1024)); + mem_idx.insert("buffers", Primitive::Bytes(x.buffers as u64 * 1024)); + mem_idx.insert("cached", Primitive::Bytes(x.cached as u64 * 1024)); + mem_idx.insert("swap total", Primitive::Bytes(x.swap_total as u64 * 1024)); + mem_idx.insert("swap free", Primitive::Bytes(x.swap_free as u64 * 1024)); + + idx.insert_spanned("mem", mem_idx); } /* @@ -107,57 +65,42 @@ pub fn sysinfo(_args: CommandArgs) -> Result { */ if let Ok(x) = hostname() { - idx.insert( - "hostname".to_string(), - Value::Primitive(Primitive::String(x)), - ); + idx.insert("hostname", Primitive::String(x)); } #[cfg(not(windows))] { if let Ok(x) = boottime() { - let mut boottime_idx = indexmap::IndexMap::new(); - boottime_idx.insert( - "days".to_string(), - Value::Primitive(Primitive::Int(x.tv_sec / (24 * 3600))), - ); - boottime_idx.insert( - "hours".to_string(), - Value::Primitive(Primitive::Int((x.tv_sec / 3600) % 24)), - ); - boottime_idx.insert( - "mins".to_string(), - Value::Primitive(Primitive::Int((x.tv_sec / 60) % 60)), - ); + let mut boottime_idx = SpannedDictBuilder::new(args.name_span); + boottime_idx.insert("days", Primitive::Int(x.tv_sec / (24 * 3600))); + boottime_idx.insert("hours", Primitive::Int((x.tv_sec / 3600) % 24)); + boottime_idx.insert("mins", Primitive::Int((x.tv_sec / 60) % 60)); - idx.insert( - "uptime".to_string(), - Value::Object(Dictionary::from(boottime_idx)), - ); + idx.insert("uptime", boottime_idx); } } let system = sysinfo::System::new_with_specifics(RefreshKind::everything().without_processes()); let components_list = system.get_components_list(); if components_list.len() > 0 { - let mut v = vec![]; + let mut v: Vec> = vec![]; for component in components_list { - let mut component_idx = indexmap::IndexMap::new(); + let mut component_idx = SpannedDictBuilder::new(args.name_span); + component_idx.insert("name", Primitive::String(component.get_label().to_string())); component_idx.insert( - "name".to_string(), - Value::string(component.get_label().to_string()), + "temp", + Primitive::Float(OF64::from(component.get_temperature() as f64)), ); component_idx.insert( - "temp".to_string(), - Value::float(component.get_temperature() as f64), + "max", + Primitive::Float(OF64::from(component.get_max() as f64)), ); - component_idx.insert("max".to_string(), Value::float(component.get_max() as f64)); if let Some(critical) = component.get_critical() { - component_idx.insert("critical".to_string(), Value::float(critical as f64)); + component_idx.insert("critical", Primitive::Float(OF64::from(critical as f64))); } - v.push(Value::Object(Dictionary::from(component_idx))); + v.push(component_idx.into()); } - idx.insert("temps".to_string(), Value::List(v)); + idx.insert("temps", Value::List(v)); } let disks = system.get_disks(); @@ -165,38 +108,26 @@ pub fn sysinfo(_args: CommandArgs) -> Result { let mut v = vec![]; for disk in disks { - let mut disk_idx = indexmap::IndexMap::new(); - disk_idx.insert( - "name".to_string(), - Value::string(disk.get_name().to_string_lossy()), - ); - disk_idx.insert( - "available".to_string(), - Value::bytes(disk.get_available_space()), - ); - disk_idx.insert("total".to_string(), Value::bytes(disk.get_total_space())); - v.push(Value::Object(Dictionary::from(disk_idx))); + let mut disk_idx = SpannedDictBuilder::new(args.name_span); + disk_idx.insert("name", Value::string(disk.get_name().to_string_lossy())); + disk_idx.insert("available", Value::bytes(disk.get_available_space())); + disk_idx.insert("total", Value::bytes(disk.get_total_space())); + v.push(disk_idx.into()); } - idx.insert("disks".to_string(), Value::List(v)); + idx.insert("disks", Value::List(v)); } let network = system.get_network(); let incoming = network.get_income(); let outgoing = network.get_outcome(); - let mut network_idx = indexmap::IndexMap::new(); - network_idx.insert("incoming".to_string(), Value::bytes(incoming)); - network_idx.insert("outgoing".to_string(), Value::bytes(outgoing)); - idx.insert( - "network".to_string(), - Value::Object(Dictionary::from(network_idx)), - ); + let mut network_idx = SpannedDictBuilder::new(args.name_span); + network_idx.insert("incoming", Value::bytes(incoming)); + network_idx.insert("outgoing", Value::bytes(outgoing)); + idx.insert_spanned("network", network_idx); - // println!("{:#?}", system.get_network()); - - let mut stream = VecDeque::new(); - stream.push_back(Value::Object(Dictionary::from(idx))); + let mut stream = stream![idx.into_spanned_value()]; Ok(stream.from_input_stream()) } diff --git a/src/commands/to_array.rs b/src/commands/to_array.rs index 9e2f4c33d9..7cea62dbe8 100644 --- a/src/commands/to_array.rs +++ b/src/commands/to_array.rs @@ -5,7 +5,7 @@ pub fn to_array(args: CommandArgs) -> Result { let out = args.input.values.collect(); Ok(out - .map(|vec: Vec<_>| stream![Value::List(vec)]) + .map(|vec: Vec<_>| stream![Value::List(vec).spanned_unknown()]) // TODO: args.input should have a span .flatten_stream() .from_input_stream()) } diff --git a/src/commands/to_json.rs b/src/commands/to_json.rs index 2244604929..8563761b2f 100644 --- a/src/commands/to_json.rs +++ b/src/commands/to_json.rs @@ -45,15 +45,16 @@ pub fn to_json(args: CommandArgs) -> Result { let out = args.input; let span = args.name_span; Ok(out - .map( - move |a| match serde_json::to_string(&value_to_json_value(&a)) { - Ok(x) => Ok(ReturnValue::Value(Value::Primitive(Primitive::String(x)))), - Err(_) => Err(ShellError::maybe_labeled_error( - "Can not convert to JSON string", - "can not convert piped data to JSON string", - span, - )), - }, - ) - .boxed()) + .values + .map(move |a| match serde_json::to_string(&a) { + Ok(x) => { + ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(args.name_span)) + } + Err(_) => Err(ShellError::maybe_labeled_error( + "Can not convert to JSON string", + "can not convert piped data to JSON string", + span, + )), + }) + .to_output_stream()) } diff --git a/src/commands/to_toml.rs b/src/commands/to_toml.rs index ca3edcf936..1c6543bc70 100644 --- a/src/commands/to_toml.rs +++ b/src/commands/to_toml.rs @@ -37,7 +37,9 @@ pub fn to_toml(args: CommandArgs) -> Result { Ok(out .values .map(move |a| match toml::to_string(&a) { - Ok(x) => ReturnSuccess::value(Value::Primitive(Primitive::String(x))), + Ok(x) => { + ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(args.name_span)) + } Err(_) => Err(ShellError::maybe_labeled_error( "Can not convert to TOML string", "can not convert piped data to TOML string", diff --git a/src/commands/trim.rs b/src/commands/trim.rs index 92466d9f34..79b4acbedd 100644 --- a/src/commands/trim.rs +++ b/src/commands/trim.rs @@ -10,15 +10,14 @@ pub fn trim(args: CommandArgs) -> Result { Ok(input .values - .map(move |v| match v { - Value::Primitive(Primitive::String(s)) => { - ReturnSuccess::value(Value::Primitive(Primitive::String(s.trim().into()))) - } - _ => Err(ShellError::maybe_labeled_error( - "Expected string values from pipeline", - "expects strings from pipeline", - span, - )), - }) + .map(move |v| ReturnSuccess::value(String::check(&v)?.clone())) + // Value::Primitive(Primitive::String(s)) => { + // ReturnSuccess::value(Value::Primitive(Primitive::String(s.trim().into()))) + // } + // _ => Err(ShellError::maybe_labeled_error( + // "Expected string values from pipeline", + // "expects strings from pipeline", + // span, + // )), .to_output_stream()) } diff --git a/src/commands/where_.rs b/src/commands/where_.rs index 9ea08b4f11..d5d9f6bb61 100644 --- a/src/commands/where_.rs +++ b/src/commands/where_.rs @@ -1,5 +1,5 @@ use crate::errors::ShellError; -use crate::object::types::*; +use crate::object::Block; use crate::prelude::*; use futures::future::ready; use log::trace; @@ -13,7 +13,7 @@ command! { let return_value = match result { Err(err) => Some(Err(err)), - Ok(v) if v.is_true() => Some(Ok(ReturnSuccess::Value(item.copy()))), + Ok(v) if v.is_true() => Some(Ok(ReturnSuccess::Value(item.clone()))), _ => None, }; diff --git a/src/context.rs b/src/context.rs index aee27d17e9..f0b8dca629 100644 --- a/src/context.rs +++ b/src/context.rs @@ -54,7 +54,7 @@ impl Context { command: Arc, name_span: Option, args: Args, - input: Vec, + input: Vec>, ) -> Result<(), ShellError> { let command_args = SinkCommandArgs { ctx: self.clone(), diff --git a/src/env/environment.rs b/src/env/environment.rs index 9b0875e651..0590cda68f 100644 --- a/src/env/environment.rs +++ b/src/env/environment.rs @@ -1,9 +1,10 @@ use crate::object::base::Value; +use crate::prelude::*; use std::path::{Path, PathBuf}; #[derive(Debug, Clone)] pub struct Environment { - crate obj: Value, + crate obj: Spanned, crate path: PathBuf, } @@ -12,7 +13,7 @@ impl Environment { let path = std::env::current_dir()?; Ok(Environment { - obj: Value::Filesystem, + obj: Value::Filesystem.spanned_unknown(), path, }) } @@ -21,7 +22,7 @@ impl Environment { self.path.as_path() } - pub fn obj(&self) -> &Value { + pub fn obj(&self) -> &Spanned { &self.obj } } diff --git a/src/errors.rs b/src/errors.rs index a87edd5ce8..d78719f50a 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -48,7 +48,7 @@ pub fn labelled( ) -> impl FnOnce(ShellError) -> ShellError + 'a { let span = span.into(); - move |error| ShellError::maybe_labeled_error(heading, span_message, span) + move |_| ShellError::maybe_labeled_error(heading, span_message, span) } #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)] @@ -247,10 +247,6 @@ impl ShellError { crate fn unexpected(title: impl Into) -> ShellError { ShellError::string(&format!("Unexpected: {}", title.into())) } - - crate fn copy_error(&self) -> ShellError { - self.clone() - } } #[derive(Debug, Clone)] diff --git a/src/evaluate/evaluator.rs b/src/evaluate/evaluator.rs index 38f9012769..0fcccee768 100644 --- a/src/evaluate/evaluator.rs +++ b/src/evaluate/evaluator.rs @@ -10,15 +10,15 @@ use indexmap::IndexMap; #[derive(new)] crate struct Scope { - it: Value, + it: Spanned, #[new(default)] - vars: IndexMap, + vars: IndexMap>, } impl Scope { crate fn empty() -> Scope { Scope { - it: Value::nothing(), + it: Value::nothing().spanned_unknown(), vars: IndexMap::new(), } } @@ -64,8 +64,10 @@ crate fn evaluate_baseline_expr( }) } Some(next) => { - item = - Spanned::from_item(next.clone(), (expr.span().start, name.span().end)) + item = Spanned::from_item( + next.clone().item, + (expr.span().start, name.span().end), + ) } }; } @@ -93,14 +95,11 @@ fn evaluate_reference( source: &Text, ) -> Result, ShellError> { match name { - hir::Variable::It(span) => Ok(Spanned::from_item(scope.it.copy(), span)), - hir::Variable::Other(span) => Ok(Spanned::from_item( - scope - .vars - .get(span.slice(source)) - .map(|v| v.copy()) - .unwrap_or_else(|| Value::nothing()), - span, - )), + hir::Variable::It(span) => Ok(Spanned::from_item(scope.it.item, span)), + hir::Variable::Other(span) => Ok(scope + .vars + .get(span.slice(source)) + .map(|v| v.clone()) + .unwrap_or_else(|| Value::nothing().spanned(span))), } } diff --git a/src/format/table.rs b/src/format/table.rs index 6b2205c3f3..0140ab70bd 100644 --- a/src/format/table.rs +++ b/src/format/table.rs @@ -13,7 +13,7 @@ pub struct TableView { } impl TableView { - fn merge_descriptors(values: &[Value]) -> Vec { + fn merge_descriptors(values: &[Spanned]) -> Vec { let mut ret = vec![]; for value in values { for desc in value.data_descriptors() { @@ -25,7 +25,7 @@ impl TableView { ret } - pub fn from_list(values: &[Value]) -> Option { + pub fn from_list(values: &[Spanned]) -> Option { if values.len() == 0 { return None; } diff --git a/src/format/vtable.rs b/src/format/vtable.rs index 9e658f5c84..ac27f3bc83 100644 --- a/src/format/vtable.rs +++ b/src/format/vtable.rs @@ -12,7 +12,7 @@ pub struct VTableView { } impl VTableView { - pub fn from_list(values: &[Value]) -> Option { + pub fn from_list(values: &[Spanned]) -> Option { if values.len() == 0 { return None; } diff --git a/src/object.rs b/src/object.rs index 7e8be20e09..f094c63a17 100644 --- a/src/object.rs +++ b/src/object.rs @@ -2,9 +2,10 @@ crate mod base; crate mod config; crate mod dict; crate mod files; +crate mod into; crate mod process; crate mod types; -crate use base::{Primitive, Value}; -crate use dict::Dictionary; +crate use base::{Block, Primitive, Switch, Value}; +crate use dict::{Dictionary, SpannedDictBuilder}; crate use files::dir_entry_dict; diff --git a/src/object/base.rs b/src/object/base.rs index 54693314a5..73f144ea08 100644 --- a/src/object/base.rs +++ b/src/object/base.rs @@ -153,8 +153,8 @@ impl Deserialize<'de> for Block { } impl Block { - pub fn invoke(&self, value: &Value) -> Result, ShellError> { - let scope = Scope::new(value.copy()); + pub fn invoke(&self, value: &Spanned) -> Result, ShellError> { + let scope = Scope::new(value.clone()); if self.expressions.len() == 0 { return Ok(Spanned::from_item(Value::nothing(), self.span)); @@ -174,20 +174,19 @@ impl Block { pub enum Value { Primitive(Primitive), Object(crate::object::Dictionary), - List(Vec), Binary(Vec), - + List(Vec>), #[allow(unused)] Block(Block), Filesystem, } -pub fn debug_list(values: &'a Vec) -> ValuesDebug<'a> { +pub fn debug_list(values: &'a Vec>) -> ValuesDebug<'a> { ValuesDebug { values } } pub struct ValuesDebug<'a> { - values: &'a Vec, + values: &'a Vec>, } impl fmt::Debug for ValuesDebug<'a> { @@ -199,12 +198,12 @@ impl fmt::Debug for ValuesDebug<'a> { } pub struct ValueDebug<'a> { - value: &'a Value, + value: &'a Spanned, } impl fmt::Debug for ValueDebug<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.value { + match self.value.item() { Value::Primitive(p) => p.debug(f), Value::Object(o) => o.debug(f), Value::List(l) => debug_list(l).fmt(f), @@ -281,6 +280,12 @@ impl std::convert::TryFrom>> for Switch { } } +impl Spanned { + crate fn debug(&'a self) -> ValueDebug<'a> { + ValueDebug { value: self } + } +} + impl Value { crate fn type_name(&self) -> String { match self { @@ -314,13 +319,16 @@ impl Value { } } - crate fn get_data_by_key(&'a self, name: &str) -> Option<&Value> { + crate fn get_data_by_key(&'a self, name: &str) -> Option<&Spanned> { match self { Value::Object(o) => o.get_data_by_key(name), Value::List(l) => { for item in l { match item { - Value::Object(o) => match o.get_data_by_key(name) { + Spanned { + item: Value::Object(o), + .. + } => match o.get_data_by_key(name) { Some(v) => return Some(v), None => {} }, @@ -333,7 +341,7 @@ impl Value { } } - crate fn get_data_by_index(&'a self, idx: usize) -> Option<&Value> { + crate fn get_data_by_index(&'a self, idx: usize) -> Option<&Spanned> { match self { Value::List(l) => l.iter().nth(idx), _ => None, @@ -352,20 +360,6 @@ impl Value { } } - crate fn copy(&self) -> Value { - match self { - Value::Primitive(p) => Value::Primitive(p.clone()), - Value::Object(o) => Value::Object(o.copy_dict()), - Value::Block(b) => Value::Block(b.clone()), - Value::List(l) => { - let list = l.iter().map(|i| i.copy()).collect(); - Value::List(list) - } - Value::Filesystem => Value::Filesystem, - Value::Binary(b) => Value::Binary(b.clone()), - } - } - crate fn format_leaf(&self, desc: Option<&String>) -> String { match self { Value::Primitive(p) => p.format(desc), @@ -417,7 +411,7 @@ impl Value { } } - crate fn as_pair(&self) -> Result<(Value, Value), ShellError> { + crate fn as_pair(&self) -> Result<(Spanned, Spanned), ShellError> { match self { Value::List(list) if list.len() == 2 => Ok((list[0].clone(), list[1].clone())), other => Err(ShellError::string(format!( @@ -509,11 +503,6 @@ impl Value { pub fn nothing() -> Value { Value::Primitive(Primitive::Nothing) } - - #[allow(unused)] - pub fn list(values: impl Into>) -> Value { - Value::List(values.into()) - } } crate fn select_fields(obj: &Value, fields: &[String]) -> crate::object::Dictionary { @@ -522,9 +511,9 @@ crate fn select_fields(obj: &Value, fields: &[String]) -> crate::object::Diction let descs = obj.data_descriptors(); for field in fields { - match descs.iter().find(|d| *d == field) { + match descs.iter().find(|d| d.name.is_string(field)) { None => out.add(field, Value::nothing()), - Some(desc) => out.add(desc.clone(), obj.get_data(desc).borrow().copy()), + Some(desc) => out.add(desc.clone(), obj.get_data(desc).borrow().clone()), } } @@ -539,7 +528,7 @@ crate fn reject_fields(obj: &Value, fields: &[String]) -> crate::object::Diction for desc in descs { match desc { x if fields.iter().any(|field| *field == x) => continue, - _ => out.add(desc.clone(), obj.get_data(&desc).borrow().copy()), + _ => out.add(desc.clone(), obj.get_data(&desc).borrow().clone()), } } @@ -552,7 +541,7 @@ crate fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool { match descs.iter().find(|d| *d == field) { None => false, Some(desc) => { - let v = obj.get_data(desc).borrow().copy(); + let v = obj.get_data(desc).borrow().clone(); match v { Value::Primitive(Primitive::Boolean(b)) => match (op, rhs) { diff --git a/src/object/config.rs b/src/object/config.rs index 288ed21328..f11fef027d 100644 --- a/src/object/config.rs +++ b/src/object/config.rs @@ -16,24 +16,31 @@ const APP_INFO: AppInfo = AppInfo { #[derive(Deserialize, Serialize)] struct Config { #[serde(flatten)] - extra: IndexMap, + extra: IndexMap>, } -crate fn write_config(map: &IndexMap) -> Result<(), ShellError> { +crate fn write_config(config: &IndexMap>) -> Result<(), ShellError> { let location = app_root(AppDataType::UserConfig, &APP_INFO) .map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?; let filename = location.join("config.toml"); touch(&filename)?; - let contents = toml::to_string(&Config { extra: map.clone() })?; + let contents = toml::to_string(&Config { + extra: config + .iter() + .map(|(k, v)| (k.clone(), v.item.clone())) + .collect(), + })?; fs::write(&filename, &contents)?; Ok(()) } -crate fn config() -> Result, ShellError> { +crate fn config(span: impl Into) -> Result>, ShellError> { + let span = span.into(); + let location = app_root(AppDataType::UserConfig, &APP_INFO) .map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?; @@ -43,9 +50,11 @@ crate fn config() -> Result, ShellError> { trace!("config file = {}", filename.display()); let contents = fs::read_to_string(filename) + .map(|v| v.spanned(span)) .map_err(|err| ShellError::string(&format!("Couldn't read config file:\n{}", err)))?; let parsed: Config = toml::from_str(&contents) + .map(|v| v.spanned(span)) .map_err(|err| ShellError::string(&format!("Couldn't parse config file:\n{}", err)))?; Ok(parsed.extra) diff --git a/src/object/dict.rs b/src/object/dict.rs index 9c0e4ed34f..c8f9965dac 100644 --- a/src/object/dict.rs +++ b/src/object/dict.rs @@ -9,7 +9,7 @@ use std::fmt; #[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize, Clone, new)] pub struct Dictionary { - pub entries: IndexMap, + pub entries: IndexMap>, } impl PartialOrd for Dictionary { @@ -28,8 +28,8 @@ impl PartialOrd for Dictionary { } } -impl From> for Dictionary { - fn from(input: IndexMap) -> Dictionary { +impl From>> for Dictionary { + fn from(input: IndexMap>) -> Dictionary { let mut out = IndexMap::default(); for (key, value) in input { @@ -93,7 +93,7 @@ impl Dictionary { } } - crate fn get_data_by_key(&self, name: &str) -> Option<&Value> { + crate fn get_data_by_key(&self, name: &str) -> Option<&Spanned> { match self .entries .iter() @@ -114,3 +114,41 @@ impl Dictionary { debug.finish() } } + +#[derive(Debug)] +pub struct SpannedDictBuilder { + span: Span, + dict: IndexMap>, +} + +impl SpannedDictBuilder { + pub fn new(span: impl Into) -> SpannedDictBuilder { + SpannedDictBuilder { + span: span.into(), + dict: IndexMap::default(), + } + } + + pub fn insert(&mut self, key: impl Into, value: impl Into) { + self.dict + .insert(key.into(), value.into().spanned(self.span)); + } + + pub fn insert_spanned( + &mut self, + key: impl Into, + value: impl Into>, + ) { + self.dict.insert(key.into(), value.into()); + } + + pub fn into_spanned_value(self) -> Spanned { + Value::Object(Dictionary { entries: self.dict }).spanned(self.span) + } +} + +impl From for Spanned { + fn from(input: SpannedDictBuilder) -> Spanned { + input.into_spanned_value() + } +} diff --git a/src/object/into.rs b/src/object/into.rs new file mode 100644 index 0000000000..dceb5192d1 --- /dev/null +++ b/src/object/into.rs @@ -0,0 +1,23 @@ +use crate::object::{Primitive, Value}; +use crate::prelude::*; + +impl From for Value { + fn from(input: Primitive) -> Value { + Value::Primitive(input) + } +} + +impl From for Value { + fn from(input: String) -> Value { + Value::Primitive(Primitive::String(input)) + } +} + +impl> Spanned { + pub fn into_spanned_value(self) -> Spanned { + let Spanned { item, span } = self; + + let value = item.into(); + value.spanned(span) + } +} diff --git a/src/object/types.rs b/src/object/types.rs index 3d026772e3..46e52548e1 100644 --- a/src/object/types.rs +++ b/src/object/types.rs @@ -2,29 +2,44 @@ use crate::object::base as value; use crate::parser::hir; use crate::prelude::*; use derive_new::new; -use serde_derive::{Deserialize, Serialize}; +use serde_derive::Deserialize; pub trait Type: std::fmt::Debug + Send { + type Extractor: ExtractType; + fn name(&self) -> &'static str; - fn check(&self, value: Spanned) -> Result, ShellError>; + fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError>; fn coerce(&self) -> Option { None } } -pub trait ExtractType: Type { - fn extract(value: Value) -> T; +pub trait ExtractType: Sized { + fn extract(value: &Spanned) -> Result; + fn check(value: &'value Spanned) -> Result<&'value Spanned, ShellError>; } #[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)] pub struct Any; impl Type for Any { + type Extractor = Spanned; + fn name(&self) -> &'static str { "Any" } - fn check(&self, value: Spanned) -> Result, ShellError> { + fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { + Ok(value) + } +} + +impl ExtractType for Spanned { + fn extract(value: &Spanned) -> Result { + Ok(value.clone()) + } + + fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { Ok(value) } } @@ -33,11 +48,13 @@ impl Type for Any { pub struct Integer; impl Type for Integer { + type Extractor = i64; + fn name(&self) -> &'static str { "Integer" } - fn check(&self, value: Spanned) -> Result, ShellError> { + fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { match value { v @ Spanned { item: Value::Primitive(Primitive::Int(_)), @@ -48,11 +65,67 @@ impl Type for Integer { } } -impl ExtractType for Integer { - fn extract(value: Value) -> i64 { +impl ExtractType for i64 { + fn extract(value: &Spanned) -> Result { match value { - Value::Primitive(Primitive::Int(int)) => int, - _ => unreachable!("invariant: must check before extract"), + &Spanned { + item: Value::Primitive(Primitive::Int(int)), + .. + } => Ok(int), + other => Err(ShellError::type_error("Integer", other.spanned_type_name())), + } + } + + fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { + match value { + v @ Spanned { + item: Value::Primitive(Primitive::Int(_)), + .. + } => Ok(v), + other => Err(ShellError::type_error("Integer", other.spanned_type_name())), + } + } +} + +#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)] +pub struct NuString; + +impl Type for NuString { + type Extractor = String; + + fn name(&self) -> &'static str { + "Integer" + } + + fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { + match value { + v @ Spanned { + item: Value::Primitive(Primitive::Int(_)), + .. + } => Ok(v), + other => Err(ShellError::type_error("Integer", other.spanned_type_name())), + } + } +} + +impl ExtractType for String { + fn extract(value: &Spanned) -> Result { + match value { + Spanned { + item: Value::Primitive(Primitive::String(string)), + .. + } => Ok(string.clone()), + other => Err(ShellError::type_error("String", other.spanned_type_name())), + } + } + + fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { + match value { + v @ Spanned { + item: Value::Primitive(Primitive::Int(_)), + .. + } => Ok(v), + other => Err(ShellError::type_error("Integer", other.spanned_type_name())), } } } @@ -61,11 +134,13 @@ impl ExtractType for Integer { pub struct Block; impl Type for Block { + type Extractor = value::Block; + fn name(&self) -> &'static str { "Block" } - fn check(&self, value: Spanned) -> Result, ShellError> { + fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { match value { v @ Spanned { item: Value::Block(_), @@ -76,11 +151,24 @@ impl Type for Block { } } -impl ExtractType for Block { - fn extract(value: Value) -> value::Block { +impl ExtractType for value::Block { + fn extract(value: &Spanned) -> Result { match value { - Value::Block(block) => block, - _ => unreachable!("invariant: must check before extract"), + Spanned { + item: Value::Block(block), + .. + } => Ok(block.clone()), + other => Err(ShellError::type_error("Block", other.spanned_type_name())), + } + } + + fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { + match value { + v @ Spanned { + item: Value::Block(_), + .. + } => Ok(v), + other => Err(ShellError::type_error("Block", other.spanned_type_name())), } } } diff --git a/src/parser.rs b/src/parser.rs index 5b7d7fcbfc..e9a6ce1ac4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -12,7 +12,7 @@ crate use parse::flag::Flag; crate use parse::operator::Operator; crate use parse::parser::{nom_input, pipeline}; crate use parse::pipeline::{Pipeline, PipelineElement}; -pub use parse::span::{Span, Spanned}; +pub use parse::span::{Span, Spanned, SpannedItem}; crate use parse::text::Text; crate use parse::token_tree::{DelimitedNode, Delimiter, PathNode, TokenNode}; crate use parse::tokens::{RawToken, Token}; diff --git a/src/parser/parse/span.rs b/src/parser/parse/span.rs index 4d3f38659a..7ed86e6a12 100644 --- a/src/parser/parse/span.rs +++ b/src/parser/parse/span.rs @@ -16,6 +16,13 @@ pub trait SpannedItem: Sized { fn spanned(self, span: impl Into) -> Spanned { Spanned::from_item(self, span.into()) } + + // For now, this is a temporary facility. In many cases, there are other useful spans that we + // could be using, such as the original source spans of JSON or Toml files, but we don't yet + // have the infrastructure to make that work. + fn spanned_unknown(self) -> Spanned { + Spanned::from_item(self, (0, 0)) + } } impl SpannedItem for T {} @@ -64,6 +71,15 @@ pub struct Span { // source: &'source str, } +impl From> for Span { + fn from(input: Option) -> Span { + match input { + None => Span { start: 0, end: 0 }, + Some(span) => span, + } + } +} + impl From<&Spanned> for Span { fn from(input: &Spanned) -> Span { input.span @@ -113,6 +129,14 @@ impl From<&std::ops::Range> for Span { } impl Span { + pub fn unknown() -> Span { + Span { start: 0, end: 0 } + } + + pub fn is_unknown(&self) -> bool { + self.start == 0 && self.end == 0 + } + pub fn slice(&self, source: &'a str) -> &'a str { &source[self.start..self.end] } diff --git a/src/prelude.rs b/src/prelude.rs index 9c79787cf9..40ef6eb098 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -42,7 +42,7 @@ crate use crate::env::{Environment, Host}; crate use crate::errors::ShellError; crate use crate::object::types::{ExtractType, Type}; crate use crate::object::{Primitive, Value}; -crate use crate::parser::{Span, Spanned}; +crate use crate::parser::{Span, Spanned, SpannedItem}; crate use crate::stream::{InputStream, OutputStream}; crate use crate::Text; crate use futures::stream::BoxStream; @@ -58,7 +58,7 @@ pub trait FromInputStream { impl FromInputStream for T where - T: Stream + Send + 'static, + T: Stream> + Send + 'static, { fn from_input_stream(self) -> OutputStream { OutputStream { diff --git a/src/stream.rs b/src/stream.rs index a7ca6e0486..9281831b89 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -1,15 +1,15 @@ use crate::prelude::*; pub struct InputStream { - crate values: BoxStream<'static, Value>, + crate values: BoxStream<'static, Spanned>, } impl InputStream { - pub fn into_vec(self) -> impl Future> { + pub fn into_vec(self) -> impl Future>> { self.values.collect() } - pub fn from_stream(input: impl Stream + Send + 'static) -> InputStream { + pub fn from_stream(input: impl Stream> + Send + 'static) -> InputStream { InputStream { values: input.boxed(), } @@ -22,8 +22,8 @@ impl From> for InputStream { } } -impl From> for InputStream { - fn from(input: VecDeque) -> InputStream { +impl From>> for InputStream { + fn from(input: VecDeque>) -> InputStream { InputStream { values: input.boxed(), } @@ -46,13 +46,7 @@ pub struct OutputStream { } impl OutputStream { - pub fn from_stream(input: impl Stream + Send + 'static) -> OutputStream { - OutputStream { - values: input.boxed(), - } - } - - pub fn from_input(input: impl Stream + Send + 'static) -> OutputStream { + pub fn from_input(input: impl Stream> + Send + 'static) -> OutputStream { OutputStream { values: input.map(ReturnSuccess::value).boxed(), } From 2da12aed5626e3f4b8417d13f767fb541c5c4f1f Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Mon, 8 Jul 2019 21:31:26 -0700 Subject: [PATCH 04/10] Tests pass --- src/commands/cd.rs | 4 +- src/commands/classified.rs | 17 +++- src/commands/config.rs | 4 +- src/commands/from_ini.rs | 48 +++++++---- src/commands/from_json.rs | 45 ++++++---- src/commands/from_toml.rs | 42 +++++---- src/commands/from_xml.rs | 42 +++++---- src/commands/from_yaml.rs | 38 ++++---- src/commands/ls.rs | 4 +- src/commands/open.rs | 120 ++++++++++++++------------ src/commands/pick.rs | 2 +- src/commands/ps.rs | 2 +- src/commands/reject.rs | 11 ++- src/commands/size.rs | 21 +++-- src/commands/split_column.rs | 24 +++--- src/commands/to_json.rs | 6 +- src/commands/to_toml.rs | 40 +++++++-- src/commands/trim.rs | 5 +- src/commands/view.rs | 2 +- src/errors.rs | 162 +++++++++++++++++++---------------- src/evaluate/evaluator.rs | 18 ++-- src/object/base.rs | 19 ++-- src/object/config.rs | 6 +- src/object/dict.rs | 50 +++++++++-- src/object/files.rs | 26 +++--- src/object/process.rs | 20 ++--- src/object/types.rs | 51 ++--------- src/parser/parse/span.rs | 22 ++++- src/parser/parse_command.rs | 38 ++++---- src/parser/registry.rs | 4 +- src/plugins/inc.rs | 24 ++++-- src/stream.rs | 33 +++++-- 32 files changed, 557 insertions(+), 393 deletions(-) diff --git a/src/commands/cd.rs b/src/commands/cd.rs index 8d76b5cbd0..383b696e14 100644 --- a/src/commands/cd.rs +++ b/src/commands/cd.rs @@ -6,9 +6,9 @@ use std::path::PathBuf; pub fn cd(args: CommandArgs) -> Result { let env = args.env.lock().unwrap(); let latest = env.back().unwrap(); - let obj = latest.obj; + let obj = &latest.obj; - match obj.item { + match obj.item() { Value::Filesystem => { let cwd = latest.path().to_path_buf(); diff --git a/src/commands/classified.rs b/src/commands/classified.rs index d29715c779..93ef2b9782 100644 --- a/src/commands/classified.rs +++ b/src/commands/classified.rs @@ -86,6 +86,17 @@ crate enum ClassifiedCommand { External(ExternalCommand), } +impl ClassifiedCommand { + pub fn span(&self) -> Span { + match self { + ClassifiedCommand::Expr(token) => token.span(), + ClassifiedCommand::Internal(internal) => internal.name_span.into(), + ClassifiedCommand::Sink(sink) => sink.name_span.into(), + ClassifiedCommand::External(external) => external.name_span.into(), + } + } +} + crate struct SinkCommand { crate command: Arc, crate name_span: Option, @@ -190,6 +201,7 @@ impl ExternalCommand { ) -> Result { let stdin = input.stdin; let inputs: Vec> = input.objects.into_vec().await; + let name_span = self.name_span.clone(); trace!("-> {}", self.name); trace!("inputs = {:?}", inputs); @@ -320,9 +332,10 @@ impl ExternalCommand { let stdout = popen.stdout.take().unwrap(); let file = futures::io::AllowStdIo::new(stdout); let stream = Framed::new(file, LinesCodec {}); - let stream = stream.map(|line| Value::string(line.unwrap())); + let stream = + stream.map(move |line| Value::string(line.unwrap()).spanned(name_span)); Ok(ClassifiedInputStream::from_input_stream( - stream.boxed() as BoxStream<'static, Value> + stream.boxed() as BoxStream<'static, Spanned> )) } } diff --git a/src/commands/config.rs b/src/commands/config.rs index 839fe9c275..c28b31da20 100644 --- a/src/commands/config.rs +++ b/src/commands/config.rs @@ -55,7 +55,7 @@ pub fn config(args: CommandArgs) -> Result { .ok_or_else(|| ShellError::string(&format!("Missing key {} in config", key)))?; return Ok( - stream![value.clone()], // futures::stream::once(futures::future::ready(ReturnSuccess::Value(value.clone()))).into(), + stream![value.clone()].into(), // futures::stream::once(futures::future::ready(ReturnSuccess::Value(value.clone()))).into(), ); } @@ -99,7 +99,7 @@ pub fn config(args: CommandArgs) -> Result { } if args.len() == 0 { - return Ok(vec![Value::Object(result.into())].into()); + return Ok(vec![Value::Object(result.into()).spanned(args.name_span)].into()); } Err(ShellError::string(format!("Unimplemented"))) diff --git a/src/commands/from_ini.rs b/src/commands/from_ini.rs index d4697d0acc..863c2d6196 100644 --- a/src/commands/from_ini.rs +++ b/src/commands/from_ini.rs @@ -1,29 +1,41 @@ -use crate::object::{Dictionary, Primitive, Value}; +use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; use indexmap::IndexMap; use std::collections::HashMap; -fn convert_ini_second_to_nu_value(v: &HashMap) -> Value { - let mut second = Dictionary::new(IndexMap::new()); +fn convert_ini_second_to_nu_value( + v: &HashMap, + span: impl Into, +) -> Spanned { + let mut second = SpannedDictBuilder::new(span); + for (key, value) in v.into_iter() { - second.add( - key.clone(), - Value::Primitive(Primitive::String(value.clone())), - ); + second.insert(key.clone(), Primitive::String(value.clone())); } - Value::Object(second) -} -fn convert_ini_top_to_nu_value(v: &HashMap>) -> Value { - let mut top_level = Dictionary::new(IndexMap::new()); - for (key, value) in v.iter() { - top_level.add(key.clone(), convert_ini_second_to_nu_value(value)); - } - Value::Object(top_level) + + second.into_spanned_value() } -pub fn from_ini_string_to_value(s: String) -> Result> { +fn convert_ini_top_to_nu_value( + v: &HashMap>, + span: impl Into, +) -> Spanned { + let span = span.into(); + let mut top_level = SpannedDictBuilder::new(span); + + for (key, value) in v.iter() { + top_level.insert_spanned(key.clone(), convert_ini_second_to_nu_value(value, span)); + } + + top_level.into_spanned_value() +} + +pub fn from_ini_string_to_value( + s: String, + span: impl Into, +) -> Result, Box> { let v: HashMap> = serde_ini::from_str(&s)?; - Ok(convert_ini_top_to_nu_value(&v)) + Ok(convert_ini_top_to_nu_value(&v, span)) } pub fn from_ini(args: CommandArgs) -> Result { @@ -32,7 +44,7 @@ pub fn from_ini(args: CommandArgs) -> Result { Ok(out .values .map(move |a| match a.item { - Value::Primitive(Primitive::String(s)) => match from_ini_string_to_value(s) { + Value::Primitive(Primitive::String(s)) => match from_ini_string_to_value(s, span) { Ok(x) => ReturnSuccess::value(x.spanned(a.span)), Err(e) => Err(ShellError::maybe_labeled_error( "Could not parse as INI", diff --git a/src/commands/from_json.rs b/src/commands/from_json.rs index edf8c1f29b..f91fa120bf 100644 --- a/src/commands/from_json.rs +++ b/src/commands/from_json.rs @@ -1,33 +1,46 @@ use crate::object::base::OF64; -use crate::object::{Dictionary, Primitive, Value}; +use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; -fn convert_json_value_to_nu_value(v: &serde_hjson::Value) -> Value { +fn convert_json_value_to_nu_value(v: &serde_hjson::Value, span: impl Into) -> Spanned { + let span = span.into(); + match v { - serde_hjson::Value::Null => Value::Primitive(Primitive::String(String::from(""))), - serde_hjson::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)), - serde_hjson::Value::F64(n) => Value::Primitive(Primitive::Float(OF64::from(*n))), - serde_hjson::Value::U64(n) => Value::Primitive(Primitive::Int(*n as i64)), - serde_hjson::Value::I64(n) => Value::Primitive(Primitive::Int(*n as i64)), - serde_hjson::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))), + serde_hjson::Value::Null => { + Value::Primitive(Primitive::String(String::from(""))).spanned(span) + } + serde_hjson::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)).spanned(span), + serde_hjson::Value::F64(n) => { + Value::Primitive(Primitive::Float(OF64::from(*n))).spanned(span) + } + serde_hjson::Value::U64(n) => Value::Primitive(Primitive::Int(*n as i64)).spanned(span), + serde_hjson::Value::I64(n) => Value::Primitive(Primitive::Int(*n as i64)).spanned(span), + serde_hjson::Value::String(s) => { + Value::Primitive(Primitive::String(String::from(s))).spanned(span) + } serde_hjson::Value::Array(a) => Value::List( a.iter() - .map(|x| convert_json_value_to_nu_value(x).spanned_unknown()) + .map(|x| convert_json_value_to_nu_value(x, span)) .collect(), - ), + ) + .spanned(span), serde_hjson::Value::Object(o) => { - let mut collected = Dictionary::default(); + let mut collected = SpannedDictBuilder::new(span); for (k, v) in o.iter() { - collected.add(k.clone(), convert_json_value_to_nu_value(v)); + collected.add(k.clone(), convert_json_value_to_nu_value(v, span)); } - Value::Object(collected) + + collected.into_spanned_value() } } } -pub fn from_json_string_to_value(s: String) -> serde_hjson::Result { +pub fn from_json_string_to_value( + s: String, + span: impl Into, +) -> serde_hjson::Result> { let v: serde_hjson::Value = serde_hjson::from_str(&s)?; - Ok(convert_json_value_to_nu_value(&v)) + Ok(convert_json_value_to_nu_value(&v, span)) } pub fn from_json(args: CommandArgs) -> Result { @@ -36,7 +49,7 @@ pub fn from_json(args: CommandArgs) -> Result { Ok(out .values .map(move |a| match a.item { - Value::Primitive(Primitive::String(s)) => match from_json_string_to_value(s) { + Value::Primitive(Primitive::String(s)) => match from_json_string_to_value(s, span) { Ok(x) => ReturnSuccess::value(x.spanned(a.span)), Err(_) => Err(ShellError::maybe_labeled_error( "Could not parse as JSON", diff --git a/src/commands/from_toml.rs b/src/commands/from_toml.rs index a91c591726..a38058f5e8 100644 --- a/src/commands/from_toml.rs +++ b/src/commands/from_toml.rs @@ -1,32 +1,44 @@ use crate::object::base::OF64; -use crate::object::{Dictionary, Primitive, Value}; +use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; -fn convert_toml_value_to_nu_value(v: &toml::Value) -> Value { +fn convert_toml_value_to_nu_value(v: &toml::Value, span: impl Into) -> Spanned { + let span = span.into(); + match v { - toml::Value::Boolean(b) => Value::Primitive(Primitive::Boolean(*b)), - toml::Value::Integer(n) => Value::Primitive(Primitive::Int(*n)), - toml::Value::Float(n) => Value::Primitive(Primitive::Float(OF64::from(*n))), - toml::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))), + toml::Value::Boolean(b) => Value::Primitive(Primitive::Boolean(*b)).spanned(span), + toml::Value::Integer(n) => Value::Primitive(Primitive::Int(*n)).spanned(span), + toml::Value::Float(n) => Value::Primitive(Primitive::Float(OF64::from(*n))).spanned(span), + toml::Value::String(s) => { + Value::Primitive(Primitive::String(String::from(s))).spanned(span) + } toml::Value::Array(a) => Value::List( a.iter() - .map(|x| convert_toml_value_to_nu_value(x).spanned_unknown()) + .map(|x| convert_toml_value_to_nu_value(x, span)) .collect(), - ), - toml::Value::Datetime(dt) => Value::Primitive(Primitive::String(dt.to_string())), + ) + .spanned(span), + toml::Value::Datetime(dt) => { + Value::Primitive(Primitive::String(dt.to_string())).spanned(span) + } toml::Value::Table(t) => { - let mut collected = Dictionary::default(); + let mut collected = SpannedDictBuilder::new(span); + for (k, v) in t.iter() { - collected.add(k.clone(), convert_toml_value_to_nu_value(v)); + collected.add(k.clone(), convert_toml_value_to_nu_value(v, span)); } - Value::Object(collected) + + collected.into_spanned_value() } } } -pub fn from_toml_string_to_value(s: String) -> Result> { +pub fn from_toml_string_to_value( + s: String, + span: impl Into, +) -> Result, Box> { let v: toml::Value = s.parse::()?; - Ok(convert_toml_value_to_nu_value(&v)) + Ok(convert_toml_value_to_nu_value(&v, span)) } pub fn from_toml(args: CommandArgs) -> Result { @@ -35,7 +47,7 @@ pub fn from_toml(args: CommandArgs) -> Result { Ok(out .values .map(move |a| match a.item { - Value::Primitive(Primitive::String(s)) => match from_toml_string_to_value(s) { + Value::Primitive(Primitive::String(s)) => match from_toml_string_to_value(s, span) { Ok(x) => ReturnSuccess::value(x.spanned(a.span)), Err(_) => Err(ShellError::maybe_labeled_error( "Could not parse as TOML", diff --git a/src/commands/from_xml.rs b/src/commands/from_xml.rs index 8a722ea3fc..9741592a8f 100644 --- a/src/commands/from_xml.rs +++ b/src/commands/from_xml.rs @@ -1,19 +1,27 @@ -use crate::object::{Dictionary, Primitive, Value}; +use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; -fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>) -> Value { +fn from_node_to_value<'a, 'd>( + n: &roxmltree::Node<'a, 'd>, + span: impl Into, +) -> Spanned { + let span = span.into(); + if n.is_element() { let name = n.tag_name().name().trim().to_string(); let mut children_values = vec![]; for c in n.children() { - children_values.push(from_node_to_value(&c)); + children_values.push(from_node_to_value(&c, span)); } let children_values: Vec> = children_values .into_iter() .filter(|x| match x { - Value::Primitive(Primitive::String(f)) => { + Spanned { + item: Value::Primitive(Primitive::String(f)), + .. + } => { if f.trim() == "" { false } else { @@ -22,31 +30,33 @@ fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>) -> Value { } _ => true, }) - .map(|v| v.spanned_unknown()) .collect(); let mut collected = Dictionary::default(); - collected.add(name.clone(), Value::List(children_values)); + collected.add(name.clone(), Value::List(children_values).spanned(span)); - Value::Object(collected) + collected.into_spanned_value() } else if n.is_comment() { - Value::string("") + Value::string("").spanned(span) } else if n.is_pi() { - Value::string("") + Value::string("").spanned(span) } else if n.is_text() { - Value::string(n.text().unwrap()) + Value::string(n.text().unwrap()).spanned(span) } else { - Value::string("") + Value::string("").spanned(span) } } -fn from_document_to_value(d: &roxmltree::Document) -> Value { - from_node_to_value(&d.root_element()) +fn from_document_to_value(d: &roxmltree::Document, span: impl Into) -> Spanned { + from_node_to_value(&d.root_element(), span) } -pub fn from_xml_string_to_value(s: String) -> Result> { +pub fn from_xml_string_to_value( + s: String, + span: impl Into, +) -> Result, Box> { let parsed = roxmltree::Document::parse(&s)?; - Ok(from_document_to_value(&parsed)) + Ok(from_document_to_value(&parsed, span)) } pub fn from_xml(args: CommandArgs) -> Result { @@ -55,7 +65,7 @@ pub fn from_xml(args: CommandArgs) -> Result { Ok(out .values .map(move |a| match a.item { - Value::Primitive(Primitive::String(s)) => match from_xml_string_to_value(s) { + Value::Primitive(Primitive::String(s)) => match from_xml_string_to_value(s, span) { Ok(x) => ReturnSuccess::value(x.spanned(a.span)), Err(_) => Err(ShellError::maybe_labeled_error( "Could not parse as XML", diff --git a/src/commands/from_yaml.rs b/src/commands/from_yaml.rs index b4679fdb78..0568ddce74 100644 --- a/src/commands/from_yaml.rs +++ b/src/commands/from_yaml.rs @@ -1,42 +1,50 @@ use crate::object::base::OF64; -use crate::object::{Dictionary, Primitive, Value}; +use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; -fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value) -> Value { +fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, span: impl Into) -> Spanned { + let span = span.into(); + match v { - serde_yaml::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)), + serde_yaml::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)).spanned(span), serde_yaml::Value::Number(n) if n.is_i64() => { - Value::Primitive(Primitive::Int(n.as_i64().unwrap())) + Value::Primitive(Primitive::Int(n.as_i64().unwrap())).spanned(span) } serde_yaml::Value::Number(n) if n.is_f64() => { - Value::Primitive(Primitive::Float(OF64::from(n.as_f64().unwrap()))) + Value::Primitive(Primitive::Float(OF64::from(n.as_f64().unwrap()))).spanned(span) } - serde_yaml::Value::String(s) => Value::string(s), + serde_yaml::Value::String(s) => Value::string(s).spanned(span), serde_yaml::Value::Sequence(a) => Value::List( a.iter() - .map(|x| convert_yaml_value_to_nu_value(x).spanned_unknown()) + .map(|x| convert_yaml_value_to_nu_value(x, span)) .collect(), - ), + ) + .spanned(span), serde_yaml::Value::Mapping(t) => { - let mut collected = Dictionary::default(); + let mut collected = SpannedDictBuilder::new(span); + for (k, v) in t.iter() { match k { serde_yaml::Value::String(k) => { - collected.add(k.clone(), convert_yaml_value_to_nu_value(v)); + collected.add(k.clone(), convert_yaml_value_to_nu_value(v, span)); } _ => unimplemented!("Unknown key type"), } } - Value::Object(collected) + + collected.into_spanned_value() } - serde_yaml::Value::Null => Value::Primitive(Primitive::Nothing), + serde_yaml::Value::Null => Value::Primitive(Primitive::Nothing).spanned(span), x => unimplemented!("Unsupported yaml case: {:?}", x), } } -pub fn from_yaml_string_to_value(s: String) -> serde_yaml::Result { +pub fn from_yaml_string_to_value( + s: String, + span: impl Into, +) -> serde_yaml::Result> { let v: serde_yaml::Value = serde_yaml::from_str(&s)?; - Ok(convert_yaml_value_to_nu_value(&v)) + Ok(convert_yaml_value_to_nu_value(&v, span)) } pub fn from_yaml(args: CommandArgs) -> Result { @@ -45,7 +53,7 @@ pub fn from_yaml(args: CommandArgs) -> Result { Ok(out .values .map(move |a| match a.item { - Value::Primitive(Primitive::String(s)) => match from_yaml_string_to_value(s) { + Value::Primitive(Primitive::String(s)) => match from_yaml_string_to_value(s, span) { Ok(x) => ReturnSuccess::value(x.spanned(a.span)), Err(_) => Err(ShellError::maybe_labeled_error( "Could not parse as YAML", diff --git a/src/commands/ls.rs b/src/commands/ls.rs index 8181e9cea3..ad4c5a723a 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -44,8 +44,8 @@ pub fn ls(args: CommandArgs) -> Result { let mut shell_entries = VecDeque::new(); for entry in entries { - let value = Value::Object(dir_entry_dict(&entry?)?); - shell_entries.push_back(ReturnSuccess::value(value.spanned_unknown())) + let value = dir_entry_dict(&entry?, args.name_span)?; + shell_entries.push_back(ReturnSuccess::value(value)) } Ok(shell_entries.to_output_stream()) } diff --git a/src/commands/open.rs b/src/commands/open.rs index 72440bea79..14e253d33d 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -155,60 +155,72 @@ pub fn parse_as_value( name_span: Option, ) -> Result, ShellError> { match extension { - Some(x) if x == "toml" => crate::commands::from_toml::from_toml_string_to_value(contents) - .map(|c| c.spanned(contents_span)) - .map_err(move |_| { - ShellError::maybe_labeled_error( - "Could not open as TOML", - "could not open as TOML", - name_span, - ) - }), - Some(x) if x == "json" => crate::commands::from_json::from_json_string_to_value(contents) - .map(|c| c.spanned(contents_span)) - .map_err(move |_| { - ShellError::maybe_labeled_error( - "Could not open as JSON", - "could not open as JSON", - name_span, - ) - }), - Some(x) if x == "ini" => crate::commands::from_ini::from_ini_string_to_value(contents) - .map(|c| c.spanned(contents_span)) - .map_err(move |_| { - ShellError::maybe_labeled_error( - "Could not open as INI", - "could not open as INI", - name_span, - ) - }), - Some(x) if x == "xml" => crate::commands::from_xml::from_xml_string_to_value(contents) - .map(|c| c.spanned(contents_span)) - .map_err(move |_| { - ShellError::maybe_labeled_error( - "Could not open as XML", - "could not open as XML", - name_span, - ) - }), - Some(x) if x == "yml" => crate::commands::from_yaml::from_yaml_string_to_value(contents) - .map(|c| c.spanned(contents_span)) - .map_err(move |_| { - ShellError::maybe_labeled_error( - "Could not open as YAML", - "could not open as YAML", - name_span, - ) - }), - Some(x) if x == "yaml" => crate::commands::from_yaml::from_yaml_string_to_value(contents) - .map(|c| c.spanned(contents_span)) - .map_err(move |_| { - ShellError::maybe_labeled_error( - "Could not open as YAML", - "could not open as YAML", - name_span, - ) - }), + Some(x) if x == "toml" => { + crate::commands::from_toml::from_toml_string_to_value(contents, contents_span) + .map(|c| c.spanned(contents_span)) + .map_err(move |_| { + ShellError::maybe_labeled_error( + "Could not open as TOML", + "could not open as TOML", + name_span, + ) + }) + } + Some(x) if x == "json" => { + crate::commands::from_json::from_json_string_to_value(contents, contents_span) + .map(|c| c.spanned(contents_span)) + .map_err(move |_| { + ShellError::maybe_labeled_error( + "Could not open as JSON", + "could not open as JSON", + name_span, + ) + }) + } + Some(x) if x == "ini" => { + crate::commands::from_ini::from_ini_string_to_value(contents, contents_span) + .map(|c| c.spanned(contents_span)) + .map_err(move |_| { + ShellError::maybe_labeled_error( + "Could not open as INI", + "could not open as INI", + name_span, + ) + }) + } + Some(x) if x == "xml" => { + crate::commands::from_xml::from_xml_string_to_value(contents, contents_span).map_err( + move |_| { + ShellError::maybe_labeled_error( + "Could not open as XML", + "could not open as XML", + name_span, + ) + }, + ) + } + Some(x) if x == "yml" => { + crate::commands::from_yaml::from_yaml_string_to_value(contents, contents_span).map_err( + move |_| { + ShellError::maybe_labeled_error( + "Could not open as YAML", + "could not open as YAML", + name_span, + ) + }, + ) + } + Some(x) if x == "yaml" => { + crate::commands::from_yaml::from_yaml_string_to_value(contents, contents_span).map_err( + move |_| { + ShellError::maybe_labeled_error( + "Could not open as YAML", + "could not open as YAML", + name_span, + ) + }, + ) + } _ => Ok(Value::string(contents).spanned(contents_span)), } } diff --git a/src/commands/pick.rs b/src/commands/pick.rs index e4b2c35b72..d9f42aa6b1 100644 --- a/src/commands/pick.rs +++ b/src/commands/pick.rs @@ -18,7 +18,7 @@ pub fn pick(args: CommandArgs) -> Result { let objects = input .values - .map(move |value| Value::Object(select_fields(&value.item, &fields)).spanned(value.span)); + .map(move |value| select_fields(&value.item, &fields, value.span)); Ok(objects.from_input_stream()) } diff --git a/src/commands/ps.rs b/src/commands/ps.rs index d2be9c0ddc..5336ec97f0 100644 --- a/src/commands/ps.rs +++ b/src/commands/ps.rs @@ -11,7 +11,7 @@ pub fn ps(args: CommandArgs) -> Result { let list = list .into_iter() - .map(|(item, process)| Value::Object(process_dict(process)).spanned(args.name_span)) + .map(|(item, process)| process_dict(process, args.name_span)) .collect::>(); Ok(list.from_input_stream()) diff --git a/src/commands/reject.rs b/src/commands/reject.rs index 7fb0161c64..fc53aaea9c 100644 --- a/src/commands/reject.rs +++ b/src/commands/reject.rs @@ -4,6 +4,8 @@ use crate::object::Value; use crate::prelude::*; pub fn reject(args: CommandArgs) -> Result { + let name_span = args.name_span; + if args.len() == 0 { return Err(ShellError::maybe_labeled_error( "Reject requires fields", @@ -15,10 +17,11 @@ pub fn reject(args: CommandArgs) -> Result { let fields: Result, _> = args.positional_iter().map(|a| a.as_string()).collect(); let fields = fields?; - let stream = args - .input - .values - .map(move |item| Value::Object(reject_fields(&item, &fields)).spanned(args.name_span)); + let stream = args.input.values.map(move |item| { + reject_fields(&item, &fields, item.span) + .into_spanned_value() + .spanned(name_span) + }); Ok(stream.from_input_stream()) } diff --git a/src/commands/size.rs b/src/commands/size.rs index 041e8181a8..b94b55cb0c 100644 --- a/src/commands/size.rs +++ b/src/commands/size.rs @@ -1,6 +1,5 @@ use crate::errors::ShellError; -use crate::object::dict::Dictionary; -use crate::object::Value; +use crate::object::{SpannedDictBuilder, Value}; use crate::prelude::*; use std::fs::File; use std::io::prelude::*; @@ -30,14 +29,14 @@ pub fn size(args: CommandArgs) -> Result { let path = cwd.join(&name); let mut file = File::open(path)?; file.read_to_string(&mut contents)?; - list.push_back(count(&name, &contents).spanned(spanned_name).into()); + list.push_back(count(&name, &contents, spanned_name).into()); contents.clear(); } Ok(list.to_output_stream()) } -fn count(name: &str, contents: &str) -> Value { +fn count(name: &str, contents: &str, span: impl Into) -> Spanned { let mut lines: i64 = 0; let mut words: i64 = 0; let mut chars: i64 = 0; @@ -62,12 +61,12 @@ fn count(name: &str, contents: &str) -> Value { } } - let mut dict = Dictionary::default(); - dict.add("name", Value::string(name)); - dict.add("lines", Value::int(lines)); - dict.add("words", Value::int(words)); - dict.add("chars", Value::int(chars)); - dict.add("max length", Value::int(bytes)); + let mut dict = SpannedDictBuilder::new(span); + dict.insert("name", Value::string(name)); + dict.insert("lines", Value::int(lines)); + dict.insert("words", Value::int(words)); + dict.insert("chars", Value::int(chars)); + dict.insert("max length", Value::int(bytes)); - Value::Object(dict) + dict.into_spanned_value() } diff --git a/src/commands/split_column.rs b/src/commands/split_column.rs index 037e34b7cb..d2acde1db6 100644 --- a/src/commands/split_column.rs +++ b/src/commands/split_column.rs @@ -1,5 +1,5 @@ use crate::errors::ShellError; -use crate::object::{Primitive, Value}; +use crate::object::{Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; use log::trace; @@ -36,29 +36,27 @@ pub fn split_column(args: CommandArgs) -> Result { gen_columns.push(format!("Column{}", i + 1)); } - let mut dict = crate::object::Dictionary::default(); + let mut dict = SpannedDictBuilder::new(v.span); for (&k, v) in split_result.iter().zip(gen_columns.iter()) { - dict.add(v.clone(), Value::Primitive(Primitive::String(k.into()))); + dict.insert(v.clone(), Primitive::String(k.into())); } - ReturnSuccess::value(Value::Object(dict).spanned(v.span)) + + ReturnSuccess::value(dict.into_spanned_value()) } else if split_result.len() == (positional.len() - 1) { - let mut dict = crate::object::Dictionary::default(); + let mut dict = SpannedDictBuilder::new(v.span); for (&k, v) in split_result.iter().zip(positional.iter().skip(1)) { - dict.add( + dict.insert( v.as_string().unwrap(), Value::Primitive(Primitive::String(k.into())), ); } - ReturnSuccess::value(Value::Object(dict).spanned(v.span)) + ReturnSuccess::value(dict.into_spanned_value()) } else { - let mut dict = crate::object::Dictionary::default(); + let mut dict = SpannedDictBuilder::new(v.span); for k in positional.iter().skip(1) { - dict.add( - k.as_string().unwrap().trim(), - Value::Primitive(Primitive::String("".into())), - ); + dict.insert(k.as_string().unwrap().trim(), Primitive::String("".into())); } - ReturnSuccess::value(Value::Object(dict).spanned(v.span)) + ReturnSuccess::value(dict.into_spanned_value()) } } _ => Err(ShellError::maybe_labeled_error( diff --git a/src/commands/to_json.rs b/src/commands/to_json.rs index 8563761b2f..d75586c219 100644 --- a/src/commands/to_json.rs +++ b/src/commands/to_json.rs @@ -43,17 +43,17 @@ pub fn value_to_json_value(v: &Value) -> serde_json::Value { pub fn to_json(args: CommandArgs) -> Result { let out = args.input; - let span = args.name_span; + let name_span = args.name_span; Ok(out .values .map(move |a| match serde_json::to_string(&a) { Ok(x) => { - ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(args.name_span)) + ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span)) } Err(_) => Err(ShellError::maybe_labeled_error( "Can not convert to JSON string", "can not convert piped data to JSON string", - span, + name_span, )), }) .to_output_stream()) diff --git a/src/commands/to_toml.rs b/src/commands/to_toml.rs index 1c6543bc70..b23ca35195 100644 --- a/src/commands/to_toml.rs +++ b/src/commands/to_toml.rs @@ -33,18 +33,40 @@ pub fn value_to_toml_value(v: &Value) -> toml::Value { pub fn to_toml(args: CommandArgs) -> Result { let out = args.input; - let span = args.name_span; + let name_span = args.name_span; + Ok(out .values - .map(move |a| match toml::to_string(&a) { - Ok(x) => { - ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(args.name_span)) + .map(move |a| { + match toml::to_string(&a) { + Ok(val) => { + return ReturnSuccess::value( + Value::Primitive(Primitive::String(val)).spanned(name_span), + ) + } + + Err(err) => Err(ShellError::type_error( + "String", + format!("{:?} - {:?}", a.type_name(), err).spanned(name_span), + )), // toml::Value::String(String) => { + // return ReturnSuccess::value( + // Value::Primitive(Primitive::String(x)).spanned(name_span), + // ) + // } + // toml::Value::Integer(i64) => "Integer", + // toml::Value::Float(f64) => "Decimal", + // toml::Value::Boolean(bool) => "Boolean", + // toml::Value::Datetime(Datetime) => "Date", + // toml::Value::Array(Array) => "Array", + // toml::Value::Table(Table) => "Table", } - Err(_) => Err(ShellError::maybe_labeled_error( - "Can not convert to TOML string", - "can not convert piped data to TOML string", - span, - )), + // return Err(ShellError::type_error("String", ty.spanned(name_span))); + + // Err(_) => Err(ShellError::maybe_labeled_error( + // "Can not convert to TOML string", + // "can not convert piped data to TOML string", + // name_span, + // )), }) .to_output_stream()) } diff --git a/src/commands/trim.rs b/src/commands/trim.rs index 79b4acbedd..e4d66ffd2e 100644 --- a/src/commands/trim.rs +++ b/src/commands/trim.rs @@ -10,7 +10,10 @@ pub fn trim(args: CommandArgs) -> Result { Ok(input .values - .map(move |v| ReturnSuccess::value(String::check(&v)?.clone())) + .map(move |v| { + let string = String::extract(&v)?; + ReturnSuccess::value(Value::string(string.trim()).spanned(v.span)) + }) // Value::Primitive(Primitive::String(s)) => { // ReturnSuccess::value(Value::Primitive(Primitive::String(s.trim().into()))) // } diff --git a/src/commands/view.rs b/src/commands/view.rs index 3522b82fe7..06f34fc54d 100644 --- a/src/commands/view.rs +++ b/src/commands/view.rs @@ -46,5 +46,5 @@ pub fn view(args: CommandArgs) -> Result { let _ = printer.file(file.display().to_string()); - Ok(VecDeque::new().into()) + Ok(OutputStream::empty()) } diff --git a/src/errors.rs b/src/errors.rs index d78719f50a..17ccf38f5f 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -52,26 +52,9 @@ pub fn labelled( } #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)] -pub enum ShellError { - String(StringError), - TypeError { - expected: String, - actual: Spanned>, - }, - MissingProperty { - subpath: Description, - expr: Description, - }, - ArgumentError { - command: String, - error: ArgumentError, - span: Span, - }, - Diagnostic(ShellDiagnostic), - CoerceError { - left: Spanned, - right: Spanned, - }, +pub struct ShellError { + error: ProximateShellError, + cause: Option>, } impl ShellError { @@ -79,10 +62,39 @@ impl ShellError { expected: impl Into, actual: Spanned>, ) -> ShellError { - ShellError::TypeError { + ProximateShellError::TypeError { expected: expected.into(), actual: actual.map(|i| Some(i.into())), } + .start() + } + + crate fn coerce_error( + left: Spanned>, + right: Spanned>, + ) -> ShellError { + ProximateShellError::CoerceError { + left: left.map(|l| l.into()), + right: right.map(|r| r.into()), + } + .start() + } + + crate fn missing_property(subpath: Description, expr: Description) -> ShellError { + ProximateShellError::MissingProperty { subpath, expr }.start() + } + + crate fn argument_error( + command: impl Into, + kind: ArgumentError, + span: Span, + ) -> ShellError { + ProximateShellError::ArgumentError { + command: command.into(), + error: kind, + span: span, + } + .start() } crate fn parse_error( @@ -97,40 +109,20 @@ impl ShellError { .with_label(Label::new_primary(Span::from(span.0))); ShellError::diagnostic(diagnostic) - // nom::Context::Code(span, kind) => { - // let diagnostic = - // Diagnostic::new(Severity::Error, format!("{}", kind.description())) - // .with_label(Label::new_primary(Span::from(span))); - - // ShellError::diagnostic(diagnostic) - // } - } // ParseError::UnrecognizedToken { - // token: (start, SpannedToken { token, .. }, end), - // expected, - // } => { - // let diagnostic = Diagnostic::new( - // Severity::Error, - // format!("Unexpected {:?}, expected {:?}", token, expected), - // ) - // .with_label(Label::new_primary(Span::from((start, end)))); - - // ShellError::diagnostic(diagnostic) - // } - // ParseError::User { error } => error, - // other => ShellError::string(format!("{:?}", other)), + } } } crate fn diagnostic(diagnostic: Diagnostic) -> ShellError { - ShellError::Diagnostic(ShellDiagnostic { diagnostic }) + ProximateShellError::Diagnostic(ShellDiagnostic { diagnostic }).start() } crate fn to_diagnostic(self) -> Diagnostic { - match self { - ShellError::String(StringError { title, .. }) => { + match self.error { + ProximateShellError::String(StringError { title, .. }) => { Diagnostic::new(Severity::Error, title) } - ShellError::ArgumentError { + ProximateShellError::ArgumentError { command, error, span, @@ -166,7 +158,7 @@ impl ShellError { ) .with_label(Label::new_primary(span)), }, - ShellError::TypeError { + ProximateShellError::TypeError { expected, actual: Spanned { @@ -178,13 +170,13 @@ impl ShellError { .with_message(format!("Expected {}, found {}", expected, actual)), ), - ShellError::TypeError { + ProximateShellError::TypeError { expected, actual: Spanned { item: None, span }, } => Diagnostic::new(Severity::Error, "Type Error") .with_label(Label::new_primary(span).with_message(expected)), - ShellError::MissingProperty { subpath, expr } => { + ProximateShellError::MissingProperty { subpath, expr } => { let subpath = subpath.into_label(); let expr = expr.into_label(); @@ -202,8 +194,8 @@ impl ShellError { diag } - ShellError::Diagnostic(diag) => diag.diagnostic, - ShellError::CoerceError { left, right } => { + ProximateShellError::Diagnostic(diag) => diag.diagnostic, + ProximateShellError::CoerceError { left, right } => { Diagnostic::new(Severity::Error, "Coercion error") .with_label(Label::new_primary(left.span).with_message(left.item)) .with_label(Label::new_secondary(right.span).with_message(right.item)) @@ -237,7 +229,7 @@ impl ShellError { } pub fn string(title: impl Into) -> ShellError { - ShellError::String(StringError::new(title.into(), Value::nothing())) + ProximateShellError::String(StringError::new(title.into(), Value::nothing())).start() } crate fn unimplemented(title: impl Into) -> ShellError { @@ -249,6 +241,37 @@ impl ShellError { } } +#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)] +pub enum ProximateShellError { + String(StringError), + TypeError { + expected: String, + actual: Spanned>, + }, + MissingProperty { + subpath: Description, + expr: Description, + }, + ArgumentError { + command: String, + error: ArgumentError, + span: Span, + }, + Diagnostic(ShellDiagnostic), + CoerceError { + left: Spanned, + right: Spanned, + }, +} +impl ProximateShellError { + fn start(self) -> ShellError { + ShellError { + cause: None, + error: self, + } + } +} + #[derive(Debug, Clone)] pub struct ShellDiagnostic { crate diagnostic: Diagnostic, @@ -322,13 +345,13 @@ pub struct StringError { impl std::fmt::Display for ShellError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - ShellError::String(s) => write!(f, "{}", &s.title), - ShellError::TypeError { .. } => write!(f, "TypeError"), - ShellError::MissingProperty { .. } => write!(f, "MissingProperty"), - ShellError::ArgumentError { .. } => write!(f, "ArgumentError"), - ShellError::Diagnostic(_) => write!(f, ""), - ShellError::CoerceError { .. } => write!(f, "CoerceError"), + match &self.error { + ProximateShellError::String(s) => write!(f, "{}", &s.title), + ProximateShellError::TypeError { .. } => write!(f, "TypeError"), + ProximateShellError::MissingProperty { .. } => write!(f, "MissingProperty"), + ProximateShellError::ArgumentError { .. } => write!(f, "ArgumentError"), + ProximateShellError::Diagnostic(_) => write!(f, ""), + ProximateShellError::CoerceError { .. } => write!(f, "CoerceError"), } } } @@ -337,45 +360,40 @@ impl std::error::Error for ShellError {} impl std::convert::From for ShellError { fn from(input: std::io::Error) -> ShellError { - ShellError::String(StringError { + ProximateShellError::String(StringError { title: format!("{}", input), error: Value::nothing(), }) + .start() } } impl std::convert::From for ShellError { fn from(_input: futures_sink::VecSinkError) -> ShellError { - ShellError::String(StringError { + ProximateShellError::String(StringError { title: format!("Unexpected Vec Sink Error"), error: Value::nothing(), }) + .start() } } impl std::convert::From for ShellError { fn from(input: subprocess::PopenError) -> ShellError { - ShellError::String(StringError { + ProximateShellError::String(StringError { title: format!("{}", input), error: Value::nothing(), }) + .start() } } -// impl std::convert::From> for ShellError { -// fn from(input: nom::Err<(&str, nom::ErrorKind)>) -> ShellError { -// ShellError::String(StringError { -// title: format!("{:?}", input), -// error: Value::nothing(), -// }) -// } -// } - impl std::convert::From for ShellError { fn from(input: toml::ser::Error) -> ShellError { - ShellError::String(StringError { + ProximateShellError::String(StringError { title: format!("{:?}", input), error: Value::nothing(), }) + .start() } } diff --git a/src/evaluate/evaluator.rs b/src/evaluate/evaluator.rs index 0fcccee768..a8a3915e97 100644 --- a/src/evaluate/evaluator.rs +++ b/src/evaluate/evaluator.rs @@ -39,10 +39,10 @@ crate fn evaluate_baseline_expr( match left.compare(binary.op(), &*right) { Ok(result) => Ok(Spanned::from_item(Value::boolean(result), *expr.span())), - Err((left_type, right_type)) => Err(ShellError::CoerceError { - left: binary.left().copy_span(left_type), - right: binary.right().copy_span(right_type), - }), + Err((left_type, right_type)) => Err(ShellError::coerce_error( + binary.left().copy_span(left_type), + binary.right().copy_span(right_type), + )), } } RawExpression::Block(block) => Ok(Spanned::from_item( @@ -58,10 +58,10 @@ crate fn evaluate_baseline_expr( match next { None => { - return Err(ShellError::MissingProperty { - subpath: Description::from(item.spanned_type_name()), - expr: Description::from(name.clone()), - }) + return Err(ShellError::missing_property( + Description::from(item.spanned_type_name()), + Description::from(name.clone()), + )) } Some(next) => { item = Spanned::from_item( @@ -95,7 +95,7 @@ fn evaluate_reference( source: &Text, ) -> Result, ShellError> { match name { - hir::Variable::It(span) => Ok(Spanned::from_item(scope.it.item, span)), + hir::Variable::It(span) => Ok(Spanned::from_item(scope.it.item.clone(), span)), hir::Variable::Other(span) => Ok(scope .vars .get(span.slice(source)) diff --git a/src/object/base.rs b/src/object/base.rs index 73f144ea08..04662972ab 100644 --- a/src/object/base.rs +++ b/src/object/base.rs @@ -1,5 +1,6 @@ use crate::errors::ShellError; use crate::evaluate::{evaluate_baseline_expr, Scope}; +use crate::object::SpannedDictBuilder; use crate::parser::{hir, Operator, Span, Spanned}; use crate::prelude::*; use crate::Text; @@ -505,34 +506,34 @@ impl Value { } } -crate fn select_fields(obj: &Value, fields: &[String]) -> crate::object::Dictionary { - let mut out = crate::object::Dictionary::default(); +crate fn select_fields(obj: &Value, fields: &[String], span: impl Into) -> Spanned { + let mut out = SpannedDictBuilder::new(span); let descs = obj.data_descriptors(); for field in fields { match descs.iter().find(|d| d.name.is_string(field)) { - None => out.add(field, Value::nothing()), - Some(desc) => out.add(desc.clone(), obj.get_data(desc).borrow().clone()), + None => out.insert(field, Value::nothing()), + Some(desc) => out.insert(desc.clone(), obj.get_data(desc).borrow().clone()), } } - out + out.into_spanned_value() } -crate fn reject_fields(obj: &Value, fields: &[String]) -> crate::object::Dictionary { - let mut out = crate::object::Dictionary::default(); +crate fn reject_fields(obj: &Value, fields: &[String], span: impl Into) -> Spanned { + let mut out = SpannedDictBuilder::new(span); let descs = obj.data_descriptors(); for desc in descs { match desc { x if fields.iter().any(|field| *field == x) => continue, - _ => out.add(desc.clone(), obj.get_data(&desc).borrow().clone()), + _ => out.insert(desc.clone(), obj.get_data(&desc).borrow().clone()), } } - out + out.into_spanned_value() } #[allow(unused)] diff --git a/src/object/config.rs b/src/object/config.rs index f11fef027d..0860feb94b 100644 --- a/src/object/config.rs +++ b/src/object/config.rs @@ -27,10 +27,7 @@ crate fn write_config(config: &IndexMap>) -> Result<(), S touch(&filename)?; let contents = toml::to_string(&Config { - extra: config - .iter() - .map(|(k, v)| (k.clone(), v.item.clone())) - .collect(), + extra: config.iter().map(|(k, v)| (k.clone(), v.clone())).collect(), })?; fs::write(&filename, &contents)?; @@ -54,7 +51,6 @@ crate fn config(span: impl Into) -> Result .map_err(|err| ShellError::string(&format!("Couldn't read config file:\n{}", err)))?; let parsed: Config = toml::from_str(&contents) - .map(|v| v.spanned(span)) .map_err(|err| ShellError::string(&format!("Couldn't parse config file:\n{}", err)))?; Ok(parsed.extra) diff --git a/src/object/dict.rs b/src/object/dict.rs index c8f9965dac..ecad285079 100644 --- a/src/object/dict.rs +++ b/src/object/dict.rs @@ -21,8 +21,8 @@ impl PartialOrd for Dictionary { return this.partial_cmp(&that); } - let this: Vec<&Value> = self.entries.values().collect(); - let that: Vec<&Value> = self.entries.values().collect(); + let this: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); + let that: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); this.partial_cmp(&that) } @@ -49,8 +49,8 @@ impl Ord for Dictionary { return this.cmp(&that); } - let this: Vec<&Value> = self.entries.values().collect(); - let that: Vec<&Value> = self.entries.values().collect(); + let this: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); + let that: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); this.cmp(&that) } @@ -72,8 +72,8 @@ impl PartialEq for Dictionary { } impl Dictionary { - crate fn add(&mut self, name: impl Into, value: Value) { - self.entries.insert(name.into(), value); + crate fn add(&mut self, name: impl Into, value: impl Into>) { + self.entries.insert(name.into(), value.into()); } crate fn copy_dict(&self) -> Dictionary { @@ -115,6 +115,38 @@ impl Dictionary { } } +pub struct SpannedListBuilder { + span: Span, + list: Vec>, +} + +impl SpannedListBuilder { + pub fn new(span: impl Into) -> SpannedListBuilder { + SpannedListBuilder { + span: span.into(), + list: vec![], + } + } + + pub fn push(&mut self, value: impl Into) { + self.list.push(value.into().spanned(self.span)); + } + + pub fn insert_spanned(&mut self, value: impl Into>) { + self.list.push(value.into()); + } + + pub fn into_spanned_value(self) -> Spanned { + Value::List(self.list).spanned(self.span) + } +} + +impl From for Spanned { + fn from(input: SpannedListBuilder) -> Spanned { + input.into_spanned_value() + } +} + #[derive(Debug)] pub struct SpannedDictBuilder { span: Span, @@ -143,7 +175,11 @@ impl SpannedDictBuilder { } pub fn into_spanned_value(self) -> Spanned { - Value::Object(Dictionary { entries: self.dict }).spanned(self.span) + self.into_spanned_dict().map(Value::Object) + } + + pub fn into_spanned_dict(self) -> Spanned { + Dictionary { entries: self.dict }.spanned(self.span) } } diff --git a/src/object/files.rs b/src/object/files.rs index a169b3d1dd..210ff5405e 100644 --- a/src/object/files.rs +++ b/src/object/files.rs @@ -1,5 +1,6 @@ use crate::errors::ShellError; -use crate::object::{Dictionary, Value}; +use crate::object::{Dictionary, SpannedDictBuilder, Value}; +use crate::prelude::*; #[derive(Debug)] pub enum FileType { @@ -8,10 +9,13 @@ pub enum FileType { Symlink, } -crate fn dir_entry_dict(entry: &std::fs::DirEntry) -> Result { - let mut dict = Dictionary::default(); +crate fn dir_entry_dict( + entry: &std::fs::DirEntry, + span: impl Into, +) -> Result, ShellError> { + let mut dict = SpannedDictBuilder::new(span); let filename = entry.file_name(); - dict.add("file name", Value::string(filename.to_string_lossy())); + dict.insert("file name", Value::string(filename.to_string_lossy())); let metadata = entry.metadata()?; @@ -23,28 +27,28 @@ crate fn dir_entry_dict(entry: &std::fs::DirEntry) -> Result dict.add("created", Value::system_date(c)), + Ok(c) => dict.insert("created", Value::system_date(c)), Err(_) => {} } match metadata.accessed() { - Ok(a) => dict.add("accessed", Value::system_date(a)), + Ok(a) => dict.insert("accessed", Value::system_date(a)), Err(_) => {} } match metadata.modified() { - Ok(m) => dict.add("modified", Value::system_date(m)), + Ok(m) => dict.insert("modified", Value::system_date(m)), Err(_) => {} } - Ok(dict) + Ok(dict.into_spanned_value()) } diff --git a/src/object/process.rs b/src/object/process.rs index 830bef27da..ba716c5156 100644 --- a/src/object/process.rs +++ b/src/object/process.rs @@ -1,11 +1,11 @@ -use crate::object::base::Value; -use crate::object::dict::Dictionary; +use crate::object::{SpannedDictBuilder, Value}; +use crate::prelude::*; use itertools::join; use sysinfo::ProcessExt; -crate fn process_dict(proc: &sysinfo::Process) -> Dictionary { - let mut dict = Dictionary::default(); - dict.add("name", Value::string(proc.name())); +crate fn process_dict(proc: &sysinfo::Process, span: impl Into) -> Spanned { + let mut dict = SpannedDictBuilder::new(span); + dict.insert("name", Value::string(proc.name())); let cmd = proc.cmd(); @@ -15,10 +15,10 @@ crate fn process_dict(proc: &sysinfo::Process) -> Dictionary { Value::string(join(cmd, "")) }; - dict.add("cmd", cmd_value); - dict.add("cpu", Value::float(proc.cpu_usage() as f64)); - dict.add("pid", Value::int(proc.pid() as i64)); - dict.add("status", Value::string(proc.status().to_string())); + dict.insert("cmd", cmd_value); + dict.insert("cpu", Value::float(proc.cpu_usage() as f64)); + dict.insert("pid", Value::int(proc.pid() as i64)); + dict.insert("status", Value::string(proc.status().to_string())); - dict + dict.into_spanned_value() } diff --git a/src/object/types.rs b/src/object/types.rs index 46e52548e1..287cb4ef92 100644 --- a/src/object/types.rs +++ b/src/object/types.rs @@ -8,7 +8,6 @@ pub trait Type: std::fmt::Debug + Send { type Extractor: ExtractType; fn name(&self) -> &'static str; - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError>; fn coerce(&self) -> Option { None } @@ -28,10 +27,6 @@ impl Type for Any { fn name(&self) -> &'static str { "Any" } - - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { - Ok(value) - } } impl ExtractType for Spanned { @@ -39,7 +34,7 @@ impl ExtractType for Spanned { Ok(value.clone()) } - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { + fn check(value: &'value Spanned) -> Result<&'value Spanned, ShellError> { Ok(value) } } @@ -53,16 +48,6 @@ impl Type for Integer { fn name(&self) -> &'static str { "Integer" } - - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { - match value { - v @ Spanned { - item: Value::Primitive(Primitive::Int(_)), - .. - } => Ok(v), - other => Err(ShellError::type_error("Integer", other.spanned_type_name())), - } - } } impl ExtractType for i64 { @@ -76,7 +61,7 @@ impl ExtractType for i64 { } } - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { + fn check(value: &'value Spanned) -> Result<&'value Spanned, ShellError> { match value { v @ Spanned { item: Value::Primitive(Primitive::Int(_)), @@ -96,16 +81,6 @@ impl Type for NuString { fn name(&self) -> &'static str { "Integer" } - - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { - match value { - v @ Spanned { - item: Value::Primitive(Primitive::Int(_)), - .. - } => Ok(v), - other => Err(ShellError::type_error("Integer", other.spanned_type_name())), - } - } } impl ExtractType for String { @@ -119,13 +94,13 @@ impl ExtractType for String { } } - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { + fn check(value: &'value Spanned) -> Result<&'value Spanned, ShellError> { match value { v @ Spanned { - item: Value::Primitive(Primitive::Int(_)), + item: Value::Primitive(Primitive::String(_)), .. } => Ok(v), - other => Err(ShellError::type_error("Integer", other.spanned_type_name())), + other => Err(ShellError::type_error("String", other.spanned_type_name())), } } } @@ -139,8 +114,10 @@ impl Type for Block { fn name(&self) -> &'static str { "Block" } +} - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { +impl ExtractType for value::Block { + fn check(value: &'value Spanned) -> Result<&'value Spanned, ShellError> { match value { v @ Spanned { item: Value::Block(_), @@ -149,9 +126,7 @@ impl Type for Block { other => Err(ShellError::type_error("Block", other.spanned_type_name())), } } -} -impl ExtractType for value::Block { fn extract(value: &Spanned) -> Result { match value { Spanned { @@ -161,14 +136,4 @@ impl ExtractType for value::Block { other => Err(ShellError::type_error("Block", other.spanned_type_name())), } } - - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { - match value { - v @ Spanned { - item: Value::Block(_), - .. - } => Ok(v), - other => Err(ShellError::type_error("Block", other.spanned_type_name())), - } - } } diff --git a/src/parser/parse/span.rs b/src/parser/parse/span.rs index 7ed86e6a12..fb885e0c60 100644 --- a/src/parser/parse/span.rs +++ b/src/parser/parse/span.rs @@ -1,17 +1,31 @@ use crate::Text; use derive_new::new; use getset::Getters; -use serde_derive::{Deserialize, Serialize}; +use serde::{Serialize, Serializer}; +use serde_derive::Deserialize; -#[derive( - new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash, Getters, -)] +#[derive(new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Deserialize, Hash, Getters)] #[get = "crate"] pub struct Spanned { pub span: Span, pub item: T, } +impl Serialize for Spanned { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.item.serialize(serializer) + } +} + +impl Spanned { + pub fn spanned(self, span: impl Into) -> Spanned { + Spanned::from_item(self.item, span.into()) + } +} + pub trait SpannedItem: Sized { fn spanned(self, span: impl Into) -> Spanned { Spanned::from_item(self, span.into()) diff --git a/src/parser/parse_command.rs b/src/parser/parse_command.rs index ff407231c1..8c7d5e7cfe 100644 --- a/src/parser/parse_command.rs +++ b/src/parser/parse_command.rs @@ -93,11 +93,11 @@ fn parse_command_tail( tail.move_to(pos); if tail.at_end() { - return Err(ShellError::ArgumentError { - command: config.name().clone(), - error: ArgumentError::MissingValueForName(name.to_string()), - span: flag.span, - }); + return Err(ShellError::argument_error( + config.name.clone(), + ArgumentError::MissingValueForName(name.to_string()), + flag.span, + )); } let expr = hir::baseline_parse_next_expr( @@ -118,11 +118,11 @@ fn parse_command_tail( tail.move_to(pos); if tail.at_end() { - return Err(ShellError::ArgumentError { - command: config.name().clone(), - error: ArgumentError::MissingValueForName(name.to_string()), - span: flag.span, - }); + return Err(ShellError::argument_error( + config.name().clone(), + ArgumentError::MissingValueForName(name.to_string()), + flag.span, + )); } let expr = hir::baseline_parse_next_expr( @@ -154,11 +154,11 @@ fn parse_command_tail( match arg { PositionalType::Mandatory(..) => { if tail.len() == 0 { - return Err(ShellError::ArgumentError { - command: config.name().clone(), - error: ArgumentError::MissingMandatoryPositional(arg.name().to_string()), - span: command_span, - }); + return Err(ShellError::argument_error( + config.name().clone(), + ArgumentError::MissingMandatoryPositional(arg.name().to_string()), + command_span, + )); } } @@ -215,11 +215,11 @@ fn extract_mandatory( let flag = tokens.extract(|t| t.as_flag(name, source)); match flag { - None => Err(ShellError::ArgumentError { - command: config.name().clone(), - error: ArgumentError::MissingMandatoryFlag(name.to_string()), + None => Err(ShellError::argument_error( + config.name().clone(), + ArgumentError::MissingMandatoryFlag(name.to_string()), span, - }), + )), Some((pos, flag)) => { tokens.remove(pos); diff --git a/src/parser/registry.rs b/src/parser/registry.rs index b753cb9aed..d168d9dbba 100644 --- a/src/parser/registry.rs +++ b/src/parser/registry.rs @@ -102,7 +102,7 @@ impl fmt::Debug for DebugPositional<'a> { None => write!(f, "None"), Some(positional) => f .debug_list() - .entries(positional.iter().map(|p| p.item().debug())) + .entries(positional.iter().map(|p| p.debug())) .finish(), } } @@ -119,7 +119,7 @@ impl fmt::Debug for DebugNamed<'a> { None => write!(f, "None"), Some(named) => f .debug_map() - .entries(named.iter().map(|(k, v)| (k, v.item().debug()))) + .entries(named.iter().map(|(k, v)| (k, v.debug()))) .finish(), } } diff --git a/src/plugins/inc.rs b/src/plugins/inc.rs index dbaeaa1d82..d301ab07ef 100644 --- a/src/plugins/inc.rs +++ b/src/plugins/inc.rs @@ -3,7 +3,7 @@ use nu::{ serve_plugin, Args, CommandConfig, Plugin, PositionalType, Primitive, ReturnValue, ShellError, Spanned, Value, }; -use nu::{Primitive, ReturnSuccess, ReturnValue, ShellError, Spanned, Value}; +use nu::{Primitive, ReturnSuccess, ReturnValue, ShellError, Spanned, SpannedItem, Value}; use serde::{Deserialize, Serialize}; use std::io; @@ -32,7 +32,7 @@ fn send_error(error: ShellError) { #[allow(non_camel_case_types)] pub enum NuCommand { init { params: Vec> }, - filter { params: Value }, + filter { params: Spanned }, quit, } @@ -62,13 +62,21 @@ fn main() -> Result<(), Box> { } } Ok(NuCommand::filter { params }) => match params { - Value::Primitive(Primitive::Int(i)) => { - send_response(vec![ReturnSuccess::value(Value::int(i + inc_by))]); + Spanned { + item: Value::Primitive(Primitive::Int(i)), + span, + } => { + send_response(vec![ReturnSuccess::value( + Value::int(i + inc_by).spanned(span), + )]); } - Value::Primitive(Primitive::Bytes(b)) => { - send_response(vec![ReturnSuccess::value(Value::bytes( - b + inc_by as u128, - ))]); + Spanned { + item: Value::Primitive(Primitive::Bytes(b)), + span, + } => { + send_response(vec![ReturnSuccess::value( + Value::bytes(b + inc_by as u128).spanned(span), + )]); } _ => { send_error(ShellError::string("Unrecognized type in stream")); diff --git a/src/stream.rs b/src/stream.rs index 9281831b89..cd94ddf3be 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -16,8 +16,8 @@ impl InputStream { } } -impl From> for InputStream { - fn from(input: BoxStream<'static, Value>) -> InputStream { +impl From>> for InputStream { + fn from(input: BoxStream<'static, Spanned>) -> InputStream { InputStream { values: input } } } @@ -30,8 +30,8 @@ impl From>> for InputStream { } } -impl From> for InputStream { - fn from(input: Vec) -> InputStream { +impl From>> for InputStream { + fn from(input: Vec>) -> InputStream { let mut list = VecDeque::default(); list.extend(input); @@ -46,6 +46,11 @@ pub struct OutputStream { } impl OutputStream { + pub fn empty() -> OutputStream { + let v: VecDeque = VecDeque::new(); + v.into() + } + pub fn from_input(input: impl Stream> + Send + 'static) -> OutputStream { OutputStream { values: input.map(ReturnSuccess::value).boxed(), @@ -61,8 +66,8 @@ impl From for OutputStream { } } -impl From> for OutputStream { - fn from(input: BoxStream<'static, Value>) -> OutputStream { +impl From>> for OutputStream { + fn from(input: BoxStream<'static, Spanned>) -> OutputStream { OutputStream { values: input.map(ReturnSuccess::value).boxed(), } @@ -83,6 +88,18 @@ impl From> for OutputStream { } } +impl From>> for OutputStream { + fn from(input: VecDeque>) -> OutputStream { + OutputStream { + values: input + .into_iter() + .map(|i| ReturnSuccess::value(i)) + .collect::>() + .boxed(), + } + } +} + impl From> for OutputStream { fn from(input: Vec) -> OutputStream { let mut list = VecDeque::default(); @@ -94,8 +111,8 @@ impl From> for OutputStream { } } -impl From> for OutputStream { - fn from(input: Vec) -> OutputStream { +impl From>> for OutputStream { + fn from(input: Vec>) -> OutputStream { let mut list = VecDeque::default(); list.extend(input.into_iter().map(ReturnSuccess::value)); From 70f9e355fd89e28848a6d6f4b54c0af97dea1bde Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Fri, 12 Jul 2019 12:22:08 -0700 Subject: [PATCH 05/10] WIP --- src/cli.rs | 2 +- src/commands/classified.rs | 14 +++++---- src/commands/from_ini.rs | 1 - src/commands/macros.rs | 57 ++++++++++++++++++++++++++++++++++++- src/commands/pick.rs | 1 - src/commands/ps.rs | 3 +- src/commands/reject.rs | 1 - src/commands/sysinfo.rs | 3 +- src/commands/trim.rs | 11 +------ src/commands/where_.rs | 2 +- src/parser/parse/parser.rs | 6 ++-- src/parser/parse_command.rs | 2 +- src/prelude.rs | 6 ++-- 13 files changed, 76 insertions(+), 33 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 4b5d5c6813..5da609a3f2 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -500,7 +500,7 @@ fn classify_command( let config = command.config(); let scope = Scope::empty(); - trace!("classifying {:?}", config); + trace!(target: "nu::build_pipeline", "classifying {:?}", config); let args = config.evaluate_args(call, context, &scope, source)?; diff --git a/src/commands/classified.rs b/src/commands/classified.rs index 93ef2b9782..477e05bb71 100644 --- a/src/commands/classified.rs +++ b/src/commands/classified.rs @@ -87,6 +87,7 @@ crate enum ClassifiedCommand { } impl ClassifiedCommand { + #[allow(unused)] pub fn span(&self) -> Span { match self { ClassifiedCommand::Expr(token) => token.span(), @@ -126,12 +127,13 @@ impl InternalCommand { input: ClassifiedInputStream, ) -> Result { if log_enabled!(log::Level::Trace) { - trace!("->"); - trace!("{}", self.command.name()); - trace!("{:?}", self.args.debug()); + trace!(target: "nu::run::internal", "->"); + trace!(target: "nu::run::internal", "{}", self.command.name()); + trace!(target: "nu::run::internal", "{:?}", self.args.debug()); } - let objects: InputStream = trace_stream!("input" = input.objects); + let objects: InputStream = + trace_stream!(target: "nu::trace_stream::internal", "input" = input.objects); let result = context.run_command(self.command, self.name_span.clone(), self.args, objects)?; @@ -203,8 +205,8 @@ impl ExternalCommand { let inputs: Vec> = input.objects.into_vec().await; let name_span = self.name_span.clone(); - trace!("-> {}", self.name); - trace!("inputs = {:?}", inputs); + trace!(target: "nu::run::external", "-> {}", self.name); + trace!(target: "nu::run::external", "inputs = {:?}", inputs); let mut arg_string = format!("{}", self.name); for arg in &self.args { diff --git a/src/commands/from_ini.rs b/src/commands/from_ini.rs index 863c2d6196..7352d4c0db 100644 --- a/src/commands/from_ini.rs +++ b/src/commands/from_ini.rs @@ -1,6 +1,5 @@ use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; -use indexmap::IndexMap; use std::collections::HashMap; fn convert_ini_second_to_nu_value( diff --git a/src/commands/macros.rs b/src/commands/macros.rs index 5a4e9e2d14..3662378fbb 100644 --- a/src/commands/macros.rs +++ b/src/commands/macros.rs @@ -215,6 +215,61 @@ macro_rules! command { ); }; + // mandatory positional block + ( + Named { $export:ident $args:ident $body:block } + Positional { $($positional_count:tt)* } + Rest { , $param_name:ident : Block $($rest:tt)* } + CommandConfig { + name: $config_name:tt, + mandatory_positional: vec![ $($mandatory_positional:tt)* ], + optional_positional: vec![ $($optional_positional:tt)* ], + rest_positional: $rest_positional:tt, + named: { + $($config_named:tt)* + } + } + + Function { + $($function:tt)* + } + + Extract { + $($extract:tt)* + } + + ) => { + command!( + Named { $export $args $body } + Positional { $($positional_count)* + 1 } + Rest { $($rest)* } + CommandConfig { + name: $config_name, + mandatory_positional: vec![ $($mandatory_positional)* $crate::parser::registry::PositionalType::mandatory_block( + stringify!($param_name) + ), ], + optional_positional: vec![ $($optional_positional)* ], + rest_positional: $rest_positional, + named: { + $($config_named)* + } + } + + Function { + $($function)* ($param_name : Block) + } + + Extract { + $($extract:tt)* { + use $crate::object::types::ExtractType; + let value = $args.expect_nth($($positional_count)*)?; + Block::extract(value)? + } + } + ); + }; + + // mandatory positional argument ( Named { $export:ident $args:ident $body:block } @@ -246,7 +301,7 @@ macro_rules! command { CommandConfig { name: $config_name, mandatory_positional: vec![ $($mandatory_positional)* $crate::parser::registry::PositionalType::mandatory( - stringify!($param_name), stringify!($param_kind) + stringify!($param_name) ), ], optional_positional: vec![ $($optional_positional)* ], rest_positional: $rest_positional, diff --git a/src/commands/pick.rs b/src/commands/pick.rs index d9f42aa6b1..0d53ce9942 100644 --- a/src/commands/pick.rs +++ b/src/commands/pick.rs @@ -1,6 +1,5 @@ use crate::errors::ShellError; use crate::object::base::select_fields; -use crate::object::Value; use crate::prelude::*; pub fn pick(args: CommandArgs) -> Result { diff --git a/src/commands/ps.rs b/src/commands/ps.rs index 5336ec97f0..14b9ba27fa 100644 --- a/src/commands/ps.rs +++ b/src/commands/ps.rs @@ -1,6 +1,5 @@ use crate::errors::ShellError; use crate::object::process::process_dict; -use crate::object::Value; use crate::prelude::*; use sysinfo::{RefreshKind, SystemExt}; @@ -11,7 +10,7 @@ pub fn ps(args: CommandArgs) -> Result { let list = list .into_iter() - .map(|(item, process)| process_dict(process, args.name_span)) + .map(|(_, process)| process_dict(process, args.name_span)) .collect::>(); Ok(list.from_input_stream()) diff --git a/src/commands/reject.rs b/src/commands/reject.rs index fc53aaea9c..362df135db 100644 --- a/src/commands/reject.rs +++ b/src/commands/reject.rs @@ -1,6 +1,5 @@ use crate::errors::ShellError; use crate::object::base::reject_fields; -use crate::object::Value; use crate::prelude::*; pub fn reject(args: CommandArgs) -> Result { diff --git a/src/commands/sysinfo.rs b/src/commands/sysinfo.rs index 3a7cd5646c..73fda3fe02 100644 --- a/src/commands/sysinfo.rs +++ b/src/commands/sysinfo.rs @@ -3,7 +3,6 @@ use crate::object::base::OF64; use crate::object::SpannedDictBuilder; use crate::object::{Primitive, Value}; use crate::prelude::*; -use log::trace; use sys_info::*; use sysinfo::{ComponentExt, DiskExt, NetworkExt, RefreshKind, SystemExt}; @@ -127,7 +126,7 @@ pub fn sysinfo(args: CommandArgs) -> Result { network_idx.insert("outgoing", Value::bytes(outgoing)); idx.insert_spanned("network", network_idx); - let mut stream = stream![idx.into_spanned_value()]; + let stream = stream![idx.into_spanned_value()]; Ok(stream.from_input_stream()) } diff --git a/src/commands/trim.rs b/src/commands/trim.rs index e4d66ffd2e..e0f2d42b0c 100644 --- a/src/commands/trim.rs +++ b/src/commands/trim.rs @@ -1,12 +1,11 @@ use crate::errors::ShellError; -use crate::object::{Primitive, Value}; +use crate::object::Value; use crate::prelude::*; // TODO: "Amount remaining" wrapper pub fn trim(args: CommandArgs) -> Result { let input = args.input; - let span = args.name_span; Ok(input .values @@ -14,13 +13,5 @@ pub fn trim(args: CommandArgs) -> Result { let string = String::extract(&v)?; ReturnSuccess::value(Value::string(string.trim()).spanned(v.span)) }) - // Value::Primitive(Primitive::String(s)) => { - // ReturnSuccess::value(Value::Primitive(Primitive::String(s.trim().into()))) - // } - // _ => Err(ShellError::maybe_labeled_error( - // "Expected string values from pipeline", - // "expects strings from pipeline", - // span, - // )), .to_output_stream()) } diff --git a/src/commands/where_.rs b/src/commands/where_.rs index d5d9f6bb61..d8f68c2b62 100644 --- a/src/commands/where_.rs +++ b/src/commands/where_.rs @@ -6,7 +6,7 @@ use log::trace; command! { Where as where(args, condition: Block) { - let input: InputStream = trace_stream!("where input" = args.input); + let input: InputStream = trace_stream!(target: "nu::trace_stream::where", "where input" = args.input); input.values.filter_map(move |item| { let result = condition.invoke(&item); diff --git a/src/parser/parse/parser.rs b/src/parser/parse/parser.rs index 7c25ff04c5..795b980ee2 100644 --- a/src/parser/parse/parser.rs +++ b/src/parser/parse/parser.rs @@ -53,15 +53,15 @@ fn trace_step<'a, T: Debug>( name: &str, block: impl FnOnce(NomSpan<'a>) -> IResult, T>, ) -> IResult, T> { - trace!("+ before {} @ {:?}", name, input); + trace!(target: "nu::lite_parse", "+ before {} @ {:?}", name, input); match block(input) { Ok((input, result)) => { - trace!("after {} @ {:?} -> {:?}", name, input, result); + trace!(target: "nu::lite_parse", "after {} @ {:?} -> {:?}", name, input, result); Ok((input, result)) } Err(e) => { - trace!("- failed {} :: {:?}", name, e); + trace!(target: "nu::lite_parse", "- failed {} :: {:?}", name, e); Err(e) } } diff --git a/src/parser/parse_command.rs b/src/parser/parse_command.rs index 8c7d5e7cfe..fc63500b45 100644 --- a/src/parser/parse_command.rs +++ b/src/parser/parse_command.rs @@ -78,7 +78,7 @@ fn parse_command_tail( trace_remaining("nodes", tail.clone(), source); for (name, kind) in config.named() { - trace!("looking for {} : {:?}", name, kind); + trace!(target: "nu::parse", "looking for {} : {:?}", name, kind); match kind { NamedType::Switch => { diff --git a/src/prelude.rs b/src/prelude.rs index 40ef6eb098..67454939c6 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -13,8 +13,8 @@ macro_rules! stream { #[macro_export] macro_rules! trace_stream { - ($desc:tt = $expr:expr) => {{ - if log::log_enabled!(target: "nu::trace_stream", log::Level::Trace) { + (target: $target:tt, $desc:tt = $expr:expr) => {{ + if log::log_enabled!(target: $target, log::Level::Trace) { use futures::stream::StreamExt; // Blocking is generally quite bad, but this is for debugging // let mut local = futures::executor::LocalPool::new(); @@ -22,7 +22,7 @@ macro_rules! trace_stream { // let objects: Vec<_> = futures::executor::block_on($expr.into_vec()); let objects = $expr.values.inspect(|o| { - trace!(target: "nu::trace_stream", "{} = {:#?}", $desc, o.debug()); + trace!(target: $target, "{} = {:#?}", $desc, o.debug()); }); $crate::stream::InputStream::from_stream(objects.boxed()) From 7c2a1c619e8740311129e7e2bf4d1620128ee94b Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Fri, 12 Jul 2019 19:07:06 -0700 Subject: [PATCH 06/10] Tests pass --- src/cli.rs | 3 - src/commands.rs | 1 - src/commands/autoview.rs | 6 +- src/commands/enter.rs | 18 ++++-- src/commands/from_json.rs | 2 +- src/commands/from_toml.rs | 2 +- src/commands/from_xml.rs | 4 +- src/commands/from_yaml.rs | 3 +- src/commands/macros.rs | 5 ++ src/commands/open.rs | 26 +++++--- src/commands/plugin.rs | 3 +- src/commands/skip_while.rs | 2 +- src/commands/to_json.rs | 1 - src/commands/to_toml.rs | 5 +- src/format/generic.rs | 5 -- src/object/base.rs | 8 +-- src/object/dict.rs | 12 ++-- src/parser/parse/span.rs | 13 +--- src/parser/registry.rs | 15 ++--- src/plugin.rs | 10 +-- src/plugins/binaryview.rs | 12 ++-- src/plugins/inc.rs | 121 ++++++++++++------------------------- src/plugins/skip.rs | 10 +-- src/plugins/tree.rs | 9 +-- 24 files changed, 126 insertions(+), 170 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 5da609a3f2..8165c87472 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -181,14 +181,11 @@ pub async fn cli() -> Result<(), Box> { command("to-toml", Box::new(to_toml::to_toml)), command("sort-by", Box::new(sort_by::sort_by)), command("sort-by", Box::new(sort_by::sort_by)), - command("inc", |x| plugin::plugin("inc".into(), x)), - command("sum", |x| plugin::plugin("sum".into(), x)), Arc::new(Open), Arc::new(Where), Arc::new(Config), Arc::new(SkipWhile), Arc::new(Enter), - Arc::new(Skip), ]); context.add_sinks(vec![ diff --git a/src/commands.rs b/src/commands.rs index 20121eb3f8..3225923481 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -44,6 +44,5 @@ crate use command::command; crate use config::Config; crate use enter::Enter; crate use open::Open; -crate use skip::Skip; crate use skip_while::SkipWhile; crate use where_::Where; diff --git a/src/commands/autoview.rs b/src/commands/autoview.rs index 55b4b42923..e9f6599f8b 100644 --- a/src/commands/autoview.rs +++ b/src/commands/autoview.rs @@ -5,7 +5,11 @@ use crate::prelude::*; pub fn autoview(args: SinkCommandArgs) -> Result<(), ShellError> { if args.input.len() > 0 { - if let Value::Binary(_) = args.input[0] { + if let Spanned { + item: Value::Binary(_), + .. + } = args.input[0] + { args.ctx.get_sink("binaryview").run(args)?; } else if equal_shapes(&args.input) { args.ctx.get_sink("table").run(args)?; diff --git a/src/commands/enter.rs b/src/commands/enter.rs index 7fd557f6dc..9dc105324d 100644 --- a/src/commands/enter.rs +++ b/src/commands/enter.rs @@ -12,8 +12,12 @@ impl Command for Enter { fn config(&self) -> CommandConfig { CommandConfig { name: self.name().to_string(), - positional: vec![PositionalType::mandatory("path", "Block")], + positional: vec![PositionalType::mandatory_block("path")], rest_positional: false, + can_load: vec![], + can_save: vec![], + is_filter: false, + is_sink: false, named: indexmap::IndexMap::new(), } } @@ -89,9 +93,15 @@ pub fn enter(args: CommandArgs) -> Result { } }; - stream.push_back(Ok(ReturnSuccess::Action(CommandAction::Enter( - parse_as_value(file_extension, contents, contents_span, span)?, - )))); + match contents { + Value::Primitive(Primitive::String(string)) => { + stream.push_back(Ok(ReturnSuccess::Action(CommandAction::Enter( + parse_as_value(file_extension, string, contents_span, span)?, + )))); + } + + other => stream.push_back(ReturnSuccess::value(other.spanned(contents_span))), + }; Ok(stream.into()) } diff --git a/src/commands/from_json.rs b/src/commands/from_json.rs index f91fa120bf..e81d81e281 100644 --- a/src/commands/from_json.rs +++ b/src/commands/from_json.rs @@ -27,7 +27,7 @@ fn convert_json_value_to_nu_value(v: &serde_hjson::Value, span: impl Into) serde_hjson::Value::Object(o) => { let mut collected = SpannedDictBuilder::new(span); for (k, v) in o.iter() { - collected.add(k.clone(), convert_json_value_to_nu_value(v, span)); + collected.insert_spanned(k.clone(), convert_json_value_to_nu_value(v, span)); } collected.into_spanned_value() diff --git a/src/commands/from_toml.rs b/src/commands/from_toml.rs index a38058f5e8..ffea6fd5d7 100644 --- a/src/commands/from_toml.rs +++ b/src/commands/from_toml.rs @@ -25,7 +25,7 @@ fn convert_toml_value_to_nu_value(v: &toml::Value, span: impl Into) -> Spa let mut collected = SpannedDictBuilder::new(span); for (k, v) in t.iter() { - collected.add(k.clone(), convert_toml_value_to_nu_value(v, span)); + collected.insert_spanned(k.clone(), convert_toml_value_to_nu_value(v, span)); } collected.into_spanned_value() diff --git a/src/commands/from_xml.rs b/src/commands/from_xml.rs index 9741592a8f..ebfce83e98 100644 --- a/src/commands/from_xml.rs +++ b/src/commands/from_xml.rs @@ -32,8 +32,8 @@ fn from_node_to_value<'a, 'd>( }) .collect(); - let mut collected = Dictionary::default(); - collected.add(name.clone(), Value::List(children_values).spanned(span)); + let mut collected = SpannedDictBuilder::new(span); + collected.insert(name.clone(), Value::List(children_values)); collected.into_spanned_value() } else if n.is_comment() { diff --git a/src/commands/from_yaml.rs b/src/commands/from_yaml.rs index 0568ddce74..3c9de7302f 100644 --- a/src/commands/from_yaml.rs +++ b/src/commands/from_yaml.rs @@ -26,7 +26,8 @@ fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, span: impl Into) for (k, v) in t.iter() { match k { serde_yaml::Value::String(k) => { - collected.add(k.clone(), convert_yaml_value_to_nu_value(v, span)); + collected + .insert_spanned(k.clone(), convert_yaml_value_to_nu_value(v, span)); } _ => unimplemented!("Unknown key type"), } diff --git a/src/commands/macros.rs b/src/commands/macros.rs index 3662378fbb..1c5268b672 100644 --- a/src/commands/macros.rs +++ b/src/commands/macros.rs @@ -48,6 +48,11 @@ macro_rules! command { name: self.name().to_string(), positional: vec![$($mandatory_positional)*], rest_positional: false, + can_load: vec![], + can_save: vec![], + is_filter: false, + is_sink: false, + named: { use $crate::parser::registry::NamedType; diff --git a/src/commands/open.rs b/src/commands/open.rs index 14e253d33d..f4a024628c 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -61,12 +61,18 @@ command! { } }; - stream.push_back(ReturnSuccess::value(parse_as_value( - file_extension, - contents, - contents_span, - span, - )?)); + match contents { + Value::Primitive(Primitive::String(string)) => + stream.push_back(ReturnSuccess::value(parse_as_value( + file_extension, + string, + contents_span, + span, + )?) + ), + + other => stream.push_back(ReturnSuccess::value(other.spanned(span))), + }; stream } @@ -76,7 +82,7 @@ pub fn fetch( cwd: &PathBuf, location: &str, span: Span, -) -> Result<(Option, String, Span), ShellError> { +) -> Result<(Option, Value, Span), ShellError> { let mut cwd = cwd.clone(); if location.starts_with("http:") || location.starts_with("https:") { let response = reqwest::get(location); @@ -107,7 +113,7 @@ pub fn fetch( None => path_extension, }; - Ok((extension, s, span)) + Ok((extension, Value::string(s), span)) } Err(_) => { return Err(ShellError::labeled_error( @@ -132,10 +138,10 @@ pub fn fetch( Ok(s) => Ok(( cwd.extension() .map(|name| name.to_string_lossy().to_string()), - s, + Value::string(s), span, )), - Err(_) => Ok((None, Value::Binary(bytes))), + Err(_) => Ok((None, Value::Binary(bytes), span)), }, Err(_) => { return Err(ShellError::labeled_error( diff --git a/src/commands/plugin.rs b/src/commands/plugin.rs index 06cd27a453..291e1f0517 100644 --- a/src/commands/plugin.rs +++ b/src/commands/plugin.rs @@ -55,6 +55,7 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result Result params, Err(e) => { let mut result = VecDeque::new(); - result.push_back(ReturnValue::Value(Value::Error(Box::new(e)))); + result.push_back(ReturnValue::Err(e)); result } }, diff --git a/src/commands/skip_while.rs b/src/commands/skip_while.rs index ce671eb2a2..eebaef83f1 100644 --- a/src/commands/skip_while.rs +++ b/src/commands/skip_while.rs @@ -16,7 +16,7 @@ impl Command for SkipWhile { fn config(&self) -> CommandConfig { CommandConfig { name: self.name().to_string(), - positional: vec![PositionalType::mandatory("condition", "Block")], + positional: vec![PositionalType::mandatory_block("condition")], rest_positional: false, named: indexmap::IndexMap::new(), is_filter: true, diff --git a/src/commands/to_json.rs b/src/commands/to_json.rs index d75586c219..0a79ca48c5 100644 --- a/src/commands/to_json.rs +++ b/src/commands/to_json.rs @@ -22,7 +22,6 @@ pub fn value_to_json_value(v: &Value) -> serde_json::Value { Value::List(l) => { serde_json::Value::Array(l.iter().map(|x| value_to_json_value(x)).collect()) } - Value::Error(e) => serde_json::Value::String(e.to_string()), Value::Block(_) => serde_json::Value::Null, Value::Binary(b) => serde_json::Value::Array( b.iter() diff --git a/src/commands/to_toml.rs b/src/commands/to_toml.rs index b23ca35195..87cf71ed26 100644 --- a/src/commands/to_toml.rs +++ b/src/commands/to_toml.rs @@ -16,7 +16,6 @@ pub fn value_to_toml_value(v: &Value) -> toml::Value { Value::Filesystem => toml::Value::String("".to_string()), Value::List(l) => toml::Value::Array(l.iter().map(|x| value_to_toml_value(x)).collect()), - Value::Error(e) => toml::Value::String(e.to_string()), Value::Block(_) => toml::Value::String("".to_string()), Value::Binary(b) => { toml::Value::Array(b.iter().map(|x| toml::Value::Integer(*x as i64)).collect()) @@ -38,7 +37,7 @@ pub fn to_toml(args: CommandArgs) -> Result { Ok(out .values .map(move |a| { - match toml::to_string(&a) { + match toml::to_string(&value_to_toml_value(&a)) { Ok(val) => { return ReturnSuccess::value( Value::Primitive(Primitive::String(val)).spanned(name_span), @@ -46,7 +45,7 @@ pub fn to_toml(args: CommandArgs) -> Result { } Err(err) => Err(ShellError::type_error( - "String", + "serializable to toml", format!("{:?} - {:?}", a.type_name(), err).spanned(name_span), )), // toml::Value::String(String) => { // return ReturnSuccess::value( diff --git a/src/format/generic.rs b/src/format/generic.rs index f5fdf07722..4524911daf 100644 --- a/src/format/generic.rs +++ b/src/format/generic.rs @@ -36,11 +36,6 @@ impl RenderView for GenericView<'value> { Ok(()) } - Value::Error(e) => { - host.stdout(&format!("{:?}", e)); - Ok(()) - } - Value::Binary(_) => { host.stdout(""); Ok(()) diff --git a/src/object/base.rs b/src/object/base.rs index 04662972ab..8b8a5a24df 100644 --- a/src/object/base.rs +++ b/src/object/base.rs @@ -299,10 +299,6 @@ impl Value { } } - crate fn debug(&'a self) -> ValueDebug<'a> { - ValueDebug { value: self } - } - pub fn data_descriptors(&self) -> Vec { match self { Value::Primitive(_) => vec![], @@ -314,7 +310,6 @@ impl Value { .collect(), Value::Block(_) => vec![], Value::List(_) => vec![], - Value::Error(_) => vec![], Value::Filesystem => vec![], Value::Binary(_) => vec![], } @@ -356,7 +351,6 @@ impl Value { Value::Object(o) => o.get_data(desc), Value::Block(_) => MaybeOwned::Owned(Value::nothing()), Value::List(_) => MaybeOwned::Owned(Value::nothing()), - Value::Error(e) => MaybeOwned::Owned(Value::string(&format!("{:#?}", e))), Value::Binary(_) => MaybeOwned::Owned(Value::nothing()), } } @@ -512,7 +506,7 @@ crate fn select_fields(obj: &Value, fields: &[String], span: impl Into) -> let descs = obj.data_descriptors(); for field in fields { - match descs.iter().find(|d| d.name.is_string(field)) { + match descs.iter().find(|d| *d == field) { None => out.insert(field, Value::nothing()), Some(desc) => out.insert(desc.clone(), obj.get_data(desc).borrow().clone()), } diff --git a/src/object/dict.rs b/src/object/dict.rs index ecad285079..e0844dda57 100644 --- a/src/object/dict.rs +++ b/src/object/dict.rs @@ -80,7 +80,7 @@ impl Dictionary { let mut out = Dictionary::default(); for (key, value) in self.entries.iter() { - out.add(key.clone(), value.copy()); + out.add(key.clone(), value.clone()); } out @@ -150,7 +150,7 @@ impl From for Spanned { #[derive(Debug)] pub struct SpannedDictBuilder { span: Span, - dict: IndexMap>, + dict: IndexMap>, } impl SpannedDictBuilder { @@ -161,16 +161,12 @@ impl SpannedDictBuilder { } } - pub fn insert(&mut self, key: impl Into, value: impl Into) { + pub fn insert(&mut self, key: impl Into, value: impl Into) { self.dict .insert(key.into(), value.into().spanned(self.span)); } - pub fn insert_spanned( - &mut self, - key: impl Into, - value: impl Into>, - ) { + pub fn insert_spanned(&mut self, key: impl Into, value: impl Into>) { self.dict.insert(key.into(), value.into()); } diff --git a/src/parser/parse/span.rs b/src/parser/parse/span.rs index fb885e0c60..3886f40e18 100644 --- a/src/parser/parse/span.rs +++ b/src/parser/parse/span.rs @@ -4,22 +4,15 @@ use getset::Getters; use serde::{Serialize, Serializer}; use serde_derive::Deserialize; -#[derive(new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Deserialize, Hash, Getters)] +#[derive( + new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash, Getters, +)] #[get = "crate"] pub struct Spanned { pub span: Span, pub item: T, } -impl Serialize for Spanned { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.item.serialize(serializer) - } -} - impl Spanned { pub fn spanned(self, span: impl Into) -> Spanned { Spanned::from_item(self.item, span.into()) diff --git a/src/parser/registry.rs b/src/parser/registry.rs index d168d9dbba..4447b496c7 100644 --- a/src/parser/registry.rs +++ b/src/parser/registry.rs @@ -40,18 +40,19 @@ pub enum PositionalType { Optional(String, PositionalValue), } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum PositionalValue { Value, Block, } impl PositionalType { - crate fn mandatory(name: &str, kind: &str) -> PositionalType { - match kind { - "Block" => PositionalType::Mandatory(name.to_string(), PositionalValue::Block), - _ => PositionalType::Mandatory(name.to_string(), PositionalValue::Value), - } + pub fn mandatory(name: &str) -> PositionalType { + PositionalType::Mandatory(name.to_string(), PositionalValue::Value) + } + + pub fn mandatory_block(name: &str) -> PositionalType { + PositionalType::Mandatory(name.to_string(), PositionalValue::Block) } crate fn to_coerce_hint(&self) -> Option { @@ -76,7 +77,7 @@ impl PositionalType { #[get = "crate"] pub struct CommandConfig { pub name: String, - crate positional: Vec, + pub positional: Vec, pub rest_positional: bool, pub named: IndexMap, pub is_filter: bool, diff --git a/src/plugin.rs b/src/plugin.rs index fcf0addde8..4489122780 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,4 +1,4 @@ -use crate::{Args, CommandConfig, ReturnValue, ShellError, Value}; +use crate::{Args, CommandConfig, ReturnValue, ShellError, Spanned, Value}; use serde::{Deserialize, Serialize}; use std::io; @@ -11,11 +11,11 @@ pub trait Plugin { )) } #[allow(unused)] - fn filter(&mut self, input: Value) -> Result, ShellError> { + fn filter(&mut self, input: Spanned) -> Result, ShellError> { Err(ShellError::string("`filter` not implemented in plugin")) } #[allow(unused)] - fn sink(&mut self, args: Args, input: Vec) {} + fn sink(&mut self, args: Args, input: Vec>) {} fn quit(&mut self) { return; @@ -127,7 +127,7 @@ fn send_response(result: T) { pub enum NuCommand { config, begin_filter { params: Args }, - filter { params: Value }, - sink { params: (Args, Vec) }, + filter { params: Spanned }, + sink { params: (Args, Vec>) }, quit, } diff --git a/src/plugins/binaryview.rs b/src/plugins/binaryview.rs index f839d12bc7..b96e0e160d 100644 --- a/src/plugins/binaryview.rs +++ b/src/plugins/binaryview.rs @@ -1,6 +1,6 @@ use crossterm::{cursor, terminal, Attribute, RawScreen}; use indexmap::IndexMap; -use nu::{serve_plugin, Args, CommandConfig, Plugin, ShellError, Value}; +use nu::{serve_plugin, Args, CommandConfig, Plugin, ShellError, Spanned, Value}; use pretty_hex::*; struct BinaryView; @@ -15,8 +15,7 @@ impl Plugin for BinaryView { fn config(&mut self) -> Result { Ok(CommandConfig { name: "binaryview".to_string(), - mandatory_positional: vec![], - optional_positional: vec![], + positional: vec![], can_load: vec![], can_save: vec![], is_filter: false, @@ -26,10 +25,13 @@ impl Plugin for BinaryView { }) } - fn sink(&mut self, _args: Args, input: Vec) { + fn sink(&mut self, _args: Args, input: Vec>) { for v in input { match v { - Value::Binary(b) => { + Spanned { + item: Value::Binary(b), + .. + } => { let _ = view_binary(&b); } _ => {} diff --git a/src/plugins/inc.rs b/src/plugins/inc.rs index d301ab07ef..c9257da132 100644 --- a/src/plugins/inc.rs +++ b/src/plugins/inc.rs @@ -1,11 +1,8 @@ use indexmap::IndexMap; use nu::{ - serve_plugin, Args, CommandConfig, Plugin, PositionalType, Primitive, ReturnValue, ShellError, - Spanned, Value, + serve_plugin, Args, CommandConfig, Plugin, PositionalType, Primitive, ReturnSuccess, + ReturnValue, ShellError, Spanned, SpannedItem, Value, }; -use nu::{Primitive, ReturnSuccess, ReturnValue, ShellError, Spanned, SpannedItem, Value}; -use serde::{Deserialize, Serialize}; -use std::io; struct Inc { inc_by: i64, @@ -16,87 +13,47 @@ impl Inc { } } -fn send_response(result: Vec) { - let response = JsonRpc::new("response", result); - let response_raw = serde_json::to_string(&response).unwrap(); - println!("{}", response_raw); -} - -fn send_error(error: ShellError) { - let message: ReturnValue = Err(error); - send_response(vec![message]) -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(tag = "method")] -#[allow(non_camel_case_types)] -pub enum NuCommand { - init { params: Vec> }, - filter { params: Spanned }, - quit, -} - -fn main() -> Result<(), Box> { - let mut inc_by = 1; - - loop { - let mut input = String::new(); - match io::stdin().read_line(&mut input) { - Ok(_) => { - let command = serde_json::from_str::(&input); - - match command { - Ok(NuCommand::init { params }) => { - for param in params { - match param { - Spanned { - item: Value::Primitive(Primitive::Int(i)), - .. - } => { - inc_by = i; - } - _ => { - send_error(ShellError::string("Unrecognized type in params")); - } - } - } - } - Ok(NuCommand::filter { params }) => match params { - Spanned { - item: Value::Primitive(Primitive::Int(i)), - span, - } => { - send_response(vec![ReturnSuccess::value( - Value::int(i + inc_by).spanned(span), - )]); - } - Spanned { - item: Value::Primitive(Primitive::Bytes(b)), - span, - } => { - send_response(vec![ReturnSuccess::value( - Value::bytes(b + inc_by as u128).spanned(span), - )]); - } - _ => { - send_error(ShellError::string("Unrecognized type in stream")); - } - }, - Ok(NuCommand::quit) => { - break; - } - Err(_) => { - send_error(ShellError::string("Unrecognized type in stream")); +impl Plugin for Inc { + fn config(&mut self) -> Result { + Ok(CommandConfig { + name: "inc".to_string(), + positional: vec![PositionalType::mandatory("Increment")], + can_load: vec![], + can_save: vec![], + is_filter: true, + is_sink: false, + named: IndexMap::new(), + rest_positional: true, + }) + } + fn begin_filter(&mut self, args: Args) -> Result<(), ShellError> { + if let Some(args) = args.positional { + for arg in args { + match arg { + Spanned { + item: Value::Primitive(Primitive::Int(i)), + .. + } => { + self.inc_by = i; } _ => return Err(ShellError::string("Unrecognized type in params")), } } - Err(_) => { - send_error(ShellError::string("Unrecognized type in stream")); - } - Value::Primitive(Primitive::Bytes(b)) => Ok(vec![ReturnValue::Value(Value::bytes( - b + self.inc_by as u64, - ))]), + } + + Ok(()) + } + + fn filter(&mut self, input: Spanned) -> Result, ShellError> { + let span = input.span; + + match input.item { + Value::Primitive(Primitive::Int(i)) => Ok(vec![ReturnSuccess::value( + Value::int(i + self.inc_by).spanned(span), + )]), + Value::Primitive(Primitive::Bytes(b)) => Ok(vec![ReturnSuccess::value( + Value::bytes(b + self.inc_by as u64).spanned(span), + )]), x => Err(ShellError::string(format!( "Unrecognized type in stream: {:?}", x diff --git a/src/plugins/skip.rs b/src/plugins/skip.rs index 14e3a5dee6..8fc852a6b6 100644 --- a/src/plugins/skip.rs +++ b/src/plugins/skip.rs @@ -1,6 +1,7 @@ use indexmap::IndexMap; use nu::{ - serve_plugin, Args, CommandConfig, Plugin, Primitive, ReturnValue, ShellError, Spanned, Value, + serve_plugin, Args, CommandConfig, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, + Spanned, Value, }; struct NewSkip { @@ -16,8 +17,7 @@ impl Plugin for NewSkip { fn config(&mut self) -> Result { Ok(CommandConfig { name: "skip".to_string(), - mandatory_positional: vec![], - optional_positional: vec![], + positional: vec![], can_load: vec![], can_save: vec![], is_filter: true, @@ -44,9 +44,9 @@ impl Plugin for NewSkip { Ok(()) } - fn filter(&mut self, input: Value) -> Result, ShellError> { + fn filter(&mut self, input: Spanned) -> Result, ShellError> { if self.skip_amount == 0 { - Ok(vec![ReturnValue::Value(input)]) + Ok(vec![ReturnSuccess::value(input)]) } else { self.skip_amount -= 1; Ok(vec![]) diff --git a/src/plugins/tree.rs b/src/plugins/tree.rs index a7a2da86a1..9c3f40b8fd 100644 --- a/src/plugins/tree.rs +++ b/src/plugins/tree.rs @@ -1,6 +1,6 @@ use derive_new::new; use indexmap::IndexMap; -use nu::{serve_plugin, Args, CommandConfig, Plugin, ShellError, Value}; +use nu::{serve_plugin, Args, CommandConfig, Plugin, ShellError, Spanned, Value}; use ptree::item::StringItem; use ptree::output::print_tree_with; use ptree::print_config::PrintConfig; @@ -31,7 +31,6 @@ impl TreeView { } } Value::Block(_) => {} - Value::Error(_) => {} Value::Filesystem => {} Value::Binary(_) => {} } @@ -85,8 +84,7 @@ impl Plugin for TreeViewer { fn config(&mut self) -> Result { Ok(CommandConfig { name: "tree".to_string(), - mandatory_positional: vec![], - optional_positional: vec![], + positional: vec![], can_load: vec![], can_save: vec![], is_filter: false, @@ -96,12 +94,11 @@ impl Plugin for TreeViewer { }) } - fn sink(&mut self, _args: Args, input: Vec) { + fn sink(&mut self, _args: Args, input: Vec>) { if input.len() > 0 { for i in input.iter() { let view = TreeView::from_value(&i); let _ = view.render_view(); - //handle_unexpected(&mut *host, |host| crate::format::print_view(&view, host)); } } From 6bf55c0f1ef90a462c08862c46233d3eaf199b46 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Fri, 12 Jul 2019 19:18:02 -0700 Subject: [PATCH 07/10] Remove more dead code and clean up JSON --- src/commands/from_ini.rs | 2 +- src/commands/from_json.rs | 2 +- src/commands/from_toml.rs | 2 +- src/commands/from_xml.rs | 2 +- src/commands/from_yaml.rs | 2 +- src/commands/to_json.rs | 22 ++++++++++++---------- src/object/dict.rs | 14 -------------- src/object/files.rs | 2 +- src/parser/parse/span.rs | 2 +- src/prelude.rs | 2 +- 10 files changed, 20 insertions(+), 32 deletions(-) diff --git a/src/commands/from_ini.rs b/src/commands/from_ini.rs index 7352d4c0db..340ad26e4f 100644 --- a/src/commands/from_ini.rs +++ b/src/commands/from_ini.rs @@ -1,4 +1,4 @@ -use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; +use crate::object::{Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; use std::collections::HashMap; diff --git a/src/commands/from_json.rs b/src/commands/from_json.rs index e81d81e281..36dae4b1b1 100644 --- a/src/commands/from_json.rs +++ b/src/commands/from_json.rs @@ -1,5 +1,5 @@ use crate::object::base::OF64; -use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; +use crate::object::{Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; fn convert_json_value_to_nu_value(v: &serde_hjson::Value, span: impl Into) -> Spanned { diff --git a/src/commands/from_toml.rs b/src/commands/from_toml.rs index ffea6fd5d7..1745548eeb 100644 --- a/src/commands/from_toml.rs +++ b/src/commands/from_toml.rs @@ -1,5 +1,5 @@ use crate::object::base::OF64; -use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; +use crate::object::{Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; fn convert_toml_value_to_nu_value(v: &toml::Value, span: impl Into) -> Spanned { diff --git a/src/commands/from_xml.rs b/src/commands/from_xml.rs index ebfce83e98..db56cb830d 100644 --- a/src/commands/from_xml.rs +++ b/src/commands/from_xml.rs @@ -1,4 +1,4 @@ -use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; +use crate::object::{Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; fn from_node_to_value<'a, 'd>( diff --git a/src/commands/from_yaml.rs b/src/commands/from_yaml.rs index 3c9de7302f..12121037bc 100644 --- a/src/commands/from_yaml.rs +++ b/src/commands/from_yaml.rs @@ -1,5 +1,5 @@ use crate::object::base::OF64; -use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; +use crate::object::{Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, span: impl Into) -> Spanned { diff --git a/src/commands/to_json.rs b/src/commands/to_json.rs index 0a79ca48c5..335ceee175 100644 --- a/src/commands/to_json.rs +++ b/src/commands/to_json.rs @@ -45,15 +45,17 @@ pub fn to_json(args: CommandArgs) -> Result { let name_span = args.name_span; Ok(out .values - .map(move |a| match serde_json::to_string(&a) { - Ok(x) => { - ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span)) - } - Err(_) => Err(ShellError::maybe_labeled_error( - "Can not convert to JSON string", - "can not convert piped data to JSON string", - name_span, - )), - }) + .map( + move |a| match serde_json::to_string(&value_to_json_value(&a)) { + Ok(x) => { + ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span)) + } + Err(_) => Err(ShellError::maybe_labeled_error( + "Can not convert to JSON string", + "can not convert piped data to JSON string", + name_span, + )), + }, + ) .to_output_stream()) } diff --git a/src/object/dict.rs b/src/object/dict.rs index e0844dda57..16c7d32818 100644 --- a/src/object/dict.rs +++ b/src/object/dict.rs @@ -72,20 +72,6 @@ impl PartialEq for Dictionary { } impl Dictionary { - crate fn add(&mut self, name: impl Into, value: impl Into>) { - self.entries.insert(name.into(), value.into()); - } - - crate fn copy_dict(&self) -> Dictionary { - let mut out = Dictionary::default(); - - for (key, value) in self.entries.iter() { - out.add(key.clone(), value.clone()); - } - - out - } - pub fn get_data(&'a self, desc: &String) -> MaybeOwned<'a, Value> { match self.entries.get(desc) { Some(v) => MaybeOwned::Borrowed(v), diff --git a/src/object/files.rs b/src/object/files.rs index 210ff5405e..0e031b1544 100644 --- a/src/object/files.rs +++ b/src/object/files.rs @@ -1,5 +1,5 @@ use crate::errors::ShellError; -use crate::object::{Dictionary, SpannedDictBuilder, Value}; +use crate::object::{SpannedDictBuilder, Value}; use crate::prelude::*; #[derive(Debug)] diff --git a/src/parser/parse/span.rs b/src/parser/parse/span.rs index 3886f40e18..7b98a00a29 100644 --- a/src/parser/parse/span.rs +++ b/src/parser/parse/span.rs @@ -1,7 +1,7 @@ use crate::Text; use derive_new::new; use getset::Getters; -use serde::{Serialize, Serializer}; +use serde::Serialize; use serde_derive::Deserialize; #[derive( diff --git a/src/prelude.rs b/src/prelude.rs index 67454939c6..7316efada3 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -40,7 +40,7 @@ crate use crate::context::Context; crate use crate::env::host::handle_unexpected; crate use crate::env::{Environment, Host}; crate use crate::errors::ShellError; -crate use crate::object::types::{ExtractType, Type}; +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}; From b2d48566ba3058f8bb6b7bbd408f9c3f96648668 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Fri, 12 Jul 2019 19:19:18 -0700 Subject: [PATCH 08/10] Remove unused tree --- src/format.rs | 2 -- src/format/tree.rs | 79 ---------------------------------------------- 2 files changed, 81 deletions(-) delete mode 100644 src/format/tree.rs diff --git a/src/format.rs b/src/format.rs index 53df2db863..be835ea76e 100644 --- a/src/format.rs +++ b/src/format.rs @@ -2,7 +2,6 @@ crate mod entries; crate mod generic; crate mod list; crate mod table; -crate mod tree; crate mod vtable; use crate::prelude::*; @@ -10,7 +9,6 @@ use crate::prelude::*; crate use entries::EntriesView; crate use generic::GenericView; crate use table::TableView; -crate use tree::TreeView; crate use vtable::VTableView; crate trait RenderView { diff --git a/src/format/tree.rs b/src/format/tree.rs deleted file mode 100644 index d124ea5cfd..0000000000 --- a/src/format/tree.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::format::RenderView; -use crate::prelude::*; -use derive_new::new; -use ptree::item::StringItem; -use ptree::output::print_tree_with; -use ptree::print_config::PrintConfig; -use ptree::style::{Color, Style}; -use ptree::TreeBuilder; - -#[derive(new)] -pub struct TreeView { - tree: StringItem, -} - -impl TreeView { - fn from_value_helper(value: &Value, mut builder: &mut TreeBuilder) { - match value { - Value::Primitive(p) => { - let _ = builder.add_empty_child(p.format(None)); - } - Value::Object(o) => { - for (k, v) in o.entries.iter() { - builder = builder.begin_child(k.clone()); - Self::from_value_helper(v, builder); - builder = builder.end_child(); - } - } - Value::List(l) => { - for elem in l.iter() { - Self::from_value_helper(elem, builder); - } - } - Value::Block(_) => {} - Value::Filesystem => {} - Value::Binary(_) => {} - } - } - crate fn from_value(value: &Value) -> TreeView { - let descs = value.data_descriptors(); - - let mut tree = TreeBuilder::new("".to_string()); - let mut builder = &mut tree; - - for desc in descs { - let value = value.get_data(&desc); - builder = builder.begin_child(desc.clone()); - Self::from_value_helper(value.borrow(), &mut builder); - builder = builder.end_child(); - //entries.push((desc.name.clone(), value.borrow().copy())) - } - - TreeView::new(builder.build()) - } -} - -impl RenderView for TreeView { - fn render_view(&self, _host: &mut dyn Host) -> Result<(), ShellError> { - // Set up the print configuration - let config = { - let mut config = PrintConfig::from_env(); - config.branch = Style { - foreground: Some(Color::Green), - dimmed: true, - ..Style::default() - }; - config.leaf = Style { - bold: true, - ..Style::default() - }; - config.indent = 4; - config - }; - - // Print out the tree using custom formatting - print_tree_with(&self.tree, &config)?; - - Ok(()) - } -} From 7e555a0ef23358a1a3d3160135d0544f7e432f31 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Sun, 14 Jul 2019 04:59:59 +1200 Subject: [PATCH 09/10] "Add plugin arg errors. Bring remaining errors to parity" --- Cargo.lock | 14 ++++++++------ Cargo.toml | 2 +- src/commands/command.rs | 4 ---- src/commands/config.rs | 2 -- src/commands/enter.rs | 2 -- src/commands/get.rs | 2 +- src/commands/macros.rs | 2 -- src/commands/plugin.rs | 23 ++++++++++++++++++++++- src/commands/skip_while.rs | 2 -- src/errors.rs | 30 ++++-------------------------- src/parser/registry.rs | 2 -- src/plugin.rs | 12 ++++++++++-- src/plugins/binaryview.rs | 2 -- src/plugins/inc.rs | 2 -- src/plugins/skip.rs | 4 +--- src/plugins/tree.rs | 2 -- 16 files changed, 47 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 646e8c1749..a2b4696208 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1278,12 +1278,14 @@ dependencies = [ [[package]] name = "language-reporting" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/jonathandturner/language-reporting#0a6c284a19a00b5b6b680480c0ad5f241fc5edac" dependencies = [ "derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "render-tree 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "render-tree 0.1.1 (git+https://github.com/jonathandturner/language-reporting)", + "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1649,7 +1651,7 @@ dependencies = [ "image 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "language-reporting 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "language-reporting 0.3.0 (git+https://github.com/jonathandturner/language-reporting)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "logos 0.10.0-rc2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2354,7 +2356,7 @@ dependencies = [ [[package]] name = "render-tree" version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/jonathandturner/language-reporting#0a6c284a19a00b5b6b680480c0ad5f241fc5edac" dependencies = [ "itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3497,7 +3499,7 @@ dependencies = [ "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum language-reporting 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61e5d4e5c7a76724d544bb5652a8a3ded29475a1b260a263b5d6743f5871ac83" +"checksum language-reporting 0.3.0 (git+https://github.com/jonathandturner/language-reporting)" = "" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" @@ -3606,7 +3608,7 @@ dependencies = [ "checksum regex 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1325e8a57b7da4cbcb38b3957112f729990bad0a18420e7e250ef6b1d9a15763" "checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum render-tree 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "68ed587df09cfb7ce1bc6fe8f77e24db219f222c049326ccbfb948ec67e31664" +"checksum render-tree 0.1.1 (git+https://github.com/jonathandturner/language-reporting)" = "" "checksum reqwest 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)" = "00eb63f212df0e358b427f0f40aa13aaea010b470be642ad422bcbca2feff2e4" "checksum result 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "194d8e591e405d1eecf28819740abed6d719d1a2db87fc0bcdedee9a26d55560" "checksum roxmltree 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "330d8f80a274bc3cb608908ee345970e7e24b96907f1ad69615a498bec57871c" diff --git a/Cargo.toml b/Cargo.toml index ca82128bb4..4fbe320d87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ serde_derive = "1.0.94" getset = "0.0.7" logos = "0.10.0-rc2" logos-derive = "0.10.0-rc2" -language-reporting = "0.3.0" +language-reporting = {git = "https://github.com/jonathandturner/language-reporting"} app_dirs = "1.2.1" toml = "0.5.1" toml-query = "0.9.2" diff --git a/src/commands/command.rs b/src/commands/command.rs index 92b0dc3b82..cf681cee6d 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -99,8 +99,6 @@ pub trait Command { named: indexmap::IndexMap::new(), is_filter: true, is_sink: false, - can_load: vec![], - can_save: vec![], } } } @@ -117,8 +115,6 @@ pub trait Sink { named: indexmap::IndexMap::new(), is_filter: false, is_sink: true, - can_load: vec![], - can_save: vec![], } } } diff --git a/src/commands/config.rs b/src/commands/config.rs index c28b31da20..47b073e0b5 100644 --- a/src/commands/config.rs +++ b/src/commands/config.rs @@ -36,8 +36,6 @@ impl Command for Config { named, is_sink: true, is_filter: false, - can_load: vec![], - can_save: vec![], } } } diff --git a/src/commands/enter.rs b/src/commands/enter.rs index 9dc105324d..f1199bfa65 100644 --- a/src/commands/enter.rs +++ b/src/commands/enter.rs @@ -14,8 +14,6 @@ impl Command for Enter { name: self.name().to_string(), positional: vec![PositionalType::mandatory_block("path")], rest_positional: false, - can_load: vec![], - can_save: vec![], is_filter: false, is_sink: false, named: indexmap::IndexMap::new(), diff --git a/src/commands/get.rs b/src/commands/get.rs index fea58ed0a9..e6d1de26b1 100644 --- a/src/commands/get.rs +++ b/src/commands/get.rs @@ -65,7 +65,7 @@ pub fn get(args: CommandArgs) -> Result { } } Ok(x) => result.push_back(ReturnSuccess::value(x.clone())), - Err(_) => {} + Err(x) => result.push_back(Err(x)), } } diff --git a/src/commands/macros.rs b/src/commands/macros.rs index 1c5268b672..c7dd74de77 100644 --- a/src/commands/macros.rs +++ b/src/commands/macros.rs @@ -48,8 +48,6 @@ macro_rules! command { name: self.name().to_string(), positional: vec![$($mandatory_positional)*], rest_positional: false, - can_load: vec![], - can_save: vec![], is_filter: false, is_sink: false, diff --git a/src/commands/plugin.rs b/src/commands/plugin.rs index 291e1f0517..3d9ecb5c54 100644 --- a/src/commands/plugin.rs +++ b/src/commands/plugin.rs @@ -43,11 +43,32 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result { + let response = serde_json::from_str::(&input); + match response { + Ok(NuResult::response { params }) => match params { + Ok(_) => {} + Err(e) => { + return Err(e); + } + }, + Err(e) => { + return Err(ShellError::string(format!( + "Error while processing input: {:?} {}", + e, input + ))); + } + } + } + _ => {} + } } let mut eos: VecDeque> = VecDeque::new(); diff --git a/src/commands/skip_while.rs b/src/commands/skip_while.rs index eebaef83f1..605747e694 100644 --- a/src/commands/skip_while.rs +++ b/src/commands/skip_while.rs @@ -21,8 +21,6 @@ impl Command for SkipWhile { named: indexmap::IndexMap::new(), is_filter: true, is_sink: false, - can_load: vec![], - can_save: vec![], } } } diff --git a/src/errors.rs b/src/errors.rs index 17ccf38f5f..c7c2ca908d 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -5,7 +5,7 @@ use crate::parser::{Span, Spanned}; use ansi_term::Color; use derive_new::new; use language_reporting::{Diagnostic, Label, Severity}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde::{Deserialize, Serialize}; #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)] pub enum Description { @@ -203,7 +203,7 @@ impl ShellError { } } - crate fn labeled_error( + pub fn labeled_error( msg: impl Into, label: impl Into, span: Span, @@ -214,7 +214,7 @@ impl ShellError { ) } - crate fn maybe_labeled_error( + pub fn maybe_labeled_error( msg: impl Into, label: impl Into, span: Option, @@ -272,7 +272,7 @@ impl ProximateShellError { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct ShellDiagnostic { crate diagnostic: Diagnostic, } @@ -315,28 +315,6 @@ impl std::cmp::Ord for ShellDiagnostic { } } -impl Serialize for ShellDiagnostic { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - "".serialize(serializer) - } -} - -impl Deserialize<'de> for ShellDiagnostic { - fn deserialize(_deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Ok(ShellDiagnostic { - diagnostic: Diagnostic::new( - language_reporting::Severity::Error, - "deserialize not implemented for ShellDiagnostic", - ), - }) - } -} #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, new, Clone, Serialize, Deserialize)] pub struct StringError { title: String, diff --git a/src/parser/registry.rs b/src/parser/registry.rs index 4447b496c7..2bdb06c23c 100644 --- a/src/parser/registry.rs +++ b/src/parser/registry.rs @@ -82,8 +82,6 @@ pub struct CommandConfig { pub named: IndexMap, pub is_filter: bool, pub is_sink: bool, - pub can_load: Vec, - pub can_save: Vec, } #[derive(Debug, Default, new, Serialize, Deserialize)] diff --git a/src/plugin.rs b/src/plugin.rs index 4489122780..4126b9d08f 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -33,7 +33,11 @@ pub fn serve_plugin(plugin: &mut dyn Plugin) { send_response(plugin.config()); } Ok(NuCommand::begin_filter { params }) => { - let _ = plugin.begin_filter(params); + send_response( + plugin + .begin_filter(params) + .map(|_| Vec::::new()), + ); } Ok(NuCommand::filter { params }) => { send_response(plugin.filter(params)); @@ -66,7 +70,11 @@ pub fn serve_plugin(plugin: &mut dyn Plugin) { send_response(plugin.config()); } Ok(NuCommand::begin_filter { params }) => { - let _ = plugin.begin_filter(params); + send_response( + plugin + .begin_filter(params) + .map(|_| Vec::::new()), + ); } Ok(NuCommand::filter { params }) => { send_response(plugin.filter(params)); diff --git a/src/plugins/binaryview.rs b/src/plugins/binaryview.rs index b96e0e160d..d56037a02d 100644 --- a/src/plugins/binaryview.rs +++ b/src/plugins/binaryview.rs @@ -16,8 +16,6 @@ impl Plugin for BinaryView { Ok(CommandConfig { name: "binaryview".to_string(), positional: vec![], - can_load: vec![], - can_save: vec![], is_filter: false, is_sink: true, named: IndexMap::new(), diff --git a/src/plugins/inc.rs b/src/plugins/inc.rs index c9257da132..be2a013dfb 100644 --- a/src/plugins/inc.rs +++ b/src/plugins/inc.rs @@ -18,8 +18,6 @@ impl Plugin for Inc { Ok(CommandConfig { name: "inc".to_string(), positional: vec![PositionalType::mandatory("Increment")], - can_load: vec![], - can_save: vec![], is_filter: true, is_sink: false, named: IndexMap::new(), diff --git a/src/plugins/skip.rs b/src/plugins/skip.rs index 8fc852a6b6..0a1fdf7a9f 100644 --- a/src/plugins/skip.rs +++ b/src/plugins/skip.rs @@ -18,8 +18,6 @@ impl Plugin for NewSkip { Ok(CommandConfig { name: "skip".to_string(), positional: vec![], - can_load: vec![], - can_save: vec![], is_filter: true, is_sink: false, named: IndexMap::new(), @@ -36,7 +34,7 @@ impl Plugin for NewSkip { } => { self.skip_amount = i; } - _ => return Err(ShellError::string("Unrecognized type in params")), + _ => return Err(ShellError::labeled_error("Unrecognized type in params", "expected an integer", arg.span)), } } } diff --git a/src/plugins/tree.rs b/src/plugins/tree.rs index 9c3f40b8fd..5d8abeb44d 100644 --- a/src/plugins/tree.rs +++ b/src/plugins/tree.rs @@ -85,8 +85,6 @@ impl Plugin for TreeViewer { Ok(CommandConfig { name: "tree".to_string(), positional: vec![], - can_load: vec![], - can_save: vec![], is_filter: false, is_sink: true, named: IndexMap::new(), From eefb6fd9a0386e7d9db97274f364c5d2e2e98d6b Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Sun, 14 Jul 2019 05:32:01 +1200 Subject: [PATCH 10/10] Bump rustc version. Fix macOS build issue --- .azure/azure-pipelines.yml | 2 +- src/commands/sysinfo.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.azure/azure-pipelines.yml b/.azure/azure-pipelines.yml index 048ab8b60d..9828066f3c 100644 --- a/.azure/azure-pipelines.yml +++ b/.azure/azure-pipelines.yml @@ -1,5 +1,5 @@ variables: - lkg-rust-nightly: "2019-06-28" + lkg-rust-nightly: "2019-07-04" trigger: - master diff --git a/src/commands/sysinfo.rs b/src/commands/sysinfo.rs index 73fda3fe02..421980dca6 100644 --- a/src/commands/sysinfo.rs +++ b/src/commands/sysinfo.rs @@ -75,7 +75,7 @@ pub fn sysinfo(args: CommandArgs) -> Result { boottime_idx.insert("hours", Primitive::Int((x.tv_sec / 3600) % 24)); boottime_idx.insert("mins", Primitive::Int((x.tv_sec / 60) % 60)); - idx.insert("uptime", boottime_idx); + idx.insert_spanned("uptime", boottime_idx); } }