forked from extern/nushell
Restructure and make commands uniform
This commit is contained in:
@@ -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"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user