Fix duplicated multi-buffer excerpts (#29193)
- **add test case** - **Merge excerpts more aggressively** - **Randomized test for set_excerpts_for_path** Closes #ISSUE Release Notes: - Fixed duplicted excerpts (and resulting panics) --------- Co-authored-by: João Marcos <marcospb19@hotmail.com>
This commit is contained in:
parent
458ffaa134
commit
3357736aea
5 changed files with 251 additions and 89 deletions
|
@ -1687,7 +1687,7 @@ impl MultiBuffer {
|
|||
if let Some(last_range) = merged_ranges.last_mut() {
|
||||
debug_assert!(last_range.context.start <= range.context.start);
|
||||
if last_range.context.end >= range.context.start {
|
||||
last_range.context.end = range.context.end;
|
||||
last_range.context.end = range.context.end.max(last_range.context.end);
|
||||
*counts.last_mut().unwrap() += 1;
|
||||
continue;
|
||||
}
|
||||
|
@ -1741,106 +1741,106 @@ impl MultiBuffer {
|
|||
excerpts_cursor.next(&());
|
||||
|
||||
loop {
|
||||
let (new, existing) = match (new_iter.peek(), existing_iter.peek()) {
|
||||
(Some(new), Some(existing)) => (new, existing),
|
||||
(None, None) => break,
|
||||
(None, Some(_)) => {
|
||||
let existing_id = existing_iter.next().unwrap();
|
||||
if let Some((new_id, last)) = to_insert.last() {
|
||||
let locator = snapshot.excerpt_locator_for_id(existing_id);
|
||||
excerpts_cursor.seek_forward(&Some(locator), Bias::Left, &());
|
||||
if let Some(existing_excerpt) = excerpts_cursor
|
||||
.item()
|
||||
.filter(|e| e.buffer_id == buffer_snapshot.remote_id())
|
||||
{
|
||||
let existing_end = existing_excerpt
|
||||
.range
|
||||
.context
|
||||
.end
|
||||
.to_point(&buffer_snapshot);
|
||||
if existing_end <= last.context.end {
|
||||
self.snapshot
|
||||
.borrow_mut()
|
||||
.replaced_excerpts
|
||||
.insert(existing_id, *new_id);
|
||||
}
|
||||
};
|
||||
let new = new_iter.peek();
|
||||
let existing = if let Some(existing_id) = existing_iter.peek() {
|
||||
let locator = snapshot.excerpt_locator_for_id(*existing_id);
|
||||
excerpts_cursor.seek_forward(&Some(locator), Bias::Left, &());
|
||||
if let Some(excerpt) = excerpts_cursor.item() {
|
||||
if excerpt.buffer_id != buffer_snapshot.remote_id() {
|
||||
to_remove.push(*existing_id);
|
||||
existing_iter.next();
|
||||
continue;
|
||||
}
|
||||
Some((
|
||||
*existing_id,
|
||||
excerpt.range.context.to_point(&buffer_snapshot),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some((last_id, last)) = to_insert.last_mut() {
|
||||
if let Some(new) = new {
|
||||
if last.context.end >= new.context.start {
|
||||
last.context.end = last.context.end.max(new.context.end);
|
||||
excerpt_ids.push(*last_id);
|
||||
new_iter.next();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if let Some((existing_id, existing_range)) = &existing {
|
||||
if last.context.end >= existing_range.start {
|
||||
last.context.end = last.context.end.max(existing_range.end);
|
||||
to_remove.push(*existing_id);
|
||||
self.snapshot
|
||||
.borrow_mut()
|
||||
.replaced_excerpts
|
||||
.insert(*existing_id, *last_id);
|
||||
existing_iter.next();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match (new, existing) {
|
||||
(None, None) => break,
|
||||
(None, Some((existing_id, _))) => {
|
||||
existing_iter.next();
|
||||
to_remove.push(existing_id);
|
||||
continue;
|
||||
}
|
||||
(Some(_), None) => {
|
||||
added_a_new_excerpt = true;
|
||||
to_insert.push((next_excerpt_id(), new_iter.next().unwrap()));
|
||||
let new_id = next_excerpt_id();
|
||||
excerpt_ids.push(new_id);
|
||||
to_insert.push((new_id, new_iter.next().unwrap()));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let locator = snapshot.excerpt_locator_for_id(*existing);
|
||||
excerpts_cursor.seek_forward(&Some(locator), Bias::Left, &());
|
||||
let Some(existing_excerpt) = excerpts_cursor
|
||||
.item()
|
||||
.filter(|e| e.buffer_id == buffer_snapshot.remote_id())
|
||||
else {
|
||||
to_remove.push(existing_iter.next().unwrap());
|
||||
to_insert.push((next_excerpt_id(), new_iter.next().unwrap()));
|
||||
continue;
|
||||
};
|
||||
(Some(new), Some((_, existing_range))) => {
|
||||
if existing_range.end < new.context.start {
|
||||
let existing_id = existing_iter.next().unwrap();
|
||||
to_remove.push(existing_id);
|
||||
continue;
|
||||
} else if existing_range.start > new.context.end {
|
||||
let new_id = next_excerpt_id();
|
||||
excerpt_ids.push(new_id);
|
||||
to_insert.push((new_id, new_iter.next().unwrap()));
|
||||
continue;
|
||||
}
|
||||
|
||||
let existing_start = existing_excerpt
|
||||
.range
|
||||
.context
|
||||
.start
|
||||
.to_point(&buffer_snapshot);
|
||||
let existing_end = existing_excerpt
|
||||
.range
|
||||
.context
|
||||
.end
|
||||
.to_point(&buffer_snapshot);
|
||||
|
||||
if existing_end < new.context.start {
|
||||
let existing_id = existing_iter.next().unwrap();
|
||||
if let Some((new_id, last)) = to_insert.last() {
|
||||
if existing_end <= last.context.end {
|
||||
if existing_range.start == new.context.start
|
||||
&& existing_range.end == new.context.end
|
||||
{
|
||||
self.insert_excerpts_with_ids_after(
|
||||
insert_after,
|
||||
buffer.clone(),
|
||||
mem::take(&mut to_insert),
|
||||
cx,
|
||||
);
|
||||
insert_after = existing_iter.next().unwrap();
|
||||
excerpt_ids.push(insert_after);
|
||||
new_iter.next();
|
||||
} else {
|
||||
let existing_id = existing_iter.next().unwrap();
|
||||
let new_id = next_excerpt_id();
|
||||
self.snapshot
|
||||
.borrow_mut()
|
||||
.replaced_excerpts
|
||||
.insert(existing_id, *new_id);
|
||||
.insert(existing_id, new_id);
|
||||
to_remove.push(existing_id);
|
||||
let mut range = new_iter.next().unwrap();
|
||||
range.context.start = range.context.start.min(existing_range.start);
|
||||
range.context.end = range.context.end.max(existing_range.end);
|
||||
excerpt_ids.push(new_id);
|
||||
to_insert.push((new_id, range));
|
||||
}
|
||||
}
|
||||
to_remove.push(existing_id);
|
||||
continue;
|
||||
} else if existing_start > new.context.end {
|
||||
to_insert.push((next_excerpt_id(), new_iter.next().unwrap()));
|
||||
continue;
|
||||
}
|
||||
|
||||
if existing_start == new.context.start && existing_end == new.context.end {
|
||||
excerpt_ids.extend(to_insert.iter().map(|(id, _)| id));
|
||||
self.insert_excerpts_with_ids_after(
|
||||
insert_after,
|
||||
buffer.clone(),
|
||||
mem::take(&mut to_insert),
|
||||
cx,
|
||||
);
|
||||
insert_after = existing_iter.next().unwrap();
|
||||
excerpt_ids.push(insert_after);
|
||||
new_iter.next();
|
||||
} else {
|
||||
let existing_id = existing_iter.next().unwrap();
|
||||
let new_id = next_excerpt_id();
|
||||
self.snapshot
|
||||
.borrow_mut()
|
||||
.replaced_excerpts
|
||||
.insert(existing_id, new_id);
|
||||
to_remove.push(existing_id);
|
||||
let mut range = new_iter.next().unwrap();
|
||||
range.context.start = range.context.start.min(existing_start);
|
||||
range.context.end = range.context.end.max(existing_end);
|
||||
to_insert.push((new_id, range));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
excerpt_ids.extend(to_insert.iter().map(|(id, _)| id));
|
||||
self.insert_excerpts_with_ids_after(insert_after, buffer, to_insert, cx);
|
||||
self.remove_excerpts(to_remove, cx);
|
||||
if excerpt_ids.is_empty() {
|
||||
|
@ -1849,7 +1849,8 @@ impl MultiBuffer {
|
|||
for excerpt_id in &excerpt_ids {
|
||||
self.paths_by_excerpt.insert(*excerpt_id, path.clone());
|
||||
}
|
||||
self.excerpts_by_path.insert(path, excerpt_ids.clone());
|
||||
self.excerpts_by_path
|
||||
.insert(path, excerpt_ids.iter().dedup().cloned().collect());
|
||||
}
|
||||
|
||||
(excerpt_ids, added_a_new_excerpt)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue