Very very basic piping working

This commit is contained in:
Yehuda Katz 2019-05-13 17:00:25 -04:00
parent ceb0487eba
commit 975ff7c2fb
7 changed files with 171 additions and 69 deletions

View file

@ -1,10 +1,3 @@
hello
ps
ls
ps
ls
ps
ls
cargo install cargo-edit cargo install cargo-edit
ls ls
ls | foo | bar ls | foo | bar
@ -90,3 +83,18 @@ cd ..
exit exit
ls ls
ps ps
to-array
exit
ls
dir
ls
cd target
cd ..
ps
ls
dir
ls
ls | to-array
ls | format
ls | to-array | format
git status

View file

@ -3,5 +3,6 @@ crate mod cd;
crate mod command; crate mod command;
crate mod ls; crate mod ls;
crate mod ps; crate mod ps;
crate mod to_array;
crate use command::Command; crate use command::Command;

32
src/commands/to_array.rs Normal file
View file

@ -0,0 +1,32 @@
use crate::errors::ShellError;
use crate::object::process::Process;
use crate::object::{DirEntry, ShellObject, Value};
use crate::prelude::*;
use crate::Args;
use derive_new::new;
use std::path::{Path, PathBuf};
use sysinfo::SystemExt;
#[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)]
pub struct ToArray;
impl crate::Command for ToArray {
fn run(&mut self, stream: VecDeque<Value>) -> Result<VecDeque<ReturnValue>, ShellError> {
let out = stream.into_iter().collect();
Ok(ReturnValue::single(Value::List(out)))
}
}

6
src/env/host.rs vendored
View file

