Fix panic in remove_item (#21480)
In #20742 we added a call to remove_item that retain an item index over an await point. This led to a race condition that could panic if another tab was removed during that time. (cc @mgsloan) This changes the API to make it harder to misuse. Release Notes: - Fixed a panic when closing tabs containing new unsaved files
This commit is contained in:
parent
492ca219d3
commit
b28287ce91
2 changed files with 18 additions and 20 deletions
|
@ -828,9 +828,10 @@ impl Pane {
|
||||||
|
|
||||||
pub fn close_current_preview_item(&mut self, cx: &mut ViewContext<Self>) -> Option<usize> {
|
pub fn close_current_preview_item(&mut self, cx: &mut ViewContext<Self>) -> Option<usize> {
|
||||||
let item_idx = self.preview_item_idx()?;
|
let item_idx = self.preview_item_idx()?;
|
||||||
|
let id = self.preview_item_id()?;
|
||||||
|
|
||||||
let prev_active_item_index = self.active_item_index;
|
let prev_active_item_index = self.active_item_index;
|
||||||
self.remove_item(item_idx, false, false, cx);
|
self.remove_item(id, false, false, cx);
|
||||||
self.active_item_index = prev_active_item_index;
|
self.active_item_index = prev_active_item_index;
|
||||||
|
|
||||||
if item_idx < self.items.len() {
|
if item_idx < self.items.len() {
|
||||||
|
@ -1403,13 +1404,7 @@ impl Pane {
|
||||||
|
|
||||||
// Remove the item from the pane.
|
// Remove the item from the pane.
|
||||||
pane.update(&mut cx, |pane, cx| {
|
pane.update(&mut cx, |pane, cx| {
|
||||||
if let Some(item_ix) = pane
|
pane.remove_item(item_to_close.item_id(), false, true, cx);
|
||||||
.items
|
|
||||||
.iter()
|
|
||||||
.position(|i| i.item_id() == item_to_close.item_id())
|
|
||||||
{
|
|
||||||
pane.remove_item(item_ix, false, true, cx);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
@ -1421,11 +1416,14 @@ impl Pane {
|
||||||
|
|
||||||
pub fn remove_item(
|
pub fn remove_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
item_index: usize,
|
item_id: EntityId,
|
||||||
activate_pane: bool,
|
activate_pane: bool,
|
||||||
close_pane_if_empty: bool,
|
close_pane_if_empty: bool,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
|
let Some(item_index) = self.index_for_item_id(item_id) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
self._remove_item(item_index, activate_pane, close_pane_if_empty, None, cx)
|
self._remove_item(item_index, activate_pane, close_pane_if_empty, None, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1615,7 +1613,9 @@ impl Pane {
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
Ok(1) => {
|
Ok(1) => {
|
||||||
pane.update(cx, |pane, cx| pane.remove_item(item_ix, false, false, cx))?;
|
pane.update(cx, |pane, cx| {
|
||||||
|
pane.remove_item(item.item_id(), false, false, cx)
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
_ => return Ok(false),
|
_ => return Ok(false),
|
||||||
}
|
}
|
||||||
|
@ -1709,9 +1709,7 @@ impl Pane {
|
||||||
if let Some(abs_path) = abs_path.await.ok().flatten() {
|
if let Some(abs_path) = abs_path.await.ok().flatten() {
|
||||||
pane.update(cx, |pane, cx| {
|
pane.update(cx, |pane, cx| {
|
||||||
if let Some(item) = pane.item_for_path(abs_path.clone(), cx) {
|
if let Some(item) = pane.item_for_path(abs_path.clone(), cx) {
|
||||||
if let Some(idx) = pane.index_for_item(&*item) {
|
pane.remove_item(item.item_id(), false, false, cx);
|
||||||
pane.remove_item(idx, false, false, cx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
item.save_as(project, abs_path, cx)
|
item.save_as(project, abs_path, cx)
|
||||||
|
@ -1777,15 +1775,15 @@ impl Pane {
|
||||||
entry_id: ProjectEntryId,
|
entry_id: ProjectEntryId,
|
||||||
cx: &mut ViewContext<Pane>,
|
cx: &mut ViewContext<Pane>,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let (item_index_to_delete, item_id) = self.items().enumerate().find_map(|(i, item)| {
|
let item_id = self.items().find_map(|item| {
|
||||||
if item.is_singleton(cx) && item.project_entry_ids(cx).as_slice() == [entry_id] {
|
if item.is_singleton(cx) && item.project_entry_ids(cx).as_slice() == [entry_id] {
|
||||||
Some((i, item.item_id()))
|
Some(item.item_id())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
self.remove_item(item_index_to_delete, false, true, cx);
|
self.remove_item(item_id, false, true, cx);
|
||||||
self.nav_history.remove_item(item_id);
|
self.nav_history.remove_item(item_id);
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
|
|
|
@ -3723,7 +3723,7 @@ impl Workspace {
|
||||||
|
|
||||||
let mut new_item = task.await?;
|
let mut new_item = task.await?;
|
||||||
pane.update(cx, |pane, cx| {
|
pane.update(cx, |pane, cx| {
|
||||||
let mut item_ix_to_remove = None;
|
let mut item_to_remove = None;
|
||||||
for (ix, item) in pane.items().enumerate() {
|
for (ix, item) in pane.items().enumerate() {
|
||||||
if let Some(item) = item.to_followable_item_handle(cx) {
|
if let Some(item) = item.to_followable_item_handle(cx) {
|
||||||
match new_item.dedup(item.as_ref(), cx) {
|
match new_item.dedup(item.as_ref(), cx) {
|
||||||
|
@ -3733,7 +3733,7 @@ impl Workspace {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Some(item::Dedup::ReplaceExisting) => {
|
Some(item::Dedup::ReplaceExisting) => {
|
||||||
item_ix_to_remove = Some(ix);
|
item_to_remove = Some((ix, item.item_id()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
|
@ -3741,8 +3741,8 @@ impl Workspace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ix) = item_ix_to_remove {
|
if let Some((ix, id)) = item_to_remove {
|
||||||
pane.remove_item(ix, false, false, cx);
|
pane.remove_item(id, false, false, cx);
|
||||||
pane.add_item(new_item.boxed_clone(), false, false, Some(ix), cx);
|
pane.add_item(new_item.boxed_clone(), false, false, Some(ix), cx);
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue