Add staged status information to diff hunks (#24475)
Release Notes: - Render unstaged hunks in the project diff editor with a slashed background --------- Co-authored-by: maxbrunsfeld <max@zed.dev> Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
a9de9e3cb4
commit
8f75fe25e5
28 changed files with 1132 additions and 753 deletions
|
@ -14,7 +14,7 @@ doctest = false
|
|||
|
||||
[features]
|
||||
test-support = [
|
||||
"diff/test-support",
|
||||
"buffer_diff/test-support",
|
||||
"gpui/test-support",
|
||||
"language/test-support",
|
||||
"text/test-support",
|
||||
|
@ -26,7 +26,7 @@ anyhow.workspace = true
|
|||
clock.workspace = true
|
||||
collections.workspace = true
|
||||
ctor.workspace = true
|
||||
diff.workspace = true
|
||||
buffer_diff.workspace = true
|
||||
env_logger.workspace = true
|
||||
futures.workspace = true
|
||||
gpui.workspace = true
|
||||
|
@ -47,7 +47,7 @@ tree-sitter.workspace = true
|
|||
util.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
diff = { workspace = true, features = ["test-support"] }
|
||||
buffer_diff = { workspace = true, features = ["test-support"] }
|
||||
gpui = { workspace = true, features = ["test-support"] }
|
||||
indoc.workspace = true
|
||||
language = { workspace = true, features = ["test-support"] }
|
||||
|
|
|
@ -73,7 +73,7 @@ impl Anchor {
|
|||
if let Some(base_text) = snapshot
|
||||
.diffs
|
||||
.get(&excerpt.buffer_id)
|
||||
.and_then(|diff| diff.base_text.as_ref())
|
||||
.and_then(|diff| diff.base_text())
|
||||
{
|
||||
let self_anchor = self.diff_base_anchor.filter(|a| base_text.can_resolve(a));
|
||||
let other_anchor = other.diff_base_anchor.filter(|a| base_text.can_resolve(a));
|
||||
|
@ -110,7 +110,7 @@ impl Anchor {
|
|||
if let Some(base_text) = snapshot
|
||||
.diffs
|
||||
.get(&excerpt.buffer_id)
|
||||
.and_then(|diff| diff.base_text.as_ref())
|
||||
.and_then(|diff| diff.base_text())
|
||||
{
|
||||
if a.buffer_id == Some(base_text.remote_id()) {
|
||||
return a.bias_left(base_text);
|
||||
|
@ -135,7 +135,7 @@ impl Anchor {
|
|||
if let Some(base_text) = snapshot
|
||||
.diffs
|
||||
.get(&excerpt.buffer_id)
|
||||
.and_then(|diff| diff.base_text.as_ref())
|
||||
.and_then(|diff| diff.base_text())
|
||||
{
|
||||
if a.buffer_id == Some(base_text.remote_id()) {
|
||||
return a.bias_right(&base_text);
|
||||
|
|
|
@ -7,9 +7,11 @@ pub use anchor::{Anchor, AnchorRangeExt, Offset};
|
|||
pub use position::{TypedOffset, TypedPoint, TypedRow};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use buffer_diff::{
|
||||
BufferDiff, BufferDiffEvent, BufferDiffSnapshot, DiffHunkSecondaryStatus, DiffHunkStatus,
|
||||
};
|
||||
use clock::ReplicaId;
|
||||
use collections::{BTreeMap, Bound, HashMap, HashSet};
|
||||
use diff::{BufferDiff, BufferDiffEvent, BufferDiffSnapshot, DiffHunkStatus};
|
||||
use futures::{channel::mpsc, SinkExt};
|
||||
use gpui::{App, Context, Entity, EntityId, EventEmitter, Task};
|
||||
use itertools::Itertools;
|
||||
|
@ -129,16 +131,18 @@ pub struct MultiBufferDiffHunk {
|
|||
pub excerpt_id: ExcerptId,
|
||||
/// The range within the buffer's diff base that this hunk corresponds to.
|
||||
pub diff_base_byte_range: Range<usize>,
|
||||
/// Whether or not this hunk also appears in the 'secondary diff'.
|
||||
pub secondary_status: DiffHunkSecondaryStatus,
|
||||
}
|
||||
|
||||
impl MultiBufferDiffHunk {
|
||||
pub fn status(&self) -> DiffHunkStatus {
|
||||
if self.buffer_range.start == self.buffer_range.end {
|
||||
DiffHunkStatus::Removed
|
||||
DiffHunkStatus::Removed(self.secondary_status)
|
||||
} else if self.diff_base_byte_range.is_empty() {
|
||||
DiffHunkStatus::Added
|
||||
DiffHunkStatus::Added(self.secondary_status)
|
||||
} else {
|
||||
DiffHunkStatus::Modified
|
||||
DiffHunkStatus::Modified(self.secondary_status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +229,14 @@ impl DiffState {
|
|||
DiffState {
|
||||
_subscription: cx.subscribe(&diff, |this, diff, event, cx| match event {
|
||||
BufferDiffEvent::DiffChanged { changed_range } => {
|
||||
this.buffer_diff_changed(diff, changed_range.clone(), cx)
|
||||
let changed_range = if let Some(changed_range) = changed_range {
|
||||
changed_range.clone()
|
||||
} else if diff.read(cx).base_text().is_none() && this.all_diff_hunks_expanded {
|
||||
text::Anchor::MIN..text::Anchor::MAX
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
this.buffer_diff_changed(diff, changed_range, cx)
|
||||
}
|
||||
BufferDiffEvent::LanguageChanged => this.buffer_diff_language_changed(diff, cx),
|
||||
}),
|
||||
|
@ -241,7 +252,7 @@ pub struct MultiBufferSnapshot {
|
|||
excerpts: SumTree<Excerpt>,
|
||||
excerpt_ids: SumTree<ExcerptIdMapping>,
|
||||
diffs: TreeMap<BufferId, BufferDiffSnapshot>,
|
||||
pub diff_transforms: SumTree<DiffTransform>,
|
||||
diff_transforms: SumTree<DiffTransform>,
|
||||
trailing_excerpt_update_count: usize,
|
||||
non_text_state_update_count: usize,
|
||||
edit_count: usize,
|
||||
|
@ -252,20 +263,27 @@ pub struct MultiBufferSnapshot {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DiffTransform {
|
||||
enum DiffTransform {
|
||||
BufferContent {
|
||||
summary: TextSummary,
|
||||
inserted_hunk_anchor: Option<(ExcerptId, text::Anchor)>,
|
||||
inserted_hunk_info: Option<DiffTransformHunkInfo>,
|
||||
},
|
||||
DeletedHunk {
|
||||
summary: TextSummary,
|
||||
buffer_id: BufferId,
|
||||
hunk_anchor: (ExcerptId, text::Anchor),
|
||||
hunk_info: DiffTransformHunkInfo,
|
||||
base_text_byte_range: Range<usize>,
|
||||
has_trailing_newline: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
struct DiffTransformHunkInfo {
|
||||
excerpt_id: ExcerptId,
|
||||
hunk_start_anchor: text::Anchor,
|
||||
hunk_secondary_status: DiffHunkSecondaryStatus,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ExcerptInfo {
|
||||
pub id: ExcerptId,
|
||||
|
@ -310,7 +328,7 @@ pub struct RowInfo {
|
|||
pub buffer_id: Option<BufferId>,
|
||||
pub buffer_row: Option<u32>,
|
||||
pub multibuffer_row: Option<MultiBufferRow>,
|
||||
pub diff_status: Option<diff::DiffHunkStatus>,
|
||||
pub diff_status: Option<buffer_diff::DiffHunkStatus>,
|
||||
}
|
||||
|
||||
/// A slice into a [`Buffer`] that is being edited in a [`MultiBuffer`].
|
||||
|
@ -431,7 +449,7 @@ struct MultiBufferCursor<'a, D: TextDimension> {
|
|||
struct MultiBufferRegion<'a, D: TextDimension> {
|
||||
buffer: &'a BufferSnapshot,
|
||||
is_main_buffer: bool,
|
||||
is_inserted_hunk: bool,
|
||||
diff_hunk_status: Option<DiffHunkStatus>,
|
||||
excerpt: &'a Excerpt,
|
||||
buffer_range: Range<D>,
|
||||
range: Range<D>,
|
||||
|
@ -2146,7 +2164,7 @@ impl MultiBuffer {
|
|||
let mut snapshot = self.snapshot.borrow_mut();
|
||||
let diff = diff.read(cx);
|
||||
let buffer_id = diff.buffer_id;
|
||||
let diff = diff.snapshot.clone();
|
||||
let diff = diff.snapshot(cx);
|
||||
snapshot.diffs.insert(buffer_id, diff);
|
||||
}
|
||||
|
||||
|
@ -2160,36 +2178,29 @@ impl MultiBuffer {
|
|||
|
||||
let diff = diff.read(cx);
|
||||
let buffer_id = diff.buffer_id;
|
||||
let mut diff = diff.snapshot.clone();
|
||||
if diff.base_text.is_none() && self.all_diff_hunks_expanded {
|
||||
diff = BufferDiffSnapshot::new_with_single_insertion(cx);
|
||||
}
|
||||
|
||||
let mut snapshot = self.snapshot.borrow_mut();
|
||||
let base_text_changed =
|
||||
snapshot
|
||||
.diffs
|
||||
.get(&buffer_id)
|
||||
.map_or(true, |diff_snapshot| {
|
||||
match (&diff_snapshot.base_text, &diff.base_text) {
|
||||
(None, None) => false,
|
||||
(None, Some(_)) => true,
|
||||
(Some(_), None) => true,
|
||||
(Some(old), Some(new)) => {
|
||||
let (old_id, old_empty) = (old.remote_id(), old.is_empty());
|
||||
let (new_id, new_empty) = (new.remote_id(), new.is_empty());
|
||||
new_id != old_id && (!new_empty || !old_empty)
|
||||
}
|
||||
}
|
||||
});
|
||||
snapshot.diffs.insert(buffer_id, diff);
|
||||
|
||||
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 buffer = buffer_state.buffer.read(cx);
|
||||
let diff_change_range = range.to_offset(buffer);
|
||||
|
||||
let mut new_diff = diff.snapshot(cx);
|
||||
if new_diff.base_text().is_none() && self.all_diff_hunks_expanded {
|
||||
let secondary_diff_insertion = new_diff
|
||||
.secondary_diff()
|
||||
.map_or(true, |secondary_diff| secondary_diff.base_text().is_none());
|
||||
new_diff = BufferDiff::build_with_single_insertion(secondary_diff_insertion, cx);
|
||||
}
|
||||
|
||||
let mut snapshot = self.snapshot.borrow_mut();
|
||||
let base_text_changed = snapshot
|
||||
.diffs
|
||||
.get(&buffer_id)
|
||||
.map_or(true, |old_diff| !new_diff.base_texts_eq(old_diff));
|
||||
|
||||
snapshot.diffs.insert(buffer_id, new_diff);
|
||||
|
||||
let mut excerpt_edits = Vec::new();
|
||||
for locator in &buffer_state.excerpts {
|
||||
|
@ -2367,7 +2378,7 @@ impl MultiBuffer {
|
|||
if *cursor.start() >= end {
|
||||
break;
|
||||
}
|
||||
if item.hunk_anchor().is_some() {
|
||||
if item.hunk_info().is_some() {
|
||||
return true;
|
||||
}
|
||||
cursor.next(&());
|
||||
|
@ -2820,11 +2831,11 @@ impl MultiBuffer {
|
|||
let keep_next_old_transform = (old_diff_transforms.start().0 >= edit.old.end)
|
||||
&& match old_diff_transforms.item() {
|
||||
Some(DiffTransform::BufferContent {
|
||||
inserted_hunk_anchor: Some(hunk_anchor),
|
||||
inserted_hunk_info: Some(hunk),
|
||||
..
|
||||
}) => excerpts
|
||||
.item()
|
||||
.is_some_and(|excerpt| hunk_anchor.1.is_valid(&excerpt.buffer)),
|
||||
}) => excerpts.item().is_some_and(|excerpt| {
|
||||
hunk.hunk_start_anchor.is_valid(&excerpt.buffer)
|
||||
}),
|
||||
_ => true,
|
||||
};
|
||||
|
||||
|
@ -2853,7 +2864,7 @@ impl MultiBuffer {
|
|||
new_diff_transforms.push(
|
||||
DiffTransform::BufferContent {
|
||||
summary: Default::default(),
|
||||
inserted_hunk_anchor: None,
|
||||
inserted_hunk_info: None,
|
||||
},
|
||||
&(),
|
||||
);
|
||||
|
@ -2876,8 +2887,8 @@ impl MultiBuffer {
|
|||
excerpts: &mut 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)>,
|
||||
old_expanded_hunks: &mut HashSet<(ExcerptId, text::Anchor)>,
|
||||
end_of_current_insert: &mut Option<(TypedOffset<Excerpt>, DiffTransformHunkInfo)>,
|
||||
old_expanded_hunks: &mut HashSet<DiffTransformHunkInfo>,
|
||||
snapshot: &MultiBufferSnapshot,
|
||||
change_kind: DiffChangeKind,
|
||||
) -> bool {
|
||||
|
@ -2889,12 +2900,12 @@ impl MultiBuffer {
|
|||
|
||||
// Record which hunks were previously expanded.
|
||||
while let Some(item) = old_diff_transforms.item() {
|
||||
if let Some(hunk_anchor) = item.hunk_anchor() {
|
||||
if let Some(hunk_info) = item.hunk_info() {
|
||||
log::trace!(
|
||||
"previously expanded hunk at {}",
|
||||
old_diff_transforms.start().0
|
||||
);
|
||||
old_expanded_hunks.insert(hunk_anchor);
|
||||
old_expanded_hunks.insert(hunk_info);
|
||||
}
|
||||
if old_diff_transforms.end(&()).0 > edit.old.end {
|
||||
break;
|
||||
|
@ -2918,7 +2929,7 @@ impl MultiBuffer {
|
|||
if let Some((diff, base_text)) = snapshot
|
||||
.diffs
|
||||
.get(&excerpt.buffer_id)
|
||||
.and_then(|diff| Some((diff, diff.base_text.as_ref()?)))
|
||||
.and_then(|diff| Some((diff, diff.base_text()?)))
|
||||
{
|
||||
let buffer = &excerpt.buffer;
|
||||
let excerpt_start = *excerpts.start();
|
||||
|
@ -2936,7 +2947,11 @@ impl MultiBuffer {
|
|||
for hunk in diff.hunks_intersecting_range(edit_anchor_range, buffer) {
|
||||
let hunk_buffer_range = hunk.buffer_range.to_offset(buffer);
|
||||
|
||||
let hunk_anchor = (excerpt.id, hunk.buffer_range.start);
|
||||
let hunk_info = DiffTransformHunkInfo {
|
||||
excerpt_id: excerpt.id,
|
||||
hunk_start_anchor: hunk.buffer_range.start,
|
||||
hunk_secondary_status: hunk.secondary_status,
|
||||
};
|
||||
if hunk_buffer_range.start < excerpt_buffer_start {
|
||||
log::trace!("skipping hunk that starts before excerpt");
|
||||
continue;
|
||||
|
@ -2960,7 +2975,7 @@ impl MultiBuffer {
|
|||
|
||||
// For every existing hunk, determine if it was previously expanded
|
||||
// and if it should currently be expanded.
|
||||
let was_previously_expanded = old_expanded_hunks.contains(&hunk_anchor);
|
||||
let was_previously_expanded = old_expanded_hunks.contains(&hunk_info);
|
||||
let should_expand_hunk = match &change_kind {
|
||||
DiffChangeKind::DiffUpdated { base_changed: true } => {
|
||||
self.all_diff_hunks_expanded
|
||||
|
@ -3008,7 +3023,7 @@ impl MultiBuffer {
|
|||
base_text_byte_range: hunk.diff_base_byte_range.clone(),
|
||||
summary: base_text_summary,
|
||||
buffer_id: excerpt.buffer_id,
|
||||
hunk_anchor,
|
||||
hunk_info,
|
||||
has_trailing_newline,
|
||||
},
|
||||
&(),
|
||||
|
@ -3016,11 +3031,8 @@ impl MultiBuffer {
|
|||
}
|
||||
|
||||
if !hunk_buffer_range.is_empty() {
|
||||
*end_of_current_insert = Some((
|
||||
hunk_excerpt_end.min(excerpt_end),
|
||||
hunk_anchor.0,
|
||||
hunk_anchor.1,
|
||||
));
|
||||
*end_of_current_insert =
|
||||
Some((hunk_excerpt_end.min(excerpt_end), hunk_info));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3042,13 +3054,13 @@ impl MultiBuffer {
|
|||
subtree: SumTree<DiffTransform>,
|
||||
) {
|
||||
if let Some(DiffTransform::BufferContent {
|
||||
inserted_hunk_anchor,
|
||||
inserted_hunk_info,
|
||||
summary,
|
||||
}) = subtree.first()
|
||||
{
|
||||
if self.extend_last_buffer_content_transform(
|
||||
new_transforms,
|
||||
*inserted_hunk_anchor,
|
||||
*inserted_hunk_info,
|
||||
*summary,
|
||||
) {
|
||||
let mut cursor = subtree.cursor::<()>(&());
|
||||
|
@ -3067,7 +3079,7 @@ impl MultiBuffer {
|
|||
transform: DiffTransform,
|
||||
) {
|
||||
if let DiffTransform::BufferContent {
|
||||
inserted_hunk_anchor,
|
||||
inserted_hunk_info: inserted_hunk_anchor,
|
||||
summary,
|
||||
} = transform
|
||||
{
|
||||
|
@ -3087,19 +3099,14 @@ impl MultiBuffer {
|
|||
old_snapshot: &MultiBufferSnapshot,
|
||||
new_transforms: &mut SumTree<DiffTransform>,
|
||||
end_offset: ExcerptOffset,
|
||||
current_inserted_hunk: Option<(ExcerptOffset, ExcerptId, text::Anchor)>,
|
||||
current_inserted_hunk: Option<(ExcerptOffset, DiffTransformHunkInfo)>,
|
||||
) {
|
||||
let inserted_region =
|
||||
current_inserted_hunk.map(|(insertion_end_offset, excerpt_id, anchor)| {
|
||||
(
|
||||
end_offset.min(insertion_end_offset),
|
||||
Some((excerpt_id, anchor)),
|
||||
)
|
||||
});
|
||||
let inserted_region = current_inserted_hunk.map(|(insertion_end_offset, hunk_info)| {
|
||||
(end_offset.min(insertion_end_offset), Some(hunk_info))
|
||||
});
|
||||
let unchanged_region = [(end_offset, None)];
|
||||
|
||||
for (end_offset, inserted_hunk_anchor) in
|
||||
inserted_region.into_iter().chain(unchanged_region)
|
||||
for (end_offset, inserted_hunk_info) in inserted_region.into_iter().chain(unchanged_region)
|
||||
{
|
||||
let start_offset = new_transforms.summary().excerpt_len();
|
||||
if end_offset <= start_offset {
|
||||
|
@ -3110,13 +3117,13 @@ impl MultiBuffer {
|
|||
|
||||
if !self.extend_last_buffer_content_transform(
|
||||
new_transforms,
|
||||
inserted_hunk_anchor,
|
||||
inserted_hunk_info,
|
||||
summary_to_add,
|
||||
) {
|
||||
new_transforms.push(
|
||||
DiffTransform::BufferContent {
|
||||
summary: summary_to_add,
|
||||
inserted_hunk_anchor,
|
||||
inserted_hunk_info,
|
||||
},
|
||||
&(),
|
||||
)
|
||||
|
@ -3127,7 +3134,7 @@ impl MultiBuffer {
|
|||
fn extend_last_buffer_content_transform(
|
||||
&self,
|
||||
new_transforms: &mut SumTree<DiffTransform>,
|
||||
new_inserted_hunk_anchor: Option<(ExcerptId, text::Anchor)>,
|
||||
new_inserted_hunk_info: Option<DiffTransformHunkInfo>,
|
||||
summary_to_add: TextSummary,
|
||||
) -> bool {
|
||||
let mut did_extend = false;
|
||||
|
@ -3135,10 +3142,10 @@ impl MultiBuffer {
|
|||
|last_transform| {
|
||||
if let DiffTransform::BufferContent {
|
||||
summary,
|
||||
inserted_hunk_anchor,
|
||||
inserted_hunk_info: inserted_hunk_anchor,
|
||||
} = last_transform
|
||||
{
|
||||
if *inserted_hunk_anchor == new_inserted_hunk_anchor {
|
||||
if *inserted_hunk_anchor == new_inserted_hunk_info {
|
||||
*summary += summary_to_add;
|
||||
did_extend = true;
|
||||
}
|
||||
|
@ -3469,6 +3476,7 @@ impl MultiBufferSnapshot {
|
|||
excerpt_id: excerpt.id,
|
||||
buffer_range: hunk.buffer_range.clone(),
|
||||
diff_base_byte_range: hunk.diff_base_byte_range.clone(),
|
||||
secondary_status: hunk.secondary_status,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -3837,6 +3845,7 @@ impl MultiBufferSnapshot {
|
|||
excerpt_id: excerpt.id,
|
||||
buffer_range: hunk.buffer_range.clone(),
|
||||
diff_base_byte_range: hunk.diff_base_byte_range.clone(),
|
||||
secondary_status: hunk.secondary_status,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -4309,10 +4318,7 @@ impl MultiBufferSnapshot {
|
|||
} => {
|
||||
let buffer_start = base_text_byte_range.start + start_overshoot;
|
||||
let mut buffer_end = base_text_byte_range.start + end_overshoot;
|
||||
let Some(base_text) = self
|
||||
.diffs
|
||||
.get(buffer_id)
|
||||
.and_then(|diff| diff.base_text.as_ref())
|
||||
let Some(base_text) = self.diffs.get(buffer_id).and_then(|diff| diff.base_text())
|
||||
else {
|
||||
panic!("{:?} is in non-existent deleted hunk", range.start)
|
||||
};
|
||||
|
@ -4361,10 +4367,7 @@ impl MultiBufferSnapshot {
|
|||
..
|
||||
} => {
|
||||
let buffer_end = base_text_byte_range.start + overshoot;
|
||||
let Some(base_text) = self
|
||||
.diffs
|
||||
.get(buffer_id)
|
||||
.and_then(|diff| diff.base_text.as_ref())
|
||||
let Some(base_text) = self.diffs.get(buffer_id).and_then(|diff| diff.base_text())
|
||||
else {
|
||||
panic!("{:?} is in non-existent deleted hunk", range.end)
|
||||
};
|
||||
|
@ -4469,10 +4472,8 @@ impl MultiBufferSnapshot {
|
|||
}) => {
|
||||
let mut in_deleted_hunk = false;
|
||||
if let Some(diff_base_anchor) = &anchor.diff_base_anchor {
|
||||
if let Some(base_text) = self
|
||||
.diffs
|
||||
.get(buffer_id)
|
||||
.and_then(|diff| diff.base_text.as_ref())
|
||||
if let Some(base_text) =
|
||||
self.diffs.get(buffer_id).and_then(|diff| diff.base_text())
|
||||
{
|
||||
if base_text.can_resolve(&diff_base_anchor) {
|
||||
let base_text_offset = diff_base_anchor.to_offset(&base_text);
|
||||
|
@ -4809,7 +4810,7 @@ impl MultiBufferSnapshot {
|
|||
let base_text = self
|
||||
.diffs
|
||||
.get(buffer_id)
|
||||
.and_then(|diff| diff.base_text.as_ref())
|
||||
.and_then(|diff| diff.base_text())
|
||||
.expect("missing diff base");
|
||||
if offset_in_transform > base_text_byte_range.len() {
|
||||
debug_assert!(*has_trailing_newline);
|
||||
|
@ -5969,17 +5970,17 @@ impl MultiBufferSnapshot {
|
|||
for item in self.diff_transforms.iter() {
|
||||
if let DiffTransform::BufferContent {
|
||||
summary,
|
||||
inserted_hunk_anchor,
|
||||
inserted_hunk_info,
|
||||
} = item
|
||||
{
|
||||
if let Some(DiffTransform::BufferContent {
|
||||
inserted_hunk_anchor: prev_inserted_hunk_anchor,
|
||||
inserted_hunk_info: prev_inserted_hunk_info,
|
||||
..
|
||||
}) = prev_transform
|
||||
{
|
||||
if *inserted_hunk_anchor == *prev_inserted_hunk_anchor {
|
||||
if *inserted_hunk_info == *prev_inserted_hunk_info {
|
||||
panic!(
|
||||
"multiple adjacent buffer content transforms with is_inserted_hunk = {inserted_hunk_anchor:?}. transforms: {:+?}",
|
||||
"multiple adjacent buffer content transforms with is_inserted_hunk = {inserted_hunk_info:?}. transforms: {:+?}",
|
||||
self.diff_transforms.items(&()));
|
||||
}
|
||||
}
|
||||
|
@ -6149,10 +6150,11 @@ where
|
|||
buffer_id,
|
||||
base_text_byte_range,
|
||||
has_trailing_newline,
|
||||
hunk_info,
|
||||
..
|
||||
} => {
|
||||
let diff = self.diffs.get(&buffer_id)?;
|
||||
let buffer = diff.base_text.as_ref()?;
|
||||
let buffer = diff.base_text()?;
|
||||
let mut rope_cursor = buffer.as_rope().cursor(0);
|
||||
let buffer_start = rope_cursor.summary::<D>(base_text_byte_range.start);
|
||||
let buffer_range_len = rope_cursor.summary::<D>(base_text_byte_range.end);
|
||||
|
@ -6165,14 +6167,15 @@ where
|
|||
excerpt,
|
||||
has_trailing_newline: *has_trailing_newline,
|
||||
is_main_buffer: false,
|
||||
is_inserted_hunk: false,
|
||||
diff_hunk_status: Some(DiffHunkStatus::Removed(
|
||||
hunk_info.hunk_secondary_status,
|
||||
)),
|
||||
buffer_range: buffer_start..buffer_end,
|
||||
range: start..end,
|
||||
});
|
||||
}
|
||||
DiffTransform::BufferContent {
|
||||
inserted_hunk_anchor,
|
||||
..
|
||||
inserted_hunk_info, ..
|
||||
} => {
|
||||
let buffer = &excerpt.buffer;
|
||||
let buffer_context_start = excerpt.range.context.start.summary::<D>(buffer);
|
||||
|
@ -6209,7 +6212,8 @@ where
|
|||
excerpt,
|
||||
has_trailing_newline,
|
||||
is_main_buffer: true,
|
||||
is_inserted_hunk: inserted_hunk_anchor.is_some(),
|
||||
diff_hunk_status: inserted_hunk_info
|
||||
.map(|info| DiffHunkStatus::Added(info.hunk_secondary_status)),
|
||||
buffer_range: buffer_start..buffer_end,
|
||||
range: start..end,
|
||||
})
|
||||
|
@ -6717,13 +6721,12 @@ impl sum_tree::KeyedItem for ExcerptIdMapping {
|
|||
}
|
||||
|
||||
impl DiffTransform {
|
||||
fn hunk_anchor(&self) -> Option<(ExcerptId, text::Anchor)> {
|
||||
fn hunk_info(&self) -> Option<DiffTransformHunkInfo> {
|
||||
match self {
|
||||
DiffTransform::DeletedHunk { hunk_anchor, .. } => Some(*hunk_anchor),
|
||||
DiffTransform::DeletedHunk { hunk_info, .. } => Some(*hunk_info),
|
||||
DiffTransform::BufferContent {
|
||||
inserted_hunk_anchor,
|
||||
..
|
||||
} => *inserted_hunk_anchor,
|
||||
inserted_hunk_info, ..
|
||||
} => *inserted_hunk_info,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7020,13 +7023,9 @@ impl<'a> Iterator for MultiBufferRows<'a> {
|
|||
buffer_id: Some(region.buffer.remote_id()),
|
||||
buffer_row: Some(buffer_point.row),
|
||||
multibuffer_row: Some(MultiBufferRow(self.point.row)),
|
||||
diff_status: if region.is_inserted_hunk && self.point < region.range.end {
|
||||
Some(DiffHunkStatus::Added)
|
||||
} else if !region.is_main_buffer {
|
||||
Some(DiffHunkStatus::Removed)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
diff_status: region
|
||||
.diff_hunk_status
|
||||
.filter(|_| self.point < region.range.end),
|
||||
});
|
||||
self.point += Point::new(1, 0);
|
||||
result
|
||||
|
@ -7194,7 +7193,7 @@ impl<'a> Iterator for MultiBufferChunks<'a> {
|
|||
}
|
||||
chunks
|
||||
} else {
|
||||
let base_buffer = &self.diffs.get(&buffer_id)?.base_text.as_ref()?;
|
||||
let base_buffer = &self.diffs.get(&buffer_id)?.base_text()?;
|
||||
base_buffer.chunks(base_text_start..base_text_end, self.language_aware)
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::*;
|
||||
use diff::DiffHunkStatus;
|
||||
use buffer_diff::DiffHunkStatus;
|
||||
use gpui::{App, TestAppContext};
|
||||
use indoc::indoc;
|
||||
use language::{Buffer, Rope};
|
||||
|
@ -979,8 +979,6 @@ fn test_empty_diff_excerpt(cx: &mut TestAppContext) {
|
|||
|
||||
let diff = cx.new(|cx| BufferDiff::new_with_base_text(base_text, &buffer, cx));
|
||||
multibuffer.update(cx, |multibuffer, cx| {
|
||||
multibuffer.set_all_diff_hunks_expanded(cx);
|
||||
multibuffer.add_diff(diff.clone(), cx);
|
||||
multibuffer.push_excerpts(
|
||||
buffer.clone(),
|
||||
[ExcerptRange {
|
||||
|
@ -989,6 +987,8 @@ fn test_empty_diff_excerpt(cx: &mut TestAppContext) {
|
|||
}],
|
||||
cx,
|
||||
);
|
||||
multibuffer.set_all_diff_hunks_expanded(cx);
|
||||
multibuffer.add_diff(diff.clone(), cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
|
@ -1325,13 +1325,13 @@ fn test_basic_diff_hunks(cx: &mut TestAppContext) {
|
|||
.map(|info| (info.buffer_row, info.diff_status))
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
(Some(0), Some(DiffHunkStatus::Added)),
|
||||
(Some(0), Some(DiffHunkStatus::added())),
|
||||
(Some(1), None),
|
||||
(Some(1), Some(DiffHunkStatus::Removed)),
|
||||
(Some(2), Some(DiffHunkStatus::Added)),
|
||||
(Some(1), Some(DiffHunkStatus::removed())),
|
||||
(Some(2), Some(DiffHunkStatus::added())),
|
||||
(Some(3), None),
|
||||
(Some(3), Some(DiffHunkStatus::Removed)),
|
||||
(Some(4), Some(DiffHunkStatus::Removed)),
|
||||
(Some(3), Some(DiffHunkStatus::removed())),
|
||||
(Some(4), Some(DiffHunkStatus::removed())),
|
||||
(Some(4), None),
|
||||
(Some(5), None)
|
||||
]
|
||||
|
@ -1999,12 +1999,8 @@ fn test_diff_hunks_with_multiple_excerpts(cx: &mut TestAppContext) {
|
|||
|
||||
let id_1 = buffer_1.read_with(cx, |buffer, _| buffer.remote_id());
|
||||
let id_2 = buffer_2.read_with(cx, |buffer, _| buffer.remote_id());
|
||||
let base_id_1 = diff_1.read_with(cx, |diff, _| {
|
||||
diff.snapshot.base_text.as_ref().unwrap().remote_id()
|
||||
});
|
||||
let base_id_2 = diff_2.read_with(cx, |diff, _| {
|
||||
diff.snapshot.base_text.as_ref().unwrap().remote_id()
|
||||
});
|
||||
let base_id_1 = diff_1.read_with(cx, |diff, _| diff.base_text().as_ref().unwrap().remote_id());
|
||||
let base_id_2 = diff_2.read_with(cx, |diff, _| diff.base_text().as_ref().unwrap().remote_id());
|
||||
|
||||
let buffer_lines = (0..=snapshot.max_row().0)
|
||||
.map(|row| {
|
||||
|
@ -2191,9 +2187,8 @@ impl ReferenceMultibuffer {
|
|||
let Some(diff) = self.diffs.get(&buffer_id) else {
|
||||
return;
|
||||
};
|
||||
let diff = diff.read(cx).snapshot.clone();
|
||||
let excerpt_range = excerpt.range.to_offset(&buffer);
|
||||
for hunk in diff.hunks_intersecting_range(range, &buffer) {
|
||||
for hunk in diff.read(cx).hunks_intersecting_range(range, &buffer, cx) {
|
||||
let hunk_range = hunk.buffer_range.to_offset(&buffer);
|
||||
if hunk_range.start < excerpt_range.start || hunk_range.start > excerpt_range.end {
|
||||
continue;
|
||||
|
@ -2226,12 +2221,12 @@ impl ReferenceMultibuffer {
|
|||
let buffer = excerpt.buffer.read(cx);
|
||||
let buffer_range = excerpt.range.to_offset(buffer);
|
||||
let diff = self.diffs.get(&buffer.remote_id()).unwrap().read(cx);
|
||||
let diff = diff.snapshot.clone();
|
||||
let base_buffer = diff.base_text.as_ref().unwrap();
|
||||
// let diff = diff.snapshot.clone();
|
||||
let base_buffer = diff.base_text().unwrap();
|
||||
|
||||
let mut offset = buffer_range.start;
|
||||
let mut hunks = diff
|
||||
.hunks_intersecting_range(excerpt.range.clone(), buffer)
|
||||
.hunks_intersecting_range(excerpt.range.clone(), buffer, cx)
|
||||
.peekable();
|
||||
|
||||
while let Some(hunk) = hunks.next() {
|
||||
|
@ -2284,7 +2279,7 @@ impl ReferenceMultibuffer {
|
|||
buffer_start: Some(
|
||||
base_buffer.offset_to_point(hunk.diff_base_byte_range.start),
|
||||
),
|
||||
status: Some(DiffHunkStatus::Removed),
|
||||
status: Some(DiffHunkStatus::Removed(hunk.secondary_status)),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2299,7 +2294,7 @@ impl ReferenceMultibuffer {
|
|||
buffer_id: Some(buffer.remote_id()),
|
||||
range: len..text.len(),
|
||||
buffer_start: Some(buffer.offset_to_point(offset)),
|
||||
status: Some(DiffHunkStatus::Added),
|
||||
status: Some(DiffHunkStatus::Added(hunk.secondary_status)),
|
||||
});
|
||||
offset = hunk_range.end;
|
||||
}
|
||||
|
@ -2365,8 +2360,8 @@ impl ReferenceMultibuffer {
|
|||
let buffer = excerpt.buffer.read(cx).snapshot();
|
||||
let excerpt_range = excerpt.range.to_offset(&buffer);
|
||||
let buffer_id = buffer.remote_id();
|
||||
let diff = &self.diffs.get(&buffer_id).unwrap().read(cx).snapshot;
|
||||
let mut hunks = diff.hunks_in_row_range(0..u32::MAX, &buffer).peekable();
|
||||
let diff = self.diffs.get(&buffer_id).unwrap().read(cx);
|
||||
let mut hunks = diff.hunks_in_row_range(0..u32::MAX, &buffer, cx).peekable();
|
||||
excerpt.expanded_diff_hunks.retain(|hunk_anchor| {
|
||||
if !hunk_anchor.is_valid(&buffer) {
|
||||
return false;
|
||||
|
@ -2670,7 +2665,7 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
|
|||
expected_row_infos
|
||||
.into_iter()
|
||||
.filter_map(
|
||||
|info| if info.diff_status == Some(DiffHunkStatus::Removed) {
|
||||
|info| if matches!(info.diff_status, Some(DiffHunkStatus::Removed(_))) {
|
||||
None
|
||||
} else {
|
||||
info.buffer_row
|
||||
|
@ -3027,9 +3022,9 @@ fn format_diff(
|
|||
.zip(row_infos)
|
||||
.map(|((ix, line), info)| {
|
||||
let marker = match info.diff_status {
|
||||
Some(DiffHunkStatus::Added) => "+ ",
|
||||
Some(DiffHunkStatus::Removed) => "- ",
|
||||
Some(DiffHunkStatus::Modified) => unreachable!(),
|
||||
Some(DiffHunkStatus::Added(_)) => "+ ",
|
||||
Some(DiffHunkStatus::Removed(_)) => "- ",
|
||||
Some(DiffHunkStatus::Modified(_)) => unreachable!(),
|
||||
None => {
|
||||
if has_diff && !line.is_empty() {
|
||||
" "
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue