diff --git a/Cargo.lock b/Cargo.lock index cc5805dbf..d9da44dec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,6 +143,15 @@ name = "byteorder" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bytes" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cc" version = "1.0.37" @@ -285,6 +294,15 @@ dependencies = [ "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-deque" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-epoch" version = "0.3.1" @@ -299,6 +317,27 @@ dependencies = [ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-epoch" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-queue" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-utils" version = "0.2.2" @@ -650,6 +689,11 @@ 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-channel-preview" version = "0.3.0-alpha.16" @@ -710,6 +754,7 @@ name = "futures-util-preview" version = "0.3.0-alpha.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", "futures-channel-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)", "futures-core-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)", "futures-io-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -717,6 +762,16 @@ dependencies = [ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures_codec" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (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)", ] [[package]] @@ -742,6 +797,15 @@ name = "indexmap" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "iovec" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itertools" version = "0.8.0" @@ -917,6 +981,7 @@ dependencies = [ "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)", + "futures_codec 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "nom 5.0.0-beta1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -927,6 +992,8 @@ dependencies = [ "rustyline 4.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "subprocess 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "sysinfo 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1633,6 +1700,51 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio-executor" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-fs" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-io" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-threadpool" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "toml" version = "0.5.1" @@ -1787,6 +1899,7 @@ dependencies = [ "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byte-unit 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6754bb4703aa167bed5381f0c6842f1cc31a9ecde3b9443f726dde3ad3afb841" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" +"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" @@ -1803,7 +1916,10 @@ dependencies = [ "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" +"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" +"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" +"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" @@ -1842,6 +1958,7 @@ dependencies = [ "checksum flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f87e68aa82b2de08a6e037f1385455759df6e445a8df5e005b4297191dbf18aa" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "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-channel-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4cd523712fc272e9b714669165a2832debee5a5b7e409bfccdc7c0d5cd0cf07a" "checksum futures-core-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)" = "719770f328642b657b849856bb5a607db9538dd5bb3000122e5ead55d0a58c36" "checksum futures-executor-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)" = "315dc58c908535d059576a329b86cd185933433382cfcd394fb2fa353330de03" @@ -1849,10 +1966,12 @@ dependencies = [ "checksum futures-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fcfeac5f016a4b5835bb93eb7961f50a64f0e001207562703d9ddf4109d7b263" "checksum futures-sink-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)" = "49dcfdacd6b5974ca0b9b78bc38ffd1071da0206179735c3df82e279f5b784e4" "checksum futures-util-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)" = "f7a0451b9c5047c2b9ab93425ffd0793165511e93c04b977cd45fbd41c6e34b2" +"checksum futures_codec 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b60f48aa03e365df015d2fbf0b79f17b440350c268a5e20305da17b394adcc1e" "checksum hashbrown 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "570178d5e4952010d138b0f1d581271ff3a02406d990f887d1e87e3d6e43b0ac" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" +"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "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 kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" @@ -1954,6 +2073,10 @@ dependencies = [ "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "83ea44c6c0773cc034771693711c35c677b4b5a4b21b9e7071704c54de7d555e" +"checksum tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe6dc22b08d6993916647d108a1a7d15b9cd29c4f4496c62b92c45b5041b7af" +"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" +"checksum tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72558af20be886ea124595ea0f806dd5703b8958e4705429dd58b3d8231f72f2" "checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" diff --git a/Cargo.toml b/Cargo.toml index 46662611e..6011395ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,9 +27,12 @@ byte-unit = "2.1.0" 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-preview = { version = "0.3.0-alpha.16", features = ["compat", "io-compat"] } futures-sink-preview = "0.3.0-alpha.16" +tokio-fs = "0.1.6" +futures_codec = "0.2.2" +term = "0.5.2" [dependencies.pancurses] version = "0.16" -features = ["win32a"] \ No newline at end of file +features = ["win32a"] diff --git a/src/cli.rs b/src/cli.rs index f7c380b93..cee37ef4e 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,7 +1,7 @@ use crate::prelude::*; use crate::commands::classified::{ - ClassifiedCommand, ClassifiedInputStream, ExternalCommand, InternalCommand, + ClassifiedCommand, ClassifiedInputStream, ExternalCommand, InternalCommand, StreamNext, }; use crate::context::Context; crate use crate::errors::ShellError; @@ -185,7 +185,7 @@ async fn process_line(readline: Result, ctx: &mut Context ( Some(ClassifiedCommand::External(left)), Some(ClassifiedCommand::External(_)), - ) => match left.run(ctx, input, true).await { + ) => match left.run(ctx, input, StreamNext::External).await { Ok(val) => val, Err(err) => return LineResult::Error(format!("{}", err.description())), }, @@ -196,12 +196,15 @@ async fn process_line(readline: Result, ctx: &mut Context ) => unimplemented!(), ( - Some(ClassifiedCommand::External(_)), + Some(ClassifiedCommand::External(left)), Some(ClassifiedCommand::Internal(_)), - ) => unimplemented!(), + ) => match left.run(ctx, input, StreamNext::Internal).await { + Ok(val) => val, + Err(err) => return LineResult::Error(format!("{}", err.description())), + }, (Some(ClassifiedCommand::External(left)), None) => { - match left.run(ctx, input, false).await { + match left.run(ctx, input, StreamNext::Last).await { Ok(val) => val, Err(err) => return LineResult::Error(format!("{}", err.description())), } diff --git a/src/commands/classified.rs b/src/commands/classified.rs index acf57d85f..5778e647c 100644 --- a/src/commands/classified.rs +++ b/src/commands/classified.rs @@ -1,4 +1,6 @@ use crate::prelude::*; +use futures::compat::AsyncRead01CompatExt; +use futures_codec::{Framed, LinesCodec}; use std::sync::Arc; use subprocess::Exec; @@ -107,20 +109,29 @@ crate struct ExternalCommand { crate args: Vec, } +crate enum StreamNext { + Last, + External, + Internal, +} + impl ExternalCommand { crate async fn run( self, context: &mut Context, mut input: ClassifiedInputStream, - stream_next: bool, + stream_next: StreamNext, ) -> Result { let mut process = Exec::shell(&self.name) .args(&self.args) .cwd(context.env.lock().unwrap().cwd()); - if stream_next { - process = process.stdout(subprocess::Redirection::Pipe) - } + let mut process = match stream_next { + StreamNext::Last => process, + StreamNext::External | StreamNext::Internal => { + process.stdout(subprocess::Redirection::Pipe) + } + }; if let Some(stdin) = input.stdin { process = process.stdin(stdin); @@ -128,15 +139,31 @@ impl ExternalCommand { let mut popen = process.popen().unwrap(); - if stream_next { - match &popen.stdout { - None => unreachable!(), - Some(stdout) => Ok(ClassifiedInputStream::from_stdout(stdout.try_clone()?)), + match stream_next { + StreamNext::Last => { + popen.wait()?; + Ok(ClassifiedInputStream::new()) + } + StreamNext::External => { + let stdout = popen.stdout.take().unwrap(); + Ok(ClassifiedInputStream::from_stdout(stdout)) + } + StreamNext::Internal => { + let stdout = popen.stdout.take().unwrap(); + let file = futures::io::AllowStdIo::new(stdout); + let stream = Framed::new(file, LinesCodec {}); + let stream = stream.map(|line| Value::string(line.unwrap())); + Ok(ClassifiedInputStream::from_input_stream(stream.boxed())) } - } else { - popen.stdin.take(); - popen.wait()?; - Ok(ClassifiedInputStream::new()) } + + // if stream_next { + // let stdout = popen.stdout.take().unwrap(); + // Ok(ClassifiedInputStream::from_stdout(stdout)) + // } else { + // // popen.stdin.take(); + // popen.wait()?; + // Ok(ClassifiedInputStream::new()) + // } } } diff --git a/src/env/host.rs b/src/env/host.rs index 7ab034733..57f606418 100644 --- a/src/env/host.rs +++ b/src/env/host.rs @@ -1,9 +1,20 @@ pub trait Host { + fn out_terminal(&self) -> Box; + fn err_terminal(&self) -> Box; + fn stdout(&mut self, out: &str); fn stderr(&mut self, out: &str); } impl Host for Box { + fn out_terminal(&self) -> Box { + (**self).out_terminal() + } + + fn err_terminal(&self) -> Box { + (**self).err_terminal() + } + fn stdout(&mut self, out: &str) { (**self).stdout(out) } @@ -16,6 +27,14 @@ impl Host for Box { crate struct BasicHost; impl Host for BasicHost { + fn out_terminal(&self) -> Box { + term::stdout().unwrap() + } + + fn err_terminal(&self) -> Box { + term::stderr().unwrap() + } + fn stdout(&mut self, out: &str) { match out { "\n" => println!(""), diff --git a/src/format.rs b/src/format.rs index 4b0b9a444..8494697e6 100644 --- a/src/format.rs +++ b/src/format.rs @@ -10,16 +10,9 @@ crate use generic::GenericView; crate use table::TableView; crate trait RenderView { - fn render_view(&self, host: &dyn Host) -> Vec; + fn render_view(&self, host: &mut dyn Host) -> Result<(), ShellError>; } -fn print_rendered(lines: &[String], host: &mut dyn Host) { - for line in lines { - host.stdout(line); - } -} - -crate fn print_view(view: &impl RenderView, host: &mut Host) { - // let mut ctx = context.lock().unwrap(); - crate::format::print_rendered(&view.render_view(host), host); +crate fn print_view(view: &impl RenderView, host: &mut dyn Host) -> Result<(), ShellError> { + view.render_view(host) } diff --git a/src/format/entries.rs b/src/format/entries.rs index c619f98b1..8f9ee8393 100644 --- a/src/format/entries.rs +++ b/src/format/entries.rs @@ -10,7 +10,7 @@ use derive_new::new; // another_name : ... #[derive(new)] pub struct EntriesView { - entries: Vec<(String, String)>, + entries: Vec<(crate::object::DescriptorName, String)>, } impl EntriesView { @@ -31,17 +31,28 @@ impl EntriesView { } impl RenderView for EntriesView { - fn render_view(&self, _host: &dyn Host) -> Vec { + fn render_view(&self, _host: &mut dyn Host) -> Result<(), ShellError> { if self.entries.len() == 0 { - return vec![]; + return Ok(()); } - let max_name_size: usize = self.entries.iter().map(|(n, _)| n.len()).max().unwrap(); - - self.entries + let max_name_size: usize = self + .entries .iter() - .map(|(k, v)| format!("{:width$} : {}", k, v, width = max_name_size)) - .collect() + .map(|(n, _)| n.display().len()) + .max() + .unwrap(); + + for (name, value) in &self.entries { + println!( + "{:width$} : {}", + name.display(), + value, + width = max_name_size + ) + } + + Ok(()) } } @@ -58,26 +69,22 @@ impl EntriesListView { } impl RenderView for EntriesListView { - fn render_view(&self, host: &dyn Host) -> Vec { + fn render_view(&self, host: &mut dyn Host) -> Result<(), ShellError> { if self.values.len() == 0 { - return vec![]; + return Ok(()); } - let mut strings = vec![]; - let last = self.values.len() - 1; for (i, item) in self.values.iter().enumerate() { let view = EntriesView::from_value(item); - let out = view.render_view(host); - - strings.extend(out); + view.render_view(host); if i != last { - strings.push("\n".to_string()); + host.stdout("\n"); } } - strings + Ok(()) } } diff --git a/src/format/generic.rs b/src/format/generic.rs index e7bb198a4..45f78af8d 100644 --- a/src/format/generic.rs +++ b/src/format/generic.rs @@ -10,17 +10,17 @@ pub struct GenericView<'value> { } impl RenderView for GenericView<'value> { - fn render_view(&self, host: &dyn Host) -> Vec { + fn render_view(&self, host: &mut dyn Host) -> Result<(), ShellError> { match self.value { - Value::Primitive(p) => vec![p.format(None)], + Value::Primitive(p) => Ok(host.stdout(&p.format(None))), Value::List(l) => { let view = TableView::from_list(l); if let Some(view) = view { - view.render_view(host) - } else { - vec![] + view.render_view(host); } + + Ok(()) // let mut list: Vec = vec![]; // for item in l { // match item { @@ -39,11 +39,14 @@ impl RenderView for GenericView<'value> { o @ Value::Object(_) => { let view = EntriesView::from_value(o); - let out = view.render_view(host); - out + view.render_view(host); + Ok(()) } - Value::Error(e) => vec![format!("{}", e)], + Value::Error(e) => { + host.stdout(&format!("{:?}", e)); + Ok(()) + } } } } diff --git a/src/format/list.rs b/src/format/list.rs index 508dc7c80..a33f2078e 100644 --- a/src/format/list.rs +++ b/src/format/list.rs @@ -11,14 +11,12 @@ pub struct ListView { } impl RenderView for ListView { - fn render_view(&self, _host: &dyn Host) -> Vec { - let mut out = vec![]; - + fn render_view(&self, host: &mut dyn Host) -> Result<(), ShellError> { for output in &self.list { let string: String = output.iter().map(|l| format!("{}\n", l)).collect(); - out.push(format!("{}{}", string, self.sep)); + host.stdout(&format!("{}{}", string, self.sep)); } - out + Ok(()) } } diff --git a/src/format/table.rs b/src/format/table.rs index 8014bf3c7..1981018ef 100644 --- a/src/format/table.rs +++ b/src/format/table.rs @@ -1,8 +1,9 @@ use crate::format::RenderView; use crate::object::Value; use crate::prelude::*; +use ansi_term::Color; use derive_new::new; -use prettytable::{Cell, Row, Table}; +use prettytable::{color, Attr, Cell, Row, Table}; // An entries list is printed like this: // @@ -24,7 +25,7 @@ impl TableView { let item = &values[0]; let descs = item.data_descriptors(); - let headers: Vec = descs.iter().map(|d| d.name.clone()).collect(); + let headers: Vec = descs.iter().map(|d| d.name.display().to_string()).collect(); let mut entries = vec![]; @@ -43,13 +44,27 @@ impl TableView { } impl RenderView for TableView { - fn render_view(&self, _host: &dyn Host) -> Vec { + fn render_view(&self, host: &mut dyn Host) -> Result<(), ShellError> { if self.entries.len() == 0 { - return vec![]; + return Ok(()); } let mut table = Table::new(); - let header: Vec = self.headers.iter().map(|h| Cell::new(h)).collect(); + + // let format = prettytable::format::FormatBuilder::new(); + // .column_separator(Color::Black.bold().paint("|")); + + table.set_format(*prettytable::format::consts::FORMAT_NO_COLSEP); + + let header: Vec = self + .headers + .iter() + .map(|h| { + Cell::new(h) + .with_style(Attr::ForegroundColor(color::GREEN)) + .with_style(Attr::Bold) + }) + .collect(); table.add_row(Row::new(header)); @@ -57,9 +72,8 @@ impl RenderView for TableView { table.add_row(Row::new(row.iter().map(|h| Cell::new(h)).collect())); } - let mut out = vec![]; - table.print(&mut out).unwrap(); + table.print_term(&mut *host.out_terminal()).unwrap(); - vec![String::from_utf8_lossy(&out).to_string()] + Ok(()) } } diff --git a/src/object.rs b/src/object.rs index fc01dc2bc..1b6557d54 100644 --- a/src/object.rs +++ b/src/object.rs @@ -6,5 +6,6 @@ crate mod process; crate mod types; crate use base::{Primitive, Value}; +crate use desc::{DataDescriptor, DescriptorName}; crate use dict::Dictionary; crate use files::dir_entry_dict; diff --git a/src/object/base.rs b/src/object/base.rs index b3cc291f2..d91584434 100644 --- a/src/object/base.rs +++ b/src/object/base.rs @@ -1,5 +1,5 @@ use crate::errors::ShellError; -use crate::object::desc::DataDescriptor; +use crate::object::{DataDescriptor, DescriptorName}; use crate::parser::parse::Operator; use crate::prelude::*; use ansi_term::Color; @@ -69,7 +69,7 @@ pub enum Value { impl Value { crate fn data_descriptors(&self) -> Vec { match self { - Value::Primitive(_) => vec![], + Value::Primitive(_) => vec![DataDescriptor::value_of()], Value::Object(o) => o.data_descriptors(), Value::List(_) => vec![], Value::Error(_) => vec![], @@ -87,7 +87,7 @@ impl Value { crate fn get_data(&'a self, desc: &DataDescriptor) -> MaybeOwned<'a, Value> { match self { - Value::Primitive(_) => MaybeOwned::Owned(Value::nothing()), + p @ Value::Primitive(_) => MaybeOwned::Borrowed(p), Value::Object(o) => o.get_data(desc), Value::List(_) => MaybeOwned::Owned(Value::nothing()), Value::Error(_) => MaybeOwned::Owned(Value::nothing()), @@ -203,9 +203,9 @@ crate fn select_fields(obj: &Value, fields: &[String]) -> crate::object::Diction let descs = obj.data_descriptors(); for field in fields { - match descs.iter().find(|d| d.name == *field) { - None => out.add(field.to_string(), Value::nothing()), - Some(desc) => out.add(field.to_string(), obj.get_data(desc).borrow().copy()), + match descs.iter().find(|d| d.name.is_string(field)) { + None => out.add(DataDescriptor::for_string_name(field), Value::nothing()), + Some(desc) => out.add(desc.copy(), obj.get_data(desc).borrow().copy()), } } @@ -218,10 +218,10 @@ crate fn reject_fields(obj: &Value, fields: &[String]) -> crate::object::Diction let descs = obj.data_descriptors(); for desc in descs { - if fields.contains(&desc.name) { - continue; - } else { - out.add(desc.name.clone(), obj.get_data(&desc).borrow().copy()) + match desc.name.as_string() { + None => continue, + Some(s) if fields.iter().any(|field| field == s) => continue, + Some(s) => out.add(desc.copy(), obj.get_data(&desc).borrow().copy()), } } @@ -230,7 +230,7 @@ crate fn reject_fields(obj: &Value, fields: &[String]) -> crate::object::Diction crate fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool { let descs = obj.data_descriptors(); - match descs.iter().find(|d| d.name == *field) { + match descs.iter().find(|d| d.name.is_string(field)) { None => false, Some(desc) => { let v = obj.get_data(desc).borrow().copy(); diff --git a/src/object/desc.rs b/src/object/desc.rs index 21c11c874..a7def78f0 100644 --- a/src/object/desc.rs +++ b/src/object/desc.rs @@ -1,17 +1,110 @@ -use crate::object::types::Type; +use crate::object::types::{AnyShell, Type}; use derive_new::new; -#[derive(new)] +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum DescriptorName { + String(String), + ValueOf, +} + +impl DescriptorName { + crate fn display(&self) -> &str { + match self { + DescriptorName::String(s) => s, + DescriptorName::ValueOf => "value", + } + } + + crate fn as_string(&self) -> Option<&str> { + match self { + DescriptorName::String(s) => Some(s), + DescriptorName::ValueOf => None, + } + } + + crate fn is_string(&self, string: &str) -> bool { + match self { + DescriptorName::String(s) => s == string, + DescriptorName::ValueOf => false, + } + } +} + +#[derive(Debug, new)] pub struct DataDescriptor { - crate name: String, + crate name: DescriptorName, crate readonly: bool, crate ty: Box, } +impl From<&str> for DataDescriptor { + fn from(input: &str) -> DataDescriptor { + DataDescriptor { + name: DescriptorName::String(input.to_string()), + readonly: true, + ty: Box::new(AnyShell), + } + } +} + +impl From for DataDescriptor { + fn from(input: String) -> DataDescriptor { + DataDescriptor { + name: DescriptorName::String(input), + readonly: true, + ty: Box::new(AnyShell), + } + } +} + impl PartialEq for DataDescriptor { fn eq(&self, other: &DataDescriptor) -> bool { self.name == other.name && self.readonly == other.readonly && self.ty.equal(&*other.ty) } } -impl DataDescriptor {} +impl std::hash::Hash for DataDescriptor { + fn hash(&self, state: &mut H) { + self.name.hash(state); + self.readonly.hash(state); + self.ty.id().hash(state); + } +} + +impl Eq for DataDescriptor {} + +impl DescriptorName { + crate fn for_string_name(name: impl Into) -> DescriptorName { + DescriptorName::String(name.into()) + } +} + +impl DataDescriptor { + crate fn value_of() -> DataDescriptor { + DataDescriptor { + name: DescriptorName::ValueOf, + readonly: true, + ty: Box::new(AnyShell), + } + } + + crate fn for_name(name: impl Into) -> DataDescriptor { + DataDescriptor { + name: name.into(), + readonly: true, + ty: Box::new(AnyShell), + } + } + + crate fn for_string_name(name: impl Into) -> DataDescriptor { + DataDescriptor::for_name(DescriptorName::for_string_name(name)) + } + + crate fn copy(&self) -> DataDescriptor { + DataDescriptor { + name: self.name.clone(), + readonly: self.readonly, + ty: self.ty.copy(), + } + } +} diff --git a/src/object/dict.rs b/src/object/dict.rs index 52f981701..1e2379304 100644 --- a/src/object/dict.rs +++ b/src/object/dict.rs @@ -1,13 +1,13 @@ use crate::prelude::*; -use crate::object::desc::DataDescriptor; +use crate::object::{DataDescriptor, DescriptorName}; use crate::object::{Primitive, Value}; use indexmap::IndexMap; use std::cmp::{Ordering, PartialOrd}; #[derive(Debug, Default, Eq, PartialEq)] pub struct Dictionary { - entries: IndexMap, + entries: IndexMap, } impl PartialOrd for Dictionary { @@ -41,7 +41,7 @@ impl PartialEq for Dictionary { } impl Dictionary { - crate fn add(&mut self, name: impl Into, value: Value) { + crate fn add(&mut self, name: impl Into, value: Value) { self.entries.insert(name.into(), value); } @@ -49,31 +49,30 @@ impl Dictionary { let mut out = Dictionary::default(); for (key, value) in self.entries.iter() { - out.add(key.clone(), value.copy()); + out.add(key.copy(), value.copy()); } out } crate fn data_descriptors(&self) -> Vec { - self.entries - .iter() - .map(|(name, _)| { - DataDescriptor::new(name.clone(), true, Box::new(crate::object::types::AnyShell)) - }) - .collect() + self.entries.iter().map(|(name, _)| name.copy()).collect() } crate fn get_data(&'a self, desc: &DataDescriptor) -> MaybeOwned<'a, Value> { - match self.entries.get(&desc.name) { + match self.entries.get(desc) { Some(v) => MaybeOwned::Borrowed(v), None => MaybeOwned::Owned(Value::Primitive(Primitive::Nothing)), } } crate fn get_data_by_key(&self, name: &str) -> MaybeOwned<'_, Value> { - match self.entries.get(name) { - Some(v) => MaybeOwned::Borrowed(v), + match self + .entries + .iter() + .find(|(desc_name, _)| desc_name.name.is_string(name)) + { + Some((_, v)) => MaybeOwned::Borrowed(v), None => MaybeOwned::Owned(Value::Primitive(Primitive::Nothing)), } } diff --git a/src/object/types.rs b/src/object/types.rs index 367334666..4edd0203a 100644 --- a/src/object/types.rs +++ b/src/object/types.rs @@ -1,11 +1,14 @@ use std::any::Any; +use std::fmt::Debug; -pub trait Type { +pub trait Type: Debug + Send { fn as_any(&self) -> &dyn Any; fn equal(&self, other: &dyn Type) -> bool; + fn id(&self) -> u64; + fn copy(&self) -> Box; } -#[derive(Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq)] pub struct AnyShell; impl Type for AnyShell { @@ -16,4 +19,12 @@ impl Type for AnyShell { fn equal(&self, other: &dyn Type) -> bool { other.as_any().is::() } + + fn id(&self) -> u64 { + 0 + } + + fn copy(&self) -> Box { + Box::new(AnyShell) + } }