Fix case where layers were processed linearly when reparsing

This commit is contained in:
Max Brunsfeld 2022-08-23 09:38:03 -07:00
parent ae9e1338f6
commit 71e17a54ae

View file

@ -63,6 +63,9 @@ struct ChangedRegion {
range: Range<Anchor>, range: Range<Anchor>,
} }
#[derive(Default)]
struct ChangeRegionSet(Vec<ChangedRegion>);
impl SyntaxMap { impl SyntaxMap {
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
@ -124,14 +127,12 @@ impl SyntaxSnapshot {
// If this layer follows all of the edits, then preserve it and any // If this layer follows all of the edits, then preserve it and any
// subsequent layers at this same depth. // subsequent layers at this same depth.
else { else {
layers.push_tree( let slice = cursor.slice(
cursor.slice( &DepthAndRange(depth + 1, Anchor::MIN..Anchor::MAX),
&DepthAndRange(depth + 1, Anchor::MIN..Anchor::MAX), Bias::Left,
Bias::Left,
text,
),
text, text,
); );
layers.push_tree(slice, text);
edits_for_depth = &edits[..]; edits_for_depth = &edits[..];
continue; continue;
}; };
@ -226,7 +227,7 @@ impl SyntaxSnapshot {
cursor.next(&text); cursor.next(&text);
let mut layers = SumTree::new(); let mut layers = SumTree::new();
let mut changed_regions = Vec::<ChangedRegion>::new(); let mut changed_regions = ChangeRegionSet::default();
let mut queue = BinaryHeap::new(); let mut queue = BinaryHeap::new();
queue.push(ReparseStep { queue.push(ReparseStep {
depth: 0, depth: 0,
@ -245,18 +246,19 @@ impl SyntaxSnapshot {
let target = DepthAndRange(depth, range.clone()); let target = DepthAndRange(depth, range.clone());
let mut done = cursor.item().is_none(); let mut done = cursor.item().is_none();
while !done && target.cmp(cursor.start(), &text).is_gt() { while !done && target.cmp(&cursor.end(text), &text).is_gt() {
let bounded_target = DepthAndRangeOrMaxPosition( done = true;
target.clone(),
changed_regions let bounded_target =
.first() DepthAndRangeOrMaxPosition(target.clone(), changed_regions.start_position());
.map_or(DepthAndMaxPosition(usize::MAX, Anchor::MAX), |region| {
DepthAndMaxPosition(region.depth, region.range.start)
}),
);
if bounded_target.cmp(&cursor.start(), &text).is_gt() { if bounded_target.cmp(&cursor.start(), &text).is_gt() {
let slice = cursor.slice(&bounded_target, Bias::Left, text); let slice = cursor.slice(&bounded_target, Bias::Left, text);
layers.push_tree(slice, &text); if !slice.is_empty() {
layers.push_tree(slice, &text);
if changed_regions.prune(cursor.end(text), text) {
done = false;
}
}
} }
while target.cmp(&cursor.end(text), text).is_gt() { while target.cmp(&cursor.end(text), text).is_gt() {
@ -266,30 +268,23 @@ impl SyntaxSnapshot {
break; break;
}; };
if layer_is_changed(layer, text, &changed_regions) { if changed_regions.intersects(&layer, text) {
ChangedRegion { changed_regions.insert(
depth: depth + 1, ChangedRegion {
range: layer.range.clone(), depth: depth + 1,
} range: layer.range.clone(),
.insert(text, &mut changed_regions); },
text,
);
} else { } else {
layers.push(layer.clone(), text); layers.push(layer.clone(), text);
} }
cursor.next(text);
}
done = true; cursor.next(text);
changed_regions.retain(|region| { if changed_regions.prune(cursor.end(text), text) {
if region.depth > depth
|| (region.depth == depth
&& region.range.end.cmp(&range.start, text).is_gt())
{
true
} else {
done = false; done = false;
false
} }
}); }
} }
let (ranges, language) = if let Some(step) = step { let (ranges, language) = if let Some(step) = step {
@ -366,11 +361,13 @@ impl SyntaxSnapshot {
) { ) {
let depth = depth + 1; let depth = depth + 1;
for range in &changed_ranges { for range in &changed_ranges {
ChangedRegion { changed_regions.insert(
depth, ChangedRegion {
range: text.anchor_before(range.start)..text.anchor_after(range.end), depth,
} range: text.anchor_before(range.start)..text.anchor_after(range.end),
.insert(text, &mut changed_regions); },
text,
);
} }
get_injections( get_injections(
config, config,
@ -571,19 +568,6 @@ fn get_injections(
result result
} }
fn layer_is_changed(
layer: &SyntaxLayer,
text: &BufferSnapshot,
changed_regions: &[ChangedRegion],
) -> bool {
changed_regions.iter().any(|region| {
let same_depth = region.depth == layer.depth;
let is_before_layer = region.range.end.cmp(&layer.range.start, text).is_le();
let is_after_layer = region.range.start.cmp(&layer.range.end, text).is_ge();
same_depth && !is_before_layer && !is_after_layer
})
}
impl std::ops::Deref for SyntaxMap { impl std::ops::Deref for SyntaxMap {
type Target = SyntaxSnapshot; type Target = SyntaxSnapshot;
@ -625,12 +609,6 @@ impl ReparseStep {
} }
impl ChangedRegion { impl ChangedRegion {
fn insert(self, text: &BufferSnapshot, set: &mut Vec<Self>) {
if let Err(ix) = set.binary_search_by(|probe| probe.cmp(&self, text)) {
set.insert(ix, self);
}
}
fn cmp(&self, other: &Self, buffer: &BufferSnapshot) -> Ordering { fn cmp(&self, other: &Self, buffer: &BufferSnapshot) -> Ordering {
let range_a = &self.range; let range_a = &self.range;
let range_b = &other.range; let range_b = &other.range;
@ -640,6 +618,55 @@ impl ChangedRegion {
} }
} }
impl ChangeRegionSet {
fn start_position(&self) -> DepthAndMaxPosition {
self.0
.first()
.map_or(DepthAndMaxPosition(usize::MAX, Anchor::MAX), |region| {
DepthAndMaxPosition(region.depth, region.range.start)
})
}
fn intersects(&self, layer: &SyntaxLayer, text: &BufferSnapshot) -> bool {
for region in &self.0 {
if region.depth < layer.depth {
continue;
}
if region.depth > layer.depth {
break;
}
if region.range.end.cmp(&layer.range.start, text).is_le() {
continue;
}
if region.range.start.cmp(&layer.range.end, text).is_ge() {
break;
}
return true;
}
false
}
fn insert(&mut self, region: ChangedRegion, text: &BufferSnapshot) {
if let Err(ix) = self.0.binary_search_by(|probe| probe.cmp(&region, text)) {
self.0.insert(ix, region);
}
}
fn prune(&mut self, summary: SyntaxLayerSummary, text: &BufferSnapshot) -> bool {
let prev_len = self.0.len();
self.0.retain(|region| {
region.depth > summary.max_depth
|| (region.depth == summary.max_depth
&& region
.range
.end
.cmp(&summary.last_layer_range.start, text)
.is_gt())
});
self.0.len() < prev_len
}
}
impl Default for SyntaxLayerSummary { impl Default for SyntaxLayerSummary {
fn default() -> Self { fn default() -> Self {
Self { Self {
@ -866,16 +893,18 @@ mod tests {
d!(D {}); d!(D {});
e!(E {}); e!(E {});
f!(F {}); f!(F {});
g!(G {});
} }
", ",
" "
fn a() { fn a() {
b!(B {}); b!(B {});
c!(C {}); c!(C {});
«g!(G {}); d!(D {});
»d!(D {}); « h!(H {});
e!(E {}); » e!(E {});
f!(F {}); f!(F {});
g!(G {});
} }
", ",
]); ]);
@ -888,10 +917,11 @@ mod tests {
fn a() { fn a() {
b!(«B {}»); b!(«B {}»);
c!(«C {}»); c!(«C {}»);
g!(«G {}»);
d!(«D {}»); d!(«D {}»);
h!(«H {}»);
e!(«E {}»); e!(«E {}»);
f!(«F {}»); f!(«F {}»);
g!(«G {}»);
} }
", ",
); );
@ -989,6 +1019,58 @@ mod tests {
]); ]);
} }
#[gpui::test]
fn test_creating_many_injections_in_one_edit() {
test_edit_sequence(&[
"
fn a() {
one(Two::three(3));
four(Five::six(6));
seven(Eight::nine(9));
}
",
"
fn a() {
one«!»(Two::three(3));
four«!»(Five::six(6));
seven«!»(Eight::nine(9));
}
",
"
fn a() {
one!(Two::three«!»(3));
four!(Five::six«!»(6));
seven!(Eight::nine«!»(9));
}
",
]);
}
#[gpui::test]
fn test_editing_across_injection_boundary() {
test_edit_sequence(&[
"
fn one() {
two();
three!(
three.four,
five.six,
);
}
",
"
fn one() {
two();
th«irty_five![»
three.four,
five.six,
« seven.eight,
];»
}
",
]);
}
fn test_edit_sequence(steps: &[&str]) -> (Buffer, SyntaxMap) { fn test_edit_sequence(steps: &[&str]) -> (Buffer, SyntaxMap) {
let registry = Arc::new(LanguageRegistry::test()); let registry = Arc::new(LanguageRegistry::test());
let language = Arc::new(rust_lang()); let language = Arc::new(rust_lang());