diff options
| author | Martin Haug <mhaug@live.de> | 2021-11-02 12:06:22 +0100 |
|---|---|---|
| committer | Martin Haug <mhaug@live.de> | 2021-11-02 12:06:22 +0100 |
| commit | 1e4cab393e55df8875c6303ebb7bde8f09f911c9 (patch) | |
| tree | 72d3bf30e24971efa5f7e2505ebfc009b3c85d1b /src/source.rs | |
| parent | 52761a3baa901865b1fc42366017740cfa7eb566 (diff) | |
Introduce incremental parsing
Diffstat (limited to 'src/source.rs')
| -rw-r--r-- | src/source.rs | 54 |
1 files changed, 51 insertions, 3 deletions
diff --git a/src/source.rs b/src/source.rs index 432688a0..069edd29 100644 --- a/src/source.rs +++ b/src/source.rs @@ -268,7 +268,7 @@ impl SourceFile { /// This panics if the `replace` range is out of bounds. pub fn edit(&mut self, replace: Range<usize>, with: &str) { let start = replace.start; - self.src.replace_range(replace, with); + self.src.replace_range(replace.clone(), with); // Remove invalidated line starts. let line = self.byte_to_line(start).unwrap(); @@ -283,8 +283,39 @@ impl SourceFile { self.line_starts .extend(newlines(&self.src[start ..]).map(|idx| start + idx)); - // Reparse. - self.root = parse(&self.src); + // Update the root node. + #[cfg(not(feature = "parse-cache"))] + { + self.root = parse(&self.src); + } + + #[cfg(feature = "parse-cache")] + { + let insertion_span = replace.into_span(self.id); + let incremental_target = + Rc::make_mut(&mut self.root).incremental_parent(insertion_span); + + match incremental_target { + Some((child_idx, parent, offset)) => { + let child = &parent.children()[child_idx]; + let src = &self.src[offset .. offset + child.len()]; + let parse_res = match child.kind() { + NodeKind::Markup => Some(parse(src)), + _ => parse_block(src), + } + .and_then(|x| x.data().erroneous().not().then(|| x)); + + if let Some(parse_res) = parse_res { + parent.replace_child(child_idx, parse_res); + } else { + self.root = parse(&self.src); + } + } + None => { + self.root = parse(&self.src); + } + } + } } /// Provide highlighting categories for the given range of the source file. @@ -473,4 +504,21 @@ mod tests { // Test removing everything. test(TEST, 0 .. 21, "", ""); } + + #[test] + fn test_source_file_edit_2() { + #[track_caller] + fn test(prev: &str, range: Range<usize>, with: &str, after: &str) { + let mut source = SourceFile::detached(prev); + let result = SourceFile::detached(after); + dbg!(Green::from(source.root.clone())); + source.edit(range, with); + assert_eq!(source.src, result.src); + assert_eq!(source.line_starts, result.line_starts); + dbg!(Green::from(source.root)); + } + + // Test inserting at the begining. + test("abc #f()[def] ghi", 10 .. 11, "xyz", "abc #f()[dxyzf] ghi"); + } } |
