Restructure and make commands uniform

This commit is contained in:
Yehuda Katz 2019-05-22 00:12:03 -07:00
parent 362ca18f88
commit 261d7a793f
22 changed files with 776 additions and 416 deletions

490
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -9,15 +9,15 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
rustyline = "4.0.0" rustyline = "4.1.0"
sysinfo = "0.8.3" sysinfo = "0.8.4"
chrono = "0.4.6" chrono = "0.4.6"
chrono-tz = "0.5.1" chrono-tz = "0.5.1"
derive-new = "0.5.6" derive-new = "0.5.6"
prettytable-rs = "0.8.0" prettytable-rs = "0.8.0"
itertools = "0.8.0" itertools = "0.8.0"
ansi_term = "0.11.0" ansi_term = "0.11.0"
conch-parser = "0.1.0" conch-parser = "0.1.1"
nom = "5.0.0-beta1" nom = "5.0.0-beta1"
subprocess = "0.1.18" subprocess = "0.1.18"
dunce = "1.0.0" dunce = "1.0.0"
@ -28,3 +28,4 @@ chrono-humanize = "0.0.11"
byte-unit = "2.1.0" byte-unit = "2.1.0"
ordered-float = "1.0.2" ordered-float = "1.0.2"
prettyprint = "0.6.0" prettyprint = "0.6.0"
cursive = { version = "0.12.0", features = ["pancurses-backend"], default-features = false }

View file

@ -1,5 +1,6 @@
crate mod args; crate mod args;
crate mod cd; crate mod cd;
crate mod classified;
crate mod command; crate mod command;
crate mod ls; crate mod ls;
crate mod ps; crate mod ps;
@ -12,4 +13,4 @@ crate mod to_array;
crate mod view; crate mod view;
crate mod where_; crate mod where_;
crate use to_array::to_array; crate use to_array::stream_to_array;

View file

@ -1,25 +1,19 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::prelude::*; use crate::prelude::*;
use derive_new::new;
use std::env; use std::env;
#[derive(new)] pub fn cd(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
pub struct Cd; let target = match args.args.first() {
// TODO: This needs better infra
None => return Err(ShellError::string(format!("cd must take one arg"))),
Some(v) => v.as_string()?.clone(),
};
impl crate::Command for Cd { let cwd = args.env.cwd().to_path_buf();
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
let target = match args.args.first() {
// TODO: This needs better infra
None => return Err(ShellError::string(format!("cd must take one arg"))),
Some(v) => v.as_string()?.clone(),
};
let cwd = args.env.cwd().to_path_buf(); let mut stream = VecDeque::new();
let path = dunce::canonicalize(cwd.join(&target).as_path())?;
let mut stream = VecDeque::new(); let _ = env::set_current_dir(&path);
let path = dunce::canonicalize(cwd.join(&target).as_path())?; stream.push_back(ReturnValue::change_cwd(path));
let _ = env::set_current_dir(&path); Ok(stream)
stream.push_back(ReturnValue::change_cwd(path));
Ok(stream)
}
} }

View file

@ -0,0 +1,55 @@
use crate::prelude::*;
use std::sync::Arc;
use subprocess::Exec;
crate enum ClassifiedCommand {
Internal(InternalCommand),
External(ExternalCommand),
}
impl ClassifiedCommand {
crate fn run(
self,
input: VecDeque<Value>,
context: &mut crate::Context,
) -> Result<VecDeque<Value>, ShellError> {
match self {
ClassifiedCommand::Internal(internal) => {
let result = context.run_command(internal.command, internal.args, input)?;
let mut next = VecDeque::new();
for v in result {
match v {
ReturnValue::Action(action) => match action {
crate::CommandAction::ChangeCwd(cwd) => context.env.cwd = cwd,
},
ReturnValue::Value(v) => next.push_back(v),
}
}
Ok(next)
}
ClassifiedCommand::External(external) => {
Exec::shell(&external.name)
.args(&external.args)
.cwd(context.env.cwd())
.join()
.unwrap();
Ok(VecDeque::new())
}
}
}
}
crate struct InternalCommand {
crate command: Arc<dyn Command>,
crate args: Vec<Value>,
}
crate struct ExternalCommand {
crate name: String,
crate args: Vec<String>,
}

