Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/syntax/src/parsing/reparsing.rs')
| -rw-r--r-- | crates/syntax/src/parsing/reparsing.rs | 59 |
1 files changed, 37 insertions, 22 deletions
diff --git a/crates/syntax/src/parsing/reparsing.rs b/crates/syntax/src/parsing/reparsing.rs index a5cc4e90df..f2eab18c27 100644 --- a/crates/syntax/src/parsing/reparsing.rs +++ b/crates/syntax/src/parsing/reparsing.rs @@ -6,8 +6,9 @@ //! - otherwise, we search for the nearest `{}` block which contains the edit //! and try to parse only this block. +use std::ops::Range; + use parser::{Edition, Reparser}; -use text_edit::Indel; use crate::{ parsing::build_tree, @@ -19,38 +20,48 @@ use crate::{ pub(crate) fn incremental_reparse( node: &SyntaxNode, - edit: &Indel, + delete: TextRange, + insert: &str, errors: impl IntoIterator<Item = SyntaxError>, edition: Edition, ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { - if let Some((green, new_errors, old_range)) = reparse_token(node, edit, edition) { - return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range)); + if let Some((green, new_errors, old_range)) = reparse_token(node, delete, insert, edition) { + return Some(( + green, + merge_errors(errors, new_errors, old_range, delete, insert), + old_range, + )); } - if let Some((green, new_errors, old_range)) = reparse_block(node, edit, edition) { - return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range)); + if let Some((green, new_errors, old_range)) = reparse_block(node, delete, insert, edition) { + return Some(( + green, + merge_errors(errors, new_errors, old_range, delete, insert), + old_range, + )); } None } fn reparse_token( root: &SyntaxNode, - edit: &Indel, + delete: TextRange, + insert: &str, edition: Edition, ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { - let prev_token = root.covering_element(edit.delete).as_token()?.clone(); + let prev_token = root.covering_element(delete).as_token()?.clone(); let prev_token_kind = prev_token.kind(); match prev_token_kind { WHITESPACE | COMMENT | IDENT | STRING | BYTE_STRING | C_STRING => { if prev_token_kind == WHITESPACE || prev_token_kind == COMMENT { // removing a new line may extends previous token - let deleted_range = edit.delete - prev_token.text_range().start(); + let deleted_range = delete - prev_token.text_range().start(); if prev_token.text()[deleted_range].contains('\n') { return None; } } - let mut new_text = get_text_after_edit(prev_token.clone().into(), edit); + let mut new_text = get_text_after_edit(prev_token.clone().into(), delete, insert); let (new_token_kind, new_err) = parser::LexedStr::single_token(edition, &new_text)?; if new_token_kind != prev_token_kind @@ -85,11 +96,12 @@ fn reparse_token( fn reparse_block( root: &SyntaxNode, - edit: &Indel, + delete: TextRange, + insert: &str, edition: parser::Edition, ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { - let (node, reparser) = find_reparsable_node(root, edit.delete)?; - let text = get_text_after_edit(node.clone().into(), edit); + let (node, reparser) = find_reparsable_node(root, delete)?; + let text = get_text_after_edit(node.clone().into(), delete, insert); let lexed = parser::LexedStr::new(edition, text.as_str()); let parser_input = lexed.to_input(edition); @@ -104,14 +116,14 @@ fn reparse_block( Some((node.replace_with(green), new_parser_errors, node.text_range())) } -fn get_text_after_edit(element: SyntaxElement, edit: &Indel) -> String { - let edit = Indel::replace(edit.delete - element.text_range().start(), edit.insert.clone()); +fn get_text_after_edit(element: SyntaxElement, mut delete: TextRange, insert: &str) -> String { + delete -= element.text_range().start(); let mut text = match element { NodeOrToken::Token(token) => token.text().to_owned(), NodeOrToken::Node(node) => node.text().to_string(), }; - edit.apply(&mut text); + text.replace_range(Range::<usize>::from(delete), insert); text } @@ -153,7 +165,8 @@ fn merge_errors( old_errors: impl IntoIterator<Item = SyntaxError>, new_errors: Vec<SyntaxError>, range_before_reparse: TextRange, - edit: &Indel, + delete: TextRange, + insert: &str, ) -> Vec<SyntaxError> { let mut res = Vec::new(); @@ -162,8 +175,8 @@ fn merge_errors( if old_err_range.end() <= range_before_reparse.start() { res.push(old_err); } else if old_err_range.start() >= range_before_reparse.end() { - let inserted_len = TextSize::of(&edit.insert); - res.push(old_err.with_range((old_err_range + inserted_len) - edit.delete.len())); + let inserted_len = TextSize::of(insert); + res.push(old_err.with_range((old_err_range + inserted_len) - delete.len())); // Note: extra parens are intentional to prevent uint underflow, HWAB (here was a bug) } } @@ -177,6 +190,8 @@ fn merge_errors( #[cfg(test)] mod tests { + use std::ops::Range; + use parser::Edition; use test_utils::{assert_eq_text, extract_range}; @@ -185,10 +200,9 @@ mod tests { fn do_check(before: &str, replace_with: &str, reparsed_len: u32) { let (range, before) = extract_range(before); - let edit = Indel::replace(range, replace_with.to_owned()); let after = { let mut after = before.clone(); - edit.apply(&mut after); + after.replace_range(Range::<usize>::from(range), replace_with); after }; @@ -197,7 +211,8 @@ mod tests { let before = SourceFile::parse(&before, Edition::CURRENT); let (green, new_errors, range) = incremental_reparse( before.tree().syntax(), - &edit, + range, + replace_with, before.errors.as_deref().unwrap_or_default().iter().cloned(), Edition::CURRENT, ) |