forked from extern/nushell
Simplify commands
This commit is contained in:
parent
af1963d148
commit
6b82e3a8a8
@ -1,42 +1,22 @@
|
|||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::object::Value;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
pub struct CdBlueprint;
|
pub struct Cd;
|
||||||
|
|
||||||
impl crate::CommandBlueprint for CdBlueprint {
|
impl crate::Command for Cd {
|
||||||
fn create(
|
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||||
&self,
|
let target = match args.args.first() {
|
||||||
args: Vec<Value>,
|
|
||||||
_host: &dyn Host,
|
|
||||||
env: &mut Environment,
|
|
||||||
) -> Result<Box<dyn Command>, ShellError> {
|
|
||||||
let target = match args.first() {
|
|
||||||
// TODO: This needs better infra
|
// TODO: This needs better infra
|
||||||
None => return Err(ShellError::string(format!("cd must take one arg"))),
|
None => return Err(ShellError::string(format!("cd must take one arg"))),
|
||||||
Some(v) => v.as_string()?.clone(),
|
Some(v) => v.as_string()?.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Box::new(Cd {
|
let cwd = args.env.cwd().to_path_buf();
|
||||||
cwd: env.cwd().to_path_buf(),
|
|
||||||
target,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(new)]
|
|
||||||
pub struct Cd {
|
|
||||||
cwd: PathBuf,
|
|
||||||
target: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::Command for Cd {
|
|
||||||
fn run(&mut self, _stream: VecDeque<Value>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
|
||||||
let mut stream = VecDeque::new();
|
let mut stream = VecDeque::new();
|
||||||
let path = dunce::canonicalize(self.cwd.join(&self.target).as_path())?;
|
let path = dunce::canonicalize(cwd.join(&target).as_path())?;
|
||||||
stream.push_back(ReturnValue::change_cwd(path));
|
stream.push_back(ReturnValue::change_cwd(path));
|
||||||
Ok(stream)
|
Ok(stream)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,13 @@ use crate::object::Value;
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub struct CommandArgs<'caller> {
|
||||||
|
pub host: &'caller dyn Host,
|
||||||
|
pub env: &'caller crate::Environment,
|
||||||
|
pub args: Vec<Value>,
|
||||||
|
pub input: VecDeque<Value>,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait CommandBlueprint {
|
pub trait CommandBlueprint {
|
||||||
fn create(
|
fn create(
|
||||||
&self,
|
&self,
|
||||||
@ -36,5 +43,5 @@ impl ReturnValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Command {
|
pub trait Command {
|
||||||
fn run(&mut self, stream: VecDeque<Value>) -> Result<VecDeque<ReturnValue>, ShellError>;
|
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError>;
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,17 @@
|
|||||||
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 crate::Command;
|
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
pub struct LsBlueprint;
|
pub struct Ls;
|
||||||
|
|
||||||
impl crate::CommandBlueprint for LsBlueprint {
|
|
||||||
fn create(
|
|
||||||
&self,
|
|
||||||
_args: Vec<Value>,
|
|
||||||
_host: &dyn crate::Host,
|
|
||||||
env: &mut crate::Environment,
|
|
||||||
) -> Result<Box<dyn Command>, ShellError> {
|
|
||||||
Ok(Box::new(Ls {
|
|
||||||
cwd: env.cwd().to_path_buf(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(new)]
|
|
||||||
pub struct Ls {
|
|
||||||
cwd: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::Command for Ls {
|
impl crate::Command for Ls {
|
||||||
fn run(&mut self, _stream: VecDeque<Value>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
fn run(&self, args: CommandArgs<'value>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||||
|
let cwd = args.env.cwd().to_path_buf();
|
||||||
|
|
||||||
let entries =
|
let entries =
|
||||||
std::fs::read_dir(&self.cwd).map_err(|e| ShellError::string(format!("{:?}", e)))?;
|
std::fs::read_dir(&cwd).map_err(|e| ShellError::string(format!("{:?}", e)))?;
|
||||||
|
|
||||||
let mut shell_entries = VecDeque::new();
|
let mut shell_entries = VecDeque::new();
|
||||||
|
|
||||||
|
@ -2,29 +2,14 @@ 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 crate::Command;
|
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use sysinfo::SystemExt;
|
use sysinfo::SystemExt;
|
||||||
|
|
||||||
#[derive(new)]
|
|
||||||
pub struct PsBlueprint;
|
|
||||||
|
|
||||||
impl crate::CommandBlueprint for PsBlueprint {
|
|
||||||
fn create(
|
|
||||||
&self,
|
|
||||||
_args: Vec<Value>,
|
|
||||||
_host: &dyn crate::Host,
|
|
||||||
_env: &mut crate::Environment,
|
|
||||||
) -> Result<Box<dyn Command>, ShellError> {
|
|
||||||
Ok(Box::new(Ps::new()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
pub struct Ps;
|
pub struct Ps;
|
||||||
|
|
||||||
impl crate::Command for Ps {
|
impl crate::Command for Ps {
|
||||||
fn run(&mut self, _stream: VecDeque<Value>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
fn run(&self, _args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||||
let mut system = sysinfo::System::new();
|
let mut system = sysinfo::System::new();
|
||||||
system.refresh_all();
|
system.refresh_all();
|
||||||
|
|
||||||
|
@ -5,35 +5,21 @@ use crate::prelude::*;
|
|||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
|
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
pub struct RejectBlueprint;
|
pub struct Reject;
|
||||||
|
|
||||||
impl crate::CommandBlueprint for RejectBlueprint {
|
|
||||||
fn create(
|
|
||||||
&self,
|
|
||||||
args: Vec<Value>,
|
|
||||||
_host: &dyn Host,
|
|
||||||
_env: &mut Environment,
|
|
||||||
) -> Result<Box<dyn Command>, ShellError> {
|
|
||||||
if args.is_empty() {
|
|
||||||
return Err(ShellError::string("take requires an integer"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let fields: Result<_, _> = args.iter().map(|a| a.as_string()).collect();
|
|
||||||
|
|
||||||
Ok(Box::new(Reject { fields: fields? }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(new)]
|
|
||||||
pub struct Reject {
|
|
||||||
fields: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::Command for Reject {
|
impl crate::Command for Reject {
|
||||||
fn run(&mut self, stream: VecDeque<Value>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
fn run(&self, args: CommandArgs<'value>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||||
let objects = stream
|
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()
|
.iter()
|
||||||
.map(|item| Value::Object(reject(item, &self.fields)))
|
.map(|item| Value::Object(reject(item, &fields)))
|
||||||
.map(|item| ReturnValue::Value(item))
|
.map(|item| ReturnValue::Value(item))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -5,35 +5,21 @@ use crate::prelude::*;
|
|||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
|
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
pub struct SelectBlueprint;
|
pub struct Select;
|
||||||
|
|
||||||
impl crate::CommandBlueprint for SelectBlueprint {
|
|
||||||
fn create(
|
|
||||||
&self,
|
|
||||||
args: Vec<Value>,
|
|
||||||
_host: &dyn Host,
|
|
||||||
_env: &mut Environment,
|
|
||||||
) -> Result<Box<dyn Command>, ShellError> {
|
|
||||||
if args.is_empty() {
|
|
||||||
return Err(ShellError::string("take requires an integer"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let fields: Result<_, _> = args.iter().map(|a| a.as_string()).collect();
|
|
||||||
|
|
||||||
Ok(Box::new(Select { fields: fields? }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(new)]
|
|
||||||
pub struct Select {
|
|
||||||
fields: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::Command for Select {
|
impl crate::Command for Select {
|
||||||
fn run(&mut self, stream: VecDeque<Value>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||||
let objects = stream
|
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()
|
.iter()
|
||||||
.map(|item| Value::Object(select(item, &self.fields)))
|
.map(|item| Value::Object(select(item, &fields)))
|
||||||
.map(|item| ReturnValue::Value(item))
|
.map(|item| ReturnValue::Value(item))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -1,42 +1,24 @@
|
|||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::object::Value;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
|
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
pub struct TakeBlueprint;
|
pub struct Take;
|
||||||
|
|
||||||
impl crate::CommandBlueprint for TakeBlueprint {
|
// TODO: "Amount remaining" wrapper
|
||||||
fn create(
|
|
||||||
&self,
|
|
||||||
args: Vec<Value>,
|
|
||||||
_host: &dyn Host,
|
|
||||||
_env: &mut Environment,
|
|
||||||
) -> Result<Box<dyn Command>, ShellError> {
|
|
||||||
if args.is_empty() {
|
|
||||||
return Err(ShellError::string("take requires an integer"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let amount = args[0].as_int()?;
|
|
||||||
|
|
||||||
Ok(Box::new(Take { amount }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(new)]
|
|
||||||
pub struct Take {
|
|
||||||
amount: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::Command for Take {
|
impl crate::Command for Take {
|
||||||
fn run(&mut self, stream: VecDeque<Value>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||||
let amount = if stream.len() > self.amount as usize {
|
let amount = args.args[0].as_int()?;
|
||||||
self.amount as usize
|
|
||||||
|
let amount = if args.input.len() > amount as usize {
|
||||||
|
amount as usize
|
||||||
} else {
|
} else {
|
||||||
stream.len()
|
args.input.len()
|
||||||
};
|
};
|
||||||
|
|
||||||
let out: VecDeque<ReturnValue> = stream
|
let out: VecDeque<ReturnValue> = args
|
||||||
|
.input
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.take(amount)
|
.take(amount)
|
||||||
.map(|v| ReturnValue::Value(v))
|
.map(|v| ReturnValue::Value(v))
|
||||||
|
@ -3,26 +3,12 @@ use crate::object::Value;
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
|
|
||||||
#[derive(new)]
|
|
||||||
pub struct ToArrayBlueprint;
|
|
||||||
|
|
||||||
impl crate::CommandBlueprint for ToArrayBlueprint {
|
|
||||||
fn create(
|
|
||||||
&self,
|
|
||||||
_args: Vec<Value>,
|
|
||||||
_host: &dyn Host,
|
|
||||||
_env: &mut Environment,
|
|
||||||
) -> Result<Box<dyn Command>, ShellError> {
|
|
||||||
Ok(Box::new(ToArray))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
pub struct ToArray;
|
pub struct ToArray;
|
||||||
|
|
||||||
impl crate::Command for ToArray {
|
impl crate::Command for ToArray {
|
||||||
fn run(&mut self, stream: VecDeque<Value>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
fn run(&self, args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||||
let out = stream.into_iter().collect();
|
let out = args.input.into_iter().collect();
|
||||||
Ok(ReturnValue::single(Value::List(out)))
|
Ok(ReturnValue::single(Value::List(out)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
commands: indexmap::IndexMap<String, Box<dyn crate::CommandBlueprint>>,
|
commands: indexmap::IndexMap<String, Box<dyn crate::Command>>,
|
||||||
crate host: Box<dyn crate::Host>,
|
crate host: Box<dyn crate::Host>,
|
||||||
crate env: Environment,
|
crate env: Environment,
|
||||||
}
|
}
|
||||||
@ -16,7 +17,7 @@ impl Context {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_commands(&mut self, commands: Vec<(&str, Box<dyn crate::CommandBlueprint>)>) {
|
pub fn add_commands(&mut self, commands: Vec<(&str, Box<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);
|
||||||
}
|
}
|
||||||
@ -26,14 +27,25 @@ impl Context {
|
|||||||
self.commands.contains_key(name)
|
self.commands.contains_key(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn create_command(
|
crate fn run_command(
|
||||||
&mut self,
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
arg_list: Vec<Value>,
|
arg_list: Vec<Value>,
|
||||||
) -> Result<Box<dyn Command>, ShellError> {
|
input: VecDeque<Value>,
|
||||||
|
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||||
|
let command_args = CommandArgs {
|
||||||
|
host: &self.host,
|
||||||
|
env: &self.env,
|
||||||
|
args: arg_list,
|
||||||
|
input,
|
||||||
|
};
|
||||||
|
|
||||||
match self.commands.get(name) {
|
match self.commands.get(name) {
|
||||||
Some(command) => Ok(command.create(arg_list, &self.host, &mut self.env)?),
|
None => Err(ShellError::string(format!(
|
||||||
None => Err(ShellError::string(format!("Missing command {}", name))),
|
"Command {} did not exist",
|
||||||
|
name
|
||||||
|
))),
|
||||||
|
Some(command) => command.run(command_args),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
23
src/main.rs
23
src/main.rs
@ -1,6 +1,9 @@
|
|||||||
#![feature(crate_visibility_modifier)]
|
#![feature(crate_visibility_modifier)]
|
||||||
#![feature(in_band_lifetimes)]
|
#![feature(in_band_lifetimes)]
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
mod context;
|
mod context;
|
||||||
mod env;
|
mod env;
|
||||||
@ -53,13 +56,13 @@ fn main() -> Result<(), Box<Error>> {
|
|||||||
use crate::commands::*;
|
use crate::commands::*;
|
||||||
|
|
||||||
context.lock().unwrap().add_commands(vec![
|
context.lock().unwrap().add_commands(vec![
|
||||||
("ps", Box::new(ps::PsBlueprint)),
|
("ps", Box::new(ps::Ps)),
|
||||||
("ls", Box::new(ls::LsBlueprint)),
|
("ls", Box::new(ls::Ls)),
|
||||||
("cd", Box::new(cd::CdBlueprint)),
|
("cd", Box::new(cd::Cd)),
|
||||||
("take", Box::new(take::TakeBlueprint)),
|
("take", Box::new(take::Take)),
|
||||||
("select", Box::new(select::SelectBlueprint)),
|
("select", Box::new(select::Select)),
|
||||||
("reject", Box::new(reject::RejectBlueprint)),
|
("reject", Box::new(reject::Reject)),
|
||||||
("to-array", Box::new(to_array::ToArrayBlueprint)),
|
("to-array", Box::new(to_array::ToArray)),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,9 +143,11 @@ fn process_command(
|
|||||||
|
|
||||||
match ctx.has_command(*command) {
|
match ctx.has_command(*command) {
|
||||||
true => {
|
true => {
|
||||||
let mut instance = ctx.create_command(command, arg_list)?;
|
// let mut instance = ctx.create_command(command, arg_list)?;
|
||||||
|
|
||||||
let result = instance.run(input)?;
|
let result = ctx.run_command(command, arg_list, input)?;
|
||||||
|
|
||||||
|
// let result = command.run(input_args)?;
|
||||||
let mut next = VecDeque::new();
|
let mut next = VecDeque::new();
|
||||||
|
|
||||||
for v in result {
|
for v in result {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
crate use crate::commands::command::{Command, ReturnValue};
|
crate use crate::commands::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};
|
||||||
|
Loading…
Reference in New Issue
Block a user