View file

@ -1,22 +1,29 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::Value; use crate::object::Value;
use crate::prelude::*; use crate::prelude::*;
use crate::Context;
use std::path::PathBuf; use std::path::PathBuf;
pub struct CommandArgs<'caller> { pub struct CommandArgs<'caller> {
pub host: &'caller dyn Host, pub host: &'caller mut dyn Host,
pub env: &'caller crate::Environment, pub env: &'caller crate::Environment,
pub args: Vec<Value>, pub args: Vec<Value>,
pub input: VecDeque<Value>, pub input: VecDeque<Value>,
} }
pub trait CommandBlueprint { impl CommandArgs<'caller> {
fn create( crate fn from_context(
&self, ctx: &'caller mut Context,
input: Vec<Value>, args: Vec<Value>,
host: &dyn crate::Host, input: VecDeque<Value>,
env: &mut crate::Environment, ) -> CommandArgs<'caller> {
) -> Result<Box<dyn Command>, ShellError>; CommandArgs {
host: &mut ctx.host,
env: &ctx.env,
args,
input,
}
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -45,3 +52,12 @@ impl ReturnValue {
pub trait Command { pub trait Command {
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError>; fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError>;
} }
impl<F> Command for F
where
F: Fn(CommandArgs<'_>) -> Result<VecDeque<ReturnValue>, ShellError>,
{
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
self(args)
}
}

View file

@ -1,25 +1,18 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::{dir_entry_dict, Value}; use crate::object::{dir_entry_dict, Value};
use crate::prelude::*; use crate::prelude::*;
use derive_new::new;
#[derive(new)] pub fn ls(args: CommandArgs<'value>) -> Result<VecDeque<ReturnValue>, ShellError> {
pub struct Ls; let cwd = args.env.cwd().to_path_buf();
impl crate::Command for Ls { let entries = std::fs::read_dir(&cwd).map_err(|e| ShellError::string(format!("{:?}", e)))?;
fn run(&self, args: CommandArgs<'value>) -> Result<VecDeque<ReturnValue>, ShellError> {
let cwd = args.env.cwd().to_path_buf();
let entries = let mut shell_entries = VecDeque::new();
std::fs::read_dir(&cwd).map_err(|e| ShellError::string(format!("{:?}", e)))?;
let mut shell_entries = VecDeque::new(); for entry in entries {
let value = Value::Object(dir_entry_dict(&entry?)?);
for entry in entries { shell_entries.push_back(ReturnValue::Value(value))
let value = Value::Object(dir_entry_dict(&entry?)?);
shell_entries.push_back(ReturnValue::Value(value))
}
Ok(shell_entries)
} }
Ok(shell_entries)
} }

View file

@ -2,24 +2,18 @@ use crate::errors::ShellError;
use crate::object::process::process_dict; use crate::object::process::process_dict;
use crate::object::Value; use crate::object::Value;
use crate::prelude::*; use crate::prelude::*;
use derive_new::new;
use sysinfo::SystemExt; use sysinfo::SystemExt;
#[derive(new)] pub fn ps(_args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
pub struct Ps; let mut system = sysinfo::System::new();
system.refresh_all();
impl crate::Command for Ps { let list = system.get_process_list();
fn run(&self, _args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
let mut system = sysinfo::System::new();
system.refresh_all();
let list = system.get_process_list(); let list = list
.into_iter()
.map(|(_, process)| ReturnValue::Value(Value::Object(process_dict(process))))
.collect::<VecDeque<_>>();
let list = list Ok(list)
.into_iter()
.map(|(_, process)| ReturnValue::Value(Value::Object(process_dict(process))))
.collect::<VecDeque<_>>();
Ok(list)
}
} }

View file

@ -1,28 +1,22 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::base::reject; use crate::object::base::reject_fields;
use crate::object::Value; use crate::object::Value;
use crate::prelude::*; use crate::prelude::*;
use derive_new::new;
#[derive(new)] pub fn reject(args: CommandArgs<'value>) -> Result<VecDeque<ReturnValue>, ShellError> {
pub struct Reject; if args.args.is_empty() {
return Err(ShellError::string("select requires a field"));
impl crate::Command for Reject {
fn run(&self, args: CommandArgs<'value>) -> Result<VecDeque<ReturnValue>, ShellError> {
if args.args.is_empty() {
return Err(ShellError::string("select requires a field"));
}
let fields: Result<Vec<String>, _> = args.args.iter().map(|a| a.as_string()).collect();
let fields = fields?;
let objects = args
.input
.iter()
.map(|item| Value::Object(reject(item, &fields)))
.map(|item| ReturnValue::Value(item))
.collect();
Ok(objects)
} }
let fields: Result<Vec<String>, _> = args.args.iter().map(|a| a.as_string()).collect();
let fields = fields?;
let objects = args
.input
.iter()
.map(|item| Value::Object(reject_fields(item, &fields)))
.map(|item| ReturnValue::Value(item))
.collect();
Ok(objects)
} }

View file

@ -1,28 +1,22 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::base::select; use crate::object::base::select_fields;
use crate::object::Value; use crate::object::Value;
use crate::prelude::*; use crate::prelude::*;
use derive_new::new;
#[derive(new)] pub fn select(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
pub struct Select; if args.args.is_empty() {
return Err(ShellError::string("select requires a field"));
impl crate::Command for Select {
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
if args.args.is_empty() {
return Err(ShellError::string("select requires a field"));
}
let fields: Result<Vec<String>, _> = args.args.iter().map(|a| a.as_string()).collect();
let fields = fields?;
let objects = args
.input
.iter()
.map(|item| Value::Object(select(item, &fields)))
.map(|item| ReturnValue::Value(item))
.collect();
Ok(objects)
} }
let fields: Result<Vec<String>, _> = args.args.iter().map(|a| a.as_string()).collect();
let fields = fields?;
let objects = args
.input
.iter()
.map(|item| Value::Object(select_fields(item, &fields)))
.map(|item| ReturnValue::Value(item))
.collect();
Ok(objects)
} }

View file

@ -1,29 +1,21 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::prelude::*; use crate::prelude::*;
use derive_new::new;
#[derive(new)] pub fn skip(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
pub struct Skip; let amount = args.args[0].as_int()?;
// TODO: "Amount remaining" wrapper let amount = if args.input.len() > amount as usize {
amount as usize
} else {
args.input.len()
};
impl crate::Command for Skip { let out: VecDeque<ReturnValue> = args
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> { .input
let amount = args.args[0].as_int()?; .into_iter()
.skip(amount)
.map(|v| ReturnValue::Value(v))
.collect();
let amount = if args.input.len() > amount as usize { Ok(out)
amount as usize
} else {
args.input.len()
};
let out: VecDeque<ReturnValue> = args
.input
.into_iter()
.skip(amount)
.map(|v| ReturnValue::Value(v))
.collect();
Ok(out)
}
} }

View file

@ -1,29 +1,23 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::prelude::*; use crate::prelude::*;
use derive_new::new;
#[derive(new)] pub fn sort_by(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
pub struct SortBy; let fields: Result<Vec<_>, _> = args.args.iter().map(|a| a.as_string()).collect();
let fields = fields?;
impl crate::Command for SortBy { let mut output = args.input.into_iter().collect::<Vec<_>>();
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
let fields: Result<Vec<_>, _> = args.args.iter().map(|a| a.as_string()).collect();
let fields = fields?;
let mut output = args.input.into_iter().collect::<Vec<_>>(); output.sort_by_key(|item| {
fields
output.sort_by_key(|item| {
fields
.iter()
.map(|f| item.get_data_by_key(f).borrow().copy())
.collect::<Vec<Value>>()
});
let output = output
.iter() .iter()
.map(|o| ReturnValue::Value(o.copy())) .map(|f| item.get_data_by_key(f).borrow().copy())
.collect(); .collect::<Vec<Value>>()
});
Ok(output) let output = output
} .iter()
.map(|o| ReturnValue::Value(o.copy()))
.collect();
Ok(output)
} }

View file

@ -1,29 +1,23 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::prelude::*; use crate::prelude::*;
use derive_new::new;
#[derive(new)]
pub struct Take;
// TODO: "Amount remaining" wrapper // TODO: "Amount remaining" wrapper
impl crate::Command for Take { pub fn take(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> { let amount = args.args[0].as_int()?;
let amount = args.args[0].as_int()?;
let amount = if args.input.len() > amount as usize { let amount = if args.input.len() > amount as usize {
amount as usize amount as usize
} else { } else {
args.input.len() args.input.len()
}; };
let out: VecDeque<ReturnValue> = args let out: VecDeque<ReturnValue> = args
.input .input
.into_iter() .into_iter()
.take(amount) .take(amount)
.map(|v| ReturnValue::Value(v)) .map(|v| ReturnValue::Value(v))
.collect(); .collect();
Ok(out) Ok(out)
}
} }

View file

@ -1,19 +1,13 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::Value; use crate::object::Value;
use crate::prelude::*; use crate::prelude::*;
use derive_new::new;
#[derive(new)] pub fn to_array(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
pub struct ToArray; let out = args.input.into_iter().collect();
Ok(ReturnValue::single(Value::List(out)))
impl crate::Command for ToArray {
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
let out = args.input.into_iter().collect();
Ok(ReturnValue::single(Value::List(out)))
}
} }
crate fn to_array(stream: VecDeque<Value>) -> VecDeque<Value> { crate fn stream_to_array(stream: VecDeque<Value>) -> VecDeque<Value> {
let out = Value::List(stream.into_iter().collect()); let out = Value::List(stream.into_iter().collect());
let mut stream = VecDeque::new(); let mut stream = VecDeque::new();
stream.push_back(out); stream.push_back(out);

View file

@ -1,32 +1,26 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::prelude::*; use crate::prelude::*;
use derive_new::new;
use prettyprint::PrettyPrinter; use prettyprint::PrettyPrinter;
#[derive(new)] pub fn view(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
pub struct View; let target = match args.args.first() {
// TODO: This needs better infra
None => return Err(ShellError::string(format!("cat must take one arg"))),
Some(v) => v.as_string()?.clone(),
};
impl crate::Command for View { let cwd = args.env.cwd().to_path_buf();
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
let target = match args.args.first() {
// TODO: This needs better infra
None => return Err(ShellError::string(format!("cat must take one arg"))),
Some(v) => v.as_string()?.clone(),
};
let cwd = args.env.cwd().to_path_buf(); let printer = PrettyPrinter::default()
.line_numbers(false)
.header(false)
.grid(false)
.build()
.map_err(|e| ShellError::string(e))?;
let printer = PrettyPrinter::default() let file = cwd.join(target);
.line_numbers(false)
.header(false)
.grid(false)
.build()
.map_err(|e| ShellError::string(e))?;
let file = cwd.join(target); let _ = printer.file(file.display().to_string());
let _ = printer.file(file.display().to_string()); Ok(VecDeque::new())
Ok(VecDeque::new())
}
} }

View file

@ -1,35 +1,29 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::base::find; use crate::object::base::find;
use crate::prelude::*; use crate::prelude::*;
use derive_new::new;
#[derive(new)] pub fn r#where(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
pub struct Where; if args.args.is_empty() {
return Err(ShellError::string("select requires a field"));
}
impl crate::Command for Where { let field: Result<String, _> = args.args[0].as_string();
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> { let field = field?;
if args.args.is_empty() {
return Err(ShellError::string("select requires a field")); match args.args[1] {
Value::Primitive(Primitive::Operator(ref operator)) => {
let objects = args
.input
.iter()
.filter(|item| find(&item, &field, operator, &args.args[2]))
.map(|item| ReturnValue::Value(item.copy()))
.collect();
Ok(objects)
} }
ref x => {
let field: Result<String, _> = args.args[0].as_string(); println!("{:?}", x);
let field = field?; Err(ShellError::string("expected a comparison operator"))
match args.args[1] {
Value::Primitive(Primitive::Operator(ref operator)) => {
let objects = args
.input
.iter()
.filter(|item| find(&item, &field, operator, &args.args[2]))
.map(|item| ReturnValue::Value(item.copy()))
.collect();
Ok(objects)
}
ref x => {
println!("{:?}", x);
Err(ShellError::string("expected a comparison operator"))
}
} }
} }
} }

