2019-05-10 16:59:12 +00:00
|
|
|
#![feature(crate_visibility_modifier)]
|
|
|
|
#![feature(in_band_lifetimes)]
|
|
|
|
#![allow(unused)]
|
|
|
|
|
|
|
|
mod commands;
|
2019-05-15 16:12:38 +00:00
|
|
|
mod context;
|
2019-05-10 16:59:12 +00:00
|
|
|
mod env;
|
|
|
|
mod errors;
|
|
|
|
mod format;
|
|
|
|
mod object;
|
2019-05-11 04:45:57 +00:00
|
|
|
mod parser;
|
2019-05-13 17:30:51 +00:00
|
|
|
mod prelude;
|
2019-05-10 16:59:12 +00:00
|
|
|
|
2019-05-11 22:59:57 +00:00
|
|
|
crate use crate::commands::args::{Args, Streams};
|
2019-05-13 17:30:51 +00:00
|
|
|
use crate::commands::command::ReturnValue;
|
|
|
|
crate use crate::commands::command::{Command, CommandAction, CommandBlueprint};
|
2019-05-15 16:12:38 +00:00
|
|
|
use crate::context::Context;
|
2019-05-10 16:59:12 +00:00
|
|
|
crate use crate::env::{Environment, Host};
|
2019-05-11 04:45:57 +00:00
|
|
|
crate use crate::errors::ShellError;
|
2019-05-15 16:12:38 +00:00
|
|
|
crate use crate::format::{EntriesListView, RenderView};
|
2019-05-10 16:59:12 +00:00
|
|
|
use crate::object::base::{ToEntriesView, ToGenericView};
|
2019-05-15 16:12:38 +00:00
|
|
|
use crate::object::{ShellObject, Value};
|
2019-05-11 22:59:57 +00:00
|
|
|
|
2019-05-11 07:00:33 +00:00
|
|
|
use ansi_term::Color;
|
|
|
|
use conch_parser::lexer::Lexer;
|
|
|
|
use conch_parser::parse::DefaultParser;
|
2019-05-10 16:59:12 +00:00
|
|
|
use rustyline::error::ReadlineError;
|
|
|
|
use rustyline::Editor;
|
2019-05-11 08:08:21 +00:00
|
|
|
use std::cell::RefCell;
|
2019-05-10 16:59:12 +00:00
|
|
|
use std::collections::BTreeMap;
|
2019-05-13 17:30:51 +00:00
|
|
|
use std::collections::VecDeque;
|
2019-05-10 16:59:12 +00:00
|
|
|
use std::error::Error;
|
2019-05-11 08:08:21 +00:00
|
|
|
use std::rc::Rc;
|
2019-05-15 16:12:38 +00:00
|
|
|
use std::sync::{Arc, Mutex};
|
2019-05-11 07:00:33 +00:00
|
|
|
use subprocess::Exec;
|
2019-05-10 16:59:12 +00:00
|
|
|
use sysinfo::{self, SystemExt};
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum MaybeOwned<'a, T> {
|
|
|
|
Owned(T),
|
|
|
|
Borrowed(&'a T),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> MaybeOwned<'a, T> {
|
|
|
|
crate fn borrow(&self) -> &T {
|
|
|
|
match self {
|
|
|
|
MaybeOwned::Owned(v) => v,
|
|
|
|
MaybeOwned::Borrowed(v) => v,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() -> Result<(), Box<Error>> {
|
|
|
|
let mut rl = Editor::<()>::new();
|
|
|
|
if rl.load_history("history.txt").is_err() {
|
|
|
|
println!("No previous history.");
|
|
|
|
}
|
|
|
|
|
2019-05-15 16:12:38 +00:00
|
|
|
let mut context = Arc::new(Mutex::new(Context::basic()?));
|
2019-05-10 16:59:12 +00:00
|
|
|
|
2019-05-15 16:12:38 +00:00
|
|
|
{
|
|
|
|
use crate::commands::*;
|
2019-05-10 16:59:12 +00:00
|
|
|
|
2019-05-15 16:12:38 +00:00
|
|
|
context.lock().unwrap().add_commands(vec![
|
|
|
|
("ps", Box::new(ps::PsBlueprint)),
|
|
|
|
("ls", Box::new(ls::LsBlueprint)),
|
|
|
|
("cd", Box::new(cd::CdBlueprint)),
|
|
|
|
("take", Box::new(take::TakeBlueprint)),
|
2019-05-15 18:14:51 +00:00
|
|
|
("select", Box::new(select::SelectBlueprint)),
|
2019-05-15 21:44:06 +00:00
|
|
|
("reject", Box::new(reject::RejectBlueprint)),
|
2019-05-15 16:12:38 +00:00
|
|
|
("to-array", Box::new(to_array::ToArrayBlueprint)),
|
|
|
|
]);
|
|
|
|
}
|
2019-05-10 16:59:12 +00:00
|
|
|
|
|
|
|
loop {
|
2019-05-11 07:00:33 +00:00
|
|
|
let readline = rl.readline(&format!(
|
|
|
|
"{}> ",
|
2019-05-15 16:12:38 +00:00
|
|
|
Color::Green.paint(context.lock().unwrap().env.cwd().display().to_string())
|
2019-05-11 07:00:33 +00:00
|
|
|
));
|
2019-05-11 04:45:57 +00:00
|
|
|
|
2019-05-10 16:59:12 +00:00
|
|
|
match readline {
|
|
|
|
Ok(line) => {
|
2019-05-11 07:00:33 +00:00
|
|
|
let result = crate::parser::shell_parser(&line)
|
2019-05-13 17:30:51 +00:00
|
|
|
.map_err(|e| ShellError::string(format!("{:?}", e)))?;
|
2019-05-11 04:45:57 +00:00
|
|
|
|
|
|
|
let parsed = result.1;
|
|
|
|
|
2019-05-10 16:59:12 +00:00
|
|
|
rl.add_history_entry(line.as_ref());
|
|
|
|
|
2019-05-13 21:00:25 +00:00
|
|
|
let mut input = VecDeque::new();
|
2019-05-13 17:30:51 +00:00
|
|
|
|
2019-05-15 16:12:38 +00:00
|
|
|
let last = parsed.len() - 1;
|
|
|
|
|
2019-05-13 21:00:25 +00:00
|
|
|
for item in parsed {
|
|
|
|
input = process_command(
|
|
|
|
crate::parser::print_items(&item),
|
|
|
|
item.clone(),
|
|
|
|
input,
|
2019-05-15 16:12:38 +00:00
|
|
|
context.clone(),
|
2019-05-13 21:00:25 +00:00
|
|
|
)?;
|
2019-05-15 16:12:38 +00:00
|
|
|
}
|
2019-05-10 16:59:12 +00:00
|
|
|
|
2019-05-15 16:12:38 +00:00
|
|
|
if input.len() > 0 {
|
|
|
|
if equal_shapes(&input) {
|
|
|
|
format(crate::commands::to_array(input), context.clone());
|
|
|
|
} else {
|
|
|
|
format(input, context.clone());
|
|
|
|
}
|
2019-05-10 16:59:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(ReadlineError::Interrupted) => {
|
|
|
|
println!("CTRL-C");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Err(ReadlineError::Eof) => {
|
|
|
|
println!("CTRL-D");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
println!("Error: {:?}", err);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rl.save_history("history.txt").unwrap();
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2019-05-13 21:00:25 +00:00
|
|
|
|
|
|
|
fn process_command(
|
|
|
|
line: String,
|
|
|
|
parsed: Vec<crate::parser::Item>,
|
|
|
|
input: VecDeque<Value>,
|
2019-05-15 16:12:38 +00:00
|
|
|
context: Arc<Mutex<Context>>,
|
2019-05-13 21:00:25 +00:00
|
|
|
) -> Result<VecDeque<Value>, ShellError> {
|
|
|
|
let command = &parsed[0].name();
|
2019-05-15 16:12:38 +00:00
|
|
|
let arg_list = parsed[1..].iter().map(|i| i.as_value()).collect();
|
2019-05-13 21:00:25 +00:00
|
|
|
|
|
|
|
let streams = Streams::new();
|
|
|
|
|
2019-05-15 16:12:38 +00:00
|
|
|
if command == &"format" {
|
|
|
|
format(input, context);
|
2019-05-13 21:00:25 +00:00
|
|
|
|
2019-05-15 16:12:38 +00:00
|
|
|
Ok(VecDeque::new())
|
|
|
|
} else if command == &"format-list" {
|
|
|
|
let view = EntriesListView::from_stream(input);
|
|
|
|
let mut ctx = context.lock().unwrap();
|
2019-05-13 21:00:25 +00:00
|
|
|
|
2019-05-15 16:12:38 +00:00
|
|
|
crate::format::print_rendered(&view.render_view(&ctx.host), &mut ctx.host);
|
|
|
|
|
|
|
|
Ok(VecDeque::new())
|
|
|
|
} else {
|
|
|
|
let mut ctx = context.lock().unwrap();
|
2019-05-13 21:00:25 +00:00
|
|
|
|
2019-05-15 16:12:38 +00:00
|
|
|
match ctx.has_command(*command) {
|
|
|
|
true => {
|
|
|
|
let mut instance = ctx.create_command(command, arg_list)?;
|
2019-05-13 21:00:25 +00:00
|
|
|
|
|
|
|
let mut result = instance.run(input)?;
|
|
|
|
let mut next = VecDeque::new();
|
|
|
|
|
|
|
|
for v in result {
|
|
|
|
match v {
|
|
|
|
ReturnValue::Action(action) => match action {
|
2019-05-15 16:12:38 +00:00
|
|
|
crate::CommandAction::ChangeCwd(cwd) => ctx.env.cwd = cwd,
|
2019-05-13 21:00:25 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
ReturnValue::Value(v) => next.push_back(v),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(next)
|
|
|
|
}
|
|
|
|
|
2019-05-15 16:12:38 +00:00
|
|
|
false => {
|
|
|
|
Exec::shell(line).cwd(ctx.env.cwd()).join().unwrap();
|
2019-05-13 21:00:25 +00:00
|
|
|
Ok(VecDeque::new())
|
|
|
|
}
|
2019-05-15 16:12:38 +00:00
|
|
|
}
|
2019-05-13 21:00:25 +00:00
|
|
|
}
|
|
|
|
}
|
2019-05-15 16:12:38 +00:00
|
|
|
|
|
|
|
fn format(input: VecDeque<Value>, context: Arc<Mutex<Context>>) {
|
|
|
|
let mut ctx = context.lock().unwrap();
|
|
|
|
|
|
|
|
let last = input.len() - 1;
|
|
|
|
for (i, item) in input.iter().enumerate() {
|
|
|
|
let view = item.to_generic_view();
|
|
|
|
crate::format::print_rendered(&view.render_view(&ctx.host), &mut ctx.host);
|
|
|
|
|
|
|
|
if last != i {
|
|
|
|
println!("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn equal_shapes(input: &VecDeque<Value>) -> bool {
|
|
|
|
let mut items = input.iter();
|
|
|
|
|
|
|
|
let item = match items.next() {
|
|
|
|
Some(item) => item,
|
|
|
|
None => return false,
|
|
|
|
};
|
|
|
|
|
|
|
|
let desc = item.data_descriptors();
|
|
|
|
|
|
|
|
for item in items {
|
|
|
|
if desc != item.data_descriptors() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|