git: Fix panic in split diff when edits cause excerpts to merge (#49122)
Our strategy for keeping excerpts in sync between the two sides of the split diff is generally - mutate the excerpts on the RHS - pull out the new excerpts for the affected path from the RHS - translate those ranges to the LHS - update the LHS excerpts with those ranges But this can break down when the translated ranges overlap on the LHS despite the original ranges not overlapping on the RHS. This can happen, for example, when a large deletion in a file crosses several excerpt boundaries. It's rare because normally excerpt boundaries in the project diff and branch diff are adjusted to keep entire diff hunks in view, but we defer this for dirty files, so it's not hard to trigger it when using the agent or editing an individual file while the diff is open in another tab. Release Notes: - Fixed a panic that could occur when editing files while the project diff or branch diff was open. --------- Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
a1b181f30f
commit
fefb81c067
3 files changed
+203
-44
No files matched your search
@@ -57,7 +57,7 @@ use theme::SyntaxTheme;
|
||||
use util::post_inc;
|
||||
use ztracing::instrument;
|
||||
|
||||
pub use self::path_key::PathKey;
|
||||
pub use self::path_key::{PathExcerptInsertResult, PathKey};
|
||||
|
||||
pub static EXCERPT_CONTEXT_LINES: OnceLock<fn(&App) -> u32> = OnceLock::new();
|
||||
|
||||
@@ -2156,6 +2156,35 @@ impl MultiBuffer {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn merge_excerpts(
|
||||
&mut self,
|
||||
excerpt_ids: &[ExcerptId],
|
||||
cx: &mut Context<Self>,
|
||||
) -> ExcerptId {
|
||||
debug_assert!(!excerpt_ids.is_empty());
|
||||
if excerpt_ids.len() == 1 {
|
||||
return excerpt_ids[0];
|
||||
}
|
||||
|
||||
let snapshot = self.snapshot(cx);
|
||||
|
||||
let first_range = snapshot
|
||||
.context_range_for_excerpt(excerpt_ids[0])
|
||||
.expect("first excerpt must exist");
|
||||
let last_range = snapshot
|
||||
.context_range_for_excerpt(*excerpt_ids.last().unwrap())
|
||||
.expect("last excerpt must exist");
|
||||
|
||||
let union_range = first_range.start..last_range.end;
|
||||
|
||||
drop(snapshot);
|
||||
|
||||
self.resize_excerpt(excerpt_ids[0], union_range, cx);
|
||||
self.remove_excerpts(excerpt_ids[1..].iter().copied(), cx);
|
||||
|
||||
excerpt_ids[0]
|
||||
}
|
||||
|
||||
pub fn remove_excerpts(
|
||||
&mut self,
|
||||
excerpt_ids: impl IntoIterator<Item = ExcerptId>,
|
||||
|
||||
Reference in new issue
Block a user