Fix diff_hunk_before in a multibuffer (#26059)
Also simplify it to avoid doing a bunch of unnecessary work. Co-Authored-By: Cole <cole@zed.dev> Closes #ISSUE Release Notes: - git: Fix jumping to the previous diff hunk --------- Co-authored-by: Cole <cole@zed.dev>
This commit is contained in:
parent
3e64f38ba0
commit
d7b90f4204
5 changed files with 162 additions and 138 deletions
|
@ -3818,104 +3818,57 @@ impl MultiBufferSnapshot {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn diff_hunk_before<T: ToOffset>(&self, position: T) -> Option<MultiBufferDiffHunk> {
|
||||
pub fn diff_hunk_before<T: ToOffset>(&self, position: T) -> Option<MultiBufferRow> {
|
||||
let offset = position.to_offset(self);
|
||||
|
||||
// Go to the region containing the given offset.
|
||||
let mut cursor = self.cursor::<DimensionPair<usize, Point>>();
|
||||
cursor.seek(&DimensionPair {
|
||||
key: offset,
|
||||
value: None,
|
||||
});
|
||||
let mut region = cursor.region()?;
|
||||
if region.range.start.key == offset || !region.is_main_buffer {
|
||||
cursor.prev();
|
||||
region = cursor.region()?;
|
||||
cursor.seek_to_start_of_current_excerpt();
|
||||
let excerpt = cursor.excerpt()?;
|
||||
|
||||
let excerpt_end = excerpt.range.context.end.to_offset(&excerpt.buffer);
|
||||
let current_position = self
|
||||
.anchor_before(offset)
|
||||
.text_anchor
|
||||
.to_offset(&excerpt.buffer);
|
||||
let excerpt_end = excerpt
|
||||
.buffer
|
||||
.anchor_before(excerpt_end.min(current_position));
|
||||
|
||||
if let Some(diff) = self.diffs.get(&excerpt.buffer_id) {
|
||||
for hunk in diff.hunks_intersecting_range_rev(
|
||||
excerpt.range.context.start..excerpt_end,
|
||||
&excerpt.buffer,
|
||||
) {
|
||||
let hunk_end = hunk.buffer_range.end.to_offset(&excerpt.buffer);
|
||||
if hunk_end >= current_position {
|
||||
continue;
|
||||
}
|
||||
let start =
|
||||
Anchor::in_buffer(excerpt.id, excerpt.buffer_id, hunk.buffer_range.start)
|
||||
.to_point(&self);
|
||||
return Some(MultiBufferRow(start.row));
|
||||
}
|
||||
}
|
||||
|
||||
// Find the corresponding buffer offset.
|
||||
let overshoot = if region.is_main_buffer {
|
||||
offset - region.range.start.key
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let mut max_buffer_offset = region
|
||||
.buffer
|
||||
.clip_offset(region.buffer_range.start.key + overshoot, Bias::Right);
|
||||
|
||||
loop {
|
||||
let excerpt = cursor.excerpt()?;
|
||||
let excerpt_end = excerpt.range.context.end.to_offset(&excerpt.buffer);
|
||||
let buffer_offset = excerpt_end.min(max_buffer_offset);
|
||||
let buffer_end = excerpt.buffer.anchor_before(buffer_offset);
|
||||
let buffer_end_row = buffer_end.to_point(&excerpt.buffer).row;
|
||||
|
||||
if let Some(diff) = self.diffs.get(&excerpt.buffer_id) {
|
||||
for hunk in diff.hunks_intersecting_range_rev(
|
||||
excerpt.range.context.start..buffer_end,
|
||||
&excerpt.buffer,
|
||||
) {
|
||||
let hunk_range = hunk.buffer_range.to_offset(&excerpt.buffer);
|
||||
if hunk.range.end >= Point::new(buffer_end_row, 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let hunk_start = hunk.range.start;
|
||||
let hunk_end = hunk.range.end;
|
||||
|
||||
cursor.seek_to_buffer_position_in_current_excerpt(&DimensionPair {
|
||||
key: hunk_range.start,
|
||||
value: None,
|
||||
});
|
||||
|
||||
let mut region = cursor.region()?;
|
||||
while !region.is_main_buffer || region.buffer_range.start.key >= hunk_range.end
|
||||
{
|
||||
cursor.prev();
|
||||
region = cursor.region()?;
|
||||
}
|
||||
|
||||
let overshoot = if region.is_main_buffer {
|
||||
hunk_start.saturating_sub(region.buffer_range.start.value.unwrap())
|
||||
} else {
|
||||
Point::zero()
|
||||
};
|
||||
let start = region.range.start.value.unwrap() + overshoot;
|
||||
|
||||
while let Some(region) = cursor.region() {
|
||||
if !region.is_main_buffer
|
||||
|| region.buffer_range.end.value.unwrap() <= hunk_end
|
||||
{
|
||||
cursor.next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let end = if let Some(region) = cursor.region() {
|
||||
let overshoot = if region.is_main_buffer {
|
||||
hunk_end.saturating_sub(region.buffer_range.start.value.unwrap())
|
||||
} else {
|
||||
Point::zero()
|
||||
};
|
||||
region.range.start.value.unwrap() + overshoot
|
||||
} else {
|
||||
self.max_point()
|
||||
};
|
||||
|
||||
return Some(MultiBufferDiffHunk {
|
||||
row_range: MultiBufferRow(start.row)..MultiBufferRow(end.row),
|
||||
buffer_id: excerpt.buffer_id,
|
||||
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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cursor.prev_excerpt();
|
||||
max_buffer_offset = usize::MAX;
|
||||
let excerpt = cursor.excerpt()?;
|
||||
|
||||
let Some(diff) = self.diffs.get(&excerpt.buffer_id) else {
|
||||
continue;
|
||||
};
|
||||
let mut hunks =
|
||||
diff.hunks_intersecting_range_rev(excerpt.range.context.clone(), &excerpt.buffer);
|
||||
let Some(hunk) = hunks.next() else {
|
||||
continue;
|
||||
};
|
||||
let start = Anchor::in_buffer(excerpt.id, excerpt.buffer_id, hunk.buffer_range.start)
|
||||
.to_point(&self);
|
||||
return Some(MultiBufferRow(start.row));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6132,21 +6085,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn seek_to_buffer_position_in_current_excerpt(&mut self, position: &D) {
|
||||
self.cached_region.take();
|
||||
if let Some(excerpt) = self.excerpts.item() {
|
||||
let excerpt_start = excerpt.range.context.start.summary::<D>(&excerpt.buffer);
|
||||
let position_in_excerpt = *position - excerpt_start;
|
||||
let mut excerpt_position = self.excerpts.start().0;
|
||||
excerpt_position.add_assign(&position_in_excerpt);
|
||||
self.diff_transforms
|
||||
.seek(&ExcerptDimension(excerpt_position), Bias::Left, &());
|
||||
if self.diff_transforms.item().is_none() {
|
||||
self.diff_transforms.next(&());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn next_excerpt(&mut self) {
|
||||
self.excerpts.next(&());
|
||||
self.seek_to_start_of_current_excerpt();
|
||||
|
|
|
@ -440,23 +440,14 @@ fn test_diff_hunks_in_range(cx: &mut TestAppContext) {
|
|||
vec![1..3, 4..6, 7..8]
|
||||
);
|
||||
|
||||
assert_eq!(snapshot.diff_hunk_before(Point::new(1, 1)), None,);
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.diff_hunk_before(Point::new(1, 1))
|
||||
.map(|hunk| hunk.row_range.start.0..hunk.row_range.end.0),
|
||||
None,
|
||||
snapshot.diff_hunk_before(Point::new(7, 0)),
|
||||
Some(MultiBufferRow(4))
|
||||
);
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.diff_hunk_before(Point::new(7, 0))
|
||||
.map(|hunk| hunk.row_range.start.0..hunk.row_range.end.0),
|
||||
Some(4..6)
|
||||
);
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.diff_hunk_before(Point::new(4, 0))
|
||||
.map(|hunk| hunk.row_range.start.0..hunk.row_range.end.0),
|
||||
Some(1..3)
|
||||
snapshot.diff_hunk_before(Point::new(4, 0)),
|
||||
Some(MultiBufferRow(1))
|
||||
);
|
||||
|
||||
multibuffer.update(cx, |multibuffer, cx| {
|
||||
|
@ -478,16 +469,12 @@ fn test_diff_hunks_in_range(cx: &mut TestAppContext) {
|
|||
);
|
||||
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.diff_hunk_before(Point::new(2, 0))
|
||||
.map(|hunk| hunk.row_range.start.0..hunk.row_range.end.0),
|
||||
Some(1..1),
|
||||
snapshot.diff_hunk_before(Point::new(2, 0)),
|
||||
Some(MultiBufferRow(1)),
|
||||
);
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.diff_hunk_before(Point::new(4, 0))
|
||||
.map(|hunk| hunk.row_range.start.0..hunk.row_range.end.0),
|
||||
Some(2..2)
|
||||
snapshot.diff_hunk_before(Point::new(4, 0)),
|
||||
Some(MultiBufferRow(2))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue