mirror of
https://github.com/nushell/nushell.git
synced 2025-08-12 17:38:36 +02:00
Refactor the repl loop
This commit is contained in:
179
src/main.rs
179
src/main.rs
@ -3,7 +3,6 @@
|
||||
|
||||
#[allow(unused)]
|
||||
use crate::prelude::*;
|
||||
use std::borrow::Cow::{self, Borrowed, Owned};
|
||||
|
||||
mod commands;
|
||||
mod context;
|
||||
@ -13,6 +12,7 @@ mod format;
|
||||
mod object;
|
||||
mod parser;
|
||||
mod prelude;
|
||||
mod shell;
|
||||
|
||||
use crate::commands::command::ReturnValue;
|
||||
crate use crate::commands::command::{Command, CommandAction, CommandBlueprint};
|
||||
@ -21,13 +21,9 @@ crate use crate::env::{Environment, Host};
|
||||
crate use crate::errors::ShellError;
|
||||
crate use crate::format::{EntriesListView, GenericView};
|
||||
use crate::object::Value;
|
||||
use rustyline::completion::{Completer, FilenameCompleter, Pair};
|
||||
use rustyline::highlight::{Highlighter, MatchingBracketHighlighter};
|
||||
use rustyline::hint::{Hinter, HistoryHinter};
|
||||
|
||||
use ansi_term::Color;
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::{ColorMode, Config, Editor, Helper, self};
|
||||
use rustyline::{self, ColorMode, Config, Editor};
|
||||
use std::collections::VecDeque;
|
||||
use std::error::Error;
|
||||
use std::sync::{Arc, Mutex};
|
||||
@ -48,54 +44,10 @@ impl<T> MaybeOwned<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
struct MyHelper(FilenameCompleter, MatchingBracketHighlighter, HistoryHinter);
|
||||
impl Completer for MyHelper {
|
||||
type Candidate = Pair;
|
||||
|
||||
fn complete(
|
||||
&self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<Pair>), ReadlineError> {
|
||||
self.0.complete(line, pos, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hinter for MyHelper {
|
||||
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||
self.2.hint(line, pos, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Highlighter for MyHelper {
|
||||
fn highlight_prompt<'p>(&self, prompt: &'p str) -> Cow<'p, str> {
|
||||
Owned("\x1b[32m".to_owned() + &prompt[0..prompt.len() - 2] + "\x1b[m> ")
|
||||
}
|
||||
|
||||
fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
|
||||
Owned("\x1b[1m".to_owned() + hint + "\x1b[m")
|
||||
}
|
||||
|
||||
fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> {
|
||||
self.1.highlight(line, pos)
|
||||
}
|
||||
|
||||
fn highlight_char(&self, line: &str, pos: usize) -> bool {
|
||||
self.1.highlight_char(line, pos)
|
||||
}
|
||||
}
|
||||
|
||||
impl Helper for MyHelper {}
|
||||
|
||||
fn main() -> Result<(), Box<Error>> {
|
||||
let config = Config::builder().color_mode(ColorMode::Forced).build();
|
||||
let h = MyHelper(
|
||||
FilenameCompleter::new(),
|
||||
MatchingBracketHighlighter::new(),
|
||||
HistoryHinter {},
|
||||
);
|
||||
let mut rl: Editor<MyHelper> = Editor::with_config(config);
|
||||
let h = crate::shell::Helper::new();
|
||||
let mut rl: Editor<crate::shell::Helper> = Editor::with_config(config);
|
||||
rl.set_helper(Some(h));
|
||||
if rl.load_history("history.txt").is_err() {
|
||||
println!("No previous history.");
|
||||
@ -125,48 +77,25 @@ fn main() -> Result<(), Box<Error>> {
|
||||
context.lock().unwrap().env.cwd().display().to_string()
|
||||
));
|
||||
|
||||
match readline {
|
||||
Ok(ref line) if line.trim() == "exit" => {
|
||||
break;
|
||||
}
|
||||
Ok(line) => {
|
||||
let result = crate::parser::shell_parser(&line)
|
||||
.map_err(|e| ShellError::string(format!("{:?}", e)))?;
|
||||
|
||||
let parsed = result.1;
|
||||
|
||||
match process_line(readline, context.clone()) {
|
||||
LineResult::Success(line) => {
|
||||
rl.add_history_entry(line.as_ref());
|
||||
|
||||
let mut input = VecDeque::new();
|
||||
|
||||
for item in parsed {
|
||||
input = process_command(
|
||||
crate::parser::print_items(&item),
|
||||
item.clone(),
|
||||
input,
|
||||
context.clone(),
|
||||
)?;
|
||||
}
|
||||
|
||||
if input.len() > 0 {
|
||||
if equal_shapes(&input) {
|
||||
format(crate::commands::to_array(input), context.clone());
|
||||
} else {
|
||||
format(input, context.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(ReadlineError::Interrupted) => {
|
||||
println!("CTRL-C");
|
||||
|
||||
LineResult::Error(err) => {
|
||||
context.lock().unwrap().host.stdout(&err);
|
||||
}
|
||||
|
||||
LineResult::Break => {
|
||||
break;
|
||||
}
|
||||
Err(ReadlineError::Eof) => {
|
||||
println!("CTRL-D");
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
break;
|
||||
|
||||
LineResult::FatalError(err) => {
|
||||
context
|
||||
.lock()
|
||||
.unwrap()
|
||||
.host
|
||||
.stdout(&format!("A surprising fatal error occurred.\n{:?}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -175,13 +104,81 @@ fn main() -> Result<(), Box<Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
enum LineResult {
|
||||
Success(String),
|
||||
Error(String),
|
||||
Break,
|
||||
|
||||
#[allow(unused)]
|
||||
FatalError(ShellError),
|
||||
}
|
||||
|
||||
fn process_line(
|
||||
readline: Result<String, ReadlineError>,
|
||||
context: Arc<Mutex<Context>>,
|
||||
) -> LineResult {
|
||||
match &readline {
|
||||
Ok(line) if line.trim() == "exit" => LineResult::Break,
|
||||
|
||||
Ok(line) if line.trim() == "" => LineResult::Success(line.clone()),
|
||||
|
||||
Ok(line) => {
|
||||
let result = match crate::parser::shell_parser(&line) {
|
||||
Err(err) => {
|
||||
return LineResult::Error(format!("{:?}", err));
|
||||
}
|
||||
|
||||
Ok(val) => val,
|
||||
};
|
||||
|
||||
let parsed = result.1;
|
||||
|
||||
let mut input = VecDeque::new();
|
||||
|
||||
for item in parsed {
|
||||
input = match process_command(
|
||||
crate::parser::print_items(&item),
|
||||
item.clone(),
|
||||
input,
|
||||
context.clone(),
|
||||
) {
|
||||
Ok(val) => val,
|
||||
Err(err) => return LineResult::Error(format!("{}", err.description())),
|
||||
};
|
||||
}
|
||||
|
||||
if input.len() > 0 {
|
||||
if equal_shapes(&input) {
|
||||
format(crate::commands::to_array(input), context.clone());
|
||||
} else {
|
||||
format(input, context.clone());
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process_command(
|
||||
line: String,
|
||||
parsed: Vec<crate::parser::Item>,
|
||||
input: VecDeque<Value>,
|
||||
context: Arc<Mutex<Context>>,
|
||||
) -> Result<VecDeque<Value>, ShellError> {
|
||||
let command = &parsed[0].name();
|
||||
let command = &parsed[0].name()?;
|
||||
let arg_list = parsed[1..].iter().map(|i| i.as_value()).collect();
|
||||
|
||||
if command == &"format" {
|
||||
|
Reference in New Issue
Block a user