mirror of
https://github.com/nushell/nushell.git
synced 2024-11-25 09:53:43 +01:00
Restructure and make commands uniform
This commit is contained in:
parent
362ca18f88
commit
261d7a793f
490
Cargo.lock
generated
490
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -9,15 +9,15 @@ edition = "2018"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rustyline = "4.0.0"
|
||||
sysinfo = "0.8.3"
|
||||
rustyline = "4.1.0"
|
||||
sysinfo = "0.8.4"
|
||||
chrono = "0.4.6"
|
||||
chrono-tz = "0.5.1"
|
||||
derive-new = "0.5.6"
|
||||
prettytable-rs = "0.8.0"
|
||||
itertools = "0.8.0"
|
||||
ansi_term = "0.11.0"
|
||||
conch-parser = "0.1.0"
|
||||
conch-parser = "0.1.1"
|
||||
nom = "5.0.0-beta1"
|
||||
subprocess = "0.1.18"
|
||||
dunce = "1.0.0"
|
||||
@ -28,3 +28,4 @@ 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 }
|
||||
|
@ -1,5 +1,6 @@
|
||||
crate mod args;
|
||||
crate mod cd;
|
||||
crate mod classified;
|
||||
crate mod command;
|
||||
crate mod ls;
|
||||
crate mod ps;
|
||||
@ -12,4 +13,4 @@ crate mod to_array;
|
||||
crate mod view;
|
||||
crate mod where_;
|
||||
|
||||
crate use to_array::to_array;
|
||||
crate use to_array::stream_to_array;
|
||||
|
@ -1,25 +1,19 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use std::env;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct Cd;
|
||||
pub fn cd(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(),
|
||||
};
|
||||
|
||||
impl crate::Command for Cd {
|
||||
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 cwd = args.env.cwd().to_path_buf();
|
||||
|
||||
let mut stream = VecDeque::new();
|
||||
let path = dunce::canonicalize(cwd.join(&target).as_path())?;
|
||||
let _ = env::set_current_dir(&path);
|
||||
stream.push_back(ReturnValue::change_cwd(path));
|
||||
Ok(stream)
|
||||
}
|
||||
let mut stream = VecDeque::new();
|
||||
let path = dunce::canonicalize(cwd.join(&target).as_path())?;
|
||||
let _ = env::set_current_dir(&path);
|
||||
stream.push_back(ReturnValue::change_cwd(path));
|
||||
Ok(stream)
|
||||
}
|
||||
|
55
src/commands/classified.rs
Normal file
55
src/commands/classified.rs
Normal 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>,
|
||||
}
|
@ -1,22 +1,29 @@
|
||||
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 dyn Host,
|
||||
pub host: &'caller mut dyn Host,
|
||||
pub env: &'caller crate::Environment,
|
||||
pub args: Vec<Value>,
|
||||
pub input: VecDeque<Value>,
|
||||
}
|
||||
|
||||
pub trait CommandBlueprint {
|
||||
fn create(
|
||||
&self,
|
||||
input: Vec<Value>,
|
||||
host: &dyn crate::Host,
|
||||
env: &mut crate::Environment,
|
||||
) -> Result<Box<dyn Command>, ShellError>;
|
||||
impl CommandArgs<'caller> {
|
||||
crate fn from_context(
|
||||
ctx: &'caller mut Context,
|
||||
args: Vec<Value>,
|
||||
input: VecDeque<Value>,
|
||||
) -> CommandArgs<'caller> {
|
||||
CommandArgs {
|
||||
host: &mut ctx.host,
|
||||
env: &ctx.env,
|
||||
args,
|
||||
input,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -45,3 +52,12 @@ impl ReturnValue {
|
||||
pub trait Command {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,18 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::{dir_entry_dict, Value};
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct Ls;
|
||||
pub fn ls(args: CommandArgs<'value>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
let cwd = args.env.cwd().to_path_buf();
|
||||
|
||||
impl crate::Command for Ls {
|
||||
fn run(&self, args: CommandArgs<'value>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
let cwd = args.env.cwd().to_path_buf();
|
||||
let entries = std::fs::read_dir(&cwd).map_err(|e| ShellError::string(format!("{:?}", e)))?;
|
||||
|
||||
let entries =
|
||||
std::fs::read_dir(&cwd).map_err(|e| ShellError::string(format!("{:?}", e)))?;
|
||||
let mut shell_entries = VecDeque::new();
|
||||
|
||||
let mut shell_entries = VecDeque::new();
|
||||
|
||||
for entry in entries {
|
||||
let value = Value::Object(dir_entry_dict(&entry?)?);
|
||||
shell_entries.push_back(ReturnValue::Value(value))
|
||||
}
|
||||
|
||||
Ok(shell_entries)
|
||||
for entry in entries {
|
||||
let value = Value::Object(dir_entry_dict(&entry?)?);
|
||||
shell_entries.push_back(ReturnValue::Value(value))
|
||||
}
|
||||
|
||||
Ok(shell_entries)
|
||||
}
|
||||
|
@ -2,24 +2,18 @@ use crate::errors::ShellError;
|
||||
use crate::object::process::process_dict;
|
||||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use sysinfo::SystemExt;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct Ps;
|
||||
pub fn ps(_args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
let mut system = sysinfo::System::new();
|
||||
system.refresh_all();
|
||||
|
||||
impl crate::Command for Ps {
|
||||
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 = system.get_process_list();
|
||||
let list = list
|
||||
.into_iter()
|
||||
.map(|(_, process)| ReturnValue::Value(Value::Object(process_dict(process))))
|
||||
.collect::<VecDeque<_>>();
|
||||
|
||||
let list = list
|
||||
.into_iter()
|
||||
.map(|(_, process)| ReturnValue::Value(Value::Object(process_dict(process))))
|
||||
.collect::<VecDeque<_>>();
|
||||
|
||||
Ok(list)
|
||||
}
|
||||
Ok(list)
|
||||
}
|
||||
|
@ -1,28 +1,22 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::base::reject;
|
||||
use crate::object::base::reject_fields;
|
||||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct Reject;
|
||||
|
||||
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)
|
||||
pub fn reject(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_fields(item, &fields)))
|
||||
.map(|item| ReturnValue::Value(item))
|
||||
.collect();
|
||||
|
||||
Ok(objects)
|
||||
}
|
||||
|
@ -1,28 +1,22 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::base::select;
|
||||
use crate::object::base::select_fields;
|
||||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct Select;
|
||||
|
||||
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)
|
||||
pub fn select(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_fields(item, &fields)))
|
||||
.map(|item| ReturnValue::Value(item))
|
||||
.collect();
|
||||
|
||||
Ok(objects)
|
||||
}
|
||||
|
@ -1,29 +1,21 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct Skip;
|
||||
pub fn skip(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
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 {
|
||||
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
let amount = args.args[0].as_int()?;
|
||||
let out: VecDeque<ReturnValue> = args
|
||||
.input
|
||||
.into_iter()
|
||||
.skip(amount)
|
||||
.map(|v| ReturnValue::Value(v))
|
||||
.collect();
|
||||
|
||||
let amount = if args.input.len() > amount as usize {
|
||||
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)
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
@ -1,29 +1,23 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct SortBy;
|
||||
pub fn sort_by(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
let fields: Result<Vec<_>, _> = args.args.iter().map(|a| a.as_string()).collect();
|
||||
let fields = fields?;
|
||||
|
||||
impl crate::Command for SortBy {
|
||||
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<_>>();
|
||||
|
||||
let mut output = args.input.into_iter().collect::<Vec<_>>();
|
||||
|
||||
output.sort_by_key(|item| {
|
||||
fields
|
||||
.iter()
|
||||
.map(|f| item.get_data_by_key(f).borrow().copy())
|
||||
.collect::<Vec<Value>>()
|
||||
});
|
||||
|
||||
let output = output
|
||||
output.sort_by_key(|item| {
|
||||
fields
|
||||
.iter()
|
||||
.map(|o| ReturnValue::Value(o.copy()))
|
||||
.collect();
|
||||
.map(|f| item.get_data_by_key(f).borrow().copy())
|
||||
.collect::<Vec<Value>>()
|
||||
});
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
let output = output
|
||||
.iter()
|
||||
.map(|o| ReturnValue::Value(o.copy()))
|
||||
.collect();
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
@ -1,29 +1,23 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct Take;
|
||||
|
||||
// TODO: "Amount remaining" wrapper
|
||||
|
||||
impl crate::Command for Take {
|
||||
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
let amount = args.args[0].as_int()?;
|
||||
pub fn take(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
let amount = args.args[0].as_int()?;
|
||||
|
||||
let amount = if args.input.len() > amount as usize {
|
||||
amount as usize
|
||||
} else {
|
||||
args.input.len()
|
||||
};
|
||||
let amount = if args.input.len() > amount as usize {
|
||||
amount as usize
|
||||
} else {
|
||||
args.input.len()
|
||||
};
|
||||
|
||||
let out: VecDeque<ReturnValue> = args
|
||||
.input
|
||||
.into_iter()
|
||||
.take(amount)
|
||||
.map(|v| ReturnValue::Value(v))
|
||||
.collect();
|
||||
let out: VecDeque<ReturnValue> = args
|
||||
.input
|
||||
.into_iter()
|
||||
.take(amount)
|
||||
.map(|v| ReturnValue::Value(v))
|
||||
.collect();
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
@ -1,19 +1,13 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct ToArray;
|
||||
|
||||
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)))
|
||||
}
|
||||
pub fn to_array(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 mut stream = VecDeque::new();
|
||||
stream.push_back(out);
|
||||
|
@ -1,32 +1,26 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use prettyprint::PrettyPrinter;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct View;
|
||||
pub fn view(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(),
|
||||
};
|
||||
|
||||
impl crate::Command for View {
|
||||
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 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()
|
||||
.line_numbers(false)
|
||||
.header(false)
|
||||
.grid(false)
|
||||
.build()
|
||||
.map_err(|e| ShellError::string(e))?;
|
||||
let file = cwd.join(target);
|
||||
|
||||
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())
|
||||
}
|
||||
|
@ -1,35 +1,29 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::base::find;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct Where;
|
||||
pub fn r#where(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
if args.args.is_empty() {
|
||||
return Err(ShellError::string("select requires a field"));
|
||||
}
|
||||
|
||||
impl crate::Command for Where {
|
||||
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
if args.args.is_empty() {
|
||||
return Err(ShellError::string("select requires a field"));
|
||||
let field: Result<String, _> = args.args[0].as_string();
|
||||
let field = 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)
|
||||
}
|
||||
|
||||
let field: Result<String, _> = args.args[0].as_string();
|
||||
let field = 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 => {
|
||||
println!("{:?}", x);
|
||||
Err(ShellError::string("expected a comparison operator"))
|
||||
}
|
||||
ref x => {
|
||||
println!("{:?}", x);
|
||||
Err(ShellError::string("expected a comparison operator"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
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 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 {
|
||||
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)
|
||||
}
|
||||
|
||||
crate fn get_command(&self, name: &str) -> Arc<dyn Command> {
|
||||
self.commands.get(name).unwrap().clone()
|
||||
}
|
||||
|
||||
crate fn run_command(
|
||||
&self,
|
||||
name: &str,
|
||||
&mut self,
|
||||
command: Arc<dyn Command>,
|
||||
arg_list: Vec<Value>,
|
||||
input: VecDeque<Value>,
|
||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
let command_args = CommandArgs {
|
||||
host: &self.host,
|
||||
host: &mut self.host,
|
||||
env: &self.env,
|
||||
args: arg_list,
|
||||
input,
|
||||
};
|
||||
|
||||
match self.commands.get(name) {
|
||||
None => Err(ShellError::string(format!(
|
||||
"Command {} did not exist",
|
||||
name
|
||||
))),
|
||||
Some(command) => command.run(command_args),
|
||||
}
|
||||
command.run(command_args)
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,6 @@ crate mod table;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::Context;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
crate use entries::{EntriesListView, EntriesView};
|
||||
crate use generic::GenericView;
|
||||
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>>) {
|
||||
let mut ctx = context.lock().unwrap();
|
||||
crate::format::print_rendered(&view.render_view(&ctx.host), &mut ctx.host);
|
||||
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);
|
||||
}
|
||||
|
152
src/main.rs
152
src/main.rs
@ -14,8 +14,9 @@ mod parser;
|
||||
mod prelude;
|
||||
mod shell;
|
||||
|
||||
use crate::commands::classified::{ClassifiedCommand, ExternalCommand, InternalCommand};
|
||||
use crate::commands::command::ReturnValue;
|
||||
crate use crate::commands::command::{Command, CommandAction, CommandBlueprint};
|
||||
crate use crate::commands::command::{Command, CommandAction};
|
||||
use crate::context::Context;
|
||||
crate use crate::env::{Environment, Host};
|
||||
crate use crate::errors::ShellError;
|
||||
@ -26,8 +27,7 @@ use rustyline::error::ReadlineError;
|
||||
use rustyline::{self, ColorMode, Config, Editor};
|
||||
use std::collections::VecDeque;
|
||||
use std::error::Error;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use subprocess::Exec;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MaybeOwned<'a, T> {
|
||||
@ -59,39 +59,38 @@ fn main() -> Result<(), Box<Error>> {
|
||||
println!("No previous history.");
|
||||
}
|
||||
|
||||
let context = Arc::new(Mutex::new(Context::basic()?));
|
||||
let mut context = Context::basic()?;
|
||||
|
||||
{
|
||||
use crate::commands::*;
|
||||
|
||||
context.lock().unwrap().add_commands(vec![
|
||||
("ps", Box::new(ps::Ps)),
|
||||
("ls", Box::new(ls::Ls)),
|
||||
("cd", Box::new(cd::Cd)),
|
||||
("view", Box::new(view::View)),
|
||||
("skip", Box::new(skip::Skip)),
|
||||
("take", Box::new(take::Take)),
|
||||
("select", Box::new(select::Select)),
|
||||
("reject", Box::new(reject::Reject)),
|
||||
("to-array", Box::new(to_array::ToArray)),
|
||||
("where", Box::new(where_::Where)),
|
||||
("sort-by", Box::new(sort_by::SortBy)),
|
||||
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.lock().unwrap().env.cwd().display().to_string()
|
||||
));
|
||||
let readline = rl.readline(&format!("{}> ", context.env.cwd().display().to_string()));
|
||||
|
||||
match process_line(readline, context.clone()) {
|
||||
match process_line(readline, &mut context) {
|
||||
LineResult::Success(line) => {
|
||||
rl.add_history_entry(line.clone());
|
||||
}
|
||||
|
||||
LineResult::Error(err) => {
|
||||
context.lock().unwrap().host.stdout(&err);
|
||||
context.host.stdout(&err);
|
||||
}
|
||||
|
||||
LineResult::Break => {
|
||||
@ -100,8 +99,6 @@ fn main() -> Result<(), Box<Error>> {
|
||||
|
||||
LineResult::FatalError(err) => {
|
||||
context
|
||||
.lock()
|
||||
.unwrap()
|
||||
.host
|
||||
.stdout(&format!("A surprising fatal error occurred.\n{:?}", err));
|
||||
}
|
||||
@ -121,10 +118,7 @@ enum LineResult {
|
||||
FatalError(ShellError),
|
||||
}
|
||||
|
||||
fn process_line(
|
||||
readline: Result<String, ReadlineError>,
|
||||
context: Arc<Mutex<Context>>,
|
||||
) -> LineResult {
|
||||
fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context) -> LineResult {
|
||||
match &readline {
|
||||
Ok(line) if line.trim() == "exit" => LineResult::Break,
|
||||
|
||||
@ -144,11 +138,7 @@ fn process_line(
|
||||
let mut input = VecDeque::new();
|
||||
|
||||
for item in parsed {
|
||||
input = match process_command(
|
||||
item.clone(),
|
||||
input,
|
||||
context.clone(),
|
||||
) {
|
||||
input = match process_command(item.clone(), input, ctx) {
|
||||
Ok(val) => val,
|
||||
Err(err) => return LineResult::Error(format!("{}", err.description())),
|
||||
};
|
||||
@ -156,9 +146,18 @@ fn process_line(
|
||||
|
||||
if input.len() > 0 {
|
||||
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 {
|
||||
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(
|
||||
parsed: Vec<crate::parser::Item>,
|
||||
input: VecDeque<Value>,
|
||||
context: Arc<Mutex<Context>>,
|
||||
context: &mut Context,
|
||||
) -> Result<VecDeque<Value>, ShellError> {
|
||||
let command = &parsed[0].name()?;
|
||||
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();
|
||||
let command = classify_command(&parsed, context)?;
|
||||
|
||||
if command == &"format" {
|
||||
format(input, context);
|
||||
command.run(input, context)
|
||||
}
|
||||
|
||||
Ok(VecDeque::new())
|
||||
} else if command == &"format-list" {
|
||||
let view = EntriesListView::from_stream(input);
|
||||
fn classify_command(
|
||||
command: &[crate::parser::Item],
|
||||
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())
|
||||
} else {
|
||||
let mut ctx = context.lock().unwrap();
|
||||
|
||||
match ctx.has_command(*command) {
|
||||
match *command_name {
|
||||
other => match context.has_command(*command_name) {
|
||||
true => {
|
||||
// let mut instance = ctx.create_command(command, arg_list)?;
|
||||
|
||||
let result = ctx.run_command(command, arg_list, input)?;
|
||||
|
||||
// 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)
|
||||
let command = context.get_command(command_name);
|
||||
Ok(ClassifiedCommand::Internal(InternalCommand {
|
||||
command,
|
||||
args: arg_list,
|
||||
}))
|
||||
}
|
||||
|
||||
false => {
|
||||
Exec::shell(command)
|
||||
.args(&arg_list_strings)
|
||||
.cwd(ctx.env.cwd())
|
||||
.join()
|
||||
.unwrap();
|
||||
Ok(VecDeque::new())
|
||||
}
|
||||
}
|
||||
false => Ok(ClassifiedCommand::External(ExternalCommand {
|
||||
name: other.to_string(),
|
||||
args: arg_list_strings,
|
||||
})),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn format(input: VecDeque<Value>, context: Arc<Mutex<Context>>) {
|
||||
let last = input.len() - 1;
|
||||
for (i, item) in input.iter().enumerate() {
|
||||
fn format(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, 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, context.clone());
|
||||
crate::format::print_view(&view, args.host);
|
||||
|
||||
if last != i {
|
||||
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 {
|
||||
|
@ -1,11 +1,11 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::desc::DataDescriptor;
|
||||
use crate::parser::parse::Operator;
|
||||
use ansi_term::Color;
|
||||
use chrono::{DateTime, Utc};
|
||||
use chrono_humanize::Humanize;
|
||||
use ordered_float::OrderedFloat;
|
||||
use std::time::SystemTime;
|
||||
use crate::parser::parse::Operator;
|
||||
|
||||
type OF64 = OrderedFloat<f64>;
|
||||
|
||||
@ -50,7 +50,7 @@ impl Primitive {
|
||||
(false, Some(_)) => format!(""),
|
||||
},
|
||||
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 descs = obj.data_descriptors();
|
||||
@ -211,7 +211,7 @@ crate fn select(obj: &Value, fields: &[String]) -> crate::object::Dictionary {
|
||||
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 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) {
|
||||
(Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => i < (*i2 as u128),
|
||||
(Operator::GreaterThan, 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::GreaterThan, 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::NotEqual, Value::Primitive(Primitive::Int(i2))) => i != (*i2 as u128),
|
||||
(Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => {
|
||||
i != (*i2 as u128)
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
Value::Primitive(Primitive::Int(i)) => match (op, rhs) {
|
||||
(Operator::LessThan, 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::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::NotEqual, Value::Primitive(Primitive::Int(i2))) => i != *i2,
|
||||
_ => 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::GreaterThan, 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::NotEqual, Value::Primitive(Primitive::Float(i2))) => i != *i2,
|
||||
(Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => (i.into_inner()) < *i2 as f64,
|
||||
(Operator::GreaterThan, 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,
|
||||
(Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => {
|
||||
(i.into_inner()) < *i2 as f64
|
||||
}
|
||||
(Operator::GreaterThan, 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,
|
||||
},
|
||||
|
@ -3,7 +3,7 @@ use std::collections::BTreeMap;
|
||||
|
||||
#[allow(unused)]
|
||||
crate struct Completer {
|
||||
commands: BTreeMap<String, Box<dyn crate::CommandBlueprint>>,
|
||||
commands: BTreeMap<String, Box<dyn crate::Command>>,
|
||||
}
|
||||
|
||||
impl completion::Completer for Completer {
|
||||
|
@ -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::errors::ShellError;
|
||||
crate use crate::object::{Primitive, Value};
|
||||
|
Loading…
Reference in New Issue
Block a user