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("sysinfo", Box::new(sysinfo::sysinfo)),
|
||||||
command("cd", Box::new(cd::cd)),
|
command("cd", Box::new(cd::cd)),
|
||||||
command("view", Box::new(view::view)),
|
command("view", Box::new(view::view)),
|
||||||
|
// command("skip", skip::Skip),
|
||||||
command("first", Box::new(first::first)),
|
command("first", Box::new(first::first)),
|
||||||
command("size", Box::new(size::size)),
|
command("size", Box::new(size::size)),
|
||||||
command("from-ini", Box::new(from_ini::from_ini)),
|
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-xml", Box::new(from_xml::from_xml)),
|
||||||
command("from-yaml", Box::new(from_yaml::from_yaml)),
|
command("from-yaml", Box::new(from_yaml::from_yaml)),
|
||||||
command("get", Box::new(get::get)),
|
command("get", Box::new(get::get)),
|
||||||
command("enter", Box::new(enter::enter)),
|
|
||||||
command("exit", Box::new(exit::exit)),
|
command("exit", Box::new(exit::exit)),
|
||||||
command("lines", Box::new(lines::lines)),
|
command("lines", Box::new(lines::lines)),
|
||||||
command("pick", Box::new(pick::pick)),
|
command("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-json", Box::new(to_json::to_json)),
|
||||||
command("to-toml", Box::new(to_toml::to_toml)),
|
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("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(Open),
|
||||||
Arc::new(Where),
|
Arc::new(Where),
|
||||||
Arc::new(Config),
|
Arc::new(Config),
|
||||||
Arc::new(SkipWhile),
|
Arc::new(SkipWhile),
|
||||||
command("sort-by", Box::new(sort_by::sort_by)),
|
Arc::new(Enter),
|
||||||
|
Arc::new(Skip),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
context.add_sinks(vec![
|
context.add_sinks(vec![
|
||||||
@ -392,7 +396,7 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
|||||||
}
|
}
|
||||||
|
|
||||||
(Some(ClassifiedCommand::Sink(left)), None) => {
|
(Some(ClassifiedCommand::Sink(left)), None) => {
|
||||||
let input_vec: Vec<Value> = input.objects.collect().await;
|
let input_vec: Vec<Value> = input.objects.into_vec().await;
|
||||||
if let Err(err) = left.run(ctx, input_vec) {
|
if let Err(err) = left.run(ctx, input_vec) {
|
||||||
return LineResult::Error(line.clone(), err);
|
return LineResult::Error(line.clone(), err);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
#[macro_use]
|
||||||
|
crate mod macros;
|
||||||
|
|
||||||
crate mod args;
|
crate mod args;
|
||||||
crate mod autoview;
|
crate mod autoview;
|
||||||
crate mod cd;
|
crate mod cd;
|
||||||
@ -39,6 +42,8 @@ crate mod where_;
|
|||||||
|
|
||||||
crate use command::command;
|
crate use command::command;
|
||||||
crate use config::Config;
|
crate use config::Config;
|
||||||
|
crate use enter::Enter;
|
||||||
crate use open::Open;
|
crate use open::Open;
|
||||||
|
crate use skip::Skip;
|
||||||
crate use skip_while::SkipWhile;
|
crate use skip_while::SkipWhile;
|
||||||
crate use where_::Where;
|
crate use where_::Where;
|
||||||
|
@ -52,14 +52,14 @@ pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stream.push_back(ReturnValue::change_cwd(path));
|
stream.push_back(ReturnSuccess::change_cwd(path));
|
||||||
Ok(stream.boxed())
|
Ok(stream.into())
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut stream = VecDeque::new();
|
let mut stream = VecDeque::new();
|
||||||
match args.nth(0) {
|
match args.nth(0) {
|
||||||
None => {
|
None => {
|
||||||
stream.push_back(ReturnValue::change_cwd(PathBuf::from("/")));
|
stream.push_back(ReturnSuccess::change_cwd(PathBuf::from("/")));
|
||||||
}
|
}
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
let mut cwd = latest.path().to_path_buf();
|
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 {
|
impl ClassifiedInputStream {
|
||||||
crate fn new() -> ClassifiedInputStream {
|
crate fn new() -> ClassifiedInputStream {
|
||||||
ClassifiedInputStream {
|
ClassifiedInputStream {
|
||||||
objects: VecDeque::new().boxed(),
|
objects: VecDeque::new().into(),
|
||||||
stdin: None,
|
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 {
|
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,
|
stdin: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn from_stdout(stdout: std::fs::File) -> ClassifiedInputStream {
|
crate fn from_stdout(stdout: std::fs::File) -> ClassifiedInputStream {
|
||||||
ClassifiedInputStream {
|
ClassifiedInputStream {
|
||||||
objects: VecDeque::new().boxed(),
|
objects: VecDeque::new().into(),
|
||||||
stdin: Some(stdout),
|
stdin: Some(stdout),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,31 +128,23 @@ impl InternalCommand {
|
|||||||
context: &mut Context,
|
context: &mut Context,
|
||||||
input: ClassifiedInputStream,
|
input: ClassifiedInputStream,
|
||||||
) -> Result<InputStream, ShellError> {
|
) -> Result<InputStream, ShellError> {
|
||||||
let objects = if log_enabled!(log::Level::Trace) {
|
if log_enabled!(log::Level::Trace) {
|
||||||
trace!("->");
|
trace!("->");
|
||||||
trace!("{}", self.command.name());
|
trace!("{}", self.command.name());
|
||||||
trace!("{:?}", self.args.debug());
|
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)?;
|
context.run_command(self.command, self.name_span.clone(), self.args, objects)?;
|
||||||
|
|
||||||
|
let mut result = result.values;
|
||||||
|
|
||||||
let mut stream = VecDeque::new();
|
let mut stream = VecDeque::new();
|
||||||
while let Some(item) = result.next().await {
|
while let Some(item) = result.next().await {
|
||||||
match item {
|
match item? {
|
||||||
ReturnValue::Value(Value::Error(err)) => {
|
ReturnSuccess::Action(action) => match action {
|
||||||
return Err(*err);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue::Action(action) => match action {
|
|
||||||
CommandAction::ChangePath(path) => {
|
CommandAction::ChangePath(path) => {
|
||||||
context.env.lock().unwrap().back_mut().map(|x| {
|
context.env.lock().unwrap().back_mut().map(|x| {
|
||||||
x.path = path;
|
x.path = path;
|
||||||
@ -158,12 +168,13 @@ impl InternalCommand {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
ReturnValue::Value(v) => {
|
ReturnSuccess::Value(v) => {
|
||||||
stream.push_back(v);
|
stream.push_back(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(stream.boxed() as InputStream)
|
|
||||||
|
Ok(stream.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,9 +198,11 @@ impl ExternalCommand {
|
|||||||
input: ClassifiedInputStream,
|
input: ClassifiedInputStream,
|
||||||
stream_next: StreamNext,
|
stream_next: StreamNext,
|
||||||
) -> Result<ClassifiedInputStream, ShellError> {
|
) -> 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);
|
let mut arg_string = format!("{}", self.name);
|
||||||
for arg in &self.args {
|
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);
|
process = process.stdin(stdin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +331,9 @@ impl ExternalCommand {
|
|||||||
let file = futures::io::AllowStdIo::new(stdout);
|
let file = futures::io::AllowStdIo::new(stdout);
|
||||||
let stream = Framed::new(file, LinesCodec {});
|
let stream = Framed::new(file, LinesCodec {});
|
||||||
let stream = stream.map(|line| Value::string(line.unwrap()));
|
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::commands::command::SinkCommandArgs;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::{labelled, ShellError};
|
||||||
use clipboard::{ClipboardContext, ClipboardProvider};
|
use clipboard::{ClipboardContext, ClipboardProvider};
|
||||||
|
|
||||||
pub fn clip(args: SinkCommandArgs) -> Result<(), ShellError> {
|
pub fn clip(args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||||
let mut clip_context: ClipboardContext = ClipboardProvider::new().unwrap();
|
let mut clip_context: ClipboardContext = ClipboardProvider::new().unwrap();
|
||||||
let mut new_copy_data = String::new();
|
let mut new_copy_data = String::new();
|
||||||
|
|
||||||
if args.input.len() > 0 {
|
if args.input.len() > 0 {
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for i in args.input.iter() {
|
for i in args.input.iter() {
|
||||||
@ -13,18 +14,17 @@ pub fn clip(args: SinkCommandArgs) -> Result<(), ShellError> {
|
|||||||
} else {
|
} else {
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
match i.as_string() {
|
|
||||||
Ok(s) => new_copy_data.push_str(&s),
|
let string = i.as_string().map_err(labelled(
|
||||||
Err(_) => {
|
args.name_span,
|
||||||
return Err(ShellError::maybe_labeled_error(
|
|
||||||
"Given non-string data",
|
"Given non-string data",
|
||||||
"expected strings from pipeline",
|
"expected strings from pipeline",
|
||||||
args.name_span,
|
))?;
|
||||||
))
|
|
||||||
}
|
new_copy_data.push_str(&string);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clip_context.set_contents(new_copy_data).unwrap();
|
clip_context.set_contents(new_copy_data).unwrap();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -7,7 +7,7 @@ use crate::parser::{
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::{ops::Try, path::PathBuf};
|
||||||
|
|
||||||
#[derive(Getters)]
|
#[derive(Getters)]
|
||||||
#[get = "crate"]
|
#[get = "crate"]
|
||||||
@ -60,14 +60,26 @@ pub enum CommandAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum ReturnValue {
|
pub enum ReturnSuccess {
|
||||||
Value(Value),
|
Value(Value),
|
||||||
Action(CommandAction),
|
Action(CommandAction),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReturnValue {
|
pub type ReturnValue = Result<ReturnSuccess, ShellError>;
|
||||||
crate fn change_cwd(path: PathBuf) -> ReturnValue {
|
|
||||||
ReturnValue::Action(CommandAction::ChangePath(path))
|
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 {
|
fn config(&self) -> registry::CommandConfig {
|
||||||
registry::CommandConfig {
|
registry::CommandConfig {
|
||||||
name: self.name().to_string(),
|
name: self.name().to_string(),
|
||||||
mandatory_positional: vec![],
|
positional: vec![],
|
||||||
optional_positional: vec![],
|
|
||||||
rest_positional: true,
|
rest_positional: true,
|
||||||
named: indexmap::IndexMap::new(),
|
named: indexmap::IndexMap::new(),
|
||||||
is_filter: true,
|
is_filter: true,
|
||||||
@ -97,8 +108,7 @@ pub trait Sink {
|
|||||||
fn config(&self) -> registry::CommandConfig {
|
fn config(&self) -> registry::CommandConfig {
|
||||||
registry::CommandConfig {
|
registry::CommandConfig {
|
||||||
name: self.name().to_string(),
|
name: self.name().to_string(),
|
||||||
mandatory_positional: vec![],
|
positional: vec![],
|
||||||
optional_positional: vec![],
|
|
||||||
rest_positional: true,
|
rest_positional: true,
|
||||||
named: indexmap::IndexMap::new(),
|
named: indexmap::IndexMap::new(),
|
||||||
is_filter: false,
|
is_filter: false,
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
|
#[macro_use]
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::object::config;
|
use crate::object::config;
|
||||||
use crate::object::Value;
|
use crate::object::Value;
|
||||||
use crate::parser::registry::{CommandConfig, NamedType, NamedValue};
|
use crate::parser::registry::{CommandConfig, NamedType, NamedValue};
|
||||||
use crate::prelude::*;
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
pub struct Config;
|
pub struct Config;
|
||||||
|
|
||||||
@ -29,8 +32,7 @@ impl Command for Config {
|
|||||||
|
|
||||||
CommandConfig {
|
CommandConfig {
|
||||||
name: self.name().to_string(),
|
name: self.name().to_string(),
|
||||||
mandatory_positional: vec![],
|
positional: vec![],
|
||||||
optional_positional: vec![],
|
|
||||||
rest_positional: false,
|
rest_positional: false,
|
||||||
named,
|
named,
|
||||||
is_sink: true,
|
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)))?;
|
.ok_or_else(|| ShellError::string(&format!("Missing key {} in config", key)))?;
|
||||||
|
|
||||||
return Ok(
|
return Ok(
|
||||||
futures::stream::once(futures::future::ready(ReturnValue::Value(value.clone())))
|
vec![value.clone()].into(), // futures::stream::once(futures::future::ready(ReturnSuccess::Value(value.clone()))).into(),
|
||||||
.boxed(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,12 +66,7 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
|
|
||||||
config::write_config(&result)?;
|
config::write_config(&result)?;
|
||||||
|
|
||||||
return Ok(
|
return Ok(stream![Value::Object(result.into())].from_input_stream());
|
||||||
futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object(
|
|
||||||
result.into(),
|
|
||||||
))))
|
|
||||||
.boxed(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,12 +75,7 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
|
|
||||||
config::write_config(&result)?;
|
config::write_config(&result)?;
|
||||||
|
|
||||||
return Ok(
|
return Ok(stream![Value::Object(result.into())].from_input_stream());
|
||||||
futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object(
|
|
||||||
result.into(),
|
|
||||||
))))
|
|
||||||
.boxed(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(v) = args.get("remove") {
|
if let Some(v) = args.get("remove") {
|
||||||
@ -99,21 +90,12 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(
|
let obj = VecDeque::from_iter(vec![Value::Object(result.into())]);
|
||||||
futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object(
|
return Ok(obj.from_input_stream());
|
||||||
result.into(),
|
|
||||||
))))
|
|
||||||
.boxed(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.len() == 0 {
|
if args.len() == 0 {
|
||||||
return Ok(
|
return Ok(vec![Value::Object(result.into())].into());
|
||||||
futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object(
|
|
||||||
result.into(),
|
|
||||||
))))
|
|
||||||
.boxed(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(ShellError::string(format!("Unimplemented")))
|
Err(ShellError::string(format!("Unimplemented")))
|
||||||
|
@ -2,9 +2,31 @@ use crate::commands::command::CommandAction;
|
|||||||
use crate::commands::open::{fetch, parse_as_value};
|
use crate::commands::open::{fetch, parse_as_value};
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::object::{Primitive, Value};
|
use crate::object::{Primitive, Value};
|
||||||
|
use crate::parser::registry::{CommandConfig, PositionalType};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use std::path::PathBuf;
|
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> {
|
pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
if args.len() == 0 {
|
if args.len() == 0 {
|
||||||
return Err(ShellError::maybe_labeled_error(
|
return Err(ShellError::maybe_labeled_error(
|
||||||
@ -67,16 +89,9 @@ pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match contents {
|
stream.push_back(Ok(ReturnSuccess::Action(CommandAction::Enter(
|
||||||
Value::Primitive(Primitive::String(x)) => {
|
parse_as_value(file_extension, contents, span)?,
|
||||||
stream.push_back(ReturnValue::Action(CommandAction::Enter(parse_as_value(
|
))));
|
||||||
file_extension,
|
|
||||||
x,
|
|
||||||
span,
|
|
||||||
)?)));
|
|
||||||
}
|
|
||||||
x => stream.push_back(ReturnValue::Action(CommandAction::Enter(x))),
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(stream.boxed())
|
Ok(stream.into())
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,5 @@ use crate::errors::ShellError;
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub fn exit(_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn exit(_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let mut stream = VecDeque::new();
|
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::Exit))].into())
|
||||||
stream.push_back(ReturnValue::Action(CommandAction::Exit));
|
|
||||||
Ok(stream.boxed())
|
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,5 @@ pub fn first(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
|
|
||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
||||||
Ok(input
|
Ok(OutputStream::from_input(input.values.take(amount as u64)))
|
||||||
.take(amount as u64)
|
|
||||||
.map(|v| ReturnValue::Value(v))
|
|
||||||
.boxed())
|
|
||||||
}
|
}
|
||||||
|
@ -30,22 +30,21 @@ pub fn from_ini(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
let out = args.input;
|
let out = args.input;
|
||||||
let span = args.name_span;
|
let span = args.name_span;
|
||||||
Ok(out
|
Ok(out
|
||||||
|
.values
|
||||||
.map(move |a| match a {
|
.map(move |a| match a {
|
||||||
Value::Primitive(Primitive::String(s)) => match from_ini_string_to_value(s) {
|
Value::Primitive(Primitive::String(s)) => match from_ini_string_to_value(s) {
|
||||||
Ok(x) => ReturnValue::Value(x),
|
Ok(x) => Ok(ReturnSuccess::Value(x)),
|
||||||
Err(e) => {
|
Err(e) => Err(ShellError::maybe_labeled_error(
|
||||||
ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
|
||||||
"Could not parse as INI",
|
"Could not parse as INI",
|
||||||
format!("{:#?}", e),
|
format!("{:#?}", e),
|
||||||
span,
|
span,
|
||||||
))))
|
)),
|
||||||
}
|
|
||||||
},
|
},
|
||||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
_ => Err(ShellError::maybe_labeled_error(
|
||||||
"Expected string values from pipeline",
|
"Expected string values from pipeline",
|
||||||
"expects strings from pipeline",
|
"expects strings from pipeline",
|
||||||
span,
|
span,
|
||||||
)))),
|
)),
|
||||||
})
|
})
|
||||||
.boxed())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
@ -34,22 +34,21 @@ pub fn from_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
let out = args.input;
|
let out = args.input;
|
||||||
let span = args.name_span;
|
let span = args.name_span;
|
||||||
Ok(out
|
Ok(out
|
||||||
|
.values
|
||||||
.map(move |a| match a {
|
.map(move |a| match a {
|
||||||
Value::Primitive(Primitive::String(s)) => match from_json_string_to_value(s) {
|
Value::Primitive(Primitive::String(s)) => match from_json_string_to_value(s) {
|
||||||
Ok(x) => ReturnValue::Value(x),
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
Err(_) => {
|
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||||
ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
|
||||||
"Could not parse as JSON",
|
"Could not parse as JSON",
|
||||||
"piped data failed JSON parse",
|
"piped data failed JSON parse",
|
||||||
span,
|
span,
|
||||||
))))
|
)),
|
||||||
}
|
|
||||||
},
|
},
|
||||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
_ => Err(ShellError::maybe_labeled_error(
|
||||||
"Expected string values from pipeline",
|
"Expected string values from pipeline",
|
||||||
"expects strings from pipeline",
|
"expects strings from pipeline",
|
||||||
span,
|
span,
|
||||||
)))),
|
)),
|
||||||
})
|
})
|
||||||
.boxed())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
@ -33,22 +33,21 @@ pub fn from_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
let out = args.input;
|
let out = args.input;
|
||||||
let span = args.name_span;
|
let span = args.name_span;
|
||||||
Ok(out
|
Ok(out
|
||||||
|
.values
|
||||||
.map(move |a| match a {
|
.map(move |a| match a {
|
||||||
Value::Primitive(Primitive::String(s)) => match from_toml_string_to_value(s) {
|
Value::Primitive(Primitive::String(s)) => match from_toml_string_to_value(s) {
|
||||||
Ok(x) => ReturnValue::Value(x),
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
Err(_) => {
|
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||||
ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
|
||||||
"Could not parse as TOML",
|
"Could not parse as TOML",
|
||||||
"piped data failed TOML parse",
|
"piped data failed TOML parse",
|
||||||
span,
|
span,
|
||||||
))))
|
)),
|
||||||
}
|
|
||||||
},
|
},
|
||||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
_ => Err(ShellError::maybe_labeled_error(
|
||||||
"Expected string values from pipeline",
|
"Expected string values from pipeline",
|
||||||
"expects strings from pipeline",
|
"expects strings from pipeline",
|
||||||
span,
|
span,
|
||||||
)))),
|
)),
|
||||||
})
|
})
|
||||||
.boxed())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
@ -52,22 +52,21 @@ pub fn from_xml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
let out = args.input;
|
let out = args.input;
|
||||||
let span = args.name_span;
|
let span = args.name_span;
|
||||||
Ok(out
|
Ok(out
|
||||||
|
.values
|
||||||
.map(move |a| match a {
|
.map(move |a| match a {
|
||||||
Value::Primitive(Primitive::String(s)) => match from_xml_string_to_value(s) {
|
Value::Primitive(Primitive::String(s)) => match from_xml_string_to_value(s) {
|
||||||
Ok(x) => ReturnValue::Value(x),
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
Err(_) => {
|
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||||
ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
|
||||||
"Could not parse as XML",
|
"Could not parse as XML",
|
||||||
"piped data failed XML parse",
|
"piped data failed XML parse",
|
||||||
span,
|
span,
|
||||||
))))
|
)),
|
||||||
}
|
|
||||||
},
|
},
|
||||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
_ => Err(ShellError::maybe_labeled_error(
|
||||||
"Expected string values from pipeline",
|
"Expected string values from pipeline",
|
||||||
"expects strings from pipeline",
|
"expects strings from pipeline",
|
||||||
span,
|
span,
|
||||||
)))),
|
)),
|
||||||
})
|
})
|
||||||
.boxed())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
@ -43,22 +43,21 @@ pub fn from_yaml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
let out = args.input;
|
let out = args.input;
|
||||||
let span = args.name_span;
|
let span = args.name_span;
|
||||||
Ok(out
|
Ok(out
|
||||||
|
.values
|
||||||
.map(move |a| match a {
|
.map(move |a| match a {
|
||||||
Value::Primitive(Primitive::String(s)) => match from_yaml_string_to_value(s) {
|
Value::Primitive(Primitive::String(s)) => match from_yaml_string_to_value(s) {
|
||||||
Ok(x) => ReturnValue::Value(x),
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
Err(_) => {
|
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||||
ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
|
||||||
"Could not parse as YAML",
|
"Could not parse as YAML",
|
||||||
"piped data failed YAML parse",
|
"piped data failed YAML parse",
|
||||||
span,
|
span,
|
||||||
))))
|
)),
|
||||||
}
|
|
||||||
},
|
},
|
||||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
_ => Err(ShellError::maybe_labeled_error(
|
||||||
"Expected string values from pipeline",
|
"Expected string values from pipeline",
|
||||||
"expects strings from pipeline",
|
"expects strings from pipeline",
|
||||||
span,
|
span,
|
||||||
)))),
|
)),
|
||||||
})
|
})
|
||||||
.boxed())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
@ -3,22 +3,22 @@ use crate::object::Value;
|
|||||||
use crate::parser::Span;
|
use crate::parser::Span;
|
||||||
use crate::prelude::*;
|
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;
|
let mut current = obj;
|
||||||
for p in path.split(".") {
|
for p in path.split(".") {
|
||||||
match current.get_data_by_key(p) {
|
match current.get_data_by_key(p) {
|
||||||
Some(v) => current = v,
|
Some(v) => current = v,
|
||||||
None => {
|
None => {
|
||||||
return Some(Value::Error(Box::new(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Unknown field",
|
"Unknown field",
|
||||||
"object missing field",
|
"object missing field",
|
||||||
span,
|
span,
|
||||||
))));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(current.copy())
|
Ok(current.copy())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
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 {
|
if let Ok(amount) = amount {
|
||||||
return Ok(args
|
return Ok(args
|
||||||
.input
|
.input
|
||||||
|
.values
|
||||||
.skip(amount as u64)
|
.skip(amount as u64)
|
||||||
.take(1)
|
.take(1)
|
||||||
.map(|v| ReturnValue::Value(v))
|
.from_input_stream());
|
||||||
.boxed());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let fields: Result<Vec<(String, Span)>, _> = args
|
let fields: Result<Vec<(String, Span)>, _> = args
|
||||||
@ -51,17 +51,18 @@ pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
|
|
||||||
let stream = args
|
let stream = args
|
||||||
.input
|
.input
|
||||||
|
.values
|
||||||
.map(move |item| {
|
.map(move |item| {
|
||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
for field in &fields {
|
for field in &fields {
|
||||||
match get_member(&field.0, field.1, &item) {
|
match get_member(&field.0, field.1, &item) {
|
||||||
Some(Value::List(l)) => {
|
Ok(Value::List(l)) => {
|
||||||
for item in 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())),
|
Ok(x) => result.push_back(ReturnSuccess::value(x.copy())),
|
||||||
None => {}
|
Err(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,5 +70,5 @@ pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
})
|
})
|
||||||
.flatten();
|
.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 span = args.name_span;
|
||||||
|
|
||||||
let stream = input
|
let stream = input
|
||||||
|
.values
|
||||||
.map(move |v| match v {
|
.map(move |v| match v {
|
||||||
Value::Primitive(Primitive::String(s)) => {
|
Value::Primitive(Primitive::String(s)) => {
|
||||||
let split_result: Vec<_> = s.lines().filter(|s| s.trim() != "").collect();
|
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();
|
let mut result = VecDeque::new();
|
||||||
for s in split_result {
|
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(),
|
s.into(),
|
||||||
))));
|
))));
|
||||||
}
|
}
|
||||||
@ -26,17 +27,15 @@ pub fn lines(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
result.push_back(ReturnValue::Value(Value::Error(Box::new(
|
result.push_back(Err(ShellError::maybe_labeled_error(
|
||||||
ShellError::maybe_labeled_error(
|
|
||||||
"Expected string values from pipeline",
|
"Expected string values from pipeline",
|
||||||
"expects strings from pipeline",
|
"expects strings from pipeline",
|
||||||
span,
|
span,
|
||||||
),
|
)));
|
||||||
))));
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.flatten();
|
.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 {
|
for entry in entries {
|
||||||
let value = Value::Object(dir_entry_dict(&entry?)?);
|
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();
|
let mut entries = VecDeque::new();
|
||||||
@ -97,7 +97,11 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
return Err(ShellError::maybe_labeled_error(
|
return Err(ShellError::maybe_labeled_error(
|
||||||
"Index not closed",
|
"Index not closed",
|
||||||
format!("path missing closing ']'"),
|
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 {
|
match viewed {
|
||||||
Value::List(l) => {
|
Value::List(l) => {
|
||||||
for item in l {
|
for item in l {
|
||||||
entries.push_back(ReturnValue::Value(item.copy()));
|
entries.push_back(ReturnSuccess::value(item.copy()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
x => {
|
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::errors::ShellError;
|
||||||
use crate::object::{Primitive, Value};
|
use crate::object::{Primitive, Switch, Value};
|
||||||
use crate::parser::parse::span::Span;
|
use crate::parser::parse::span::Span;
|
||||||
use crate::parser::registry::{CommandConfig, NamedType};
|
use crate::parser::registry::NamedType;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use indexmap::IndexMap;
|
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
pub struct Open;
|
command! {
|
||||||
|
Open as open(args, --raw: Switch) {
|
||||||
|
let span = args.name_span;
|
||||||
|
|
||||||
impl Command for Open {
|
let cwd = args
|
||||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
.env
|
||||||
open(args)
|
.lock()
|
||||||
}
|
.unwrap()
|
||||||
fn name(&self) -> &str {
|
.front()
|
||||||
"open"
|
.unwrap()
|
||||||
}
|
.path()
|
||||||
|
.to_path_buf();
|
||||||
|
|
||||||
fn config(&self) -> CommandConfig {
|
let full_path = PathBuf::from(cwd);
|
||||||
let mut named: IndexMap<String, NamedType> = IndexMap::new();
|
|
||||||
named.insert("raw".to_string(), NamedType::Switch);
|
|
||||||
|
|
||||||
CommandConfig {
|
let (file_extension, contents) = match &args.expect_nth(0)?.item {
|
||||||
name: self.name().to_string(),
|
Value::Primitive(Primitive::String(s)) => fetch(&full_path, s, args.expect_nth(0)?.span)?,
|
||||||
mandatory_positional: vec![],
|
_ => {
|
||||||
optional_positional: vec![],
|
return Err(ShellError::labeled_error(
|
||||||
rest_positional: false,
|
"Expected string value for filename",
|
||||||
named,
|
"expected filename",
|
||||||
is_filter: true,
|
args.expect_nth(0)?.span,
|
||||||
is_sink: false,
|
));
|
||||||
can_load: vec![],
|
|
||||||
can_save: vec![],
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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,
|
cwd: &PathBuf,
|
||||||
location: &str,
|
location: &str,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Result<(Option<String>, Value), ShellError> {
|
) -> Result<(Option<String>, String), ShellError> {
|
||||||
let mut cwd = cwd.clone();
|
let mut cwd = cwd.clone();
|
||||||
if location.starts_with("http:") || location.starts_with("https:") {
|
if location.starts_with("http:") || location.starts_with("https:") {
|
||||||
let response = reqwest::get(location);
|
let response = reqwest::get(location);
|
||||||
@ -168,74 +204,3 @@ pub fn parse_as_value(
|
|||||||
_ => Ok(Value::string(contents)),
|
_ => 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
|
let objects = args
|
||||||
.input
|
.input
|
||||||
.map(move |item| Value::Object(select_fields(&item, &fields)))
|
.values
|
||||||
.map(|item| ReturnValue::Value(item));
|
.map(move |item| Value::Object(select_fields(&item, &fields)));
|
||||||
|
|
||||||
let stream = Pin::new(Box::new(objects));
|
Ok(objects.from_input_stream())
|
||||||
Ok(stream)
|
|
||||||
}
|
}
|
||||||
|
@ -93,11 +93,9 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
|||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
result.push_back(ReturnValue::Value(Value::Error(Box::new(
|
result.push_back(Err(ShellError::string(format!(
|
||||||
ShellError::string(format!(
|
|
||||||
"Error while processing input: {:?} {}",
|
"Error while processing input: {:?} {}",
|
||||||
e, input
|
e, input
|
||||||
)),
|
|
||||||
))));
|
))));
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -105,8 +103,9 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
|||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
result.push_back(ReturnValue::Value(Value::Error(Box::new(
|
result.push_back(Err(ShellError::string(format!(
|
||||||
ShellError::string(format!("Error while processing input: {:?}", e)),
|
"Error while processing input: {:?}",
|
||||||
|
e
|
||||||
))));
|
))));
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -115,7 +114,7 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
|||||||
})
|
})
|
||||||
.flatten();
|
.flatten();
|
||||||
|
|
||||||
Ok(stream.boxed())
|
Ok(stream.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sink_plugin(path: String, args: SinkCommandArgs) -> Result<(), ShellError> {
|
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
|
let list = list
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(_, process)| ReturnValue::Value(Value::Object(process_dict(process))))
|
.map(|(_, process)| Value::Object(process_dict(process)))
|
||||||
.collect::<VecDeque<_>>();
|
.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
|
let stream = args
|
||||||
.input
|
.input
|
||||||
.map(move |item| Value::Object(reject_fields(&item, &fields)))
|
.values
|
||||||
.map(|item| ReturnValue::Value(item));
|
.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();
|
contents.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(list.boxed())
|
Ok(list.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count(name: &str, contents: &str) -> ReturnValue {
|
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("chars", Value::int(chars));
|
||||||
dict.add("max length", Value::int(bytes));
|
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 {
|
fn config(&self) -> CommandConfig {
|
||||||
CommandConfig {
|
CommandConfig {
|
||||||
name: self.name().to_string(),
|
name: self.name().to_string(),
|
||||||
mandatory_positional: vec![PositionalType::Block("condition".to_string())],
|
positional: vec![PositionalType::mandatory("condition", "Block")],
|
||||||
optional_positional: vec![],
|
|
||||||
rest_positional: false,
|
rest_positional: false,
|
||||||
named: indexmap::IndexMap::new(),
|
named: indexmap::IndexMap::new(),
|
||||||
is_filter: true,
|
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 block = args.nth(0).unwrap().as_block()?;
|
||||||
let input = args.input;
|
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 result = block.invoke(&item);
|
||||||
|
|
||||||
let return_value = match result {
|
let return_value = match result {
|
||||||
@ -51,5 +50,5 @@ pub fn skip_while(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
futures::future::ready(return_value)
|
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: Result<Vec<_>, _> = args.positional_iter().map(|a| a.as_string()).collect();
|
||||||
let fields = fields?;
|
let fields = fields?;
|
||||||
|
|
||||||
let output = args.input.collect::<Vec<_>>();
|
let output = args.input.values.collect::<Vec<_>>();
|
||||||
|
|
||||||
let output = output.map(move |mut vec| {
|
let output = output.map(move |mut vec| {
|
||||||
vec.sort_by_key(|item| {
|
vec.sort_by_key(|item| {
|
||||||
@ -15,11 +15,8 @@ pub fn sort_by(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
.collect::<Vec<Option<Value>>>()
|
.collect::<Vec<Option<Value>>>()
|
||||||
});
|
});
|
||||||
|
|
||||||
vec.into_iter()
|
vec.into_iter().collect::<VecDeque<_>>()
|
||||||
.map(|v| ReturnValue::Value(v.copy()))
|
|
||||||
.collect::<VecDeque<_>>()
|
|
||||||
.boxed()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(output.flatten_stream().boxed())
|
Ok(output.flatten_stream().from_input_stream())
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
|
.values
|
||||||
.map(move |v| match v {
|
.map(move |v| match v {
|
||||||
Value::Primitive(Primitive::String(s)) => {
|
Value::Primitive(Primitive::String(s)) => {
|
||||||
let splitter = positional[0].as_string().unwrap().replace("\\n", "\n");
|
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()) {
|
for (&k, v) in split_result.iter().zip(gen_columns.iter()) {
|
||||||
dict.add(v.clone(), Value::Primitive(Primitive::String(k.into())));
|
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) {
|
} else if split_result.len() == (positional.len() - 1) {
|
||||||
let mut dict = crate::object::Dictionary::default();
|
let mut dict = crate::object::Dictionary::default();
|
||||||
for (&k, v) in split_result.iter().zip(positional.iter().skip(1)) {
|
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())),
|
Value::Primitive(Primitive::String(k.into())),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ReturnValue::Value(Value::Object(dict))
|
ReturnSuccess::value(Value::Object(dict))
|
||||||
} else {
|
} else {
|
||||||
let mut dict = crate::object::Dictionary::default();
|
let mut dict = crate::object::Dictionary::default();
|
||||||
for k in positional.iter().skip(1) {
|
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())),
|
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",
|
"Expected string values from pipeline",
|
||||||
"expects strings from pipeline",
|
"expects strings from pipeline",
|
||||||
span,
|
span,
|
||||||
)))),
|
)),
|
||||||
})
|
})
|
||||||
.boxed())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ pub fn split_row(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
||||||
let stream = input
|
let stream = input
|
||||||
|
.values
|
||||||
.map(move |v| match v {
|
.map(move |v| match v {
|
||||||
Value::Primitive(Primitive::String(s)) => {
|
Value::Primitive(Primitive::String(s)) => {
|
||||||
let splitter = positional[0].as_string().unwrap().replace("\\n", "\n");
|
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();
|
let mut result = VecDeque::new();
|
||||||
for s in split_result {
|
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(),
|
s.into(),
|
||||||
))));
|
))));
|
||||||
}
|
}
|
||||||
@ -39,17 +40,15 @@ pub fn split_row(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
result.push_back(ReturnValue::Value(Value::Error(Box::new(
|
result.push_back(Err(ShellError::maybe_labeled_error(
|
||||||
ShellError::maybe_labeled_error(
|
|
||||||
"Expected string values from pipeline",
|
"Expected string values from pipeline",
|
||||||
"expects strings from pipeline",
|
"expects strings from pipeline",
|
||||||
span,
|
span,
|
||||||
),
|
)));
|
||||||
))));
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.flatten();
|
.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());
|
// println!("{:#?}", system.get_network());
|
||||||
|
|
||||||
let mut stream = VecDeque::new();
|
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::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub fn to_array(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn to_array(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let out = args.input.collect();
|
let out = args.input.values.collect();
|
||||||
|
|
||||||
Ok(out
|
Ok(out
|
||||||
.map(|vec: Vec<_>| single_output(Value::List(vec)))
|
.map(|vec: Vec<_>| stream![Value::List(vec)])
|
||||||
.flatten_stream()
|
.flatten_stream()
|
||||||
.boxed())
|
.from_input_stream())
|
||||||
}
|
}
|
||||||
|
@ -47,14 +47,12 @@ pub fn to_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
Ok(out
|
Ok(out
|
||||||
.map(
|
.map(
|
||||||
move |a| match serde_json::to_string(&value_to_json_value(&a)) {
|
move |a| match serde_json::to_string(&value_to_json_value(&a)) {
|
||||||
Ok(x) => ReturnValue::Value(Value::Primitive(Primitive::String(x))),
|
Ok(x) => Ok(ReturnValue::Value(Value::Primitive(Primitive::String(x)))),
|
||||||
Err(_) => {
|
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||||
ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
|
||||||
"Can not convert to JSON string",
|
"Can not convert to JSON string",
|
||||||
"can not convert piped data to JSON string",
|
"can not convert piped data to JSON string",
|
||||||
span,
|
span,
|
||||||
))))
|
)),
|
||||||
}
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.boxed())
|
.boxed())
|
||||||
|
@ -35,13 +35,14 @@ pub fn to_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
let out = args.input;
|
let out = args.input;
|
||||||
let span = args.name_span;
|
let span = args.name_span;
|
||||||
Ok(out
|
Ok(out
|
||||||
.map(move |a| match toml::to_string(&value_to_toml_value(&a)) {
|
.values
|
||||||
Ok(x) => ReturnValue::Value(Value::Primitive(Primitive::String(x))),
|
.map(move |a| match toml::to_string(&a) {
|
||||||
Err(_) => ReturnValue::Value(Value::Error(Box::new(ShellError::maybe_labeled_error(
|
Ok(x) => ReturnSuccess::value(Value::Primitive(Primitive::String(x))),
|
||||||
|
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||||
"Can not convert to TOML string",
|
"Can not convert to TOML string",
|
||||||
"can not convert piped data to TOML string",
|
"can not convert piped data to TOML string",
|
||||||
span,
|
span,
|
||||||
)))),
|
)),
|
||||||
})
|
})
|
||||||
.boxed())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
@ -9,15 +9,16 @@ pub fn trim(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
let span = args.name_span;
|
let span = args.name_span;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
|
.values
|
||||||
.map(move |v| match v {
|
.map(move |v| match v {
|
||||||
Value::Primitive(Primitive::String(s)) => {
|
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",
|
"Expected string values from pipeline",
|
||||||
"expects strings from pipeline",
|
"expects strings from pipeline",
|
||||||
span,
|
span,
|
||||||
)))),
|
)),
|
||||||
})
|
})
|
||||||
.boxed())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
@ -46,5 +46,5 @@ pub fn view(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
|
|
||||||
let _ = printer.file(file.display().to_string());
|
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::errors::ShellError;
|
||||||
use crate::parser::registry::{CommandConfig, PositionalType};
|
use crate::object::Block;
|
||||||
use crate::prelude::*;
|
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 {
|
input.values.filter_map(move |item| {
|
||||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
let result = condition.invoke(&item);
|
||||||
r#where(args)
|
|
||||||
}
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"where"
|
|
||||||
}
|
|
||||||
|
|
||||||
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![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
let return_value = match result {
|
||||||
Err(err) => Some(ReturnValue::Value(Value::Error(Box::new(err)))),
|
Err(err) => Some(Err(err)),
|
||||||
Ok(v) if v.is_true() => Some(ReturnValue::Value(item.copy())),
|
Ok(v) if v.is_true() => Some(Ok(ReturnSuccess::Value(item.copy()))),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
futures::future::ready(return_value)
|
ready(return_value)
|
||||||
});
|
})
|
||||||
|
}
|
||||||
Ok(objects.boxed())
|
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,16 @@ pub enum ArgumentError {
|
|||||||
MissingValueForName(String),
|
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)]
|
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)]
|
||||||
pub enum ShellError {
|
pub enum ShellError {
|
||||||
String(StringError),
|
String(StringError),
|
||||||
@ -53,6 +63,7 @@ pub enum ShellError {
|
|||||||
expr: Description,
|
expr: Description,
|
||||||
},
|
},
|
||||||
ArgumentError {
|
ArgumentError {
|
||||||
|
command: String,
|
||||||
error: ArgumentError,
|
error: ArgumentError,
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
@ -119,28 +130,38 @@ impl ShellError {
|
|||||||
ShellError::String(StringError { title, .. }) => {
|
ShellError::String(StringError { title, .. }) => {
|
||||||
Diagnostic::new(Severity::Error, title)
|
Diagnostic::new(Severity::Error, title)
|
||||||
}
|
}
|
||||||
ShellError::ArgumentError { error, span } => match error {
|
ShellError::ArgumentError {
|
||||||
|
command,
|
||||||
|
error,
|
||||||
|
span,
|
||||||
|
} => match error {
|
||||||
ArgumentError::MissingMandatoryFlag(name) => Diagnostic::new(
|
ArgumentError::MissingMandatoryFlag(name) => Diagnostic::new(
|
||||||
Severity::Error,
|
Severity::Error,
|
||||||
format!(
|
format!(
|
||||||
"Command requires {}{}",
|
"{} requires {}{}",
|
||||||
Color::Cyan.paint("--"),
|
Color::Cyan.paint(command),
|
||||||
Color::Cyan.paint(name)
|
Color::Black.bold().paint("--"),
|
||||||
|
Color::Black.bold().paint(name)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.with_label(Label::new_primary(span)),
|
.with_label(Label::new_primary(span)),
|
||||||
ArgumentError::MissingMandatoryPositional(name) => Diagnostic::new(
|
ArgumentError::MissingMandatoryPositional(name) => Diagnostic::new(
|
||||||
Severity::Error,
|
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)),
|
.with_label(Label::new_primary(span)),
|
||||||
|
|
||||||
ArgumentError::MissingValueForName(name) => Diagnostic::new(
|
ArgumentError::MissingValueForName(name) => Diagnostic::new(
|
||||||
Severity::Error,
|
Severity::Error,
|
||||||
format!(
|
format!(
|
||||||
"Missing value for flag {}{}",
|
"{} is missing value for flag {}{}",
|
||||||
Color::Cyan.paint("--"),
|
Color::Cyan.paint(command),
|
||||||
Color::Cyan.paint(name)
|
Color::Black.bold().paint("--"),
|
||||||
|
Color::Black.bold().paint(name)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.with_label(Label::new_primary(span)),
|
.with_label(Label::new_primary(span)),
|
||||||
|
@ -31,7 +31,6 @@ impl TreeView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::Block(_) => {}
|
Value::Block(_) => {}
|
||||||
Value::Error(_) => {}
|
|
||||||
Value::Filesystem => {}
|
Value::Filesystem => {}
|
||||||
Value::Binary(_) => {}
|
Value::Binary(_) => {}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,10 @@
|
|||||||
#![feature(try_trait)]
|
#![feature(try_trait)]
|
||||||
#![feature(bind_by_move_pattern_guards)]
|
#![feature(bind_by_move_pattern_guards)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
|
#![feature(type_ascription)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod prelude;
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
mod commands;
|
mod commands;
|
||||||
@ -16,11 +20,10 @@ mod git;
|
|||||||
mod object;
|
mod object;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod plugin;
|
mod plugin;
|
||||||
mod prelude;
|
|
||||||
mod shell;
|
mod shell;
|
||||||
mod stream;
|
mod stream;
|
||||||
|
|
||||||
pub use crate::commands::command::ReturnValue;
|
pub use crate::commands::command::{ReturnSuccess, ReturnValue};
|
||||||
pub use crate::env::host::BasicHost;
|
pub use crate::env::host::BasicHost;
|
||||||
pub use crate::parser::parse::span::SpannedItem;
|
pub use crate::parser::parse::span::SpannedItem;
|
||||||
pub use crate::parser::Spanned;
|
pub use crate::parser::Spanned;
|
||||||
|
@ -185,9 +185,6 @@ pub enum Value {
|
|||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
Block(Block),
|
Block(Block),
|
||||||
Filesystem,
|
Filesystem,
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
Error(Box<ShellError>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_list(values: &'a Vec<Value>) -> ValuesDebug<'a> {
|
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::Object(o) => o.debug(f),
|
||||||
Value::List(l) => debug_list(l).fmt(f),
|
Value::List(l) => debug_list(l).fmt(f),
|
||||||
Value::Block(_) => write!(f, "[[block]]"),
|
Value::Block(_) => write!(f, "[[block]]"),
|
||||||
Value::Error(err) => write!(f, "[[error :: {} ]]", err),
|
|
||||||
Value::Filesystem => write!(f, "[[filesystem]]"),
|
Value::Filesystem => write!(f, "[[filesystem]]"),
|
||||||
Value::Binary(_) => write!(f, "[[binary]]"),
|
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 {
|
impl Value {
|
||||||
crate fn type_name(&self) -> String {
|
crate fn type_name(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
@ -238,7 +293,6 @@ impl Value {
|
|||||||
Value::Object(_) => format!("object"),
|
Value::Object(_) => format!("object"),
|
||||||
Value::List(_) => format!("list"),
|
Value::List(_) => format!("list"),
|
||||||
Value::Block(_) => format!("block"),
|
Value::Block(_) => format!("block"),
|
||||||
Value::Error(_) => format!("error"),
|
|
||||||
Value::Filesystem => format!("filesystem"),
|
Value::Filesystem => format!("filesystem"),
|
||||||
Value::Binary(_) => format!("binary"),
|
Value::Binary(_) => format!("binary"),
|
||||||
}
|
}
|
||||||
@ -312,7 +366,6 @@ impl Value {
|
|||||||
let list = l.iter().map(|i| i.copy()).collect();
|
let list = l.iter().map(|i| i.copy()).collect();
|
||||||
Value::List(list)
|
Value::List(list)
|
||||||
}
|
}
|
||||||
Value::Error(e) => Value::Error(Box::new(e.copy_error())),
|
|
||||||
Value::Filesystem => Value::Filesystem,
|
Value::Filesystem => Value::Filesystem,
|
||||||
Value::Binary(b) => Value::Binary(b.clone()),
|
Value::Binary(b) => Value::Binary(b.clone()),
|
||||||
}
|
}
|
||||||
@ -329,7 +382,6 @@ impl Value {
|
|||||||
),
|
),
|
||||||
Value::Object(_) => format!("[object Object]"),
|
Value::Object(_) => format!("[object Object]"),
|
||||||
Value::List(_) => format!("[list List]"),
|
Value::List(_) => format!("[list List]"),
|
||||||
Value::Error(e) => format!("{}", e),
|
|
||||||
Value::Filesystem => format!("<filesystem>"),
|
Value::Filesystem => format!("<filesystem>"),
|
||||||
Value::Binary(_) => format!("<binary>"),
|
Value::Binary(_) => format!("<binary>"),
|
||||||
}
|
}
|
||||||
@ -459,14 +511,6 @@ impl Value {
|
|||||||
Ok(Value::Primitive(Primitive::Date(date)))
|
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 {
|
pub fn nothing() -> Value {
|
||||||
Value::Primitive(Primitive::Nothing)
|
Value::Primitive(Primitive::Nothing)
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ impl language_reporting::ReportingFiles for Files {
|
|||||||
0
|
0
|
||||||
}
|
}
|
||||||
fn file_name(&self, _file: Self::FileId) -> FileName {
|
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> {
|
fn byte_index(&self, _file: Self::FileId, _line: usize, _column: usize) -> Option<usize> {
|
||||||
unimplemented!("byte_index")
|
unimplemented!("byte_index")
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::errors::{ArgumentError, ShellError};
|
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::{baseline_parse_tokens, CallNode, Span, Spanned};
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
hir::{self, NamedArguments},
|
hir::{self, NamedArguments},
|
||||||
@ -86,14 +86,15 @@ fn parse_command_tail(
|
|||||||
|
|
||||||
named.insert_switch(name, flag);
|
named.insert_switch(name, flag);
|
||||||
}
|
}
|
||||||
NamedType::Mandatory(kind) => match extract_mandatory(name, tail, source, command_span)
|
NamedType::Mandatory(kind) => {
|
||||||
{
|
match extract_mandatory(config, name, tail, source, command_span) {
|
||||||
Err(err) => return Err(err), // produce a correct diagnostic
|
Err(err) => return Err(err), // produce a correct diagnostic
|
||||||
Ok((pos, flag)) => {
|
Ok((pos, flag)) => {
|
||||||
tail.move_to(pos);
|
tail.move_to(pos);
|
||||||
|
|
||||||
if tail.at_end() {
|
if tail.at_end() {
|
||||||
return Err(ShellError::ArgumentError {
|
return Err(ShellError::ArgumentError {
|
||||||
|
command: config.name().clone(),
|
||||||
error: ArgumentError::MissingValueForName(name.to_string()),
|
error: ArgumentError::MissingValueForName(name.to_string()),
|
||||||
span: flag.span,
|
span: flag.span,
|
||||||
});
|
});
|
||||||
@ -109,7 +110,8 @@ fn parse_command_tail(
|
|||||||
tail.restart();
|
tail.restart();
|
||||||
named.insert_mandatory(name, expr);
|
named.insert_mandatory(name, expr);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
NamedType::Optional(kind) => match extract_optional(name, tail, source) {
|
NamedType::Optional(kind) => match extract_optional(name, tail, source) {
|
||||||
Err(err) => return Err(err), // produce a correct diagnostic
|
Err(err) => return Err(err), // produce a correct diagnostic
|
||||||
Ok(Some((pos, flag))) => {
|
Ok(Some((pos, flag))) => {
|
||||||
@ -117,6 +119,7 @@ fn parse_command_tail(
|
|||||||
|
|
||||||
if tail.at_end() {
|
if tail.at_end() {
|
||||||
return Err(ShellError::ArgumentError {
|
return Err(ShellError::ArgumentError {
|
||||||
|
command: config.name().clone(),
|
||||||
error: ArgumentError::MissingValueForName(name.to_string()),
|
error: ArgumentError::MissingValueForName(name.to_string()),
|
||||||
span: flag.span,
|
span: flag.span,
|
||||||
});
|
});
|
||||||
@ -144,38 +147,34 @@ fn parse_command_tail(
|
|||||||
trace_remaining("after named", tail.clone(), source);
|
trace_remaining("after named", tail.clone(), source);
|
||||||
|
|
||||||
let mut positional = vec![];
|
let mut positional = vec![];
|
||||||
let mandatory = config.mandatory_positional();
|
|
||||||
|
|
||||||
for arg in mandatory {
|
for arg in config.positional() {
|
||||||
trace!("Processing mandatory {:?}", arg);
|
trace!("Processing positional {:?}", arg);
|
||||||
|
|
||||||
|
match arg {
|
||||||
|
PositionalType::Mandatory(..) => {
|
||||||
if tail.len() == 0 {
|
if tail.len() == 0 {
|
||||||
return Err(ShellError::ArgumentError {
|
return Err(ShellError::ArgumentError {
|
||||||
|
command: config.name().clone(),
|
||||||
error: ArgumentError::MissingMandatoryPositional(arg.name().to_string()),
|
error: ArgumentError::MissingMandatoryPositional(arg.name().to_string()),
|
||||||
span: command_span,
|
span: command_span,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = hir::baseline_parse_next_expr(tail, registry, source, arg.to_coerce_hint())?;
|
|
||||||
|
|
||||||
positional.push(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trace_remaining("after mandatory", tail.clone(), source);
|
PositionalType::Optional(..) => {
|
||||||
|
|
||||||
let optional = config.optional_positional();
|
|
||||||
|
|
||||||
for arg in optional {
|
|
||||||
if tail.len() == 0 {
|
if tail.len() == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let result = hir::baseline_parse_next_expr(tail, registry, source, arg.to_coerce_hint())?;
|
let result = hir::baseline_parse_next_expr(tail, registry, source, arg.to_coerce_hint())?;
|
||||||
|
|
||||||
positional.push(result);
|
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
|
// TODO: Only do this if rest params are specified
|
||||||
let remainder = baseline_parse_tokens(tail, registry, source)?;
|
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(
|
fn extract_mandatory(
|
||||||
|
config: &CommandConfig,
|
||||||
name: &str,
|
name: &str,
|
||||||
tokens: &mut hir::TokensIterator<'a>,
|
tokens: &mut hir::TokensIterator<'a>,
|
||||||
source: &Text,
|
source: &Text,
|
||||||
@ -216,6 +216,7 @@ fn extract_mandatory(
|
|||||||
|
|
||||||
match flag {
|
match flag {
|
||||||
None => Err(ShellError::ArgumentError {
|
None => Err(ShellError::ArgumentError {
|
||||||
|
command: config.name().clone(),
|
||||||
error: ArgumentError::MissingMandatoryFlag(name.to_string()),
|
error: ArgumentError::MissingMandatoryFlag(name.to_string()),
|
||||||
span,
|
span,
|
||||||
}),
|
}),
|
||||||
|
@ -36,22 +36,38 @@ impl NamedValue {
|
|||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum PositionalType {
|
pub enum PositionalType {
|
||||||
Value(String),
|
Mandatory(String, PositionalValue),
|
||||||
Block(String),
|
Optional(String, PositionalValue),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum PositionalValue {
|
||||||
|
Value,
|
||||||
|
Block,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PositionalType {
|
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> {
|
crate fn to_coerce_hint(&self) -> Option<ExpressionKindHint> {
|
||||||
match self {
|
match self {
|
||||||
PositionalType::Value(_) => None,
|
PositionalType::Mandatory(_, PositionalValue::Block)
|
||||||
PositionalType::Block(_) => Some(ExpressionKindHint::Block),
|
| PositionalType::Optional(_, PositionalValue::Block) => {
|
||||||
|
Some(ExpressionKindHint::Block)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn name(&self) -> &str {
|
crate fn name(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
PositionalType::Value(s) => s,
|
PositionalType::Mandatory(s, _) => s,
|
||||||
PositionalType::Block(s) => s,
|
PositionalType::Optional(s, _) => s,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,8 +76,7 @@ impl PositionalType {
|
|||||||
#[get = "crate"]
|
#[get = "crate"]
|
||||||
pub struct CommandConfig {
|
pub struct CommandConfig {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub mandatory_positional: Vec<PositionalType>,
|
crate positional: Vec<PositionalType>,
|
||||||
pub optional_positional: Vec<PositionalType>,
|
|
||||||
pub rest_positional: bool,
|
pub rest_positional: bool,
|
||||||
pub named: IndexMap<String, NamedType>,
|
pub named: IndexMap<String, NamedType>,
|
||||||
pub is_filter: bool,
|
pub is_filter: bool,
|
||||||
|
@ -3,6 +3,9 @@ use nu::{
|
|||||||
serve_plugin, Args, CommandConfig, Plugin, PositionalType, Primitive, ReturnValue, ShellError,
|
serve_plugin, Args, CommandConfig, Plugin, PositionalType, Primitive, ReturnValue, ShellError,
|
||||||
Spanned, Value,
|
Spanned, Value,
|
||||||
};
|
};
|
||||||
|
use nu::{Primitive, ReturnSuccess, ReturnValue, ShellError, Spanned, Value};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::io;
|
||||||
|
|
||||||
struct Inc {
|
struct Inc {
|
||||||
inc_by: i64,
|
inc_by: i64,
|
||||||
@ -13,42 +16,75 @@ impl Inc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Plugin for Inc {
|
fn send_response<T: Serialize>(result: Vec<T>) {
|
||||||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
let response = JsonRpc::new("response", result);
|
||||||
Ok(CommandConfig {
|
let response_raw = serde_json::to_string(&response).unwrap();
|
||||||
name: "inc".to_string(),
|
println!("{}", response_raw);
|
||||||
mandatory_positional: vec![],
|
}
|
||||||
optional_positional: vec![PositionalType::Value("Increment".into())],
|
|
||||||
can_load: vec![],
|
fn send_error(error: ShellError) {
|
||||||
can_save: vec![],
|
let message: ReturnValue = Err(error);
|
||||||
is_filter: true,
|
send_response(vec![message])
|
||||||
is_sink: false,
|
}
|
||||||
named: IndexMap::new(),
|
|
||||||
rest_positional: true,
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
})
|
#[serde(tag = "method")]
|
||||||
}
|
#[allow(non_camel_case_types)]
|
||||||
fn begin_filter(&mut self, args: Args) -> Result<(), ShellError> {
|
pub enum NuCommand {
|
||||||
if let Some(args) = args.positional {
|
init { params: Vec<Spanned<Value>> },
|
||||||
for arg in args {
|
filter { params: Value },
|
||||||
match arg {
|
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 {
|
Spanned {
|
||||||
item: Value::Primitive(Primitive::Int(i)),
|
item: Value::Primitive(Primitive::Int(i)),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
self.inc_by = 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")),
|
_ => return Err(ShellError::string("Unrecognized type in params")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Err(_) => {
|
||||||
|
send_error(ShellError::string("Unrecognized type in stream"));
|
||||||
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))])
|
|
||||||
}
|
}
|
||||||
Value::Primitive(Primitive::Bytes(b)) => Ok(vec![ReturnValue::Value(Value::bytes(
|
Value::Primitive(Primitive::Bytes(b)) => Ok(vec![ReturnValue::Value(Value::bytes(
|
||||||
b + self.inc_by as u64,
|
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::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::context::Context;
|
||||||
crate use crate::env::host::handle_unexpected;
|
crate use crate::env::host::handle_unexpected;
|
||||||
crate use crate::env::{Environment, Host};
|
crate use crate::env::{Environment, Host};
|
||||||
crate use crate::errors::ShellError;
|
crate use crate::errors::ShellError;
|
||||||
crate use crate::object::{Primitive, Value};
|
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 crate::Text;
|
||||||
|
crate use futures::stream::BoxStream;
|
||||||
|
crate use futures::Stream;
|
||||||
crate use futures::{FutureExt, StreamExt};
|
crate use futures::{FutureExt, StreamExt};
|
||||||
crate use std::collections::VecDeque;
|
crate use std::collections::VecDeque;
|
||||||
crate use std::pin::Pin;
|
crate use std::future::Future;
|
||||||
crate use std::sync::{Arc, Mutex};
|
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 crate::prelude::*;
|
||||||
use futures::stream::BoxStream;
|
|
||||||
|
|
||||||
pub type InputStream = BoxStream<'static, Value>;
|
pub struct InputStream {
|
||||||
pub type OutputStream = BoxStream<'static, ReturnValue>;
|
crate values: BoxStream<'static, Value>,
|
||||||
|
}
|
||||||
crate fn single_output(item: Value) -> OutputStream {
|
|
||||||
let value = ReturnValue::Value(item);
|
impl InputStream {
|
||||||
let mut vec = VecDeque::new();
|
pub fn into_vec(self) -> impl Future<Output = Vec<Value>> {
|
||||||
vec.push_back(value);
|
self.values.collect()
|
||||||
vec.boxed()
|
}
|
||||||
|
|
||||||
|
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