Mitigate panic in merge conflict resolution (#29678)
We have a report of a panic when indexing into `BufferConflicts.block_ids` using the `old_range` from the `ConflictsUpdated` event, indicating that the `block_ids` array can get out of sync with the underlying `ConflictSet`. This PR adds a mitigation so that we won't panic in this situation, as a stopgap until the bug can be reproduced in a test and fixed at the root. Release Notes: - N/A
This commit is contained in:
parent
632f08d2a3
commit
ff4900c942
1 changed files with 45 additions and 5 deletions
|
@ -14,6 +14,7 @@ use ui::{
|
|||
ActiveTheme, AnyElement, Element as _, StatefulInteractiveElement, Styled,
|
||||
StyledTypography as _, div, h_flex, rems,
|
||||
};
|
||||
use util::{debug_panic, maybe};
|
||||
|
||||
pub(crate) struct ConflictAddon {
|
||||
buffers: HashMap<BufferId, BufferConflicts>,
|
||||
|
@ -89,12 +90,22 @@ fn excerpt_for_buffer_updated(
|
|||
cx: &mut Context<Editor>,
|
||||
) {
|
||||
let conflicts_len = conflict_set.read(cx).snapshot().conflicts.len();
|
||||
let buffer_id = conflict_set.read(cx).snapshot().buffer_id;
|
||||
let Some(buffer_conflicts) = editor
|
||||
.addon_mut::<ConflictAddon>()
|
||||
.unwrap()
|
||||
.buffers
|
||||
.get(&buffer_id)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let addon_conflicts_len = buffer_conflicts.block_ids.len();
|
||||
conflicts_updated(
|
||||
editor,
|
||||
conflict_set,
|
||||
&ConflictSetUpdate {
|
||||
buffer_range: None,
|
||||
old_range: 0..conflicts_len,
|
||||
old_range: 0..addon_conflicts_len,
|
||||
new_range: 0..conflicts_len,
|
||||
},
|
||||
cx,
|
||||
|
@ -174,10 +185,37 @@ fn conflicts_updated(
|
|||
return;
|
||||
};
|
||||
|
||||
let old_range = maybe!({
|
||||
let conflict_addon = editor.addon_mut::<ConflictAddon>().unwrap();
|
||||
let buffer_conflicts = conflict_addon.buffers.get(&buffer_id)?;
|
||||
match buffer_conflicts.block_ids.get(event.old_range.clone()) {
|
||||
Some(_) => Some(event.old_range.clone()),
|
||||
None => {
|
||||
debug_panic!(
|
||||
"conflicts updated event old range is invalid for buffer conflicts view (block_ids len is {:?}, old_range is {:?})",
|
||||
buffer_conflicts.block_ids.len(),
|
||||
event.old_range,
|
||||
);
|
||||
if event.old_range.start <= event.old_range.end {
|
||||
Some(
|
||||
event.old_range.start.min(buffer_conflicts.block_ids.len())
|
||||
..event.old_range.end.min(buffer_conflicts.block_ids.len()),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Remove obsolete highlights and blocks
|
||||
let conflict_addon = editor.addon_mut::<ConflictAddon>().unwrap();
|
||||
if let Some(buffer_conflicts) = conflict_addon.buffers.get_mut(&buffer_id) {
|
||||
let old_conflicts = buffer_conflicts.block_ids[event.old_range.clone()].to_owned();
|
||||
if let Some((buffer_conflicts, old_range)) = conflict_addon
|
||||
.buffers
|
||||
.get_mut(&buffer_id)
|
||||
.zip(old_range.clone())
|
||||
{
|
||||
let old_conflicts = buffer_conflicts.block_ids[old_range].to_owned();
|
||||
let mut removed_highlighted_ranges = Vec::new();
|
||||
let mut removed_block_ids = HashSet::default();
|
||||
for (conflict_range, block_id) in old_conflicts {
|
||||
|
@ -263,9 +301,11 @@ fn conflicts_updated(
|
|||
let new_block_ids = editor.insert_blocks(blocks, None, cx);
|
||||
|
||||
let conflict_addon = editor.addon_mut::<ConflictAddon>().unwrap();
|
||||
if let Some(buffer_conflicts) = conflict_addon.buffers.get_mut(&buffer_id) {
|
||||
if let Some((buffer_conflicts, old_range)) =
|
||||
conflict_addon.buffers.get_mut(&buffer_id).zip(old_range)
|
||||
{
|
||||
buffer_conflicts.block_ids.splice(
|
||||
event.old_range.clone(),
|
||||
old_range,
|
||||
new_conflicts
|
||||
.iter()
|
||||
.map(|conflict| conflict.range.clone())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue