diff --git a/crates/nu-command/tests/main.rs b/crates/nu-command/tests/main.rs index 5ecefec90f..e880db033d 100644 --- a/crates/nu-command/tests/main.rs +++ b/crates/nu-command/tests/main.rs @@ -1,5 +1,5 @@ use nu_command::create_default_context; -use nu_protocol::{engine::StateWorkingSet, Category}; +use nu_protocol::{engine::StateWorkingSet, Category, Span}; use quickcheck_macros::quickcheck; mod commands; @@ -15,7 +15,8 @@ fn quickcheck_parse(data: String) -> bool { let mut working_set = StateWorkingSet::new(&context); let _ = working_set.add_file("quickcheck".into(), data.as_bytes()); - let _ = nu_parser::parse_block(&mut working_set, &tokens, false, false); + let _ = + nu_parser::parse_block(&mut working_set, &tokens, Span::new(0, 0), false, false); } } true diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index a85f8160bc..e945e5f723 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -2671,7 +2671,7 @@ pub fn parse_source(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeli // working set, if it was a successful parse. let block = parse( working_set, - path.file_name().and_then(|x| x.to_str()), + Some(&path.to_string_lossy()), &contents, scoped, ); diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index f533e8f8d4..86afa0794a 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -1998,7 +1998,7 @@ pub fn parse_full_cell_path( // Creating a Type scope to parse the new block. This will keep track of // the previous input type found in that block - let output = parse_block(working_set, &output, true, true); + let output = parse_block(working_set, &output, span, true, true); working_set .type_scope .add_type(working_set.type_scope.get_last_output()); @@ -4015,7 +4015,7 @@ pub fn parse_block_expression(working_set: &mut StateWorkingSet, span: Span) -> _ => (None, 0), }; - let mut output = parse_block(working_set, &output[amt_to_skip..], false, false); + let mut output = parse_block(working_set, &output[amt_to_skip..], span, false, false); if let Some(signature) = signature { output.signature = signature.0; @@ -4309,7 +4309,7 @@ pub fn parse_closure_expression( } } - let mut output = parse_block(working_set, &output[amt_to_skip..], false, false); + let mut output = parse_block(working_set, &output[amt_to_skip..], span, false, false); if let Some(signature) = signature { output.signature = signature.0; @@ -5196,6 +5196,7 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression pub fn parse_block( working_set: &mut StateWorkingSet, tokens: &[Token], + span: Span, scoped: bool, is_subexpression: bool, ) -> Block { @@ -5352,6 +5353,8 @@ pub fn parse_block( } working_set.type_scope.exit_scope(); + block.span = Some(span); + block } @@ -5816,12 +5819,20 @@ pub fn parse( let file_id = working_set.add_file(name, contents); let new_span = working_set.get_span_for_file(file_id); - let (output, err) = lex(contents, new_span.start, &[], &[], false); - if let Some(err) = err { - working_set.error(err) - } + let previously_parsed_block = working_set.find_block_by_span(new_span); - let mut output = parse_block(working_set, &output, scoped, false); + let mut output = { + if let Some(block) = previously_parsed_block { + return block; + } else { + let (output, err) = lex(contents, new_span.start, &[], &[], false); + if let Some(err) = err { + working_set.error(err) + } + + parse_block(working_set, &output, new_span, scoped, false) + } + }; let mut seen = vec![]; let mut seen_blocks = HashMap::new(); diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index 2464ba7f12..dfce6cdeee 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -1941,6 +1941,22 @@ impl<'a> StateWorkingSet<'a> { .collect(); build_usage(&comment_lines) } + + pub fn find_block_by_span(&self, span: Span) -> Option { + for block in &self.delta.blocks { + if Some(span) == block.span { + return Some(block.clone()); + } + } + + for block in &self.permanent_state.blocks { + if Some(span) == block.span { + return Some(block.clone()); + } + } + + None + } } impl Default for EngineState {