From 31dd579d6faa00b3e0e9b31a1329e32493dd90c3 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Wed, 22 May 2019 21:30:43 -0700 Subject: [PATCH] Small restructuring --- Cargo.lock | 91 ++++++++++++-- Cargo.toml | 7 +- src/cli.rs | 240 ++++++++++++++++++++++++++++++++++++ src/commands/classified.rs | 4 +- src/commands/command.rs | 3 +- src/context.rs | 8 +- src/errors.rs | 1 - src/format/entries.rs | 1 - src/format/generic.rs | 2 +- src/format/list.rs | 2 +- src/format/table.rs | 2 +- src/main.rs | 241 +------------------------------------ src/object/base.rs | 17 +-- src/object/dict.rs | 2 - src/parser/completer.rs | 3 +- src/prelude.rs | 4 +- src/stream.rs | 0 17 files changed, 354 insertions(+), 274 deletions(-) create mode 100644 src/cli.rs create mode 100644 src/stream.rs diff --git a/Cargo.lock b/Cargo.lock index d7a304c059..25d84b06b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -651,16 +651,72 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "futures" -version = "0.1.27" +name = "futures-channel-preview" +version = "0.3.0-alpha.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-core-preview" +version = "0.3.0-alpha.16" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "futures-core" -version = "0.2.1" +name = "futures-executor-preview" +version = "0.3.0-alpha.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "either 1.5.2 (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-util-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.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)", +] + +[[package]] +name = "futures-io-preview" +version = "0.3.0-alpha.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-preview" +version = "0.3.0-alpha.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "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-executor-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)", + "futures-sink-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-sink-preview" +version = "0.3.0-alpha.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "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)", +] + +[[package]] +name = "futures-util-preview" +version = "0.3.0-alpha.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "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)", + "futures-sink-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", ] [[package]] @@ -859,12 +915,12 @@ dependencies = [ "cursive 0.12.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)", + "futures-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)", "ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pancurses 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", "prettyprint 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "prettytable-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustyline 4.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1031,6 +1087,11 @@ dependencies = [ "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pin-utils" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "pkg-config" version = "0.3.14" @@ -1395,6 +1456,11 @@ dependencies = [ "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "smallvec" version = "0.6.9" @@ -1775,8 +1841,13 @@ 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-core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7455c91eb2eae38f33b013f77ebe766c75761af333efd9d550e154045c63e225" +"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" +"checksum futures-io-preview 0.3.0-alpha.16 (registry+https://github.com/rust-lang/crates.io-index)" = "cca0bf7a1f39c9d32b797b0def93d5932aa71796236aad6b549bac6f7df159a3" +"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 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" @@ -1819,6 +1890,7 @@ dependencies = [ "checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" "checksum parse-zoneinfo 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "089a398ccdcdd77b8c38909d5a1e4b67da1bc4c9dbfe6d5b536c828eddb779e5" "checksum pdcurses-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "084dd22796ff60f1225d4eb6329f33afaf4c85419d51d440ab6b8c6f4529166b" +"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" "checksum plist 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f4739851c08dd9a62a78beff2edf1a438517268b2c563c42fc6d9d3139e42d2a" "checksum prettyprint 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2705417f8aa07cb6308db42e55623479c1c9667942a4d5e4174c684e5da5590d" @@ -1861,6 +1933,7 @@ dependencies = [ "checksum shell-words 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39acde55a154c4cd3ae048ac78cc21c25f3a0145e44111b523279113dce0d94a" "checksum signal-hook 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "72ab58f1fda436857e6337dcb6a5aaa34f16c5ddc87b3a8b6ef7a212f90b9c5a" "checksum signal-hook-registry 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cded4ffa32146722ec54ab1f16320568465aa922aa9ab4708129599740da85d7" +"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stackvector 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c049c77bf85fbc036484c97b008276d539d9ebff9dfbde37b632ebcd5b8746b6" diff --git a/Cargo.toml b/Cargo.toml index be014c70dc..02ae4a3a60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,11 +21,14 @@ conch-parser = "0.1.1" nom = "5.0.0-beta1" subprocess = "0.1.18" dunce = "1.0.0" -futures = "0.1.27" -futures-core = "0.2.1" indexmap = "1.0.2" chrono-humanize = "0.0.11" 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" + +[dependencies.pancurses] +version = "0.16" +features = ["win32a"] \ No newline at end of file diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000000..bc16001036 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,240 @@ +use crate::prelude::*; + +use crate::commands::classified::{ClassifiedCommand, ExternalCommand, InternalCommand}; +use crate::commands::command::ReturnValue; +use crate::context::Context; +crate use crate::env::Host; +crate use crate::errors::ShellError; +crate use crate::format::{EntriesListView, GenericView}; +use crate::object::Value; + +use rustyline::error::ReadlineError; +use rustyline::{self, ColorMode, Config, Editor}; +use std::collections::VecDeque; +use std::error::Error; +use std::sync::Arc; + +#[derive(Debug)] +pub enum MaybeOwned<'a, T> { + Owned(T), + Borrowed(&'a T), +} + +impl MaybeOwned<'a, T> { + crate fn borrow(&self) -> &T { + match self { + MaybeOwned::Owned(v) => v, + MaybeOwned::Borrowed(v) => v, + } + } +} + +pub fn cli() -> Result<(), Box> { + let config = Config::builder().color_mode(ColorMode::Forced).build(); + let h = crate::shell::Helper::new(); + let mut rl: Editor = Editor::with_config(config); + + #[cfg(windows)] + { + let _ = ansi_term::enable_ansi_support(); + } + + rl.set_helper(Some(h)); + if rl.load_history("history.txt").is_err() { + println!("No previous history."); + } + + let mut context = Context::basic()?; + + { + use crate::commands::*; + + context.add_commands(vec![ + ("format", Arc::new(format)), + ("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)), + ("select", Arc::new(select::select)), + ("reject", Arc::new(reject::reject)), + ("to-array", Arc::new(to_array::to_array)), + ("where", Arc::new(where_::r#where)), + ("sort-by", Arc::new(sort_by::sort_by)), + ]); + } + + loop { + let readline = rl.readline(&format!("{}> ", context.env.cwd().display().to_string())); + + match process_line(readline, &mut context) { + LineResult::Success(line) => { + rl.add_history_entry(line.clone()); + } + + LineResult::Error(err) => { + context.host.stdout(&err); + } + + LineResult::Break => { + break; + } + + LineResult::FatalError(err) => { + context + .host + .stdout(&format!("A surprising fatal error occurred.\n{:?}", err)); + } + } + } + rl.save_history("history.txt").unwrap(); + + Ok(()) +} + +enum LineResult { + Success(String), + Error(String), + Break, + + #[allow(unused)] + FatalError(ShellError), +} + +fn process_line(readline: Result, ctx: &mut Context) -> LineResult { + match &readline { + Ok(line) if line.trim() == "exit" => LineResult::Break, + + Ok(line) if line.trim() == "" => LineResult::Success(line.clone()), + + Ok(line) => { + let result = match crate::parser::shell_parser(&line) { + Err(err) => { + return LineResult::Error(format!("{:?}", err)); + } + + Ok(val) => val, + }; + + let parsed = result.1; + + let mut input = VecDeque::new(); + + for item in parsed { + input = match process_command(item.clone(), input, ctx) { + Ok(val) => val, + Err(err) => return LineResult::Error(format!("{}", err.description())), + }; + } + + if input.len() > 0 { + if equal_shapes(&input) { + let array = crate::commands::stream_to_array(input); + let args = CommandArgs::from_context(ctx, vec![], array); + match format(args) { + Ok(_) => {} + Err(err) => return LineResult::Error(err.to_string()), + } + } else { + let args = CommandArgs::from_context(ctx, vec![], input); + match format(args) { + Ok(_) => {} + Err(err) => return LineResult::Error(err.to_string()), + } + } + } + + LineResult::Success(line.to_string()) + } + Err(ReadlineError::Interrupted) => { + println!("CTRL-C"); + LineResult::Break + } + Err(ReadlineError::Eof) => { + println!("CTRL-D"); + LineResult::Break + } + Err(err) => { + println!("Error: {:?}", err); + LineResult::Break + } + } +} + +fn process_command( + parsed: Vec, + input: VecDeque, + context: &mut Context, +) -> Result, ShellError> { + let command = classify_command(&parsed, context)?; + + command.run(input, context) +} + +fn classify_command( + command: &[crate::parser::Item], + context: &Context, +) -> Result { + let command_name = &command[0].name()?; + + let arg_list: Vec = command[1..].iter().map(|i| i.as_value()).collect(); + let arg_list_strings: Vec = command[1..].iter().map(|i| i.print()).collect(); + + match *command_name { + other => match context.has_command(*command_name) { + true => { + let command = context.get_command(command_name); + Ok(ClassifiedCommand::Internal(InternalCommand { + command, + args: arg_list, + })) + } + false => Ok(ClassifiedCommand::External(ExternalCommand { + name: other.to_string(), + args: arg_list_strings, + })), + }, + } +} + +fn format(args: CommandArgs<'caller>) -> Result, ShellError> { + let last = args.input.len() - 1; + for (i, item) in args.input.iter().enumerate() { + let view = GenericView::new(item); + crate::format::print_view(&view, args.host); + + if last != i { + println!(""); + } + } + + Ok(VecDeque::new()) +} + +fn format_list(args: CommandArgs<'caller>) -> Result, ShellError> { + let view = EntriesListView::from_stream(args.input); + crate::format::print_view(&view, args.host); + + Ok(VecDeque::new()) +} + +fn equal_shapes(input: &VecDeque) -> bool { + let mut items = input.iter(); + + let item = match items.next() { + Some(item) => item, + None => return false, + }; + + let desc = item.data_descriptors(); + + for item in items { + if desc != item.data_descriptors() { + return false; + } + } + + true +} diff --git a/src/commands/classified.rs b/src/commands/classified.rs index 07cda3c179..36a23ce6dd 100644 --- a/src/commands/classified.rs +++ b/src/commands/classified.rs @@ -11,7 +11,7 @@ impl ClassifiedCommand { crate fn run( self, input: VecDeque, - context: &mut crate::Context, + context: &mut Context, ) -> Result, ShellError> { match self { ClassifiedCommand::Internal(internal) => { @@ -22,7 +22,7 @@ impl ClassifiedCommand { for v in result { match v { ReturnValue::Action(action) => match action { - crate::CommandAction::ChangeCwd(cwd) => context.env.cwd = cwd, + CommandAction::ChangeCwd(cwd) => context.env.cwd = cwd, }, ReturnValue::Value(v) => next.push_back(v), diff --git a/src/commands/command.rs b/src/commands/command.rs index bba76df199..d48adab03e 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -1,12 +1,11 @@ use crate::errors::ShellError; use crate::object::Value; use crate::prelude::*; -use crate::Context; use std::path::PathBuf; pub struct CommandArgs<'caller> { pub host: &'caller mut dyn Host, - pub env: &'caller crate::Environment, + pub env: &'caller Environment, pub args: Vec, pub input: VecDeque, } diff --git a/src/context.rs b/src/context.rs index c60b97b2f8..bcbb30afcc 100644 --- a/src/context.rs +++ b/src/context.rs @@ -4,8 +4,8 @@ use std::error::Error; use std::sync::Arc; pub struct Context { - commands: indexmap::IndexMap>, - crate host: Box, + commands: indexmap::IndexMap>, + crate host: Box, crate env: Environment, } @@ -14,11 +14,11 @@ impl Context { Ok(Context { commands: indexmap::IndexMap::new(), host: Box::new(crate::env::host::BasicHost), - env: crate::Environment::basic()?, + env: Environment::basic()?, }) } - pub fn add_commands(&mut self, commands: Vec<(&str, Arc)>) { + pub fn add_commands(&mut self, commands: Vec<(&str, Arc)>) { for (name, command) in commands { self.commands.insert(name.to_string(), command); } diff --git a/src/errors.rs b/src/errors.rs index 9d9cadc729..eb270f30e1 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,7 +1,6 @@ #[allow(unused)] use crate::prelude::*; -use crate::Value; use derive_new::new; #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, new)] diff --git a/src/format/entries.rs b/src/format/entries.rs index 5b7c87e83d..02845c0854 100644 --- a/src/format/entries.rs +++ b/src/format/entries.rs @@ -1,6 +1,5 @@ use crate::format::RenderView; use crate::prelude::*; -use crate::Host; use derive_new::new; diff --git a/src/format/generic.rs b/src/format/generic.rs index 7ba3b132dd..e7bb198a45 100644 --- a/src/format/generic.rs +++ b/src/format/generic.rs @@ -1,6 +1,6 @@ use crate::format::{EntriesView, RenderView, TableView}; use crate::object::Value; -use crate::Host; +use crate::prelude::*; use derive_new::new; // A list is printed one line at a time with an optional separator between groups diff --git a/src/format/list.rs b/src/format/list.rs index ad423c0ad7..508dc7c804 100644 --- a/src/format/list.rs +++ b/src/format/list.rs @@ -1,5 +1,5 @@ use crate::format::RenderView; -use crate::Host; +use crate::prelude::*; use derive_new::new; // A list is printed one line at a time with an optional separator between groups diff --git a/src/format/table.rs b/src/format/table.rs index 02d463a293..8014bf3c7a 100644 --- a/src/format/table.rs +++ b/src/format/table.rs @@ -1,6 +1,6 @@ use crate::format::RenderView; use crate::object::Value; -use crate::Host; +use crate::prelude::*; use derive_new::new; use prettytable::{Cell, Row, Table}; diff --git a/src/main.rs b/src/main.rs index 1422ab4515..6cf266b286 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,7 @@ #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] -#[allow(unused)] -use crate::prelude::*; - +mod cli; mod commands; mod context; mod env; @@ -13,243 +11,10 @@ mod object; mod parser; mod prelude; mod shell; +mod stream; -use crate::commands::classified::{ClassifiedCommand, ExternalCommand, InternalCommand}; -use crate::commands::command::ReturnValue; -crate use crate::commands::command::{Command, CommandAction}; -use crate::context::Context; -crate use crate::env::{Environment, Host}; -crate use crate::errors::ShellError; -crate use crate::format::{EntriesListView, GenericView}; -use crate::object::Value; - -use rustyline::error::ReadlineError; -use rustyline::{self, ColorMode, Config, Editor}; -use std::collections::VecDeque; use std::error::Error; -use std::sync::Arc; - -#[derive(Debug)] -pub enum MaybeOwned<'a, T> { - Owned(T), - Borrowed(&'a T), -} - -impl MaybeOwned<'a, T> { - crate fn borrow(&self) -> &T { - match self { - MaybeOwned::Owned(v) => v, - MaybeOwned::Borrowed(v) => v, - } - } -} fn main() -> Result<(), Box> { - let config = Config::builder().color_mode(ColorMode::Forced).build(); - let h = crate::shell::Helper::new(); - let mut rl: Editor = Editor::with_config(config); - - #[cfg(windows)] - { - let _ = ansi_term::enable_ansi_support(); - } - - rl.set_helper(Some(h)); - if rl.load_history("history.txt").is_err() { - println!("No previous history."); - } - - let mut context = Context::basic()?; - - { - use crate::commands::*; - - context.add_commands(vec![ - ("format", Arc::new(format)), - ("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)), - ("select", Arc::new(select::select)), - ("reject", Arc::new(reject::reject)), - ("to-array", Arc::new(to_array::to_array)), - ("where", Arc::new(where_::r#where)), - ("sort-by", Arc::new(sort_by::sort_by)), - ]); - } - - loop { - let readline = rl.readline(&format!("{}> ", context.env.cwd().display().to_string())); - - match process_line(readline, &mut context) { - LineResult::Success(line) => { - rl.add_history_entry(line.clone()); - } - - LineResult::Error(err) => { - context.host.stdout(&err); - } - - LineResult::Break => { - break; - } - - LineResult::FatalError(err) => { - context - .host - .stdout(&format!("A surprising fatal error occurred.\n{:?}", err)); - } - } - } - rl.save_history("history.txt").unwrap(); - - Ok(()) -} - -enum LineResult { - Success(String), - Error(String), - Break, - - #[allow(unused)] - FatalError(ShellError), -} - -fn process_line(readline: Result, ctx: &mut Context) -> LineResult { - match &readline { - Ok(line) if line.trim() == "exit" => LineResult::Break, - - Ok(line) if line.trim() == "" => LineResult::Success(line.clone()), - - Ok(line) => { - let result = match crate::parser::shell_parser(&line) { - Err(err) => { - return LineResult::Error(format!("{:?}", err)); - } - - Ok(val) => val, - }; - - let parsed = result.1; - - let mut input = VecDeque::new(); - - for item in parsed { - input = match process_command(item.clone(), input, ctx) { - Ok(val) => val, - Err(err) => return LineResult::Error(format!("{}", err.description())), - }; - } - - if input.len() > 0 { - if equal_shapes(&input) { - let array = crate::commands::stream_to_array(input); - let args = CommandArgs::from_context(ctx, vec![], array); - match format(args) { - Ok(_) => {} - Err(err) => return LineResult::Error(err.to_string()), - } - } else { - let args = CommandArgs::from_context(ctx, vec![], input); - match format(args) { - Ok(_) => {} - Err(err) => return LineResult::Error(err.to_string()), - } - } - } - - LineResult::Success(line.to_string()) - } - Err(ReadlineError::Interrupted) => { - println!("CTRL-C"); - LineResult::Break - } - Err(ReadlineError::Eof) => { - println!("CTRL-D"); - LineResult::Break - } - Err(err) => { - println!("Error: {:?}", err); - LineResult::Break - } - } -} - -fn process_command( - parsed: Vec, - input: VecDeque, - context: &mut Context, -) -> Result, ShellError> { - let command = classify_command(&parsed, context)?; - - command.run(input, context) -} - -fn classify_command( - command: &[crate::parser::Item], - context: &Context, -) -> Result { - let command_name = &command[0].name()?; - - let arg_list: Vec = command[1..].iter().map(|i| i.as_value()).collect(); - let arg_list_strings: Vec = command[1..].iter().map(|i| i.print()).collect(); - - match *command_name { - other => match context.has_command(*command_name) { - true => { - let command = context.get_command(command_name); - Ok(ClassifiedCommand::Internal(InternalCommand { - command, - args: arg_list, - })) - } - false => Ok(ClassifiedCommand::External(ExternalCommand { - name: other.to_string(), - args: arg_list_strings, - })), - }, - } -} - -fn format(args: CommandArgs<'caller>) -> Result, ShellError> { - let last = args.input.len() - 1; - for (i, item) in args.input.iter().enumerate() { - let view = GenericView::new(item); - crate::format::print_view(&view, args.host); - - if last != i { - println!(""); - } - } - - Ok(VecDeque::new()) -} - -fn format_list(args: CommandArgs<'caller>) -> Result, ShellError> { - let view = EntriesListView::from_stream(args.input); - crate::format::print_view(&view, args.host); - - Ok(VecDeque::new()) -} - -fn equal_shapes(input: &VecDeque) -> bool { - let mut items = input.iter(); - - let item = match items.next() { - Some(item) => item, - None => return false, - }; - - let desc = item.data_descriptors(); - - for item in items { - if desc != item.data_descriptors() { - return false; - } - } - - true + crate::cli::cli() } diff --git a/src/object/base.rs b/src/object/base.rs index dae2d2e4e1..b3cc291f2a 100644 --- a/src/object/base.rs +++ b/src/object/base.rs @@ -1,6 +1,7 @@ use crate::errors::ShellError; use crate::object::desc::DataDescriptor; use crate::parser::parse::Operator; +use crate::prelude::*; use ansi_term::Color; use chrono::{DateTime, Utc}; use chrono_humanize::Humanize; @@ -75,21 +76,21 @@ impl Value { } } - crate fn get_data_by_key(&'a self, name: &str) -> crate::MaybeOwned<'a, Value> { + crate fn get_data_by_key(&'a self, name: &str) -> MaybeOwned<'a, Value> { match self { - Value::Primitive(_) => crate::MaybeOwned::Owned(Value::nothing()), + Value::Primitive(_) => MaybeOwned::Owned(Value::nothing()), Value::Object(o) => o.get_data_by_key(name), - Value::List(_) => crate::MaybeOwned::Owned(Value::nothing()), - Value::Error(_) => crate::MaybeOwned::Owned(Value::nothing()), + Value::List(_) => MaybeOwned::Owned(Value::nothing()), + Value::Error(_) => MaybeOwned::Owned(Value::nothing()), } } - crate fn get_data(&'a self, desc: &DataDescriptor) -> crate::MaybeOwned<'a, Value> { + crate fn get_data(&'a self, desc: &DataDescriptor) -> MaybeOwned<'a, Value> { match self { - Value::Primitive(_) => crate::MaybeOwned::Owned(Value::nothing()), + Value::Primitive(_) => MaybeOwned::Owned(Value::nothing()), Value::Object(o) => o.get_data(desc), - Value::List(_) => crate::MaybeOwned::Owned(Value::nothing()), - Value::Error(_) => crate::MaybeOwned::Owned(Value::nothing()), + Value::List(_) => MaybeOwned::Owned(Value::nothing()), + Value::Error(_) => MaybeOwned::Owned(Value::nothing()), } } diff --git a/src/object/dict.rs b/src/object/dict.rs index 3d561a0a19..52f981701b 100644 --- a/src/object/dict.rs +++ b/src/object/dict.rs @@ -1,9 +1,7 @@ -#[allow(unused)] use crate::prelude::*; use crate::object::desc::DataDescriptor; use crate::object::{Primitive, Value}; -use crate::MaybeOwned; use indexmap::IndexMap; use std::cmp::{Ordering, PartialOrd}; diff --git a/src/parser/completer.rs b/src/parser/completer.rs index 98328e96c1..a22ac3abaf 100644 --- a/src/parser/completer.rs +++ b/src/parser/completer.rs @@ -1,9 +1,10 @@ +use crate::prelude::*; use rustyline::{completion, Context}; use std::collections::BTreeMap; #[allow(unused)] crate struct Completer { - commands: BTreeMap>, + commands: BTreeMap>, } impl completion::Completer for Completer { diff --git a/src/prelude.rs b/src/prelude.rs index a0eb2b3d21..0480c26932 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,4 +1,6 @@ -crate use crate::commands::command::{Command, CommandArgs, ReturnValue}; +crate use crate::cli::MaybeOwned; +crate use crate::commands::command::{Command, CommandAction, CommandArgs, ReturnValue}; +crate use crate::context::Context; crate use crate::env::{Environment, Host}; crate use crate::errors::ShellError; crate use crate::object::{Primitive, Value}; diff --git a/src/stream.rs b/src/stream.rs new file mode 100644 index 0000000000..e69de29bb2