Fix unnecessarily large edits emitted from multi buffer on diff recalculation (#23753)
This fixes an issue introduced in #22994 where soft wrap would recalculate for the entire buffer when editing. Release Notes: - N/A --------- Co-authored-by: Conrad <conrad@zed.dev>
This commit is contained in:
parent
5331418f3a
commit
ee5f270f3f
7 changed files with 402 additions and 251 deletions
|
@ -21,7 +21,7 @@ use language::{
|
|||
TextDimension, TextObject, ToOffset as _, ToPoint as _, TransactionId, TreeSitterOptions,
|
||||
Unclipped,
|
||||
};
|
||||
use project::buffer_store::BufferChangeSet;
|
||||
use project::buffer_store::{BufferChangeSet, BufferChangeSetEvent};
|
||||
use rope::DimensionPair;
|
||||
use smallvec::SmallVec;
|
||||
use smol::future::yield_now;
|
||||
|
@ -434,7 +434,6 @@ struct BufferEdit {
|
|||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum DiffChangeKind {
|
||||
BufferEdited,
|
||||
ExcerptsChanged,
|
||||
DiffUpdated { base_changed: bool },
|
||||
ExpandOrCollapseHunks { expand: bool },
|
||||
}
|
||||
|
@ -546,8 +545,14 @@ impl MultiBuffer {
|
|||
diff_bases.insert(
|
||||
*buffer_id,
|
||||
ChangeSetState {
|
||||
_subscription: new_cx
|
||||
.observe(&change_set_state.change_set, Self::buffer_diff_changed),
|
||||
_subscription: new_cx.subscribe(
|
||||
&change_set_state.change_set,
|
||||
|this, change_set, event, cx| match event {
|
||||
BufferChangeSetEvent::DiffChanged { changed_range } => {
|
||||
this.buffer_diff_changed(change_set, changed_range.clone(), cx)
|
||||
}
|
||||
},
|
||||
),
|
||||
change_set: change_set_state.change_set.clone(),
|
||||
},
|
||||
);
|
||||
|
@ -1603,7 +1608,7 @@ impl MultiBuffer {
|
|||
old: edit_start..edit_start,
|
||||
new: edit_start..edit_end,
|
||||
}],
|
||||
DiffChangeKind::ExcerptsChanged,
|
||||
DiffChangeKind::BufferEdited,
|
||||
);
|
||||
cx.emit(Event::Edited {
|
||||
singleton_buffer_edited: false,
|
||||
|
@ -1636,7 +1641,7 @@ impl MultiBuffer {
|
|||
old: start..prev_len,
|
||||
new: start..start,
|
||||
}],
|
||||
DiffChangeKind::ExcerptsChanged,
|
||||
DiffChangeKind::BufferEdited,
|
||||
);
|
||||
cx.emit(Event::Edited {
|
||||
singleton_buffer_edited: false,
|
||||
|
@ -1909,7 +1914,7 @@ impl MultiBuffer {
|
|||
snapshot.trailing_excerpt_update_count += 1;
|
||||
}
|
||||
|
||||
self.sync_diff_transforms(snapshot, edits, DiffChangeKind::ExcerptsChanged);
|
||||
self.sync_diff_transforms(snapshot, edits, DiffChangeKind::BufferEdited);
|
||||
cx.emit(Event::Edited {
|
||||
singleton_buffer_edited: false,
|
||||
edited_buffer: None,
|
||||
|
@ -1998,22 +2003,26 @@ impl MultiBuffer {
|
|||
});
|
||||
}
|
||||
|
||||
fn buffer_diff_changed(&mut self, change_set: Entity<BufferChangeSet>, cx: &mut Context<Self>) {
|
||||
fn buffer_diff_changed(
|
||||
&mut self,
|
||||
change_set: Entity<BufferChangeSet>,
|
||||
range: Range<text::Anchor>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let change_set = change_set.read(cx);
|
||||
let buffer_id = change_set.buffer_id;
|
||||
let diff = change_set.diff_to_buffer.clone();
|
||||
let base_text = change_set.base_text.clone();
|
||||
self.sync(cx);
|
||||
let mut snapshot = self.snapshot.borrow_mut();
|
||||
let base_text_version_changed =
|
||||
snapshot
|
||||
.diffs
|
||||
.get(&buffer_id)
|
||||
.map_or(true, |diff_snapshot| {
|
||||
change_set.base_text.as_ref().map_or(true, |base_text| {
|
||||
base_text.remote_id() != diff_snapshot.base_text.remote_id()
|
||||
})
|
||||
});
|
||||
let base_text_changed = snapshot
|
||||
.diffs
|
||||
.get(&buffer_id)
|
||||
.map_or(true, |diff_snapshot| {
|
||||
change_set.base_text.as_ref().map_or(true, |base_text| {
|
||||
base_text.remote_id() != diff_snapshot.base_text.remote_id()
|
||||
})
|
||||
});
|
||||
|
||||
if let Some(base_text) = base_text {
|
||||
snapshot.diffs.insert(
|
||||
|
@ -2026,26 +2035,44 @@ impl MultiBuffer {
|
|||
} else {
|
||||
snapshot.diffs.remove(&buffer_id);
|
||||
}
|
||||
let buffers = self.buffers.borrow();
|
||||
let Some(buffer_state) = buffers.get(&buffer_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let diff_change_range = range.to_offset(buffer_state.buffer.read(cx));
|
||||
|
||||
let mut excerpt_edits = Vec::new();
|
||||
for locator in self
|
||||
.buffers
|
||||
.borrow()
|
||||
.get(&buffer_id)
|
||||
.map(|state| &state.excerpts)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
for locator in &buffer_state.excerpts {
|
||||
let mut cursor = snapshot
|
||||
.excerpts
|
||||
.cursor::<(Option<&Locator>, ExcerptOffset)>(&());
|
||||
cursor.seek_forward(&Some(locator), Bias::Left, &());
|
||||
if let Some(excerpt) = cursor.item() {
|
||||
if excerpt.locator == *locator {
|
||||
let excerpt_range = cursor.start().1..cursor.end(&()).1;
|
||||
let excerpt_buffer_range = excerpt.range.context.to_offset(&excerpt.buffer);
|
||||
if diff_change_range.end < excerpt_buffer_range.start
|
||||
|| diff_change_range.start > excerpt_buffer_range.end
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let excerpt_start = cursor.start().1;
|
||||
let excerpt_len = ExcerptOffset::new(excerpt.text_summary.len);
|
||||
let diff_change_start_in_excerpt = ExcerptOffset::new(
|
||||
diff_change_range
|
||||
.start
|
||||
.saturating_sub(excerpt_buffer_range.start),
|
||||
);
|
||||
let diff_change_end_in_excerpt = ExcerptOffset::new(
|
||||
diff_change_range
|
||||
.end
|
||||
.saturating_sub(excerpt_buffer_range.start),
|
||||
);
|
||||
let edit_start = excerpt_start + diff_change_start_in_excerpt.min(excerpt_len);
|
||||
let edit_end = excerpt_start + diff_change_end_in_excerpt.min(excerpt_len);
|
||||
excerpt_edits.push(Edit {
|
||||
old: excerpt_range.clone(),
|
||||
new: excerpt_range.clone(),
|
||||
old: edit_start..edit_end,
|
||||
new: edit_start..edit_end,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2055,7 +2082,7 @@ impl MultiBuffer {
|
|||
snapshot,
|
||||
excerpt_edits,
|
||||
DiffChangeKind::DiffUpdated {
|
||||
base_changed: base_text_version_changed,
|
||||
base_changed: base_text_changed,
|
||||
},
|
||||
);
|
||||
cx.emit(Event::Edited {
|
||||
|
@ -2145,11 +2172,18 @@ impl MultiBuffer {
|
|||
|
||||
pub fn add_change_set(&mut self, change_set: Entity<BufferChangeSet>, cx: &mut Context<Self>) {
|
||||
let buffer_id = change_set.read(cx).buffer_id;
|
||||
self.buffer_diff_changed(change_set.clone(), cx);
|
||||
self.buffer_diff_changed(change_set.clone(), text::Anchor::MIN..text::Anchor::MAX, cx);
|
||||
self.diff_bases.insert(
|
||||
buffer_id,
|
||||
ChangeSetState {
|
||||
_subscription: cx.observe(&change_set, Self::buffer_diff_changed),
|
||||
_subscription: cx.subscribe(
|
||||
&change_set,
|
||||
|this, change_set, event, cx| match event {
|
||||
BufferChangeSetEvent::DiffChanged { changed_range } => {
|
||||
this.buffer_diff_changed(change_set, changed_range.clone(), cx);
|
||||
}
|
||||
},
|
||||
),
|
||||
change_set,
|
||||
},
|
||||
);
|
||||
|
@ -2329,7 +2363,7 @@ impl MultiBuffer {
|
|||
drop(cursor);
|
||||
snapshot.excerpts = new_excerpts;
|
||||
|
||||
self.sync_diff_transforms(snapshot, edits, DiffChangeKind::ExcerptsChanged);
|
||||
self.sync_diff_transforms(snapshot, edits, DiffChangeKind::BufferEdited);
|
||||
cx.emit(Event::Edited {
|
||||
singleton_buffer_edited: false,
|
||||
edited_buffer: None,
|
||||
|
@ -2430,7 +2464,7 @@ impl MultiBuffer {
|
|||
drop(cursor);
|
||||
snapshot.excerpts = new_excerpts;
|
||||
|
||||
self.sync_diff_transforms(snapshot, edits, DiffChangeKind::ExcerptsChanged);
|
||||
self.sync_diff_transforms(snapshot, edits, DiffChangeKind::BufferEdited);
|
||||
cx.emit(Event::Edited {
|
||||
singleton_buffer_edited: false,
|
||||
edited_buffer: None,
|
||||
|
@ -2595,63 +2629,52 @@ impl MultiBuffer {
|
|||
let edit_old_start = old_diff_transforms.start().1 + edit_start_overshoot;
|
||||
let edit_new_start = (edit_old_start as isize + output_delta) as usize;
|
||||
|
||||
if change_kind == DiffChangeKind::BufferEdited {
|
||||
self.interpolate_diff_transforms_for_edit(
|
||||
&edit,
|
||||
&excerpts,
|
||||
&mut old_diff_transforms,
|
||||
&mut new_diff_transforms,
|
||||
&mut end_of_current_insert,
|
||||
);
|
||||
} else {
|
||||
self.recompute_diff_transforms_for_edit(
|
||||
&edit,
|
||||
&mut excerpts,
|
||||
&mut old_diff_transforms,
|
||||
&mut new_diff_transforms,
|
||||
&mut end_of_current_insert,
|
||||
&mut old_expanded_hunks,
|
||||
&snapshot,
|
||||
change_kind,
|
||||
);
|
||||
}
|
||||
|
||||
self.push_buffer_content_transform(
|
||||
&snapshot,
|
||||
let changed_diff_hunks = self.recompute_diff_transforms_for_edit(
|
||||
&edit,
|
||||
&mut excerpts,
|
||||
&mut old_diff_transforms,
|
||||
&mut new_diff_transforms,
|
||||
edit.new.end,
|
||||
end_of_current_insert,
|
||||
&mut end_of_current_insert,
|
||||
&mut old_expanded_hunks,
|
||||
&snapshot,
|
||||
change_kind,
|
||||
);
|
||||
|
||||
// Compute the end of the edit in output coordinates.
|
||||
let edit_end_overshoot = (edit.old.end - old_diff_transforms.start().0).value;
|
||||
let edit_old_end = old_diff_transforms.start().1 + edit_end_overshoot;
|
||||
let edit_new_end = new_diff_transforms.summary().output.len;
|
||||
let edit_old_end_overshoot = edit.old.end - old_diff_transforms.start().0;
|
||||
let edit_new_end_overshoot = edit.new.end - new_diff_transforms.summary().excerpt_len();
|
||||
let edit_old_end = old_diff_transforms.start().1 + edit_old_end_overshoot.value;
|
||||
let edit_new_end =
|
||||
new_diff_transforms.summary().output.len + edit_new_end_overshoot.value;
|
||||
let output_edit = Edit {
|
||||
old: edit_old_start..edit_old_end,
|
||||
new: edit_new_start..edit_new_end,
|
||||
};
|
||||
|
||||
output_delta += (output_edit.new.end - output_edit.new.start) as isize
|
||||
- (output_edit.old.end - output_edit.old.start) as isize;
|
||||
output_edits.push(output_edit);
|
||||
output_delta += (output_edit.new.end - output_edit.new.start) as isize;
|
||||
output_delta -= (output_edit.old.end - output_edit.old.start) as isize;
|
||||
if changed_diff_hunks || matches!(change_kind, DiffChangeKind::BufferEdited) {
|
||||
output_edits.push(output_edit);
|
||||
}
|
||||
|
||||
// If this is the last edit that intersects the current diff transform,
|
||||
// then preserve a suffix of the this diff transform.
|
||||
// then recreate the content up to the end of this transform, to prepare
|
||||
// for reusing additional slices of the old transforms.
|
||||
if excerpt_edits.peek().map_or(true, |next_edit| {
|
||||
next_edit.old.start >= old_diff_transforms.end(&()).0
|
||||
}) {
|
||||
let mut excerpt_offset = edit.new.end;
|
||||
if old_diff_transforms.start().0 < edit.old.end {
|
||||
let suffix = old_diff_transforms.end(&()).0 - edit.old.end;
|
||||
let transform_end = new_diff_transforms.summary().excerpt_len() + suffix;
|
||||
self.push_buffer_content_transform(
|
||||
&snapshot,
|
||||
&mut new_diff_transforms,
|
||||
transform_end,
|
||||
end_of_current_insert,
|
||||
);
|
||||
excerpt_offset += old_diff_transforms.end(&()).0 - edit.old.end;
|
||||
old_diff_transforms.next(&());
|
||||
}
|
||||
old_expanded_hunks.clear();
|
||||
self.push_buffer_content_transform(
|
||||
&snapshot,
|
||||
&mut new_diff_transforms,
|
||||
excerpt_offset,
|
||||
end_of_current_insert,
|
||||
);
|
||||
at_transform_boundary = true;
|
||||
}
|
||||
}
|
||||
|
@ -2691,7 +2714,7 @@ impl MultiBuffer {
|
|||
old_expanded_hunks: &mut HashSet<(ExcerptId, text::Anchor)>,
|
||||
snapshot: &MultiBufferSnapshot,
|
||||
change_kind: DiffChangeKind,
|
||||
) {
|
||||
) -> bool {
|
||||
log::trace!(
|
||||
"recomputing diff transform for edit {:?} => {:?}",
|
||||
edit.old.start.value..edit.old.end.value,
|
||||
|
@ -2699,11 +2722,7 @@ impl MultiBuffer {
|
|||
);
|
||||
|
||||
// Record which hunks were previously expanded.
|
||||
old_expanded_hunks.clear();
|
||||
while let Some(item) = old_diff_transforms.item() {
|
||||
if old_diff_transforms.end(&()).0 > edit.old.end {
|
||||
break;
|
||||
}
|
||||
if let Some(hunk_anchor) = item.hunk_anchor() {
|
||||
log::trace!(
|
||||
"previously expanded hunk at {}",
|
||||
|
@ -2711,10 +2730,22 @@ impl MultiBuffer {
|
|||
);
|
||||
old_expanded_hunks.insert(hunk_anchor);
|
||||
}
|
||||
if old_diff_transforms.end(&()).0 > edit.old.end {
|
||||
break;
|
||||
}
|
||||
old_diff_transforms.next(&());
|
||||
}
|
||||
|
||||
// Avoid querying diff hunks if there's no possibility of hunks being expanded.
|
||||
if old_expanded_hunks.is_empty()
|
||||
&& change_kind == DiffChangeKind::BufferEdited
|
||||
&& !self.all_diff_hunks_expanded
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Visit each excerpt that intersects the edit.
|
||||
let mut did_expand_hunks = false;
|
||||
while let Some(excerpt) = excerpts.item() {
|
||||
if excerpt.text_summary.len == 0 {
|
||||
if excerpts.end(&()) <= edit.new.end {
|
||||
|
@ -2754,8 +2785,10 @@ impl MultiBuffer {
|
|||
+ ExcerptOffset::new(
|
||||
hunk_buffer_range.start.saturating_sub(excerpt_buffer_start),
|
||||
);
|
||||
let hunk_excerpt_end = excerpt_start
|
||||
+ ExcerptOffset::new(hunk_buffer_range.end - excerpt_buffer_start);
|
||||
let hunk_excerpt_end = excerpt_end.min(
|
||||
excerpt_start
|
||||
+ ExcerptOffset::new(hunk_buffer_range.end - excerpt_buffer_start),
|
||||
);
|
||||
|
||||
self.push_buffer_content_transform(
|
||||
snapshot,
|
||||
|
@ -2787,7 +2820,11 @@ impl MultiBuffer {
|
|||
};
|
||||
|
||||
if should_expand_hunk {
|
||||
log::trace!("expanding hunk at {}", hunk_excerpt_start.value);
|
||||
did_expand_hunks = true;
|
||||
log::trace!(
|
||||
"expanding hunk {:?}",
|
||||
hunk_excerpt_start.value..hunk_excerpt_end.value,
|
||||
);
|
||||
|
||||
if !hunk.diff_base_byte_range.is_empty()
|
||||
&& hunk_buffer_range.start >= edit_buffer_start
|
||||
|
@ -2833,68 +2870,8 @@ impl MultiBuffer {
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn interpolate_diff_transforms_for_edit(
|
||||
&self,
|
||||
edit: &Edit<TypedOffset<Excerpt>>,
|
||||
excerpts: &Cursor<Excerpt, TypedOffset<Excerpt>>,
|
||||
old_diff_transforms: &mut Cursor<DiffTransform, (TypedOffset<Excerpt>, usize)>,
|
||||
new_diff_transforms: &mut SumTree<DiffTransform>,
|
||||
end_of_current_insert: &mut Option<(TypedOffset<Excerpt>, ExcerptId, text::Anchor)>,
|
||||
) {
|
||||
log::trace!(
|
||||
"interpolating diff transform for edit {:?} => {:?}",
|
||||
edit.old.start.value..edit.old.end.value,
|
||||
edit.new.start.value..edit.new.end.value
|
||||
);
|
||||
|
||||
// Preserve deleted hunks immediately preceding edits.
|
||||
if let Some(transform) = old_diff_transforms.item() {
|
||||
if old_diff_transforms.start().0 == edit.old.start {
|
||||
if let DiffTransform::DeletedHunk { hunk_anchor, .. } = transform {
|
||||
if excerpts
|
||||
.item()
|
||||
.map_or(false, |excerpt| hunk_anchor.1.is_valid(&excerpt.buffer))
|
||||
{
|
||||
self.push_diff_transform(new_diff_transforms, transform.clone());
|
||||
old_diff_transforms.next(&());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let edit_start_transform = old_diff_transforms.item();
|
||||
|
||||
// When an edit starts within an inserted hunks, extend the hunk
|
||||
// to include the lines of the edit.
|
||||
if let Some((
|
||||
DiffTransform::BufferContent {
|
||||
inserted_hunk_anchor: Some(inserted_hunk_anchor),
|
||||
..
|
||||
},
|
||||
excerpt,
|
||||
)) = edit_start_transform.zip(excerpts.item())
|
||||
{
|
||||
let buffer = &excerpt.buffer;
|
||||
if inserted_hunk_anchor.1.is_valid(buffer) {
|
||||
let excerpt_start = *excerpts.start();
|
||||
let excerpt_end = excerpt_start + ExcerptOffset::new(excerpt.text_summary.len);
|
||||
let excerpt_buffer_start = excerpt.range.context.start.to_offset(buffer);
|
||||
let edit_buffer_end =
|
||||
excerpt_buffer_start + edit.new.end.value.saturating_sub(excerpt_start.value);
|
||||
let edit_buffer_end_point = buffer.offset_to_point(edit_buffer_end);
|
||||
let edited_buffer_line_end =
|
||||
buffer.point_to_offset(edit_buffer_end_point + Point::new(1, 0));
|
||||
let edited_line_end = excerpt_start
|
||||
+ ExcerptOffset::new(edited_buffer_line_end - excerpt_buffer_start);
|
||||
let hunk_end = edited_line_end.min(excerpt_end);
|
||||
*end_of_current_insert =
|
||||
Some((hunk_end, inserted_hunk_anchor.0, inserted_hunk_anchor.1));
|
||||
}
|
||||
}
|
||||
|
||||
old_diff_transforms.seek_forward(&edit.old.end, Bias::Right, &());
|
||||
did_expand_hunks || !old_expanded_hunks.is_empty()
|
||||
}
|
||||
|
||||
fn append_diff_transforms(
|
||||
|
|
|
@ -354,16 +354,17 @@ fn test_excerpt_boundaries_and_clipping(cx: &mut App) {
|
|||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_diff_boundary_anchors(cx: &mut App) {
|
||||
fn test_diff_boundary_anchors(cx: &mut TestAppContext) {
|
||||
let base_text = "one\ntwo\nthree\n";
|
||||
let text = "one\nthree\n";
|
||||
let buffer = cx.new(|cx| Buffer::local(text, cx));
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
|
||||
let change_set = cx.new(|cx| {
|
||||
let mut change_set = BufferChangeSet::new(&buffer, cx);
|
||||
change_set.recalculate_diff_sync(base_text.into(), snapshot.text, true, cx);
|
||||
let _ = change_set.set_base_text(base_text.into(), snapshot.text, cx);
|
||||
change_set
|
||||
});
|
||||
cx.run_until_parked();
|
||||
let multibuffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
|
||||
multibuffer.update(cx, |multibuffer, cx| {
|
||||
multibuffer.add_change_set(change_set, cx)
|
||||
|
@ -375,9 +376,9 @@ fn test_diff_boundary_anchors(cx: &mut App) {
|
|||
multibuffer.set_all_diff_hunks_expanded(cx);
|
||||
(before, after)
|
||||
});
|
||||
cx.background_executor().run_until_parked();
|
||||
cx.run_until_parked();
|
||||
|
||||
let snapshot = multibuffer.read(cx).snapshot(cx);
|
||||
let snapshot = multibuffer.read_with(cx, |multibuffer, cx| multibuffer.snapshot(cx));
|
||||
let actual_text = snapshot.text();
|
||||
let actual_row_infos = snapshot.row_infos(MultiBufferRow(0)).collect::<Vec<_>>();
|
||||
let actual_diff = format_diff(&actual_text, &actual_row_infos, &Default::default());
|
||||
|
@ -410,9 +411,10 @@ fn test_diff_hunks_in_range(cx: &mut TestAppContext) {
|
|||
let change_set = cx.new(|cx| {
|
||||
let mut change_set = BufferChangeSet::new(&buffer, cx);
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
change_set.recalculate_diff_sync(base_text.into(), snapshot.text, true, cx);
|
||||
let _ = change_set.set_base_text(base_text.into(), snapshot.text, cx);
|
||||
change_set
|
||||
});
|
||||
cx.run_until_parked();
|
||||
let multibuffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
|
||||
let (mut snapshot, mut subscription) = multibuffer.update(cx, |multibuffer, cx| {
|
||||
(multibuffer.snapshot(cx), multibuffer.subscribe())
|
||||
|
@ -507,10 +509,11 @@ fn test_editing_text_in_diff_hunks(cx: &mut TestAppContext) {
|
|||
let buffer = cx.new(|cx| Buffer::local(text, cx));
|
||||
let change_set = cx.new(|cx| {
|
||||
let mut change_set = BufferChangeSet::new(&buffer, cx);
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
change_set.recalculate_diff_sync(base_text.into(), snapshot.text, true, cx);
|
||||
let snapshot = buffer.read(cx).text_snapshot();
|
||||
let _ = change_set.set_base_text(base_text.into(), snapshot, cx);
|
||||
change_set
|
||||
});
|
||||
cx.run_until_parked();
|
||||
let multibuffer = cx.new(|cx| MultiBuffer::singleton(buffer.clone(), cx));
|
||||
|
||||
let (mut snapshot, mut subscription) = multibuffer.update(cx, |multibuffer, cx| {
|
||||
|
@ -586,14 +589,6 @@ fn test_editing_text_in_diff_hunks(cx: &mut TestAppContext) {
|
|||
);
|
||||
|
||||
multibuffer.update(cx, |multibuffer, cx| multibuffer.undo(cx));
|
||||
change_set.update(cx, |change_set, cx| {
|
||||
change_set.recalculate_diff_sync(
|
||||
base_text.into(),
|
||||
buffer.read(cx).text_snapshot(),
|
||||
true,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
assert_new_snapshot(
|
||||
&multibuffer,
|
||||
&mut snapshot,
|
||||
|
@ -1861,7 +1856,7 @@ impl ReferenceMultibuffer {
|
|||
.buffer_range
|
||||
.end
|
||||
.cmp(&excerpt.range.start, &buffer)
|
||||
.is_le();
|
||||
.is_lt();
|
||||
let hunk_follows_excerpt = hunk
|
||||
.buffer_range
|
||||
.start
|
||||
|
@ -2064,7 +2059,7 @@ impl ReferenceMultibuffer {
|
|||
}
|
||||
|
||||
#[gpui::test(iterations = 100)]
|
||||
fn test_random_multibuffer(cx: &mut App, mut rng: StdRng) {
|
||||
async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
|
||||
let operations = env::var("OPERATIONS")
|
||||
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
|
||||
.unwrap_or(10);
|
||||
|
@ -2085,7 +2080,7 @@ fn test_random_multibuffer(cx: &mut App, mut rng: StdRng) {
|
|||
buf.randomly_edit(&mut rng, edit_count, cx);
|
||||
needs_diff_calculation = true;
|
||||
});
|
||||
reference.diffs_updated(cx);
|
||||
cx.update(|cx| reference.diffs_updated(cx));
|
||||
}
|
||||
15..=19 if !reference.excerpts.is_empty() => {
|
||||
multibuffer.update(cx, |multibuffer, cx| {
|
||||
|
@ -2119,10 +2114,11 @@ fn test_random_multibuffer(cx: &mut App, mut rng: StdRng) {
|
|||
break;
|
||||
};
|
||||
let id = excerpt.id;
|
||||
reference.remove_excerpt(id, cx);
|
||||
cx.update(|cx| reference.remove_excerpt(id, cx));
|
||||
ids_to_remove.push(id);
|
||||
}
|
||||
let snapshot = multibuffer.read(cx).read(cx);
|
||||
let snapshot =
|
||||
multibuffer.read_with(cx, |multibuffer, cx| multibuffer.snapshot(cx));
|
||||
ids_to_remove.sort_unstable_by(|a, b| a.cmp(b, &snapshot));
|
||||
drop(snapshot);
|
||||
multibuffer.update(cx, |multibuffer, cx| {
|
||||
|
@ -2130,7 +2126,8 @@ fn test_random_multibuffer(cx: &mut App, mut rng: StdRng) {
|
|||
});
|
||||
}
|
||||
30..=39 if !reference.excerpts.is_empty() => {
|
||||
let multibuffer = multibuffer.read(cx).read(cx);
|
||||
let multibuffer =
|
||||
multibuffer.read_with(cx, |multibuffer, cx| multibuffer.snapshot(cx));
|
||||
let offset =
|
||||
multibuffer.clip_offset(rng.gen_range(0..=multibuffer.len()), Bias::Left);
|
||||
let bias = if rng.gen() { Bias::Left } else { Bias::Right };
|
||||
|
@ -2139,7 +2136,8 @@ fn test_random_multibuffer(cx: &mut App, mut rng: StdRng) {
|
|||
anchors.sort_by(|a, b| a.cmp(b, &multibuffer));
|
||||
}
|
||||
40..=44 if !anchors.is_empty() => {
|
||||
let multibuffer = multibuffer.read(cx).read(cx);
|
||||
let multibuffer =
|
||||
multibuffer.read_with(cx, |multibuffer, cx| multibuffer.snapshot(cx));
|
||||
let prev_len = anchors.len();
|
||||
anchors = multibuffer
|
||||
.refresh_anchors(&anchors)
|
||||
|
@ -2189,12 +2187,7 @@ fn test_random_multibuffer(cx: &mut App, mut rng: StdRng) {
|
|||
"recalculating diff for buffer {:?}",
|
||||
snapshot.remote_id(),
|
||||
);
|
||||
change_set.recalculate_diff_sync(
|
||||
change_set.base_text.clone().unwrap().text(),
|
||||
snapshot.text,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
change_set.recalculate_diff(snapshot.text, cx)
|
||||
});
|
||||
}
|
||||
reference.diffs_updated(cx);
|
||||
|
@ -2208,15 +2201,17 @@ fn test_random_multibuffer(cx: &mut App, mut rng: StdRng) {
|
|||
.collect::<String>();
|
||||
|
||||
let buffer = cx.new(|cx| Buffer::local(base_text.clone(), cx));
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
let change_set = cx.new(|cx| {
|
||||
let mut change_set = BufferChangeSet::new(&buffer, cx);
|
||||
change_set.recalculate_diff_sync(base_text, snapshot.text, true, cx);
|
||||
change_set
|
||||
});
|
||||
let change_set = cx.new(|cx| BufferChangeSet::new(&buffer, cx));
|
||||
change_set
|
||||
.update(cx, |change_set, cx| {
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
change_set.set_base_text(base_text, snapshot.text, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
reference.add_change_set(change_set.clone(), cx);
|
||||
multibuffer.update(cx, |multibuffer, cx| {
|
||||
reference.add_change_set(change_set.clone(), cx);
|
||||
multibuffer.add_change_set(change_set, cx)
|
||||
});
|
||||
buffers.push(buffer);
|
||||
|
@ -2225,12 +2220,6 @@ fn test_random_multibuffer(cx: &mut App, mut rng: StdRng) {
|
|||
buffers.choose(&mut rng).unwrap()
|
||||
};
|
||||
|
||||
let buffer = buffer_handle.read(cx);
|
||||
let end_row = rng.gen_range(0..=buffer.max_point().row);
|
||||
let start_row = rng.gen_range(0..=end_row);
|
||||
let end_ix = buffer.point_to_offset(Point::new(end_row, 0));
|
||||
let start_ix = buffer.point_to_offset(Point::new(start_row, 0));
|
||||
let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
|
||||
let prev_excerpt_ix = rng.gen_range(0..=reference.excerpts.len());
|
||||
let prev_excerpt_id = reference
|
||||
.excerpts
|
||||
|
@ -2238,15 +2227,25 @@ fn test_random_multibuffer(cx: &mut App, mut rng: StdRng) {
|
|||
.map_or(ExcerptId::max(), |e| e.id);
|
||||
let excerpt_ix = (prev_excerpt_ix + 1).min(reference.excerpts.len());
|
||||
|
||||
log::info!(
|
||||
"Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}",
|
||||
excerpt_ix,
|
||||
reference.excerpts.len(),
|
||||
buffer_handle.read(cx).remote_id(),
|
||||
buffer.text(),
|
||||
start_ix..end_ix,
|
||||
&buffer.text()[start_ix..end_ix]
|
||||
);
|
||||
let (range, anchor_range) = buffer_handle.read_with(cx, |buffer, _| {
|
||||
let end_row = rng.gen_range(0..=buffer.max_point().row);
|
||||
let start_row = rng.gen_range(0..=end_row);
|
||||
let end_ix = buffer.point_to_offset(Point::new(end_row, 0));
|
||||
let start_ix = buffer.point_to_offset(Point::new(start_row, 0));
|
||||
let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
|
||||
|
||||
log::info!(
|
||||
"Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}",
|
||||
excerpt_ix,
|
||||
reference.excerpts.len(),
|
||||
buffer.remote_id(),
|
||||
buffer.text(),
|
||||
start_ix..end_ix,
|
||||
&buffer.text()[start_ix..end_ix]
|
||||
);
|
||||
|
||||
(start_ix..end_ix, anchor_range)
|
||||
});
|
||||
|
||||
let excerpt_id = multibuffer.update(cx, |multibuffer, cx| {
|
||||
multibuffer
|
||||
|
@ -2254,7 +2253,7 @@ fn test_random_multibuffer(cx: &mut App, mut rng: StdRng) {
|
|||
prev_excerpt_id,
|
||||
buffer_handle.clone(),
|
||||
[ExcerptRange {
|
||||
context: start_ix..end_ix,
|
||||
context: range,
|
||||
primary: None,
|
||||
}],
|
||||
cx,
|
||||
|
@ -2277,7 +2276,7 @@ fn test_random_multibuffer(cx: &mut App, mut rng: StdRng) {
|
|||
})
|
||||
}
|
||||
|
||||
let snapshot = multibuffer.read(cx).snapshot(cx);
|
||||
let snapshot = multibuffer.read_with(cx, |multibuffer, cx| multibuffer.snapshot(cx));
|
||||
let actual_text = snapshot.text();
|
||||
let actual_boundary_rows = snapshot
|
||||
.excerpt_boundaries_in_range(0..)
|
||||
|
@ -2287,7 +2286,7 @@ fn test_random_multibuffer(cx: &mut App, mut rng: StdRng) {
|
|||
let actual_diff = format_diff(&actual_text, &actual_row_infos, &actual_boundary_rows);
|
||||
|
||||
let (expected_text, expected_row_infos, expected_boundary_rows) =
|
||||
reference.expected_content(cx);
|
||||
cx.update(|cx| reference.expected_content(cx));
|
||||
let expected_diff =
|
||||
format_diff(&expected_text, &expected_row_infos, &expected_boundary_rows);
|
||||
|
||||
|
@ -2404,7 +2403,7 @@ fn test_random_multibuffer(cx: &mut App, mut rng: StdRng) {
|
|||
}
|
||||
}
|
||||
|
||||
let snapshot = multibuffer.read(cx).snapshot(cx);
|
||||
let snapshot = multibuffer.read_with(cx, |multibuffer, cx| multibuffer.snapshot(cx));
|
||||
for (old_snapshot, subscription) in old_versions {
|
||||
let edits = subscription.consume().into_inner();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue