Detailed changes
@@ -27,12 +27,21 @@ pub struct BufferDiff {
secondary_diff: Option<Entity<BufferDiff>>,
}
-#[derive(Clone, Debug)]
+#[derive(Clone)]
pub struct BufferDiffSnapshot {
inner: BufferDiffInner,
secondary_diff: Option<Box<BufferDiffSnapshot>>,
}
+impl std::fmt::Debug for BufferDiffSnapshot {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("BufferDiffSnapshot")
+ .field("inner", &self.inner)
+ .field("secondary_diff", &self.secondary_diff)
+ .finish()
+ }
+}
+
#[derive(Clone)]
struct BufferDiffInner {
hunks: SumTree<InternalDiffHunk>,
@@ -338,9 +347,16 @@ impl BufferDiffSnapshot {
pub fn hunks_intersecting_base_text_range<'a>(
&'a self,
range: Range<usize>,
+ main_buffer: &'a text::BufferSnapshot,
) -> impl 'a + Iterator<Item = DiffHunk> {
- // FIXME
- std::iter::empty()
+ let unstaged_counterpart = self.secondary_diff.as_ref().map(|diff| &diff.inner);
+ let filter = move |summary: &DiffHunkSummary| {
+ let before_start = summary.diff_base_byte_range.end < range.start;
+ let after_end = summary.diff_base_byte_range.start > range.end;
+ !before_start && !after_end
+ };
+ self.inner
+ .hunks_intersecting_range_impl(filter, main_buffer, unstaged_counterpart)
}
pub fn base_text(&self) -> &language::BufferSnapshot {
@@ -623,15 +639,22 @@ impl BufferDiffInner {
secondary: Option<&'a Self>,
) -> impl 'a + Iterator<Item = DiffHunk> {
let range = range.to_offset(buffer);
+ let filter = move |summary: &DiffHunkSummary| {
+ let summary_range = summary.buffer_range.to_offset(buffer);
+ let before_start = summary_range.end < range.start;
+ let after_end = summary_range.start > range.end;
+ !before_start && !after_end
+ };
+ self.hunks_intersecting_range_impl(filter, buffer, secondary)
+ }
- let mut cursor = self
- .hunks
- .filter::<_, DiffHunkSummary>(buffer, move |summary| {
- let summary_range = summary.buffer_range.to_offset(buffer);
- let before_start = summary_range.end < range.start;
- let after_end = summary_range.start > range.end;
- !before_start && !after_end
- });
+ fn hunks_intersecting_range_impl<'a>(
+ &'a self,
+ filter: impl 'a + Fn(&DiffHunkSummary) -> bool,
+ buffer: &'a text::BufferSnapshot,
+ secondary: Option<&'a Self>,
+ ) -> impl 'a + Iterator<Item = DiffHunk> {
+ let mut cursor = self.hunks.filter::<_, DiffHunkSummary>(buffer, filter);
let anchor_iter = iter::from_fn(move || {
cursor.next();
@@ -781,13 +804,19 @@ impl BufferDiffInner {
})
}
- fn compare(&self, old: &Self, new_snapshot: &text::BufferSnapshot) -> Option<Range<Anchor>> {
+ fn compare(
+ &self,
+ old: &Self,
+ new_snapshot: &text::BufferSnapshot,
+ ) -> (Option<Range<Anchor>>, Option<Range<usize>>) {
let mut new_cursor = self.hunks.cursor::<()>(new_snapshot);
let mut old_cursor = old.hunks.cursor::<()>(new_snapshot);
old_cursor.next();
new_cursor.next();
let mut start = None;
let mut end = None;
+ let mut base_text_start = None;
+ let mut base_text_end = None;
loop {
match (new_cursor.item(), old_cursor.item()) {
@@ -799,12 +828,15 @@ impl BufferDiffInner {
{
Ordering::Less => {
start.get_or_insert(new_hunk.buffer_range.start);
+ base_text_start.get_or_insert(new_hunk.diff_base_byte_range.start);
end.replace(new_hunk.buffer_range.end);
+ base_text_end.get_or_insert(new_hunk.diff_base_byte_range.end);
new_cursor.next();
}
Ordering::Equal => {
if new_hunk != old_hunk {
start.get_or_insert(new_hunk.buffer_range.start);
+ base_text_start.get_or_insert(new_hunk.diff_base_byte_range.start);
if old_hunk
.buffer_range
.end
@@ -812,8 +844,10 @@ impl BufferDiffInner {
.is_ge()
{
end.replace(old_hunk.buffer_range.end);
+ base_text_end.replace(old_hunk.diff_base_byte_range.end);
} else {
end.replace(new_hunk.buffer_range.end);
+ base_text_end.replace(new_hunk.diff_base_byte_range.end);
}
}
@@ -822,26 +856,37 @@ impl BufferDiffInner {
}
Ordering::Greater => {
start.get_or_insert(old_hunk.buffer_range.start);
+ base_text_start.get_or_insert(old_hunk.diff_base_byte_range.start);
end.replace(old_hunk.buffer_range.end);
+ base_text_end.replace(old_hunk.diff_base_byte_range.end);
old_cursor.next();
}
}
}
(Some(new_hunk), None) => {
start.get_or_insert(new_hunk.buffer_range.start);
+ base_text_start.get_or_insert(new_hunk.diff_base_byte_range.start);
end.replace(new_hunk.buffer_range.end);
+ base_text_end.replace(new_hunk.diff_base_byte_range.end);
new_cursor.next();
}
(None, Some(old_hunk)) => {
start.get_or_insert(old_hunk.buffer_range.start);
+ base_text_start.get_or_insert(old_hunk.diff_base_byte_range.start);
end.replace(old_hunk.buffer_range.end);
+ base_text_end.replace(old_hunk.diff_base_byte_range.end);
old_cursor.next();
}
(None, None) => break,
}
}
- start.zip(end).map(|(start, end)| start..end)
+ (
+ start.zip(end).map(|(start, end)| start..end),
+ base_text_start
+ .zip(base_text_end)
+ .map(|(start, end)| start..end),
+ )
}
}
@@ -1135,7 +1180,7 @@ impl BufferDiff {
});
cx.emit(BufferDiffEvent::DiffChanged {
changed_range: Some(Anchor::min_max_range_for_buffer(self.buffer_id)),
- base_text_changed_range: todo!(),
+ base_text_changed_range: Some(0..self.base_text().len()),
});
}
}
@@ -1161,9 +1206,11 @@ impl BufferDiff {
));
if let Some((first, last)) = hunks.first().zip(hunks.last()) {
let changed_range = first.buffer_range.start..last.buffer_range.end;
+ let base_text_changed_range =
+ first.diff_base_byte_range.start..last.diff_base_byte_range.end;
cx.emit(BufferDiffEvent::DiffChanged {
changed_range: Some(changed_range),
- base_text_changed_range: todo!(),
+ base_text_changed_range: Some(base_text_changed_range),
});
}
new_index_text
@@ -1174,18 +1221,19 @@ impl BufferDiff {
range: Range<Anchor>,
buffer: &text::BufferSnapshot,
cx: &App,
- ) -> Option<Range<Anchor>> {
- let start = self
+ ) -> (Option<Range<Anchor>>, Option<Range<usize>>) {
+ let first_hunk = self
.hunks_intersecting_range(range.clone(), buffer, cx)
- .next()?
- .buffer_range
- .start;
- let end = self
- .hunks_intersecting_range_rev(range, buffer)
- .next()?
- .buffer_range
- .end;
- Some(start..end)
+ .next();
+ let last_hunk = self.hunks_intersecting_range_rev(range, buffer).next();
+ let range = first_hunk
+ .as_ref()
+ .zip(last_hunk.as_ref())
+ .map(|(first, last)| first.buffer_range.start..last.buffer_range.end);
+ let base_text_range = first_hunk
+ .zip(last_hunk)
+ .map(|(first, last)| first.diff_base_byte_range.start..last.diff_base_byte_range.end);
+ (range, base_text_range)
}
pub async fn update_diff(
@@ -1247,9 +1295,9 @@ impl BufferDiff {
let state = &mut self.inner;
let new_state = new_snapshot.inner;
- let (base_text_changed, mut changed_range) =
+ let (base_text_changed, (mut changed_range, mut base_text_changed_range)) =
match (state.base_text_exists, new_state.base_text_exists) {
- (false, false) => (true, None),
+ (false, false) => (true, (None, None)),
(true, true)
if state.base_text.remote_id() == new_state.base_text.remote_id()
&& state.base_text.syntax_update_count()
@@ -1259,12 +1307,15 @@ impl BufferDiff {
}
_ => (
true,
- Some(text::Anchor::min_max_range_for_buffer(self.buffer_id)),
+ (
+ Some(text::Anchor::min_max_range_for_buffer(self.buffer_id)),
+ Some(0..new_state.base_text.len()),
+ ),
),
};
if let Some(secondary_changed_range) = secondary_diff_change
- && let Some(secondary_hunk_range) =
+ && let (Some(secondary_hunk_range), Some(secondary_base_range)) =
self.range_to_hunk_range(secondary_changed_range, buffer, cx)
{
if let Some(range) = &mut changed_range {
@@ -1273,6 +1324,13 @@ impl BufferDiff {
} else {
changed_range = Some(secondary_hunk_range);
}
+
+ if let Some(base_text_range) = &mut base_text_changed_range {
+ base_text_range.start = secondary_base_range.start.min(base_text_range.start);
+ base_text_range.end = secondary_base_range.end.max(base_text_range.end);
+ } else {
+ base_text_changed_range = Some(secondary_base_range);
+ }
}
let state = &mut self.inner;
@@ -1288,13 +1346,22 @@ impl BufferDiff {
} else {
changed_range = Some(first.buffer_range.start..last.buffer_range.end);
}
+
+ if let Some(base_text_range) = &mut base_text_changed_range {
+ base_text_range.start =
+ base_text_range.start.min(first.diff_base_byte_range.start);
+ base_text_range.end = base_text_range.end.max(last.diff_base_byte_range.end);
+ } else {
+ base_text_changed_range =
+ Some(first.diff_base_byte_range.start..last.diff_base_byte_range.end);
+ }
}
state.pending_hunks = SumTree::new(buffer);
}
cx.emit(BufferDiffEvent::DiffChanged {
changed_range: changed_range.clone(),
- base_text_changed_range: todo!(),
+ base_text_changed_range,
});
changed_range
}
@@ -2163,7 +2230,7 @@ mod tests {
let empty_diff = cx.update(|cx| BufferDiffSnapshot::empty(&buffer, cx));
let diff_1 = BufferDiffSnapshot::new_sync(buffer.clone(), base_text.clone(), cx);
- let range = diff_1.inner.compare(&empty_diff.inner, &buffer).unwrap();
+ let range = diff_1.inner.compare(&empty_diff.inner, &buffer).0.unwrap();
assert_eq!(range.to_point(&buffer), Point::new(0, 0)..Point::new(8, 0));
// Edit does not affect the diff.
@@ -2181,7 +2248,7 @@ mod tests {
.unindent(),
);
let diff_2 = BufferDiffSnapshot::new_sync(buffer.clone(), base_text.clone(), cx);
- assert_eq!(None, diff_2.inner.compare(&diff_1.inner, &buffer));
+ assert_eq!(None, diff_2.inner.compare(&diff_1.inner, &buffer).0);
// Edit turns a deletion hunk into a modification.
buffer.edit_via_marked_text(
@@ -2198,7 +2265,7 @@ mod tests {
.unindent(),
);
let diff_3 = BufferDiffSnapshot::new_sync(buffer.clone(), base_text.clone(), cx);
- let range = diff_3.inner.compare(&diff_2.inner, &buffer).unwrap();
+ let range = diff_3.inner.compare(&diff_2.inner, &buffer).0.unwrap();
assert_eq!(range.to_point(&buffer), Point::new(1, 0)..Point::new(2, 0));
// Edit turns a modification hunk into a deletion.
@@ -2215,7 +2282,7 @@ mod tests {
.unindent(),
);
let diff_4 = BufferDiffSnapshot::new_sync(buffer.clone(), base_text.clone(), cx);
- let range = diff_4.inner.compare(&diff_3.inner, &buffer).unwrap();
+ let range = diff_4.inner.compare(&diff_3.inner, &buffer).0.unwrap();
assert_eq!(range.to_point(&buffer), Point::new(3, 4)..Point::new(4, 0));
// Edit introduces a new insertion hunk.
@@ -2233,7 +2300,7 @@ mod tests {
.unindent(),
);
let diff_5 = BufferDiffSnapshot::new_sync(buffer.snapshot(), base_text.clone(), cx);
- let range = diff_5.inner.compare(&diff_4.inner, &buffer).unwrap();
+ let range = diff_5.inner.compare(&diff_4.inner, &buffer).0.unwrap();
assert_eq!(range.to_point(&buffer), Point::new(3, 0)..Point::new(4, 0));
// Edit removes a hunk.
@@ -2251,7 +2318,7 @@ mod tests {
.unindent(),
);
let diff_6 = BufferDiffSnapshot::new_sync(buffer.snapshot(), base_text, cx);
- let range = diff_6.inner.compare(&diff_5.inner, &buffer).unwrap();
+ let range = diff_6.inner.compare(&diff_5.inner, &buffer).0.unwrap();
assert_eq!(range.to_point(&buffer), Point::new(7, 0)..Point::new(8, 0));
}
@@ -8,6 +8,7 @@ use language::{Buffer, Capability, LanguageRegistry};
use multi_buffer::{Anchor, ExcerptRange, MultiBuffer, PathKey};
use project::Project;
use rope::Point;
+use text::OffsetRangeExt as _;
use ui::{
App, Context, InteractiveElement as _, IntoElement as _, ParentElement as _, Render,
Styled as _, Window, div,
@@ -242,6 +243,8 @@ impl SplittableEditor {
}
}
+ // FIXME need add_diff management in here too
+
pub fn set_excerpts_for_path(
&mut self,
path: PathKey,
@@ -15,7 +15,7 @@ use buffer_diff::{
};
use clock::ReplicaId;
use collections::{BTreeMap, Bound, HashMap, HashSet};
-use gpui::{App, Context, Entity, EntityId, EventEmitter};
+use gpui::{App, Context, Entity, EntityId, EventEmitter, WeakEntity};
use itertools::Itertools;
use language::{
AutoindentMode, BracketMatch, Buffer, BufferChunks, BufferRow, BufferSnapshot, Capability,
@@ -514,7 +514,7 @@ struct DiffState {
///
/// The [`DiffState`]s in a [`MultiBuffer`] must either be all inverted, or
// all not inverted.
- is_inverted: bool,
+ main_buffer: Option<WeakEntity<Buffer>>,
_subscription: gpui::Subscription,
}
@@ -522,7 +522,11 @@ impl DiffState {
fn snapshot(&self, cx: &App) -> DiffStateSnapshot {
DiffStateSnapshot {
diff: self.diff.read(cx).snapshot(cx),
- is_inverted: self.is_inverted,
+ main_buffer: self.main_buffer.as_ref().and_then(|main_buffer| {
+ main_buffer
+ .read_with(cx, |main_buffer, _| main_buffer.snapshot())
+ .ok()
+ }),
}
}
}
@@ -530,7 +534,7 @@ impl DiffState {
#[derive(Clone)]
struct DiffStateSnapshot {
diff: BufferDiffSnapshot,
- is_inverted: bool,
+ main_buffer: Option<BufferSnapshot>,
}
impl std::ops::Deref for DiffStateSnapshot {
@@ -558,37 +562,43 @@ impl DiffState {
_ => {}
}),
diff,
- is_inverted: false,
+ main_buffer: None,
}
}
fn new_inverted(
diff: Entity<BufferDiff>,
base_text_buffer_id: BufferId,
+ main_buffer: Entity<Buffer>,
cx: &mut Context<MultiBuffer>,
) -> Self {
+ let main_buffer = main_buffer.downgrade();
DiffState {
- _subscription: cx.subscribe(&diff, move |this, diff, event, cx| match event {
- BufferDiffEvent::DiffChanged {
- changed_range: _,
- base_text_changed_range,
- } => {
- if let Some(base_text_changed_range) = base_text_changed_range.clone() {
- this.inverted_buffer_diff_changed(
- diff,
- base_text_changed_range,
- base_text_buffer_id,
- cx,
- )
+ _subscription: cx.subscribe(&diff, {
+ let main_buffer = main_buffer.clone();
+ move |this, diff, event, cx| match event {
+ BufferDiffEvent::DiffChanged {
+ changed_range: _,
+ base_text_changed_range,
+ } => {
+ if let Some(base_text_changed_range) = base_text_changed_range.clone() {
+ this.inverted_buffer_diff_changed(
+ diff,
+ base_text_changed_range,
+ base_text_buffer_id,
+ main_buffer.clone(),
+ cx,
+ )
+ }
+ cx.emit(Event::BufferDiffChanged);
}
- cx.emit(Event::BufferDiffChanged);
+ // FIXME
+ BufferDiffEvent::LanguageChanged => this.buffer_diff_language_changed(diff, cx),
+ _ => {}
}
- // FIXME
- BufferDiffEvent::LanguageChanged => this.buffer_diff_language_changed(diff, cx),
- _ => {}
}),
diff,
- is_inverted: true,
+ main_buffer: Some(main_buffer),
}
}
}
@@ -2267,7 +2277,7 @@ impl MultiBuffer {
let buffer_id = diff.buffer_id;
let diff = DiffStateSnapshot {
diff: diff.snapshot(cx),
- is_inverted: false,
+ main_buffer: None,
};
self.snapshot.get_mut().diffs.insert(buffer_id, diff);
}
@@ -2276,12 +2286,15 @@ impl MultiBuffer {
&mut self,
base_text_buffer_id: BufferId,
diff: Entity<BufferDiff>,
+ main_buffer: WeakEntity<Buffer>,
cx: &mut Context<Self>,
) {
let diff = diff.read(cx);
let diff = DiffStateSnapshot {
diff: diff.snapshot(cx),
- is_inverted: true,
+ main_buffer: main_buffer
+ .update(cx, |main_buffer, _| main_buffer.snapshot())
+ .ok(),
};
self.snapshot
.get_mut()
@@ -2309,7 +2322,7 @@ impl MultiBuffer {
let new_diff = DiffStateSnapshot {
diff: diff.snapshot(cx),
- is_inverted: false,
+ main_buffer: None,
};
let mut snapshot = self.snapshot.get_mut();
let base_text_changed = snapshot
@@ -2371,15 +2384,9 @@ impl MultiBuffer {
diff: Entity<BufferDiff>,
diff_change_range: Range<usize>,
base_text_buffer_id: BufferId,
+ main_buffer: WeakEntity<Buffer>,
cx: &mut Context<Self>,
) {
- // FIXME move this to the level of the splittableeditor
- // if base_text_changed && let Some(buffer_state) = self.buffers.get(&base_text_buffer_id) {
- // buffer_state.buffer.update(cx, |buffer, cx| {
- // // FIXME use the rope directly
- // buffer.set_text(diff.read(cx).base_text().text(), cx);
- // });
- // }
self.sync_mut(cx);
let diff = diff.read(cx);
@@ -2390,7 +2397,9 @@ impl MultiBuffer {
let new_diff = DiffStateSnapshot {
diff: diff.snapshot(cx),
- is_inverted: true,
+ main_buffer: main_buffer
+ .update(cx, |main_buffer, _| main_buffer.snapshot())
+ .ok(),
};
let mut snapshot = self.snapshot.get_mut();
let base_text_changed = snapshot
@@ -2601,7 +2610,7 @@ impl MultiBuffer {
}
pub fn add_diff(&mut self, diff: Entity<BufferDiff>, cx: &mut Context<Self>) {
- debug_assert!(self.diffs.values().all(|diff| !diff.is_inverted));
+ debug_assert!(self.diffs.values().all(|diff| diff.main_buffer.is_none()));
let buffer_id = diff.read(cx).buffer_id;
self.buffer_diff_changed(
@@ -2617,15 +2626,22 @@ impl MultiBuffer {
&mut self,
base_text_buffer_id: BufferId,
diff: Entity<BufferDiff>,
+ main_buffer: Entity<Buffer>,
cx: &mut Context<Self>,
) {
- debug_assert!(self.diffs.values().all(|diff| diff.is_inverted));
+ debug_assert!(self.diffs.values().all(|diff| diff.main_buffer.is_some()));
let diff_change_range = 0..diff.read(cx).base_text().len();
- self.inverted_buffer_diff_changed(diff.clone(), diff_change_range, base_text_buffer_id, cx);
+ self.inverted_buffer_diff_changed(
+ diff.clone(),
+ diff_change_range,
+ base_text_buffer_id,
+ main_buffer.downgrade(),
+ cx,
+ );
self.diffs.insert(
base_text_buffer_id,
- DiffState::new_inverted(diff, base_text_buffer_id, cx),
+ DiffState::new_inverted(diff, base_text_buffer_id, main_buffer, cx),
);
}
@@ -3300,10 +3316,11 @@ impl MultiBuffer {
excerpt_buffer_start + edit.new.end.saturating_sub(excerpt_start);
let edit_buffer_end = edit_buffer_end.min(excerpt_buffer_end);
- if diff.is_inverted {
- for hunk in
- diff.hunks_intersecting_base_text_range(edit_buffer_start..edit_buffer_end)
- {
+ if let Some(main_buffer) = &diff.main_buffer {
+ for hunk in diff.hunks_intersecting_base_text_range(
+ edit_buffer_start..edit_buffer_end,
+ main_buffer,
+ ) {
let hunk_buffer_range = hunk.diff_base_byte_range.clone();
if hunk_buffer_range.start < excerpt_buffer_start {
log::trace!("skipping hunk that starts before excerpt");
@@ -3838,12 +3855,15 @@ impl MultiBufferSnapshot {
self.lift_buffer_metadata(query_range.clone(), move |buffer, buffer_range| {
let diff = self.diffs.get(&buffer.remote_id())?;
let iter: Box<dyn Iterator<Item = (DiffHunk, &BufferSnapshot, bool)>> =
- if diff.is_inverted {
+ if let Some(main_buffer) = &diff.main_buffer {
let buffer_start = buffer.point_to_offset(buffer_range.start);
let buffer_end = buffer.point_to_offset(buffer_range.end);
Box::new(
- diff.hunks_intersecting_base_text_range(buffer_start..buffer_end)
- .map(move |hunk| (hunk, buffer, true)),
+ diff.hunks_intersecting_base_text_range(
+ buffer_start..buffer_end,
+ main_buffer,
+ )
+ .map(move |hunk| (hunk, buffer, true)),
)
} else {
let buffer_start = buffer.anchor_before(buffer_range.start);