forked from extern/nushell
WIP improve error infrastructure
Also simplify commands and reduce papercuts
This commit is contained in:
parent
5d73c73fe8
commit
34033afce4
10
src/cli.rs
10
src/cli.rs
@ -159,6 +159,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
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<dyn Error>> {
|
||||
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<dyn Error>> {
|
||||
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<String, ReadlineError>, ctx: &mut Context
|
||||
}
|
||||
|
||||
(Some(ClassifiedCommand::Sink(left)), None) => {
|
||||
let input_vec: Vec<Value> = input.objects.collect().await;
|
||||
let input_vec: Vec<Value> = input.objects.into_vec().await;
|
||||
if let Err(err) = left.run(ctx, input_vec) {
|
||||
return LineResult::Error(line.clone(), err);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -52,14 +52,14 @@ pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
}
|
||||
}
|
||||
}
|
||||
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<OutputStream, ShellError> {
|
||||
}
|
||||
},
|
||||
}
|
||||
stream.push_back(ReturnValue::change_cwd(cwd));
|
||||
stream.push_back(ReturnSuccess::change_cwd(cwd));
|
||||
}
|
||||
};
|
||||
Ok(stream.boxed())
|
||||
Ok(stream.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Output = Vec<Value>> {
|
||||
self.objects.into_vec()
|
||||
}
|
||||
|
||||
crate fn from_vec(stream: VecDeque<Value>) -> ClassifiedInputStream {
|
||||
ClassifiedInputStream {
|
||||
objects: stream,
|
||||
objects: stream.into(),
|
||||
stdin: None,
|
||||
}
|
||||
}
|
||||
|
||||
crate fn from_list(stream: Vec<Value>) -> ClassifiedInputStream {
|
||||
ClassifiedInputStream {
|
||||
objects: stream.into(),
|
||||
stdin: None,
|
||||
}
|
||||
}
|
||||
|
||||
crate fn from_input_stream(stream: impl Into<InputStream>) -> 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<InputStream, ShellError> {
|
||||
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::<Vec<_>>(),
|
||||
);
|
||||
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<ClassifiedInputStream, ShellError> {
|
||||
let inputs: Vec<Value> = input.objects.collect().await;
|
||||
let stdin = input.stdin;
|
||||
let inputs: Vec<Value> = 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>
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(())
|
||||
|
@ -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<ReturnSuccess, ShellError>;
|
||||
|
||||
impl From<Value> 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,
|
||||
|
@ -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<OutputStream, ShellError> {
|
||||
.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<OutputStream, ShellError> {
|
||||
|
||||
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<OutputStream, ShellError> {
|
||||
|
||||
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<OutputStream, ShellError> {
|
||||
)));
|
||||
}
|
||||
|
||||
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")))
|
||||
|
@ -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<OutputStream, ShellError> {
|
||||
enter(args)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.len() == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
@ -67,16 +89,9 @@ pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
}
|
||||
};
|
||||
|
||||
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())
|
||||
}
|
||||
|
@ -3,7 +3,5 @@ use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn exit(_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let mut stream = VecDeque::new();
|
||||
stream.push_back(ReturnValue::Action(CommandAction::Exit));
|
||||
Ok(stream.boxed())
|
||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::Exit))].into())
|
||||
}
|
||||
|
@ -27,8 +27,5 @@ pub fn first(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
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)))
|
||||
}
|
||||
|
@ -30,22 +30,21 @@ pub fn from_ini(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
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())
|
||||
}
|
||||
|
@ -34,22 +34,21 @@ pub fn from_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
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())
|
||||
}
|
||||
|
@ -33,22 +33,21 @@ pub fn from_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
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())
|
||||
}
|
||||
|
@ -52,22 +52,21 @@ pub fn from_xml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
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())
|
||||
}
|
||||
|
@ -43,22 +43,21 @@ pub fn from_yaml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
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())
|
||||
}
|
||||
|
@ -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<Value> {
|
||||
fn get_member(path: &str, span: Span, obj: &Value) -> Result<Value, ShellError> {
|
||||
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<OutputStream, ShellError> {
|
||||
@ -36,10 +36,10 @@ pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
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<Vec<(String, Span)>, _> = args
|
||||
@ -51,17 +51,18 @@ pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
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<OutputStream, ShellError> {
|
||||
})
|
||||
.flatten();
|
||||
|
||||
Ok(stream.boxed())
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ pub fn lines(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
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<OutputStream, ShellError> {
|
||||
|
||||
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<OutputStream, ShellError> {
|
||||
}
|
||||
_ => {
|
||||
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())
|
||||
}
|
||||
|
@ -45,9 +45,9 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
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<OutputStream, ShellError> {
|
||||
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<OutputStream, ShellError> {
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
326
src/commands/macros.rs
Normal file
326
src/commands/macros.rs
Normal file
@ -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<OutputStream, ShellError> {
|
||||
fn command($args: CommandArgs, ( $($param_name),*, ): ( $($param_type),*, )) -> Result<OutputStream, ShellError> {
|
||||
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<String, NamedType> = 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<OutputStream, ShellError> {
|
||||
// fn command($args: CommandArgs, $param: $kind) -> Result<OutputStream, ShellError> {
|
||||
// $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<String, NamedType> = 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,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
}
|
@ -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<OutputStream, ShellError> {
|
||||
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<String, NamedType> = 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<String>, Value), ShellError> {
|
||||
) -> Result<(Option<String>, 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<OutputStream, ShellError> {
|
||||
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())
|
||||
}
|
||||
|
@ -17,9 +17,8 @@ pub fn pick(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
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())
|
||||
}
|
||||
|
@ -93,11 +93,9 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
||||
},
|
||||
Err(e) => {
|
||||
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<OutputStream, Sh
|
||||
}
|
||||
Err(e) => {
|
||||
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<OutputStream, Sh
|
||||
})
|
||||
.flatten();
|
||||
|
||||
Ok(stream.boxed())
|
||||
Ok(stream.to_output_stream())
|
||||
}
|
||||
|
||||
pub fn sink_plugin(path: String, args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
|
@ -11,8 +11,8 @@ pub fn ps(_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
let list = list
|
||||
.into_iter()
|
||||
.map(|(_, process)| ReturnValue::Value(Value::Object(process_dict(process))))
|
||||
.map(|(_, process)| Value::Object(process_dict(process)))
|
||||
.collect::<VecDeque<_>>();
|
||||
|
||||
Ok(list.boxed())
|
||||
Ok(list.from_input_stream())
|
||||
}
|
||||
|
@ -17,8 +17,8 @@ pub fn reject(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
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())
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ pub fn size(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
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))
|
||||
}
|
||||
|
@ -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<OutputStream, ShellError> {
|
||||
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<OutputStream, ShellError> {
|
||||
futures::future::ready(return_value)
|
||||
});
|
||||
|
||||
Ok(objects.map(|x| ReturnValue::Value(x)).boxed())
|
||||
Ok(objects.from_input_stream())
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ pub fn sort_by(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let fields: Result<Vec<_>, _> = args.positional_iter().map(|a| a.as_string()).collect();
|
||||
let fields = fields?;
|
||||
|
||||
let output = args.input.collect::<Vec<_>>();
|
||||
let output = args.input.values.collect::<Vec<_>>();
|
||||
|
||||
let output = output.map(move |mut vec| {
|
||||
vec.sort_by_key(|item| {
|
||||
@ -15,11 +15,8 @@ pub fn sort_by(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
.collect::<Vec<Option<Value>>>()
|
||||
});
|
||||
|
||||
vec.into_iter()
|
||||
.map(|v| ReturnValue::Value(v.copy()))
|
||||
.collect::<VecDeque<_>>()
|
||||
.boxed()
|
||||
vec.into_iter().collect::<VecDeque<_>>()
|
||||
});
|
||||
|
||||
Ok(output.flatten_stream().boxed())
|
||||
Ok(output.flatten_stream().from_input_stream())
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use log::trace;
|
||||
pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
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<OutputStream, ShellError> {
|
||||
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<OutputStream, ShellError> {
|
||||
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<OutputStream, ShellError> {
|
||||
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<OutputStream, ShellError> {
|
||||
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())
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ pub fn split_row(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
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<OutputStream, ShellError> {
|
||||
|
||||
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<OutputStream, ShellError> {
|
||||
}
|
||||
_ => {
|
||||
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())
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ pub fn sysinfo(_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
// 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())
|
||||
}
|
||||
|
@ -2,9 +2,10 @@ use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn to_array(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
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())
|
||||
}
|
||||
|
@ -47,14 +47,12 @@ pub fn to_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
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())
|
||||
|
@ -35,13 +35,14 @@ pub fn to_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
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())
|
||||
}
|
||||
|
@ -9,15 +9,16 @@ pub fn trim(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
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())
|
||||
}
|
||||
|
@ -46,5 +46,5 @@ pub fn view(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
let _ = printer.file(file.display().to_string());
|
||||
|
||||
Ok(VecDeque::new().boxed())
|
||||
Ok(VecDeque::new().into())
|
||||
}
|
||||
|
@ -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<OutputStream, ShellError> {
|
||||
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<OutputStream, ShellError> {
|
||||
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())
|
||||
}
|
||||
|
@ -41,6 +41,16 @@ pub enum ArgumentError {
|
||||
MissingValueForName(String),
|
||||
}
|
||||
|
||||
pub fn labelled(
|
||||
span: impl Into<Option<Span>>,
|
||||
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)),
|
||||
|
@ -31,7 +31,6 @@ impl TreeView {
|
||||
}
|
||||
}
|
||||
Value::Block(_) => {}
|
||||
Value::Error(_) => {}
|
||||
Value::Filesystem => {}
|
||||
Value::Binary(_) => {}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -185,9 +185,6 @@ pub enum Value {
|
||||
#[allow(unused)]
|
||||
Block(Block),
|
||||
Filesystem,
|
||||
|
||||
#[allow(unused)]
|
||||
Error(Box<ShellError>),
|
||||
}
|
||||
|
||||
pub fn debug_list(values: &'a Vec<Value>) -> 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<Value> {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&'a Spanned<Value>> for Block {
|
||||
type Error = ShellError;
|
||||
|
||||
fn try_from(value: &'a Spanned<Value>) -> Result<Block, ShellError> {
|
||||
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<Value>> for i64 {
|
||||
type Error = ShellError;
|
||||
|
||||
fn try_from(value: &'a Spanned<Value>) -> Result<i64, ShellError> {
|
||||
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<Option<&'a Spanned<Value>>> for Switch {
|
||||
type Error = ShellError;
|
||||
|
||||
fn try_from(value: Option<&'a Spanned<Value>>) -> Result<Switch, ShellError> {
|
||||
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!("<filesystem>"),
|
||||
Value::Binary(_) => format!("<binary>"),
|
||||
}
|
||||
@ -459,14 +511,6 @@ impl Value {
|
||||
Ok(Value::Primitive(Primitive::Date(date)))
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn system_date_result(s: Result<SystemTime, std::io::Error>) -> 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)
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ impl language_reporting::ReportingFiles for Files {
|
||||
0
|
||||
}
|
||||
fn file_name(&self, _file: Self::FileId) -> FileName {
|
||||
FileName::Verbatim(format!("<eval>"))
|
||||
FileName::Verbatim(format!("shell"))
|
||||
}
|
||||
fn byte_index(&self, _file: Self::FileId, _line: usize, _column: usize) -> Option<usize> {
|
||||
unimplemented!("byte_index")
|
||||
|
@ -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,
|
||||
}),
|
||||
|
@ -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<ExpressionKindHint> {
|
||||
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<PositionalType>,
|
||||
pub optional_positional: Vec<PositionalType>,
|
||||
crate positional: Vec<PositionalType>,
|
||||
pub rest_positional: bool,
|
||||
pub named: IndexMap<String, NamedType>,
|
||||
pub is_filter: bool,
|
||||
|
@ -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<CommandConfig, ShellError> {
|
||||
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<T: Serialize>(result: Vec<T>) {
|
||||
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<Spanned<Value>> },
|
||||
filter { params: Value },
|
||||
quit,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
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::<NuCommand>(&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<Vec<ReturnValue>, 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,
|
||||
|
@ -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<T> FromInputStream for T
|
||||
where
|
||||
T: Stream<Item = Value> + 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<T, U> ToOutputStream for T
|
||||
where
|
||||
T: Stream<Item = U> + Send + 'static,
|
||||
U: Into<ReturnValue>,
|
||||
{
|
||||
fn to_output_stream(self) -> OutputStream {
|
||||
OutputStream {
|
||||
values: self.map(|item| item.into()).boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
118
src/stream.rs
118
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<Output = Vec<Value>> {
|
||||
self.values.collect()
|
||||
}
|
||||
|
||||
pub fn from_stream(input: impl Stream<Item = Value> + Send + 'static) -> InputStream {
|
||||
InputStream {
|
||||
values: input.boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BoxStream<'static, Value>> for InputStream {
|
||||
fn from(input: BoxStream<'static, Value>) -> InputStream {
|
||||
InputStream { values: input }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<VecDeque<Value>> for InputStream {
|
||||
fn from(input: VecDeque<Value>) -> InputStream {
|
||||
InputStream {
|
||||
values: input.boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Value>> for InputStream {
|
||||
fn from(input: Vec<Value>) -> 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<Item = ReturnValue> + Send + 'static) -> OutputStream {
|
||||
OutputStream {
|
||||
values: input.boxed(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_input(input: impl Stream<Item = Value> + Send + 'static) -> OutputStream {
|
||||
OutputStream {
|
||||
values: input.map(ReturnSuccess::value).boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InputStream> for OutputStream {
|
||||
fn from(input: InputStream) -> OutputStream {
|
||||
OutputStream {
|
||||
values: input.values.map(ReturnSuccess::value).boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BoxStream<'static, Value>> for OutputStream {
|
||||
fn from(input: BoxStream<'static, Value>) -> OutputStream {
|
||||
OutputStream {
|
||||
values: input.map(ReturnSuccess::value).boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BoxStream<'static, ReturnValue>> for OutputStream {
|
||||
fn from(input: BoxStream<'static, ReturnValue>) -> OutputStream {
|
||||
OutputStream { values: input }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<VecDeque<ReturnValue>> for OutputStream {
|
||||
fn from(input: VecDeque<ReturnValue>) -> OutputStream {
|
||||
OutputStream {
|
||||
values: input.boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<ReturnValue>> for OutputStream {
|
||||
fn from(input: Vec<ReturnValue>) -> OutputStream {
|
||||
let mut list = VecDeque::default();
|
||||
list.extend(input);
|
||||
|
||||
OutputStream {
|
||||
values: list.boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Value>> for OutputStream {
|
||||
fn from(input: Vec<Value>) -> OutputStream {
|
||||
let mut list = VecDeque::default();
|
||||
list.extend(input.into_iter().map(ReturnSuccess::value));
|
||||
|
||||
OutputStream {
|
||||
values: list.boxed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user