View file

@ -1,9 +1,10 @@
use crate::prelude::*; use crate::prelude::*;
use std::error::Error; use std::error::Error;
use std::sync::Arc;
pub struct Context { pub struct Context {
commands: indexmap::IndexMap<String, Box<dyn crate::Command>>, commands: indexmap::IndexMap<String, Arc<dyn crate::Command>>,
crate host: Box<dyn crate::Host>, crate host: Box<dyn crate::Host>,
crate env: Environment, crate env: Environment,
} }
@ -17,35 +18,33 @@ impl Context {
}) })
} }
pub fn add_commands(&mut self, commands: Vec<(&str, Box<dyn crate::Command>)>) { pub fn add_commands(&mut self, commands: Vec<(&str, Arc<dyn crate::Command>)>) {
for (name, command) in commands { for (name, command) in commands {
self.commands.insert(name.to_string(), command); self.commands.insert(name.to_string(), command);
} }
} }
crate fn has_command(&mut self, name: &str) -> bool { crate fn has_command(&self, name: &str) -> bool {
self.commands.contains_key(name) self.commands.contains_key(name)
} }
crate fn get_command(&self, name: &str) -> Arc<dyn Command> {
self.commands.get(name).unwrap().clone()
}
crate fn run_command( crate fn run_command(
&self, &mut self,
name: &str, command: Arc<dyn Command>,
arg_list: Vec<Value>, arg_list: Vec<Value>,
input: VecDeque<Value>, input: VecDeque<Value>,
) -> Result<VecDeque<ReturnValue>, ShellError> { ) -> Result<VecDeque<ReturnValue>, ShellError> {
let command_args = CommandArgs { let command_args = CommandArgs {
host: &self.host, host: &mut self.host,
env: &self.env, env: &self.env,
args: arg_list, args: arg_list,
input, input,
}; };
match self.commands.get(name) { command.run(command_args)
None => Err(ShellError::string(format!(
"Command {} did not exist",
name
))),
Some(command) => command.run(command_args),
}
} }
} }

View file

@ -5,9 +5,6 @@ crate mod table;
use crate::prelude::*; use crate::prelude::*;
use crate::Context;
use std::sync::{Arc, Mutex};
crate use entries::{EntriesListView, EntriesView}; crate use entries::{EntriesListView, EntriesView};
crate use generic::GenericView; crate use generic::GenericView;
crate use table::TableView; crate use table::TableView;
@ -22,7 +19,7 @@ fn print_rendered(lines: &[String], host: &mut dyn Host) {
} }
} }
crate fn print_view(view: &impl RenderView, context: Arc<Mutex<Context>>) { crate fn print_view(view: &impl RenderView, host: &mut Host) {
let mut ctx = context.lock().unwrap(); // let mut ctx = context.lock().unwrap();
crate::format::print_rendered(&view.render_view(&ctx.host), &mut ctx.host); crate::format::print_rendered(&view.render_view(host), host);
} }

View file

