nushell/src/main.rs

256 lines
6.9 KiB
Rust
Raw Normal View History

2019-05-10 18:59:12 +02:00
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
2019-05-16 02:21:46 +02:00
#[allow(unused)]
use crate::prelude::*;
2019-05-10 18:59:12 +02:00
mod commands;
2019-05-15 18:12:38 +02:00
mod context;
2019-05-10 18:59:12 +02:00
mod env;
mod errors;
mod format;
mod object;
2019-05-11 06:45:57 +02:00
mod parser;
mod prelude;
2019-05-16 23:43:36 +02:00
mod shell;
2019-05-10 18:59:12 +02:00
2019-05-22 09:12:03 +02:00
use crate::commands::classified::{ClassifiedCommand, ExternalCommand, InternalCommand};
use crate::commands::command::ReturnValue;
2019-05-22 09:12:03 +02:00
crate use crate::commands::command::{Command, CommandAction};
2019-05-15 18:12:38 +02:00
use crate::context::Context;
2019-05-10 18:59:12 +02:00
crate use crate::env::{Environment, Host};
2019-05-11 06:45:57 +02:00
crate use crate::errors::ShellError;
2019-05-16 00:58:44 +02:00
crate use crate::format::{EntriesListView, GenericView};
2019-05-16 00:23:36 +02:00
use crate::object::Value;
2019-05-12 00:59:57 +02:00
2019-05-10 18:59:12 +02:00
use rustyline::error::ReadlineError;
2019-05-16 23:43:36 +02:00
use rustyline::{self, ColorMode, Config, Editor};
use std::collections::VecDeque;
2019-05-10 18:59:12 +02:00
use std::error::Error;
2019-05-22 09:12:03 +02:00
use std::sync::Arc;
2019-05-10 18:59:12 +02:00
#[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 config = Config::builder().color_mode(ColorMode::Forced).build();
2019-05-16 23:43:36 +02:00
let h = crate::shell::Helper::new();
let mut rl: Editor<crate::shell::Helper> = Editor::with_config(config);
2019-05-17 06:37:18 +02:00
2019-05-17 17:30:10 +02:00
#[cfg(windows)]
{
2019-05-17 06:37:18 +02:00
let _ = ansi_term::enable_ansi_support();
}
rl.set_helper(Some(h));
2019-05-10 18:59:12 +02:00
if rl.load_history("history.txt").is_err() {
println!("No previous history.");
}
2019-05-22 09:12:03 +02:00
let mut context = Context::basic()?;
2019-05-10 18:59:12 +02:00
2019-05-15 18:12:38 +02:00
{
use crate::commands::*;
2019-05-10 18:59:12 +02:00
2019-05-22 09:12:03 +02:00
context.add_commands(vec![
("format", Arc::new(format)),
("format-list", Arc::new(format_list)),
("ps", Arc::new(ps::ps)),
("ls", Arc::new(ls::ls)),
("cd", Arc::new(cd::cd)),
("view", Arc::new(view::view)),
("skip", Arc::new(skip::skip)),
("take", Arc::new(take::take)),
("select", Arc::new(select::select)),
("reject", Arc::new(reject::reject)),
("to-array", Arc::new(to_array::to_array)),
("where", Arc::new(where_::r#where)),
("sort-by", Arc::new(sort_by::sort_by)),
2019-05-15 18:12:38 +02:00
]);
}
2019-05-10 18:59:12 +02:00
loop {
2019-05-22 09:12:03 +02:00
let readline = rl.readline(&format!("{}> ", context.env.cwd().display().to_string()));
2019-05-11 06:45:57 +02:00
2019-05-22 09:12:03 +02:00
match process_line(readline, &mut context) {
2019-05-16 23:43:36 +02:00
LineResult::Success(line) => {
2019-05-17 08:37:35 +02:00
rl.add_history_entry(line.clone());
2019-05-16 23:43:36 +02:00
}
LineResult::Error(err) => {
2019-05-22 09:12:03 +02:00
context.host.stdout(&err);
2019-05-16 23:43:36 +02:00
}
LineResult::Break => {
2019-05-16 04:42:44 +02:00
break;
}
2019-05-11 06:45:57 +02:00
2019-05-16 23:43:36 +02:00
LineResult::FatalError(err) => {
context
.host
.stdout(&format!("A surprising fatal error occurred.\n{:?}", err));
}
}
}
rl.save_history("history.txt").unwrap();
2019-05-11 06:45:57 +02:00
2019-05-16 23:43:36 +02:00
Ok(())
}
2019-05-10 18:59:12 +02:00
2019-05-16 23:43:36 +02:00
enum LineResult {
Success(String),
Error(String),
Break,
2019-05-16 23:43:36 +02:00
#[allow(unused)]
FatalError(ShellError),
}
2019-05-22 09:12:03 +02:00
fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context) -> LineResult {
2019-05-16 23:43:36 +02:00
match &readline {
Ok(line) if line.trim() == "exit" => LineResult::Break,
Ok(line) if line.trim() == "" => LineResult::Success(line.clone()),
2019-05-10 18:59:12 +02:00
2019-05-16 23:43:36 +02:00
Ok(line) => {
let result = match crate::parser::shell_parser(&line) {
Err(err) => {
return LineResult::Error(format!("{:?}", err));
2019-05-10 18:59:12 +02:00
}
2019-05-16 23:43:36 +02:00
Ok(val) => val,
};
let parsed = result.1;
let mut input = VecDeque::new();
for item in parsed {
2019-05-22 09:12:03 +02:00
input = match process_command(item.clone(), input, ctx) {
2019-05-16 23:43:36 +02:00
Ok(val) => val,
Err(err) => return LineResult::Error(format!("{}", err.description())),
};
2019-05-10 18:59:12 +02:00
}
2019-05-16 23:43:36 +02:00
if input.len() > 0 {
if equal_shapes(&input) {
2019-05-22 09:12:03 +02:00
let array = crate::commands::stream_to_array(input);
let args = CommandArgs::from_context(ctx, vec![], array);
match format(args) {
Ok(_) => {}
Err(err) => return LineResult::Error(err.to_string()),
}
2019-05-16 23:43:36 +02:00
} else {
2019-05-22 09:12:03 +02:00
let args = CommandArgs::from_context(ctx, vec![], input);
match format(args) {
Ok(_) => {}
Err(err) => return LineResult::Error(err.to_string()),
}
2019-05-16 23:43:36 +02:00
}
2019-05-10 18:59:12 +02:00
}
2019-05-16 23:43:36 +02:00
LineResult::Success(line.to_string())
}
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
LineResult::Break
}
Err(ReadlineError::Eof) => {
println!("CTRL-D");
LineResult::Break
}
Err(err) => {
println!("Error: {:?}", err);
LineResult::Break
2019-05-10 18:59:12 +02:00
}
}
}
2019-05-13 23:00:25 +02:00
fn process_command(
parsed: Vec<crate::parser::Item>,
input: VecDeque<Value>,
2019-05-22 09:12:03 +02:00
context: &mut Context,
2019-05-13 23:00:25 +02:00
) -> Result<VecDeque<Value>, ShellError> {
2019-05-22 09:12:03 +02:00
let command = classify_command(&parsed, context)?;
2019-05-13 23:00:25 +02:00
2019-05-22 09:12:03 +02:00
command.run(input, context)
}
2019-05-13 23:00:25 +02:00
2019-05-22 09:12:03 +02:00
fn classify_command(
command: &[crate::parser::Item],
context: &Context,
) -> Result<ClassifiedCommand, ShellError> {
let command_name = &command[0].name()?;
2019-05-15 18:12:38 +02:00
2019-05-22 09:12:03 +02:00
let arg_list: Vec<Value> = command[1..].iter().map(|i| i.as_value()).collect();
let arg_list_strings: Vec<String> = command[1..].iter().map(|i| i.print()).collect();
2019-05-13 23:00:25 +02:00
2019-05-22 09:12:03 +02:00
match *command_name {
other => match context.has_command(*command_name) {
2019-05-15 18:12:38 +02:00
true => {
2019-05-22 09:12:03 +02:00
let command = context.get_command(command_name);
Ok(ClassifiedCommand::Internal(InternalCommand {
command,
args: arg_list,
}))
2019-05-13 23:00:25 +02:00
}
2019-05-22 09:12:03 +02:00
false => Ok(ClassifiedCommand::External(ExternalCommand {
name: other.to_string(),
args: arg_list_strings,
})),
},
2019-05-13 23:00:25 +02:00
}
}
2019-05-15 18:12:38 +02:00
2019-05-22 09:12:03 +02:00
fn format(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
let last = args.input.len() - 1;
for (i, item) in args.input.iter().enumerate() {
2019-05-16 00:23:36 +02:00
let view = GenericView::new(item);
2019-05-22 09:12:03 +02:00
crate::format::print_view(&view, args.host);
2019-05-15 18:12:38 +02:00
if last != i {
println!("");
}
}
2019-05-22 09:12:03 +02:00
Ok(VecDeque::new())
}
fn format_list(args: CommandArgs<'caller>) -> Result<VecDeque<ReturnValue>, ShellError> {
let view = EntriesListView::from_stream(args.input);
crate::format::print_view(&view, args.host);
Ok(VecDeque::new())
2019-05-15 18:12:38 +02:00
}
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
}