mirror of
https://github.com/nushell/nushell
synced 2024-12-26 04:53:09 +00:00
Very very basic piping working
This commit is contained in:
parent
ceb0487eba
commit
975ff7c2fb
7 changed files with 171 additions and 69 deletions
22
history.txt
22
history.txt
|
@ -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
|
||||||
|
|
|
@ -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
32
src/commands/to_array.rs
Normal 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
6
src/env/host.rs
vendored
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
146
src/main.rs
146
src/main.rs
|
@ -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())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,24 +1,35 @@
|
||||||
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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn esc(s: &str) -> IResult<&str, &str> {
|
fn esc(s: &str) -> IResult<&str, &str> {
|
||||||
|
|
Loading…
Reference in a new issue