diff --git a/Cargo.lock b/Cargo.lock index 7077cc6109..78c80a42d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -254,6 +254,19 @@ name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "futures" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itertools" version = "0.8.0" @@ -372,6 +385,8 @@ dependencies = [ "conch-parser 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "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 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.2.1 (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)", "prettytable-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -751,6 +766,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "a2037ec1c6c1c4f79557762eab1f7eae1f64f6cb418ace90fae88f0942b60139" +"checksum futures-core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7455c91eb2eae38f33b013f77ebe766c75761af333efd9d550e154045c63e225" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" diff --git a/Cargo.toml b/Cargo.toml index c2f7aae581..f206bcd7e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,3 +19,5 @@ conch-parser = "0.1.0" nom = "5.0.0-beta1" subprocess = "0.1.18" dunce = "1.0.0" +futures = "0.1.27" +futures-core = "0.2.1" diff --git a/history.txt b/history.txt index ad50e5da69..cd2e1f2578 100644 --- a/history.txt +++ b/history.txt @@ -81,3 +81,12 @@ cd target cd .. cd target ls +git status +git add . +git commit +git push +cd target +cd .. +exit +ls +ps diff --git a/src/commands.rs b/src/commands.rs index c22d85ac10..01d943d38c 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -3,3 +3,5 @@ crate mod cd; crate mod command; crate mod ls; crate mod ps; + +crate use command::Command; diff --git a/src/commands/args.rs b/src/commands/args.rs index 1cedae9c5f..671567bb12 100644 --- a/src/commands/args.rs +++ b/src/commands/args.rs @@ -1,20 +1,60 @@ use crate::object::Value; +use crate::ShellError; use derive_new::new; use std::cell::Cell; use std::collections::VecDeque; -#[derive(Debug, Default)] -pub struct ObjectStream { - queue: VecDeque, +#[derive(Debug)] +pub enum LogLevel { + Trace, + Debug, + Info, + Warn, + Error, + Fatal, } +#[derive(Debug)] +pub struct LogItem { + level: LogLevel, + value: Value, +} + +#[derive(Debug, Default)] +pub struct ObjectStream { + queue: VecDeque, +} + +impl ObjectStream { + crate fn empty() -> ObjectStream { + ObjectStream { + queue: VecDeque::new(), + } + } + + crate fn iter(&self) -> impl Iterator { + self.queue.iter() + } + + crate fn take(&mut self) -> Option { + self.queue.pop_front() + } + + crate fn add(&mut self, value: T) { + self.queue.push_back(value); + } +} + +#[derive(new)] pub struct Streams { - success: Cell, - // error: ObjectStream, - // warning: ObjectStream, - // debug: ObjectStream, - // trace: ObjectStream, - // verbose: ObjectStream, + #[new(value = "ObjectStream::empty()")] + success: ObjectStream, + + #[new(value = "ObjectStream::empty()")] + errors: ObjectStream, + + #[new(value = "ObjectStream::empty()")] + log: ObjectStream, } impl std::fmt::Debug for Streams { @@ -24,16 +64,12 @@ impl std::fmt::Debug for Streams { } impl Streams { - crate fn new() -> Streams { - Streams { - success: Cell::new(ObjectStream::default()), - } + crate fn read(&mut self) -> Option { + self.success.take() } - crate fn take_success(&mut self) -> Cell { - let new_stream = Cell::new(ObjectStream::default()); - self.success.swap(&new_stream); - new_stream + crate fn add(&mut self, value: Value) { + self.success.add(value); } // fn take_stream(&mut self, stream: &mut ObjectStream) -> ObjectStream { diff --git a/src/commands/cd.rs b/src/commands/cd.rs index 3a9cfc1521..1199d76563 100644 --- a/src/commands/cd.rs +++ b/src/commands/cd.rs @@ -1,6 +1,7 @@ use crate::errors::ShellError; use crate::object::process::Process; use crate::object::{DirEntry, ShellObject, Value}; +use crate::prelude::*; use crate::Args; use derive_new::new; use std::path::{Path, PathBuf}; @@ -12,13 +13,13 @@ pub struct CdBlueprint; impl crate::CommandBlueprint for CdBlueprint { fn create( &self, - args: Args, - host: &dyn crate::Host, - env: &mut crate::Environment, - ) -> Result, ShellError> { + args: Vec, + host: &dyn Host, + env: &mut Environment, + ) -> Result, ShellError> { let target = match args.first() { // TODO: This needs better infra - None => return Err(ShellError::new(format!("cd must take one arg"))), + None => return Err(ShellError::string(format!("cd must take one arg"))), Some(v) => v.as_string()?.clone(), }; @@ -36,12 +37,10 @@ pub struct Cd { } impl crate::Command for Cd { - fn run(&mut self) -> Result { - Ok(crate::CommandSuccess { - value: Value::nothing(), - action: vec![crate::CommandAction::ChangeCwd(dunce::canonicalize( - self.cwd.join(&self.target).as_path(), - )?)], - }) + fn run(&mut self, stream: VecDeque) -> Result, ShellError> { + let mut stream = VecDeque::new(); + let path = dunce::canonicalize(self.cwd.join(&self.target).as_path())?; + stream.push_back(ReturnValue::change_cwd(path)); + Ok(stream) } } diff --git a/src/commands/command.rs b/src/commands/command.rs index d3385465cf..f259901a04 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -1,31 +1,38 @@ use crate::errors::ShellError; use crate::object::Value; +use crate::prelude::*; use std::path::PathBuf; pub trait CommandBlueprint { fn create( &self, - input: crate::Args, + input: Vec, host: &dyn crate::Host, env: &mut crate::Environment, ) -> Result, ShellError>; } -crate enum CommandAction { +pub enum CommandAction { ChangeCwd(PathBuf), } -pub struct CommandSuccess { - crate value: Value, - crate action: Vec, +pub enum ReturnValue { + Value(Value), + Action(CommandAction), +} + +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)) + } } pub trait Command { - fn begin(&mut self) -> Result<(), ShellError> { - Ok(()) - } - fn run(&mut self) -> Result; - fn end(&mut self) -> Result<(), ShellError> { - Ok(()) - } + fn run(&mut self, stream: VecDeque) -> Result, ShellError>; } diff --git a/src/commands/ls.rs b/src/commands/ls.rs index 4c34874c1b..4941463b04 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -1,8 +1,9 @@ use crate::errors::ShellError; use crate::object::process::Process; use crate::object::{DirEntry, ShellObject, Value}; +use crate::prelude::*; use crate::Args; -use crate::{Command, CommandSuccess}; +use crate::Command; use derive_new::new; use std::path::PathBuf; use sysinfo::SystemExt; @@ -13,7 +14,7 @@ pub struct LsBlueprint; impl crate::CommandBlueprint for LsBlueprint { fn create( &self, - args: Args, + args: Vec, host: &dyn crate::Host, env: &mut crate::Environment, ) -> Result, ShellError> { @@ -29,20 +30,17 @@ pub struct Ls { } impl crate::Command for Ls { - fn run(&mut self) -> Result { + fn run(&mut self, stream: VecDeque) -> Result, ShellError> { let entries = - std::fs::read_dir(&self.cwd).map_err((|e| ShellError::new(format!("{:?}", e))))?; + std::fs::read_dir(&self.cwd).map_err((|e| ShellError::string(format!("{:?}", e))))?; - let mut shell_entries = vec![]; + let mut shell_entries = VecDeque::new(); for entry in entries { let value = Value::object(DirEntry::new(entry?)?); - shell_entries.push(value) + shell_entries.push_back(ReturnValue::Value(value)) } - Ok(CommandSuccess { - value: Value::list(shell_entries), - action: vec![], - }) + Ok(shell_entries) } } diff --git a/src/commands/ps.rs b/src/commands/ps.rs index faf2687bbb..559f979c5e 100644 --- a/src/commands/ps.rs +++ b/src/commands/ps.rs @@ -1,6 +1,7 @@ use crate::errors::ShellError; use crate::object::process::Process; use crate::object::{ShellObject, Value}; +use crate::prelude::*; use crate::Command; use derive_new::new; use std::cell::RefCell; @@ -15,7 +16,7 @@ pub struct PsBlueprint { impl crate::CommandBlueprint for PsBlueprint { fn create( &self, - args: crate::Args, + args: Vec, host: &dyn crate::Host, env: &mut crate::Environment, ) -> Result, ShellError> { @@ -29,7 +30,7 @@ pub struct Ps { } impl crate::Command for Ps { - fn run(&mut self) -> Result { + fn run(&mut self, stream: VecDeque) -> Result, ShellError> { let mut system = self.system.borrow_mut(); system.refresh_all(); @@ -37,13 +38,12 @@ impl crate::Command for Ps { let list = list .into_iter() - .map(|(_, process)| Value::Object(Box::new(Process::new(process.clone())))) + .map(|(_, process)| { + ReturnValue::Value(Value::Object(Box::new(Process::new(process.clone())))) + }) .take(5) - .collect(); + .collect::>(); - Ok(crate::CommandSuccess { - value: Value::List(list), - action: vec![], - }) + Ok(list) } } diff --git a/src/errors.rs b/src/errors.rs index efe13dab22..568482eb03 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,8 +1,16 @@ +use crate::Value; use derive_new::new; #[derive(Debug, new)] pub struct ShellError { title: String, + error: Value, +} + +impl ShellError { + crate fn string(title: impl Into) -> ShellError { + ShellError::new(title.into(), Value::nothing()) + } } impl std::fmt::Display for ShellError { @@ -17,6 +25,7 @@ impl std::convert::From for ShellError { fn from(input: std::io::Error) -> ShellError { ShellError { title: format!("{}", input), + error: Value::nothing(), } } } diff --git a/src/main.rs b/src/main.rs index 83d892c2ae..63db5b0ef7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,9 +8,11 @@ mod errors; mod format; mod object; mod parser; +mod prelude; crate use crate::commands::args::{Args, Streams}; -crate use crate::commands::command::{Command, CommandAction, CommandBlueprint, CommandSuccess}; +use crate::commands::command::ReturnValue; +crate use crate::commands::command::{Command, CommandAction, CommandBlueprint}; crate use crate::env::{Environment, Host}; crate use crate::errors::ShellError; crate use crate::format::RenderView; @@ -24,6 +26,7 @@ use rustyline::error::ReadlineError; use rustyline::Editor; use std::cell::RefCell; use std::collections::BTreeMap; +use std::collections::VecDeque; use std::error::Error; use std::rc::Rc; use subprocess::Exec; @@ -73,7 +76,7 @@ fn main() -> Result<(), Box> { match readline { Ok(line) => { let result = crate::parser::shell_parser(&line) - .map_err(|e| ShellError::new(format!("{:?}", e)))?; + .map_err(|e| ShellError::string(format!("{:?}", e)))?; let parsed = result.1; @@ -89,26 +92,38 @@ fn main() -> Result<(), Box> { .map(|i| Value::string(i.name().to_string())) .collect(); - let args = Args::new(arg_list); + let streams = Streams::new(); + + // let args = Args::new(arg_list); match commands.get_mut(*command) { Some(command) => { - let mut instance = command.create(args, &mut host, &mut env)?; - let result = instance.run()?; + let mut instance = command.create(arg_list, &mut host, &mut env)?; - for action in result.action { - match action { - crate::CommandAction::ChangeCwd(cwd) => env.cwd = cwd, + let out = VecDeque::new(); + + let mut result = instance.run(out)?; + let mut next = VecDeque::new(); + + for v in result { + match v { + ReturnValue::Action(action) => match action { + crate::CommandAction::ChangeCwd(cwd) => env.cwd = cwd, + }, + + ReturnValue::Value(v) => next.push_back(v), } } - let view = result.value.to_generic_view(); - let rendered = view.render_view(&mut host); + for item in next { + let view = item.to_generic_view(); + let rendered = view.render_view(&mut host); - for line in rendered { - match line.as_ref() { - "\n" => println!(""), - line => println!("{}", line), + for line in rendered { + match line.as_ref() { + "\n" => println!(""), + line => println!("{}", line), + } } } } diff --git a/src/object/base.rs b/src/object/base.rs index 4946d89bf5..15c0bf62b4 100644 --- a/src/object/base.rs +++ b/src/object/base.rs @@ -73,7 +73,10 @@ impl Value { Value::Primitive(Primitive::String(s)) => Ok(s.to_string()), // TODO: this should definitely be more general with better errors - other => Err(ShellError::new(format!("Expected string, got {:?}", other))), + other => Err(ShellError::string(format!( + "Expected string, got {:?}", + other + ))), } } diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 0000000000..ba4f2c44e5 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,6 @@ +crate use crate::commands::args::{Args, Streams}; +crate use crate::commands::command::{Command, CommandAction, CommandBlueprint, ReturnValue}; +crate use crate::env::{Environment, Host}; +crate use crate::errors::ShellError; +crate use crate::format::RenderView; +crate use std::collections::VecDeque;