@ -2,6 +2,12 @@ pub trait Host {
fn stdout(&mut self, out: &str); fn stdout(&mut self, out: &str);
} }
impl Host for Box<dyn Host> {
fn stdout(&mut self, out: &str) {
(**self).stdout(out)
}
}
crate struct BasicHost; crate struct BasicHost;
impl Host for BasicHost { impl Host for BasicHost {

View file

@ -4,7 +4,7 @@ crate mod list;
crate mod table; crate mod table;
use crate::object::Value; use crate::object::Value;
use crate::Host; use crate::prelude::*;
crate use entries::EntriesView; crate use entries::EntriesView;
crate use generic::GenericView; crate use generic::GenericView;
@ -14,3 +14,9 @@ crate use table::TableView;
crate trait RenderView { crate trait RenderView {
fn render_view(&self, host: &dyn Host) -> Vec<String>; fn render_view(&self, host: &dyn Host) -> Vec<String>;
} }
crate fn print_rendered(lines: &[String], host: &mut dyn Host) {
for line in lines {
host.stdout(line);
}
}

View file

@ -47,30 +47,51 @@ impl<T> MaybeOwned<'a, T> {
} }
} }
type Commands = BTreeMap<String, Box<dyn crate::CommandBlueprint>>;
struct Context {
commands: BTreeMap<String, Box<dyn crate::CommandBlueprint>>,
host: Box<dyn crate::Host>,
env: Environment,
}
impl Context {
fn basic() -> Result<Context, Box<Error>> {
Ok(Context {
commands: BTreeMap::new(),
host: Box::new(crate::env::host::BasicHost),
env: crate::Environment::basic()?,
})
}
}
fn main() -> Result<(), Box<Error>> { fn main() -> Result<(), Box<Error>> {
let mut rl = Editor::<()>::new(); let mut rl = Editor::<()>::new();
if rl.load_history("history.txt").is_err() { if rl.load_history("history.txt").is_err() {
println!("No previous history."); println!("No previous history.");
} }
let mut host = crate::env::host::BasicHost; let mut context = Context::basic()?;
let mut env = crate::Environment::basic()?;
let mut commands = BTreeMap::<String, Box<dyn crate::CommandBlueprint>>::new(); // let mut commands = BTreeMap::<String, Box<dyn crate::CommandBlueprint>>::new();
let mut system = Rc::new(RefCell::new(sysinfo::System::new())); let mut system = Rc::new(RefCell::new(sysinfo::System::new()));
let mut ps = crate::commands::ps::PsBlueprint::new(system); let mut ps = crate::commands::ps::PsBlueprint::new(system);
let mut ls = crate::commands::ls::LsBlueprint; let mut ls = crate::commands::ls::LsBlueprint;
let mut cd = crate::commands::cd::CdBlueprint; let mut cd = crate::commands::cd::CdBlueprint;
let mut to_array = crate::commands::to_array::ToArrayBlueprint;
commands.insert("ps".to_string(), Box::new(ps)); context.commands.insert("ps".to_string(), Box::new(ps));
commands.insert("ls".to_string(), Box::new(ls)); context.commands.insert("ls".to_string(), Box::new(ls));
commands.insert("cd".to_string(), Box::new(cd)); context.commands.insert("cd".to_string(), Box::new(cd));
context
.commands
.insert("to-array".to_string(), Box::new(to_array));
loop { loop {
let readline = rl.readline(&format!( let readline = rl.readline(&format!(
"{}> ", "{}> ",
Color::Green.paint(env.cwd().display().to_string()) Color::Green.paint(context.env.cwd().display().to_string())
)); ));
match readline { match readline {
@ -82,55 +103,18 @@ fn main() -> Result<(), Box<Error>> {
rl.add_history_entry(line.as_ref()); rl.add_history_entry(line.as_ref());
if parsed.len() > 1 { let mut input = VecDeque::new();
println!("Piping is not yet implemented");
}
let command = &parsed[0][0].name(); for item in parsed {
let arg_list = parsed[0][1..] // println!("Processing {:?}", item);
.iter() input = process_command(
.map(|i| Value::string(i.name().to_string())) crate::parser::print_items(&item),
.collect(); item.clone(),
input,
&mut context,
)?;
let streams = Streams::new(); // println!("OUTPUT: {:?}", input);
// let args = Args::new(arg_list);
match commands.get_mut(*command) {
Some(command) => {
let mut instance = command.create(arg_list, &mut host, &mut env)?;
let out = VecDeque::new();
let mut result = instance.run(out)?;
let mut next = VecDeque::new();
for v in result {
match v {
ReturnValue::Action(action) => match action {
crate::CommandAction::ChangeCwd(cwd) => env.cwd = cwd,
},
ReturnValue::Value(v) => next.push_back(v),
}
}
for item in next {
let view = item.to_generic_view();
let rendered = view.render_view(&mut host);
for line in rendered {
match line.as_ref() {
"\n" => println!(""),
line => println!("{}", line),
}
}
}
}
other => {
Exec::shell(line).cwd(env.cwd()).join().unwrap();
}
} }
} }
Err(ReadlineError::Interrupted) => { Err(ReadlineError::Interrupted) => {
@ -151,3 +135,57 @@ fn main() -> Result<(), Box<Error>> {
Ok(()) Ok(())
} }
fn process_command(
line: String,
parsed: Vec<crate::parser::Item>,
input: VecDeque<Value>,
context: &mut Context,
) -> Result<VecDeque<Value>, ShellError> {
let command = &parsed[0].name();
let arg_list = parsed[1..]
.iter()
.map(|i| Value::string(i.name().to_string()))
.collect();
let streams = Streams::new();
// let args = Args::new(arg_list);
match *command {
"format" => {
for item in input {
let view = item.to_generic_view();
crate::format::print_rendered(&view.render_view(&context.host), &mut context.host);
}
Ok(VecDeque::new())
}
command => match context.commands.get_mut(command) {
Some(command) => {
let mut instance = command.create(arg_list, &context.host, &mut context.env)?;
let mut result = instance.run(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)
}
other => {
Exec::shell(line).cwd(context.env.cwd()).join().unwrap();
Ok(VecDeque::new())
}
},
}
}

View file

@ -1,22 +1,33 @@
use nom::branch::alt; use nom::branch::alt;
use nom::bytes::complete::{escaped, is_not, tag}; use nom::bytes::complete::{escaped, is_not, tag};
use nom::{ws, named, separated_list, complete};
use nom::character::complete::one_of; use nom::character::complete::one_of;
use nom::multi::separated_list; use nom::multi::separated_list;
use nom::sequence::{preceded, terminated}; use nom::sequence::{preceded, terminated};
use nom::IResult; use nom::IResult;
use nom::{complete, named, separated_list, ws};
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum Item { pub enum Item {
Quoted(String), Quoted(String),
Bare(String), Bare(String),
} }
crate fn print_items(items: &[Item]) -> String {
let mut out = String::new();
let formatted = items.iter().map(|item| match item {
Item::Bare(s) => format!("{}", s),
Item::Quoted(s) => format!("{:?}", s),
});
itertools::join(formatted, " ")
}
impl Item { impl Item {
crate fn name(&self) -> &str { crate fn name(&self) -> &str {
match self { match self {
Item::Quoted(s) => s, Item::Quoted(s) => s,
Item::Bare(s) => s Item::Bare(s) => s,
} }
} }
} }