diff --git a/Cargo.lock b/Cargo.lock index 25d84b06b5..cc5805dbf0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -916,6 +916,7 @@ dependencies = [ "derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "dunce 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "nom 5.0.0-beta1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 02ae4a3a60..46662611e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ ordered-float = "1.0.2" prettyprint = "0.6.0" cursive = { version = "0.12.0", features = ["pancurses-backend"], default-features = false } futures-preview = "0.3.0-alpha.16" +futures-sink-preview = "0.3.0-alpha.16" [dependencies.pancurses] version = "0.16" diff --git a/src/cli.rs b/src/cli.rs index afa320e3c8..15ee6c499f 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -49,12 +49,13 @@ pub async fn cli() -> Result<(), Box> { use crate::commands::*; context.add_commands(vec![ + ("format-list", Arc::new(format_list)), ("ps", Arc::new(ps::ps)), ("ls", Arc::new(ls::ls)), ("cd", Arc::new(cd::cd)), ("view", Arc::new(view::view)), ("skip", Arc::new(skip::skip)), - ("take", Arc::new(take::take)), + ("first", Arc::new(take::take)), ("select", Arc::new(select::select)), ("reject", Arc::new(reject::reject)), ("to-array", Arc::new(to_array::to_array)), @@ -105,6 +106,30 @@ enum LineResult { FatalError(ShellError), } +impl std::ops::Try for LineResult { + type Ok = Option; + type Error = ShellError; + + fn into_result(self) -> Result, ShellError> { + match self { + LineResult::Success(s) => Ok(Some(s)), + LineResult::Error(s) => Err(ShellError::string(s)), + LineResult::Break => Ok(None), + LineResult::FatalError(err) => Err(err), + } + } + fn from_error(v: ShellError) -> Self { + LineResult::Error(v.to_string()) + } + + fn from_ok(v: Option) -> Self { + match v { + None => LineResult::Break, + Some(v) => LineResult::Success(v), + } + } +} + async fn process_line(readline: Result, ctx: &mut Context) -> LineResult { match &readline { Ok(line) if line.trim() == "exit" => LineResult::Break, @@ -137,10 +162,12 @@ async fn process_line(readline: Result, ctx: &mut Context if equal_shapes(&input_vec) { let array = crate::commands::stream_to_array(input_vec.boxed()).await; let args = CommandArgs::from_context(ctx, vec![], array); - format(args).await; + let mut result = format(args); + let mut vec = vec![]; + vec.send_all(&mut result).await?; } else { let args = CommandArgs::from_context(ctx, vec![], input_vec.boxed()); - format(args).await; + format(args).collect::>().await; } } @@ -197,26 +224,57 @@ fn classify_command( } } -async fn format(args: CommandArgs) -> OutputStream { - let input: Vec<_> = args.input.collect().await; - let last = input.len() - 1; - for (i, item) in input.iter().enumerate() { - let view = GenericView::new(item); - crate::format::print_view(&view, &mut *args.host.lock().unwrap()); +crate fn format(args: CommandArgs) -> OutputStream { + let host = args.host.clone(); + let input = args.input.map(|a| a.copy()); + let input = input.collect::>(); - if last != i { - println!(""); - } - } + input + .then(move |input| { + let last = input.len() - 1; + let mut host = host.lock().unwrap(); + for (i, item) in input.iter().enumerate() { + let view = GenericView::new(item); + crate::format::print_view(&view, &mut *host); - empty_stream() + if last != i { + println!(""); + } + } + + futures::future::ready(empty_stream()) + }) + .flatten_stream() + .boxed() } -async fn format_list(args: CommandArgs) -> OutputStream { - let view = EntriesListView::from_stream(args.input).await; - crate::format::print_view(&view, &mut *args.host.lock().unwrap()); +crate fn format_list(args: CommandArgs) -> Result { + let host = args.host.clone(); + // let input = args.input.map(|a| a.copy()); + // let input = input.collect::>(); - empty_stream() + let view = EntriesListView::from_stream(args.input); + + Ok(view + .then(move |view| { + crate::format::print_view(&view, &mut *host.lock().unwrap()); + + futures::future::ready(empty_stream()) + }) + .flatten_stream() + .boxed()) + + // Ok(empty_stream()) + // Ok(args + // .input + // .map(|input| { + // let view = EntriesListView::from_stream(input); + // crate::format::print_view(&view, &mut *args.host.lock().unwrap()); + // }) + // .collect() + // .then(|_| empty_stream()) + // .flatten_stream() + // .boxed()) } fn equal_shapes(input: &VecDeque) -> bool { diff --git a/src/commands/command.rs b/src/commands/command.rs index 71479ceb0f..81848a7c07 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -4,7 +4,7 @@ use crate::prelude::*; use std::path::PathBuf; pub struct CommandArgs { - pub host: Arc>, + pub host: Arc>, pub env: Arc>, pub args: Vec, pub input: InputStream, @@ -37,12 +37,6 @@ pub enum ReturnValue { } impl ReturnValue { - crate fn single(value: Value) -> VecDeque { - let mut v = VecDeque::new(); - v.push_back(ReturnValue::Value(value)); - v - } - crate fn change_cwd(path: PathBuf) -> ReturnValue { ReturnValue::Action(CommandAction::ChangeCwd(path)) } diff --git a/src/commands/sort_by.rs b/src/commands/sort_by.rs index 13663d88a1..d00b0dc604 100644 --- a/src/commands/sort_by.rs +++ b/src/commands/sort_by.rs @@ -1,6 +1,5 @@ use crate::errors::ShellError; use crate::prelude::*; -use futures::stream::BoxStream; pub fn sort_by(args: CommandArgs) -> Result { let fields: Result, _> = args.args.iter().map(|a| a.as_string()).collect(); diff --git a/src/context.rs b/src/context.rs index 6f49f6b279..6bea845ca4 100644 --- a/src/context.rs +++ b/src/context.rs @@ -5,7 +5,7 @@ use std::sync::Arc; pub struct Context { commands: indexmap::IndexMap>, - crate host: Arc>, + crate host: Arc>, crate env: Arc>, } diff --git a/src/env/host.rs b/src/env/host.rs index 736c6bb056..7ab034733c 100644 --- a/src/env/host.rs +++ b/src/env/host.rs @@ -17,10 +17,16 @@ crate struct BasicHost; impl Host for BasicHost { fn stdout(&mut self, out: &str) { - println!("{}", out) + match out { + "\n" => println!(""), + other => println!("{}", other), + } } fn stderr(&mut self, out: &str) { - eprintln!("{}", out) + match out { + "\n" => eprintln!(""), + other => eprintln!("{}", other), + } } } diff --git a/src/errors.rs b/src/errors.rs index eb270f30e1..6cee99ebcf 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -42,3 +42,12 @@ impl std::convert::From for ShellError { } } } + +impl std::convert::From for ShellError { + fn from(_input: futures_sink::VecSinkError) -> ShellError { + ShellError { + title: format!("Unexpected Vec Sink Error"), + error: Value::nothing(), + } + } +} diff --git a/src/main.rs b/src/main.rs index 3f08472912..45da4ec084 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] #![feature(async_await)] +#![feature(try_trait)] mod cli; mod commands; @@ -17,6 +18,6 @@ mod stream; use std::error::Error; fn main() -> Result<(), Box> { - futures::executor::block_on(crate::cli::cli()); + futures::executor::block_on(crate::cli::cli())?; Ok(()) } diff --git a/src/prelude.rs b/src/prelude.rs index ebf084ad9f..7349baccee 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -7,7 +7,7 @@ crate use crate::object::{Primitive, Value}; #[allow(unused)] crate use crate::stream::{empty_stream, single_output, InputStream, OutputStream}; #[allow(unused)] -crate use futures::{Future, FutureExt, Stream, StreamExt}; +crate use futures::{Future, FutureExt, Sink, SinkExt, Stream, StreamExt}; crate use std::collections::VecDeque; crate use std::pin::Pin; crate use std::sync::{Arc, Mutex};