aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/parsing/reparsing.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/parsing/reparsing.rs')
-rw-r--r--crates/ra_syntax/src/parsing/reparsing.rs43
1 files changed, 27 insertions, 16 deletions
diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs
index f2d218ab9..19d8adcfb 100644
--- a/crates/ra_syntax/src/parsing/reparsing.rs
+++ b/crates/ra_syntax/src/parsing/reparsing.rs
@@ -1,18 +1,25 @@
1//! Implementation of incremental re-parsing.
2//!
3//! We use two simple strategies for this:
4//! - if the edit modifies only a single token (like changing an identifier's
5//! letter), we replace only this token.
6//! - otherwise, we search for the nearest `{}` block which contains the edit
7//! and try to parse only this block.
8
9use ra_text_edit::AtomTextEdit;
10use ra_parser::Reparser;
11
1use crate::{ 12use crate::{
2 SyntaxKind::*, TextRange, TextUnit, 13 SyntaxKind::*, TextRange, TextUnit, SyntaxError,
3 algo, 14 algo,
4 syntax_node::{GreenNode, SyntaxNode}, 15 syntax_node::{GreenNode, SyntaxNode},
5 syntax_error::SyntaxError,
6 parsing::{ 16 parsing::{
7 grammar, parse_with, 17 input::ParserInput,
8 builder::GreenBuilder, 18 builder::TreeBuilder,
9 parser::Parser,
10 lexer::{tokenize, Token}, 19 lexer::{tokenize, Token},
11 } 20 }
12}; 21};
13 22
14use ra_text_edit::AtomTextEdit;
15
16pub(crate) fn incremental_reparse( 23pub(crate) fn incremental_reparse(
17 node: &SyntaxNode, 24 node: &SyntaxNode,
18 edit: &AtomTextEdit, 25 edit: &AtomTextEdit,
@@ -61,7 +68,10 @@ fn reparse_block<'node>(
61 if !is_balanced(&tokens) { 68 if !is_balanced(&tokens) {
62 return None; 69 return None;
63 } 70 }
64 let (green, new_errors) = parse_with(GreenBuilder::default(), &text, &tokens, reparser); 71 let token_source = ParserInput::new(&text, &tokens);
72 let mut tree_sink = TreeBuilder::new(&text, &tokens);
73 reparser.parse(&token_source, &mut tree_sink);
74 let (green, new_errors) = tree_sink.finish();
65 Some((node, green, new_errors)) 75 Some((node, green, new_errors))
66} 76}
67 77
@@ -77,12 +87,13 @@ fn is_contextual_kw(text: &str) -> bool {
77 } 87 }
78} 88}
79 89
80fn find_reparsable_node( 90fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(&SyntaxNode, Reparser)> {
81 node: &SyntaxNode,
82 range: TextRange,
83) -> Option<(&SyntaxNode, fn(&mut Parser))> {
84 let node = algo::find_covering_node(node, range); 91 let node = algo::find_covering_node(node, range);
85 node.ancestors().find_map(|node| grammar::reparser(node).map(|r| (node, r))) 92 node.ancestors().find_map(|node| {
93 let first_child = node.first_child().map(|it| it.kind());
94 let parent = node.parent().map(|it| it.kind());
95 Reparser::for_node(node.kind(), first_child, parent).map(|r| (node, r))
96 })
86} 97}
87 98
88fn is_balanced(tokens: &[Token]) -> bool { 99fn is_balanced(tokens: &[Token]) -> bool {
@@ -132,7 +143,7 @@ fn merge_errors(
132mod tests { 143mod tests {
133 use test_utils::{extract_range, assert_eq_text}; 144 use test_utils::{extract_range, assert_eq_text};
134 145
135 use crate::{SourceFile, AstNode, utils::dump_tree}; 146 use crate::{SourceFile, AstNode};
136 use super::*; 147 use super::*;
137 148
138 fn do_check<F>(before: &str, replace_with: &str, reparser: F) 149 fn do_check<F>(before: &str, replace_with: &str, reparser: F)
@@ -158,8 +169,8 @@ mod tests {
158 }; 169 };
159 170
160 assert_eq_text!( 171 assert_eq_text!(
161 &dump_tree(fully_reparsed.syntax()), 172 &fully_reparsed.syntax().debug_dump(),
162 &dump_tree(incrementally_reparsed.syntax()), 173 &incrementally_reparsed.syntax().debug_dump(),
163 ) 174 )
164 } 175 }
165 176