@ -14,8 +14,9 @@ mod parser;
mod prelude; mod prelude;
mod shell; mod shell;
use crate::commands::classified::{ClassifiedCommand, ExternalCommand, InternalCommand};
use crate::commands::command::ReturnValue; use crate::commands::command::ReturnValue;
crate use crate::commands::command::{Command, CommandAction, CommandBlueprint}; crate use crate::commands::command::{Command, CommandAction};
use crate::context::Context; use crate::context::Context;
crate use crate::env::{Environment, Host}; crate use crate::env::{Environment, Host};
crate use crate::errors::ShellError; crate use crate::errors::ShellError;
@ -26,8 +27,7 @@ use rustyline::error::ReadlineError;
use rustyline::{self, ColorMode, Config, Editor}; use rustyline::{self, ColorMode, Config, Editor};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::error::Error; use std::error::Error;
use std::sync::{Arc, Mutex}; use std::sync::Arc;
use subprocess::Exec;
#[derive(Debug)] #[derive(Debug)]
pub enum MaybeOwned<'a, T> { pub enum MaybeOwned<'a, T> {
@ -59,39 +59,38 @@ fn main() -> Result<(), Box<Error>> {
println!("No previous history."); println!("No previous history.");
} }
let context = Arc::new(Mutex::new(Context::basic()?)); let mut context = Context::basic()?;
{ {
use crate::commands::*; use crate::commands::*;
context.lock().unwrap().add_commands(vec![ context.add_commands(vec![
("ps", Box::new(ps::Ps)), ("format", Arc::new(format)),
("ls", Box::new(ls::Ls)), ("format-list", Arc::new(format_list)),
("cd", Box::new(cd::Cd)), ("ps", Arc::new(ps::ps)),
("view", Box::new(view::View)), ("ls", Arc::new(ls::ls)),
("skip", Box::new(skip::Skip)), ("cd", Arc::new(cd::cd)),
("take", Box::new(take::Take)), ("view", Arc::new(view::view)),
("select", Box::new(select::Select)), ("skip", Arc::new(skip::skip)),
("reject", Box::new(reject::Reject)), ("take", Arc::new(take::take)),
("to-array", Box::new(to_array::ToArray)), ("select", Arc::new(select::select)),
("where", Box::new(where_::Where)), ("reject", Arc::new(reject::reject)),
("sort-by", Box::new(sort_by::SortBy)), ("to-array", Arc::new(to_array::to_array)),
("where", Arc::new(where_::r#where)),
("sort-by", Arc::new(sort_by::sort_by)),
]); ]);
} }
loop { loop {
let readline = rl.readline(&format!( let readline = rl.readline(&format!("{}> ", context.env.cwd().display().to_string()));
"{}> ",
context.lock().unwrap().env.cwd().display().to_string()
));
match process_line(readline, context.clone()) { match process_line(readline, &mut context) {
LineResult::Success(line) => { LineResult::Success(line) => {
rl.add_history_entry(line.clone()); rl.add_history_entry(line.clone());
} }
LineResult::Error(err) => { LineResult::Error(err) => {
context.lock().unwrap().host.stdout(&err); context.host.stdout(&err);
} }
LineResult::Break => { LineResult::Break => {
@ -100,8 +99,6 @@ fn main() -> Result<(), Box<Error>> {
LineResult::FatalError(err) => { LineResult::FatalError(err) => {
context context
.lock()
.unwrap()
.host .host
.stdout(&format!("A surprising fatal error occurred.\n{:?}", err)); .stdout(&format!("A surprising fatal error occurred.\n{:?}", err));
} }
@ -121,10 +118,7 @@ enum LineResult {
FatalError(ShellError), FatalError(ShellError),
} }
fn process_line( fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context) -> LineResult {
readline: Result<String, ReadlineError>,
context: Arc<Mutex<Context>>,
) -> LineResult {
match &readline { match &readline {
Ok(line) if line.trim() == "exit" => LineResult::Break, Ok(line) if line.trim() == "exit" => LineResult::Break,
@ -144,11 +138,7 @@ fn process_line(
let mut input = VecDeque::new(); let mut input = VecDeque::new();
for item in parsed { for item in parsed {
input = match process_command( input = match process_command(item.clone(), input, ctx) {
item.clone(),
input,
context.clone(),
) {
Ok(val) => val, Ok(val) => val,
Err(err) => return LineResult::Error(format!("{}", err.description())), Err(err) => return LineResult::Error(format!("{}", err.description())),
}; };
@ -156,9 +146,18 @@ fn process_line(
if input.len() > 0 { if input.len() > 0 {
if equal_shapes(&input) { if equal_shapes(&input) {
format(crate::commands::to_array(input), context.clone()); 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 { } else {
format(input, context.clone()); let args = CommandArgs::from_context(ctx, vec![], input);
match format(args) {
Ok(_) => {}
Err(err) => return LineResult::Error(err.to_string()),
}
} }
} }
@ -182,69 +181,58 @@ fn process_line(
fn process_command( fn process_command(
parsed: Vec<crate::parser::Item>, parsed: Vec<crate::parser::Item>,
input: VecDeque<Value>, input: VecDeque<Value>,
context: Arc<Mutex<Context>>, context: &mut Context,
) -> Result<VecDeque<Value>, ShellError> { ) -> Result<VecDeque<Value>, ShellError> {
let command = &parsed[0].name()?; let command = classify_command(&parsed, context)?;
let arg_list = parsed[1..].iter().map(|i| i.as_value()).collect();
let arg_list_strings: Vec<String> = parsed[1..].iter().map(|i| i.print()).collect();
if command == &"format" { command.run(input, context)
format(input, context); }
Ok(VecDeque::new()) fn classify_command(
} else if command == &"format-list" { command: &[crate::parser::Item],
let view = EntriesListView::from_stream(input); context: &Context,
) -> Result<ClassifiedCommand, ShellError> {
let command_name = &command[0].name()?;
crate::format::print_view(&view, context.clone()); let arg_list: Vec<Value> = command[1..].iter().map(|i| i.as_value()).collect();
let arg_list_strings: Vec<String> = command[1..].iter().map(|i| i.print()).collect();
Ok(VecDeque::new()) match *command_name {
} else { other => match context.has_command(*command_name) {
let mut ctx = context.lock().unwrap();
match ctx.has_command(*command) {
true => { true => {
// let mut instance = ctx.create_command(command, arg_list)?; let command = context.get_command(command_name);
Ok(ClassifiedCommand::Internal(InternalCommand {
let result = ctx.run_command(command, arg_list, input)?; command,
args: arg_list,
// let result = command.run(input_args)?; }))
let mut next = VecDeque::new();
for v in result {
match v {
ReturnValue::Action(action) => match action {
crate::CommandAction::ChangeCwd(cwd) => ctx.env.cwd = cwd,
},
ReturnValue::Value(v) => next.push_back(v),
}
}
Ok(next)
} }
false => Ok(ClassifiedCommand::External(ExternalCommand {
false => { name: other.to_string(),
Exec::shell(command) args: arg_list_strings,
.args(&arg_list_strings) })),
.cwd(ctx.env.cwd()) },
.join()
.unwrap();
Ok(VecDeque::new())
}
}
} }
} }
fn format(input: VecDeque<Value>, context: Arc<Mutex<Context>>) { fn format(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
let last = input.len() - 1; let last = args.input.len() - 1;
for (i, item) in input.iter().enumerate() { for (i, item) in args.input.iter().enumerate() {
let view = GenericView::new(item); let view = GenericView::new(item);
crate::format::print_view(&view, context.clone()); crate::format::print_view(&view, args.host);
if last != i { if last != i {
println!(""); println!("");
} }
} }
Ok(VecDeque::new())
}
fn format_list(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
let view = EntriesListView::from_stream(args.input);
crate::format::print_view(&view, args.host);
Ok(VecDeque::new())
} }
fn equal_shapes(input: &VecDeque<Value>) -> bool { fn equal_shapes(input: &VecDeque<Value>) -> bool {

View file

@ -1,11 +1,11 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::desc::DataDescriptor; use crate::object::desc::DataDescriptor;
use crate::parser::parse::Operator;
use ansi_term::Color; use ansi_term::Color;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use chrono_humanize::Humanize; use chrono_humanize::Humanize;
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use std::time::SystemTime; use std::time::SystemTime;
use crate::parser::parse::Operator;
type OF64 = OrderedFloat<f64>; type OF64 = OrderedFloat<f64>;
@ -50,7 +50,7 @@ impl Primitive {
(false, Some(_)) => format!(""), (false, Some(_)) => format!(""),
}, },
Primitive::Date(d) => format!("{}", d.humanize()), Primitive::Date(d) => format!("{}", d.humanize()),
Primitive::Operator(o) => o.print() Primitive::Operator(o) => o.print(),
} }
} }
} }
@ -196,7 +196,7 @@ impl Value {
} }
} }
crate fn select(obj: &Value, fields: &[String]) -> crate::object::Dictionary { crate fn select_fields(obj: &Value, fields: &[String]) -> crate::object::Dictionary {
let mut out = crate::object::Dictionary::default(); let mut out = crate::object::Dictionary::default();
let descs = obj.data_descriptors(); let descs = obj.data_descriptors();
@ -211,7 +211,7 @@ crate fn select(obj: &Value, fields: &[String]) -> crate::object::Dictionary {
out out
} }
crate fn reject(obj: &Value, fields: &[String]) -> crate::object::Dictionary { crate fn reject_fields(obj: &Value, fields: &[String]) -> crate::object::Dictionary {
let mut out = crate::object::Dictionary::default(); let mut out = crate::object::Dictionary::default();
let descs = obj.data_descriptors(); let descs = obj.data_descriptors();
@ -243,18 +243,28 @@ crate fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool {
}, },
Value::Primitive(Primitive::Bytes(i)) => match (op, rhs) { Value::Primitive(Primitive::Bytes(i)) => match (op, rhs) {
(Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => i < (*i2 as u128), (Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => i < (*i2 as u128),
(Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => i > (*i2 as u128), (Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => {
(Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i <= (*i2 as u128), i > (*i2 as u128)
(Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i >= (*i2 as u128), }
(Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => {
i <= (*i2 as u128)
}
(Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => {
i >= (*i2 as u128)
}
(Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i == (*i2 as u128), (Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i == (*i2 as u128),
(Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => i != (*i2 as u128), (Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => {
i != (*i2 as u128)
}
_ => false, _ => false,
}, },
Value::Primitive(Primitive::Int(i)) => match (op, rhs) { Value::Primitive(Primitive::Int(i)) => match (op, rhs) {
(Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => i < *i2, (Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => i < *i2,
(Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => i > *i2, (Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => i > *i2,
(Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i <= *i2, (Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i <= *i2,
(Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i >= *i2, (Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => {
i >= *i2
}
(Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i == *i2, (Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i == *i2,
(Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => i != *i2, (Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => i != *i2,
_ => false, _ => false,
@ -263,15 +273,29 @@ crate fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool {
(Operator::LessThan, Value::Primitive(Primitive::Float(i2))) => i < *i2, (Operator::LessThan, Value::Primitive(Primitive::Float(i2))) => i < *i2,
(Operator::GreaterThan, Value::Primitive(Primitive::Float(i2))) => i > *i2, (Operator::GreaterThan, Value::Primitive(Primitive::Float(i2))) => i > *i2,
(Operator::LessThanOrEqual, Value::Primitive(Primitive::Float(i2))) => i <= *i2, (Operator::LessThanOrEqual, Value::Primitive(Primitive::Float(i2))) => i <= *i2,
(Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Float(i2))) => i >= *i2, (Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Float(i2))) => {
i >= *i2
}
(Operator::Equal, Value::Primitive(Primitive::Float(i2))) => i == *i2, (Operator::Equal, Value::Primitive(Primitive::Float(i2))) => i == *i2,
(Operator::NotEqual, Value::Primitive(Primitive::Float(i2))) => i != *i2, (Operator::NotEqual, Value::Primitive(Primitive::Float(i2))) => i != *i2,
(Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => (i.into_inner()) < *i2 as f64, (Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => {
(Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => i.into_inner() > *i2 as f64, (i.into_inner()) < *i2 as f64
(Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i.into_inner() <= *i2 as f64, }
(Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i.into_inner() >= *i2 as f64, (Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => {
(Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i.into_inner() == *i2 as f64, i.into_inner() > *i2 as f64
(Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => i.into_inner() != *i2 as f64, }
(Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => {
i.into_inner() <= *i2 as f64
}
(Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => {
i.into_inner() >= *i2 as f64
}
(Operator::Equal, Value::Primitive(Primitive::Int(i2))) => {
i.into_inner() == *i2 as f64
}
(Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => {
i.into_inner() != *i2 as f64
}
_ => false, _ => false,
}, },

View file

@ -3,7 +3,7 @@ use std::collections::BTreeMap;
#[allow(unused)] #[allow(unused)]
crate struct Completer { crate struct Completer {
commands: BTreeMap<String, Box<dyn crate::CommandBlueprint>>, commands: BTreeMap<String, Box<dyn crate::Command>>,
} }
impl completion::Completer for Completer { impl completion::Completer for Completer {

View file

@ -1,4 +1,4 @@
crate use crate::commands::command::{CommandArgs, ReturnValue}; crate use crate::commands::command::{Command, CommandArgs, ReturnValue};
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};