git: Correct logic for updating companion excerpt IDs mapping (#48906)

We try to remove old excerpt IDs from the companion when mutating
excerpts for a path, but we were incorrectly doing this using the
excerpt IDs for the right-hand side multibuffer _after_ any excerpt
mutations had occurred, causing stale excerpt IDs to accumulate.

Release Notes:

- N/A
This commit is contained in:
Cole Miller authored and GitHub committed 2026-02-11 04:02:02 +00:00
1 parent ba1253c210
commit 56e2ec022c
1 file changed
+108 -93
+108 -93
View File
@@ -1002,41 +1002,33 @@ impl SplittableEditor {
cx: &mut Context<Self>,
) -> (Vec<Range<Anchor>>, bool) {
let rhs_display_map = self.rhs_editor.read(cx).display_map.clone();
let lhs = &mut self.lhs;
let (anchors, added_a_new_excerpt) =
self.rhs_multibuffer.update(cx, |rhs_multibuffer, cx| {
let (anchors, added_a_new_excerpt) = rhs_multibuffer.set_excerpts_for_path(
path.clone(),
buffer.clone(),
ranges,
context_line_count,
cx,
);
if !anchors.is_empty()
&& rhs_multibuffer
.diff_for(buffer.read(cx).remote_id())
.is_none_or(|old_diff| old_diff.entity_id() != diff.entity_id())
{
rhs_multibuffer.add_diff(diff.clone(), cx);
}
if let Some(lhs) = lhs {
lhs.multibuffer.update(cx, |lhs_multibuffer, lhs_cx| {
LhsEditor::sync_path_excerpts(
path,
rhs_multibuffer,
lhs_multibuffer,
diff,
&rhs_display_map,
lhs_cx,
)
})
}
(anchors, added_a_new_excerpt)
});
(anchors, added_a_new_excerpt)
let lhs = self.lhs.as_ref();
self.rhs_multibuffer.update(cx, |rhs_multibuffer, cx| {
mutate_excerpts_for_paths(
rhs_multibuffer,
lhs,
&rhs_display_map,
vec![(path.clone(), diff.clone())],
cx,
|rhs_multibuffer, cx| {
let (anchors, added_a_new_excerpt) = rhs_multibuffer.set_excerpts_for_path(
path.clone(),
buffer.clone(),
ranges,
context_line_count,
cx,
);
if !anchors.is_empty()
&& rhs_multibuffer
.diff_for(buffer.read(cx).remote_id())
.is_none_or(|old_diff| old_diff.entity_id() != diff.entity_id())
{
rhs_multibuffer.add_diff(diff.clone(), cx);
}
(anchors, added_a_new_excerpt)
},
)
})
}
fn expand_excerpts(
@@ -1047,37 +1039,35 @@ impl SplittableEditor {
cx: &mut Context<Self>,
) {
let rhs_display_map = self.rhs_editor.read(cx).display_map.clone();
let lhs = &mut self.lhs;
let lhs_multibuffer = lhs.as_ref().map(|l| l.multibuffer.clone());
let lhs = self.lhs.as_ref();
self.rhs_multibuffer.update(cx, |rhs_multibuffer, cx| {
if let Some(lhs_multibuffer) = lhs_multibuffer {
if lhs.is_some() {
let snapshot = rhs_multibuffer.snapshot(cx);
let affected_paths: HashMap<_, _> = excerpt_ids
let paths_with_diffs: Vec<_> = excerpt_ids
.clone()
.map(|excerpt_id| {
let path = rhs_multibuffer.path_for_excerpt(excerpt_id).unwrap();
let buffer = snapshot.buffer_for_excerpt(excerpt_id).unwrap();
let diff = rhs_multibuffer.diff_for(buffer.remote_id()).unwrap();
(path, diff)
.filter_map(|excerpt_id| {
let path = rhs_multibuffer.path_for_excerpt(excerpt_id)?;
let buffer = snapshot.buffer_for_excerpt(excerpt_id)?;
let diff = rhs_multibuffer.diff_for(buffer.remote_id())?;
Some((path, diff))
})
.collect::<HashMap<_, _>>()
.into_iter()
.collect();
rhs_multibuffer.expand_excerpts(excerpt_ids.clone(), lines, direction, cx);
for (path, diff) in affected_paths {
lhs_multibuffer.update(cx, |lhs_multibuffer, lhs_cx| {
LhsEditor::sync_path_excerpts(
path,
rhs_multibuffer,
lhs_multibuffer,
diff,
&rhs_display_map,
lhs_cx,
);
});
}
mutate_excerpts_for_paths(
rhs_multibuffer,
lhs,
&rhs_display_map,
paths_with_diffs,
cx,
|rhs_multibuffer, cx| {
rhs_multibuffer.expand_excerpts(excerpt_ids.clone(), lines, direction, cx);
},
);
} else {
rhs_multibuffer.expand_excerpts(excerpt_ids.clone(), lines, direction, cx);
};
rhs_multibuffer.expand_excerpts(excerpt_ids, lines, direction, cx);
}
});
}
@@ -1086,15 +1076,17 @@ impl SplittableEditor {
if let Some(lhs) = &self.lhs {
self.rhs_multibuffer.update(cx, |rhs_multibuffer, cx| {
lhs.multibuffer.update(cx, |lhs_multibuffer, cx| {
LhsEditor::remove_mappings_for_path(
&path,
rhs_multibuffer,
lhs_multibuffer,
&rhs_display_map,
cx,
);
});
let rhs_excerpt_ids: Vec<ExcerptId> =
rhs_multibuffer.excerpts_for_path(&path).collect();
let lhs_excerpt_ids: Vec<ExcerptId> =
lhs.multibuffer.read(cx).excerpts_for_path(&path).collect();
if let Some(companion) = rhs_display_map.read(cx).companion().cloned() {
companion.update(cx, |c, _| {
c.remove_excerpt_mappings(lhs_excerpt_ids, rhs_excerpt_ids);
});
}
rhs_multibuffer.remove_excerpts_for_path(path.clone(), cx);
});
lhs.multibuffer.update(cx, |lhs_multibuffer, cx| {
@@ -1938,6 +1930,44 @@ impl Render for SplittableEditor {
}
}
fn mutate_excerpts_for_paths<R>(
rhs_multibuffer: &mut MultiBuffer,
lhs: Option<&LhsEditor>,
rhs_display_map: &Entity<DisplayMap>,
paths_with_diffs: Vec<(PathKey, Entity<BufferDiff>)>,
cx: &mut Context<MultiBuffer>,
mutate: impl FnOnce(&mut MultiBuffer, &mut Context<MultiBuffer>) -> R,
) -> R {
let old_rhs_ids: Vec<_> = paths_with_diffs
.iter()
.map(|(path, _)| {
rhs_multibuffer
.excerpts_for_path(path)
.collect::<Vec<ExcerptId>>()
})
.collect();
let result = mutate(rhs_multibuffer, cx);
if let Some(lhs) = lhs {
for ((path, diff), old_rhs_ids) in paths_with_diffs.into_iter().zip(old_rhs_ids) {
lhs.multibuffer.update(cx, |lhs_multibuffer, lhs_cx| {
LhsEditor::sync_path_excerpts(
path,
old_rhs_ids,
rhs_multibuffer,
lhs_multibuffer,
diff,
rhs_display_map,
lhs_cx,
);
});
}
}
result
}
impl LhsEditor {
fn update_path_excerpts_from_rhs(
path_key: PathKey,
@@ -2012,19 +2042,21 @@ impl LhsEditor {
fn sync_path_excerpts(
path_key: PathKey,
old_rhs_excerpt_ids: Vec<ExcerptId>,
rhs_multibuffer: &MultiBuffer,
lhs_multibuffer: &mut MultiBuffer,
diff: Entity<BufferDiff>,
rhs_display_map: &Entity<DisplayMap>,
lhs_cx: &mut Context<MultiBuffer>,
) {
Self::remove_mappings_for_path(
&path_key,
rhs_multibuffer,
lhs_multibuffer,
rhs_display_map,
lhs_cx,
);
let old_lhs_excerpt_ids: Vec<ExcerptId> =
lhs_multibuffer.excerpts_for_path(&path_key).collect();
if let Some(companion) = rhs_display_map.read(lhs_cx).companion().cloned() {
companion.update(lhs_cx, |c, _| {
c.remove_excerpt_mappings(old_lhs_excerpt_ids, old_rhs_excerpt_ids);
});
}
let mappings = Self::update_path_excerpts_from_rhs(
path_key,
@@ -2046,23 +2078,6 @@ impl LhsEditor {
});
}
}
fn remove_mappings_for_path(
path_key: &PathKey,
rhs_multibuffer: &MultiBuffer,
lhs_multibuffer: &MultiBuffer,
rhs_display_map: &Entity<DisplayMap>,
cx: &mut App,
) {
let rhs_excerpt_ids: Vec<ExcerptId> = rhs_multibuffer.excerpts_for_path(path_key).collect();
let lhs_excerpt_ids: Vec<ExcerptId> = lhs_multibuffer.excerpts_for_path(path_key).collect();
if let Some(companion) = rhs_display_map.read(cx).companion().cloned() {
companion.update(cx, |c, _| {
c.remove_excerpt_mappings(lhs_excerpt_ids, rhs_excerpt_ids);
});
}
}
}
#[cfg(test)]