Getting ready for multiline scripts (#2737)

* WIP

* WIP

* WIP

* Tests are passing

* make parser more resilient

* lint
This commit is contained in:
Jonathan Turner
2020-11-10 05:27:07 +13:00
committed by GitHub
parent 0113661c81
commit 8df748463d
10 changed files with 570 additions and 471 deletions

View File

@ -393,52 +393,56 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
if let Some(prompt) = configuration.var("prompt") {
let prompt_line = prompt.as_string()?;
match nu_parser::lite_parse(&prompt_line, 0).map_err(ShellError::from) {
Ok(result) => {
let prompt_block = nu_parser::classify_block(&result, context.registry());
let (result, err) = nu_parser::lite_parse(&prompt_line, 0);
let env = context.get_env();
if err.is_some() {
use crate::git::current_branch;
format!(
"\x1b[32m{}{}\x1b[m> ",
cwd,
match current_branch() {
Some(s) => format!("({})", s),
None => "".to_string(),
}
)
} else {
let prompt_block = nu_parser::classify_block(&result, context.registry());
match run_block(
&prompt_block.block,
&mut context,
InputStream::empty(),
Scope::from_env(env),
)
.await
{
Ok(result) => match result.collect_string(Tag::unknown()).await {
Ok(string_result) => {
let errors = context.get_errors();
context.maybe_print_errors(Text::from(prompt_line));
context.clear_errors();
let env = context.get_env();
if !errors.is_empty() {
"> ".to_string()
} else {
string_result.item
}
}
Err(e) => {
crate::cli::print_err(e, &Text::from(prompt_line));
context.clear_errors();
match run_block(
&prompt_block.block,
&mut context,
InputStream::empty(),
Scope::from_env(env),
)
.await
{
Ok(result) => match result.collect_string(Tag::unknown()).await {
Ok(string_result) => {
let errors = context.get_errors();
context.maybe_print_errors(Text::from(prompt_line));
context.clear_errors();
if !errors.is_empty() {
"> ".to_string()
} else {
string_result.item
}
},
}
Err(e) => {
crate::cli::print_err(e, &Text::from(prompt_line));
context.clear_errors();
"> ".to_string()
}
}
}
Err(e) => {
crate::cli::print_err(e, &Text::from(prompt_line));
context.clear_errors();
},
Err(e) => {
crate::cli::print_err(e, &Text::from(prompt_line));
context.clear_errors();
"> ".to_string()
"> ".to_string()
}
}
}
} else {
@ -864,7 +868,10 @@ pub async fn parse_and_eval(line: &str, ctx: &mut EvaluationContext) -> Result<S
line
};
let lite_result = nu_parser::lite_parse(&line, 0)?;
let (lite_result, err) = nu_parser::lite_parse(&line, 0);
if let Some(err) = err {
return Err(err.into());
}
// TODO ensure the command whose examples we're testing is actually in the pipeline
let classified_block = nu_parser::classify_block(&lite_result, ctx.registry());
@ -897,13 +904,11 @@ pub async fn process_line(
let line = chomp_newline(line);
ctx.raw_input = line.to_string();
let result = match nu_parser::lite_parse(&line, 0) {
Err(err) => {
return LineResult::Error(line.to_string(), err.into());
}
let (result, err) = nu_parser::lite_parse(&line, 0);
Ok(val) => val,
};
if let Some(err) = err {
return LineResult::Error(line.to_string(), err.into());
}
debug!("=== Parsed ===");
debug!("{:#?}", result);
@ -1100,7 +1105,8 @@ pub fn print_err(err: ShellError, source: &Text) {
mod tests {
#[quickcheck]
fn quickcheck_parse(data: String) -> bool {
if let Ok(lite_block) = nu_parser::lite_parse(&data, 0) {
let (lite_block, err) = nu_parser::lite_parse(&data, 0);
if err.is_none() {
let context = crate::evaluation_context::EvaluationContext::basic().unwrap();
let _ = nu_parser::classify_block(&lite_block, context.registry());
}

View File

@ -288,10 +288,7 @@ mod tests {
registry: &dyn SignatureRegistry,
pos: usize,
) -> Vec<LocationType> {
let lite_block = match lite_parse(line, 0) {
Ok(v) => v,
Err(e) => e.partial.expect("lite_parse result"),
};
let (lite_block, _) = lite_parse(line, 0);
let block = classify_block(&lite_block, registry);

View File

@ -197,7 +197,10 @@ fn parse_line(line: &str, ctx: &mut EvaluationContext) -> Result<ClassifiedBlock
line
};
let lite_result = nu_parser::lite_parse(&line, 0)?;
let (lite_result, err) = nu_parser::lite_parse(&line, 0);
if let Some(err) = err {
return Err(err.into());
}
// TODO ensure the command whose examples we're testing is actually in the pipeline
let classified_block = nu_parser::classify_block(&lite_result, ctx.registry());

View File

@ -23,15 +23,10 @@ impl NuCompleter {
use completion::engine::LocationType;
let nu_context: &EvaluationContext = context.as_ref();
let lite_block = match nu_parser::lite_parse(line, 0) {
Ok(block) => Some(block),
Err(result) => result.partial,
};
let (lite_block, _) = nu_parser::lite_parse(line, 0);
let locations = lite_block
.map(|block| nu_parser::classify_block(&block, &nu_context.registry))
.map(|block| completion::engine::completion_location(line, &block.block, pos))
.unwrap_or_default();
let classified_block = nu_parser::classify_block(&lite_block, &nu_context.registry);
let locations = completion::engine::completion_location(line, &classified_block.block, pos);
let matcher = nu_data::config::config(Tag::unknown())
.ok()

View File

@ -121,10 +121,10 @@ impl rustyline::validate::Validator for NuValidator {
) -> rustyline::Result<rustyline::validate::ValidationResult> {
let src = ctx.input();
let lite_result = nu_parser::lite_parse(src, 0);
let (_, err) = nu_parser::lite_parse(src, 0);
if let Err(err) = lite_result {
if let nu_errors::ParseErrorReason::Eof { .. } = err.cause.reason() {
if let Some(err) = err {
if let nu_errors::ParseErrorReason::Eof { .. } = err.reason() {
return Ok(rustyline::validate::ValidationResult::Incomplete);
}
}

View File

@ -25,22 +25,21 @@ impl Painter {
registry: &dyn SignatureRegistry,
palette: &P,
) -> Cow<'l, str> {
let lite_block = nu_parser::lite_parse(line, 0);
let (lb, err) = nu_parser::lite_parse(line, 0);
match lite_block {
Err(_) => Cow::Borrowed(line),
Ok(lb) => {
let classified = nu_parser::classify_block(&lb, registry);
if err.is_some() {
Cow::Borrowed(line)
} else {
let classified = nu_parser::classify_block(&lb, registry);
let shapes = nu_parser::shapes(&classified.block);
let mut painter = Painter::new(line);
let shapes = nu_parser::shapes(&classified.block);
let mut painter = Painter::new(line);
for shape in shapes {
painter.paint_shape(&shape, palette);
}
Cow::Owned(painter.into_string())
for shape in shapes {
painter.paint_shape(&shape, palette);
}
Cow::Owned(painter.into_string())
}
}