diff options
author | darksv <[email protected]> | 2018-09-13 22:25:05 +0100 |
---|---|---|
committer | darksv <[email protected]> | 2018-09-13 22:25:05 +0100 |
commit | 4356240fa42eebbd17fdb63b2d0e6f86387ca21c (patch) | |
tree | 96785c930199eac49a9f48cd1d9c67f0f7c1dc4f /crates/libsyntax2/src/lib.rs | |
parent | b6f8037a6f8fbcb4f127e1d2b518279650b1f5ea (diff) |
Incremental reparsing for single tokens (WHITESPACE, COMMENT, DOC_COMMENT, IDENT, STRING, RAW_STRING)
Diffstat (limited to 'crates/libsyntax2/src/lib.rs')
-rw-r--r-- | crates/libsyntax2/src/lib.rs | 80 |
1 files changed, 67 insertions, 13 deletions
diff --git a/crates/libsyntax2/src/lib.rs b/crates/libsyntax2/src/lib.rs index fd58cb4fa..bae685fb4 100644 --- a/crates/libsyntax2/src/lib.rs +++ b/crates/libsyntax2/src/lib.rs | |||
@@ -82,22 +82,68 @@ impl File { | |||
82 | self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) | 82 | self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) |
83 | } | 83 | } |
84 | pub fn incremental_reparse(&self, edit: &AtomEdit) -> Option<File> { | 84 | pub fn incremental_reparse(&self, edit: &AtomEdit) -> Option<File> { |
85 | let (node, green, new_errors) = | ||
86 | self.reparse_leaf(&edit).or_else(|| self.reparse_block(&edit))?; | ||
87 | |||
88 | let green_root = node.replace_with(green); | ||
89 | let errors = merge_errors(self.errors(), new_errors, node, edit); | ||
90 | Some(File::new(green_root, errors)) | ||
91 | } | ||
92 | fn reparse_leaf(&self, edit: &AtomEdit) -> Option<(SyntaxNodeRef, GreenNode, Vec<SyntaxError>)> { | ||
93 | let node = algo::find_covering_node(self.syntax(), edit.delete); | ||
94 | match node.kind() { | ||
95 | | WHITESPACE | ||
96 | | COMMENT | ||
97 | | DOC_COMMENT | ||
98 | | IDENT | ||
99 | | STRING | ||
100 | | RAW_STRING => { | ||
101 | let text = get_text_after_edit(node, &edit); | ||
102 | let tokens = tokenize(&text); | ||
103 | if tokens.len() != 1 || tokens[0].kind != node.kind() { | ||
104 | return None; | ||
105 | } | ||
106 | |||
107 | let reparser: fn(&mut Parser) = if node.kind().is_trivia() { | ||
108 | // since trivia is omitted by parser when it doesn't have a parent, \ | ||
109 | // we need to create one for it | ||
110 | |p| { | ||
111 | p.start().complete(p, ROOT); | ||
112 | } | ||
113 | } else { | ||
114 | |p| { | ||
115 | p.bump(); | ||
116 | } | ||
117 | }; | ||
118 | |||
119 | let (green, new_errors) = | ||
120 | parser_impl::parse_with::<yellow::GreenBuilder>( | ||
121 | &text, &tokens, reparser, | ||
122 | ); | ||
123 | |||
124 | let green = if node.kind().is_trivia() { | ||
125 | green.children().first().cloned().unwrap() | ||
126 | } else { | ||
127 | green | ||
128 | }; | ||
129 | |||
130 | Some((node, green, new_errors)) | ||
131 | }, | ||
132 | _ => None, | ||
133 | } | ||
134 | } | ||
135 | fn reparse_block(&self, edit: &AtomEdit) -> Option<(SyntaxNodeRef, GreenNode, Vec<SyntaxError>)> { | ||
85 | let (node, reparser) = find_reparsable_node(self.syntax(), edit.delete)?; | 136 | let (node, reparser) = find_reparsable_node(self.syntax(), edit.delete)?; |
86 | let text = replace_range( | 137 | let text = get_text_after_edit(node, &edit); |
87 | node.text().to_string(), | ||
88 | edit.delete - node.range().start(), | ||
89 | &edit.insert, | ||
90 | ); | ||
91 | let tokens = tokenize(&text); | 138 | let tokens = tokenize(&text); |
92 | if !is_balanced(&tokens) { | 139 | if !is_balanced(&tokens) { |
93 | return None; | 140 | return None; |
94 | } | 141 | } |
95 | let (green, new_errors) = parser_impl::parse_with::<yellow::GreenBuilder>( | 142 | let (green, new_errors) = |
96 | &text, &tokens, reparser, | 143 | parser_impl::parse_with::<yellow::GreenBuilder>( |
97 | ); | 144 | &text, &tokens, reparser, |
98 | let green_root = node.replace_with(green); | 145 | ); |
99 | let errors = merge_errors(self.errors(), new_errors, node, edit); | 146 | Some((node, green, new_errors)) |
100 | Some(File::new(green_root, errors)) | ||
101 | } | 147 | } |
102 | fn full_reparse(&self, edit: &AtomEdit) -> File { | 148 | fn full_reparse(&self, edit: &AtomEdit) -> File { |
103 | let text = replace_range(self.syntax().text().to_string(), edit.delete, &edit.insert); | 149 | let text = replace_range(self.syntax().text().to_string(), edit.delete, &edit.insert); |
@@ -134,6 +180,14 @@ impl AtomEdit { | |||
134 | } | 180 | } |
135 | } | 181 | } |
136 | 182 | ||
183 | fn get_text_after_edit(node: SyntaxNodeRef, edit: &AtomEdit) -> String { | ||
184 | replace_range( | ||
185 | node.text().to_string(), | ||
186 | edit.delete - node.range().start(), | ||
187 | &edit.insert, | ||
188 | ) | ||
189 | } | ||
190 | |||
137 | fn find_reparsable_node(node: SyntaxNodeRef, range: TextRange) -> Option<(SyntaxNodeRef, fn(&mut Parser))> { | 191 | fn find_reparsable_node(node: SyntaxNodeRef, range: TextRange) -> Option<(SyntaxNodeRef, fn(&mut Parser))> { |
138 | let node = algo::find_covering_node(node, range); | 192 | let node = algo::find_covering_node(node, range); |
139 | return algo::ancestors(node) | 193 | return algo::ancestors(node) |
@@ -200,9 +254,9 @@ fn merge_errors( | |||
200 | ) -> Vec<SyntaxError> { | 254 | ) -> Vec<SyntaxError> { |
201 | let mut res = Vec::new(); | 255 | let mut res = Vec::new(); |
202 | for e in old_errors { | 256 | for e in old_errors { |
203 | if e.offset < old_node.range().start() { | 257 | if e.offset <= old_node.range().start() { |
204 | res.push(e) | 258 | res.push(e) |
205 | } else if e.offset > old_node.range().end() { | 259 | } else if e.offset >= old_node.range().end() { |
206 | res.push(SyntaxError { | 260 | res.push(SyntaxError { |
207 | msg: e.msg, | 261 | msg: e.msg, |
208 | offset: e.offset + TextUnit::of_str(&edit.insert) - edit.delete.len(), | 262 | offset: e.offset + TextUnit::of_str(&edit.insert) - edit.delete.len(), |