fix(floating-panes): handle uncaught errors (#3944)

* fix(floating-panes): handle uncaught errors

* style(fmt): rustfmt
This commit is contained in:
Aram Drevekenin 2025-01-17 17:52:04 +01:00 committed by GitHub
parent 9d3b4c5391
commit ce6a08f86b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 119 additions and 59 deletions

View file

@ -761,16 +761,12 @@ impl<'a> FloatingPaneGrid<'a> {
a_pane.y().cmp(&b_pane.y())
}
});
let active_pane_position = panes
.iter()
.position(|(id, _)| id == current_pane_id)
.unwrap();
let active_pane_position = panes.iter().position(|(id, _)| id == current_pane_id)?;
let next_active_pane_id = panes
.get(active_pane_position + 1)
.or_else(|| panes.get(0))
.map(|p| p.0)
.unwrap();
.map(|p| p.0)?;
Some(next_active_pane_id)
}
pub fn previous_selectable_pane_id(&self, current_pane_id: &PaneId) -> Option<PaneId> {

View file

@ -88,12 +88,16 @@ impl FloatingPanes {
}
pub fn stack(&self) -> Option<FloatingPanesStack> {
if self.panes_are_visible() {
let layers = self
let layers: Vec<PaneGeom> = self
.z_indices
.iter()
.map(|pane_id| self.panes.get(pane_id).unwrap().position_and_size())
.filter_map(|pane_id| self.panes.get(pane_id).map(|p| p.position_and_size()))
.collect();
Some(FloatingPanesStack { layers })
if layers.is_empty() {
None
} else {
Some(FloatingPanesStack { layers })
}
} else if self.has_pinned_panes() {
let layers = self
.z_indices
@ -257,7 +261,8 @@ impl FloatingPanes {
pub fn position_floating_pane_layout(
&mut self,
floating_pane_layout: &FloatingPaneLayout,
) -> PaneGeom {
) -> Result<PaneGeom> {
let err_context = || format!("failed to find position for floating pane");
let display_area = *self.display_area.borrow();
let viewport = *self.viewport.borrow();
let floating_pane_grid = FloatingPaneGrid::new(
@ -266,7 +271,9 @@ impl FloatingPanes {
display_area,
viewport,
);
let mut position = floating_pane_grid.find_room_for_new_pane().unwrap(); // TODO: no unwrap
let mut position = floating_pane_grid
.find_room_for_new_pane()
.with_context(err_context)?;
if let Some(x) = &floating_pane_layout.x {
position.x = x.to_position(viewport.cols);
}
@ -301,7 +308,7 @@ impl FloatingPanes {
.y
.saturating_sub((position.y + position.rows.as_usize()) - viewport.rows);
}
position
Ok(position)
}
pub fn first_floating_pane_id(&self) -> Option<PaneId> {
self.panes.keys().next().copied()
@ -432,7 +439,7 @@ impl FloatingPanes {
display_area,
viewport,
);
floating_pane_grid.resize(new_screen_size).unwrap();
floating_pane_grid.resize(new_screen_size).non_fatal();
self.set_force_render();
}
@ -530,17 +537,20 @@ impl FloatingPanes {
Some(p) => {
// render previously active pane so that its frame does not remain actively
// colored
let previously_active_pane = self
.panes
.get_mut(self.active_panes.get(&client_id).unwrap())
.unwrap();
let Some(previously_active_pane) = self.get_active_pane_mut(client_id) else {
log::error!("Failed to get active pane");
return Ok(false);
};
previously_active_pane.set_should_render(true);
// we render the full viewport to remove any ui elements that might have been
// there before (eg. another user's cursor)
previously_active_pane.render_full_viewport();
let next_active_pane = self.panes.get_mut(&p).unwrap();
let Some(next_active_pane) = self.get_pane_mut(p) else {
log::error!("Failed to get next active pane");
return Ok(false);
};
next_active_pane.set_should_render(true);
// we render the full viewport to remove any ui elements that might have been
// there before (eg. another user's cursor)
@ -588,9 +598,10 @@ impl FloatingPanes {
display_area,
viewport,
);
let pane_id = floating_pane_grid.pane_id_on_edge(direction).unwrap();
self.focus_pane(pane_id, client_id);
self.set_force_render();
if let Some(pane_id) = floating_pane_grid.pane_id_on_edge(direction) {
self.focus_pane(pane_id, client_id);
self.set_force_render();
}
}
pub fn move_active_pane_down(&mut self, client_id: ClientId) {
@ -641,7 +652,7 @@ impl FloatingPanes {
display_area,
viewport,
);
floating_pane_grid.move_pane_left(&pane_id).unwrap();
floating_pane_grid.move_pane_left(&pane_id).non_fatal();
self.set_force_render();
}
pub fn move_active_pane_right(&mut self, client_id: ClientId) {
@ -658,7 +669,7 @@ impl FloatingPanes {
display_area,
viewport,
);
floating_pane_grid.move_pane_right(&pane_id).unwrap();
floating_pane_grid.move_pane_right(&pane_id).non_fatal();
self.set_force_render();
}
pub fn move_active_pane(
@ -667,8 +678,9 @@ impl FloatingPanes {
_os_api: &mut Box<dyn ServerOsApi>,
client_id: ClientId,
) {
let active_pane_id = self.get_active_pane_id(client_id).unwrap();
self.move_pane(search_backwards, active_pane_id)
if let Some(active_pane_id) = self.get_active_pane_id(client_id) {
self.move_pane(search_backwards, active_pane_id)
}
}
pub fn move_pane(&mut self, search_backwards: bool, pane_id: PaneId) {
let new_position_id = {
@ -685,11 +697,17 @@ impl FloatingPanes {
}
};
if let Some(new_position_id) = new_position_id {
let current_position = self.panes.get(&pane_id).unwrap();
let Some(current_position) = self.panes.get(&pane_id) else {
log::error!("Failed to find current position");
return;
};
let prev_geom = current_position.position_and_size();
let prev_geom_override = current_position.geom_override();
let new_position = self.panes.get_mut(&new_position_id).unwrap();
let Some(new_position) = self.panes.get_mut(&new_position_id) else {
log::error!("Failed to find new position");
return;
};
let next_geom = new_position.position_and_size();
let next_geom_override = new_position.geom_override();
new_position.set_geom(prev_geom);
@ -698,7 +716,10 @@ impl FloatingPanes {
}
new_position.set_should_render(true);
let current_position = self.panes.get_mut(&pane_id).unwrap();
let Some(current_position) = self.panes.get_mut(&pane_id) else {
log::error!("Failed to find current position");
return;
};
current_position.set_geom(next_geom);
if let Some(geom) = next_geom_override {
current_position.set_geom_override(geom);
@ -801,8 +822,16 @@ impl FloatingPanes {
panes.sort_by(|(a_id, _a_pane), (b_id, _b_pane)| {
// TODO: continue
Ord::cmp(
&self.z_indices.iter().position(|id| id == *b_id).unwrap(),
&self.z_indices.iter().position(|id| id == *a_id).unwrap(),
&self
.z_indices
.iter()
.position(|id| id == *b_id)
.unwrap_or(0),
&self
.z_indices
.iter()
.position(|id| id == *a_id)
.unwrap_or(0),
)
});
Ok(panes
@ -832,8 +861,16 @@ impl FloatingPanes {
panes.sort_by(|(a_id, _a_pane), (b_id, _b_pane)| {
// TODO: continue
Ord::cmp(
&self.z_indices.iter().position(|id| id == *b_id).unwrap(),
&self.z_indices.iter().position(|id| id == *a_id).unwrap(),
&self
.z_indices
.iter()
.position(|id| id == *b_id)
.unwrap_or(0),
&self
.z_indices
.iter()
.position(|id| id == *a_id)
.unwrap_or(0),
)
});
Ok(panes
@ -850,8 +887,16 @@ impl FloatingPanes {
panes.sort_by(|(a_id, _a_pane), (b_id, _b_pane)| {
Ord::cmp(
&self.z_indices.iter().position(|id| id == *b_id).unwrap(),
&self.z_indices.iter().position(|id| id == *a_id).unwrap(),
&self
.z_indices
.iter()
.position(|id| id == *b_id)
.unwrap_or(0),
&self
.z_indices
.iter()
.position(|id| id == *a_id)
.unwrap_or(0),
)
});
panes.iter().find(|(_, p)| p.contains(point)).is_some()
@ -862,7 +907,7 @@ impl FloatingPanes {
search_selectable: bool,
) -> Option<&mut Box<dyn Pane>> {
self.get_pane_id_at(position, search_selectable)
.unwrap()
.ok()?
.and_then(|pane_id| self.panes.get_mut(&pane_id))
}
pub fn set_pane_being_moved_with_mouse(&mut self, pane_id: PaneId, position: Position) {
@ -875,7 +920,10 @@ impl FloatingPanes {
// true => changed position
let display_area = *self.display_area.borrow();
let viewport = *self.viewport.borrow();
let (pane_id, previous_position) = self.pane_being_moved_with_mouse.unwrap();
let Some((pane_id, previous_position)) = self.pane_being_moved_with_mouse else {
log::error!("Pane is not being moved with mousd");
return false;
};
if click_position == &previous_position {
return false;
}
@ -889,7 +937,7 @@ impl FloatingPanes {
);
floating_pane_grid
.move_pane_by(pane_id, move_x_by, move_y_by)
.unwrap();
.non_fatal();
self.set_pane_being_moved_with_mouse(pane_id, *click_position);
self.set_force_render();
true
@ -962,21 +1010,30 @@ impl FloatingPanes {
}
pub fn switch_active_pane_with(&mut self, _os_api: &mut Box<dyn ServerOsApi>, pane_id: PaneId) {
if let Some(active_pane_id) = self.first_active_floating_pane_id() {
let current_position = self.panes.get(&active_pane_id).unwrap();
let Some(current_position) = self.panes.get(&active_pane_id) else {
log::error!("Can't find current position");
return;
};
let prev_geom = current_position.position_and_size();
let prev_geom_override = current_position.geom_override();
let new_position = self.panes.get_mut(&pane_id).unwrap();
let Some(new_position) = self.panes.get_mut(&pane_id) else {
log::error!("Can't find position");
return;
};
let next_geom = new_position.position_and_size();
let next_geom_override = new_position.geom_override();
new_position.set_geom(prev_geom);
if let Some(geom) = prev_geom_override {
new_position.set_geom_override(geom);
}
resize_pty!(new_position, os_api, self.senders, self.character_cell_size).unwrap();
resize_pty!(new_position, os_api, self.senders, self.character_cell_size).non_fatal();
new_position.set_should_render(true);
let current_position = self.panes.get_mut(&active_pane_id).unwrap();
let Some(current_position) = self.panes.get_mut(&active_pane_id) else {
log::error!("Can't find current position");
return;
};
current_position.set_geom(next_geom);
if let Some(geom) = next_geom_override {
current_position.set_geom_override(geom);
@ -987,7 +1044,7 @@ impl FloatingPanes {
self.senders,
self.character_cell_size
)
.unwrap();
.non_fatal();
current_position.set_should_render(true);
self.focus_pane_for_all_clients(active_pane_id);
}

View file

@ -588,7 +588,7 @@ impl<'a> LayoutApplier<'a> {
for floating_pane_layout in floating_panes_layout {
let position_and_size = self
.floating_panes
.position_floating_pane_layout(&floating_pane_layout);
.position_floating_pane_layout(&floating_pane_layout)?;
let pid_to_focus = if floating_pane_layout.already_running {
self.floating_panes.set_geom_for_pane_with_run(
floating_pane_layout.run.clone(),
@ -682,7 +682,8 @@ impl<'a> LayoutApplier<'a> {
// contain partial positioning information (eg. just x coords with no y or size) or no
// positioning information at all
for (pane, floating_pane_layout) in panes_to_apply.drain(..) {
pane_applier.apply_floating_panes_layout_to_floating_pane(pane, floating_pane_layout);
pane_applier
.apply_floating_panes_layout_to_floating_pane(pane, floating_pane_layout)?;
}
// here we apply positioning on a best-effort basis to any remaining panes we've got (these
@ -969,17 +970,18 @@ impl<'a> PaneApplier<'a> {
&mut self,
mut pane: Box<dyn Pane>,
floating_panes_layout: FloatingPaneLayout,
) {
) -> Result<()> {
let position_and_size = self
.floating_panes
.position_floating_pane_layout(&floating_panes_layout);
.position_floating_pane_layout(&floating_panes_layout)?;
if let Some(pane_title) = floating_panes_layout.name.as_ref() {
pane.set_title(pane_title.into());
}
if floating_panes_layout.focus.unwrap_or(false) {
self.new_focused_pane_id = Some(pane.pid());
}
self.apply_position_and_size_to_floating_pane(pane, position_and_size)
self.apply_position_and_size_to_floating_pane(pane, position_and_size);
Ok(())
}
pub fn apply_position_and_size_to_floating_pane(
&mut self,

View file

@ -691,7 +691,7 @@ impl Tab {
) -> Result<()> {
self.swap_layouts
.set_base_layout((layout.clone(), floating_panes_layout.clone()));
let should_show_floating_panes = LayoutApplier::new(
if let Ok(should_show_floating_panes) = LayoutApplier::new(
&self.viewport,
&self.senders,
&self.sixel_image_store,
@ -719,16 +719,19 @@ impl Tab {
new_floating_terminal_ids,
new_plugin_ids,
client_id,
)?;
#[allow(clippy::if_same_then_else)]
if should_show_floating_panes && !self.floating_panes.panes_are_visible() {
self.toggle_floating_panes(Some(client_id), None)?;
} else if !should_show_floating_panes && self.floating_panes.panes_are_visible() {
self.toggle_floating_panes(Some(client_id), None)?;
) {
#[allow(clippy::if_same_then_else)]
if should_show_floating_panes && !self.floating_panes.panes_are_visible() {
self.toggle_floating_panes(Some(client_id), None)
.non_fatal();
} else if !should_show_floating_panes && self.floating_panes.panes_are_visible() {
self.toggle_floating_panes(Some(client_id), None)
.non_fatal();
}
self.tiled_panes.reapply_pane_frames();
self.is_pending = false;
self.apply_buffered_instructions().non_fatal();
}
self.tiled_panes.reapply_pane_frames();
self.is_pending = false;
self.apply_buffered_instructions()?;
Ok(())
}
pub fn swap_layout_info(&self) -> (Option<String>, bool) {
@ -771,7 +774,8 @@ impl Tab {
self.styled_underlines,
self.explicitly_disable_kitty_keyboard_protocol,
)
.apply_floating_panes_layout_to_existing_panes(&layout_candidate)?;
.apply_floating_panes_layout_to_existing_panes(&layout_candidate)
.non_fatal();
}
self.set_force_render();
Ok(())
@ -805,7 +809,8 @@ impl Tab {
self.styled_underlines,
self.explicitly_disable_kitty_keyboard_protocol,
)
.apply_tiled_panes_layout_to_existing_panes(&layout_candidate)?;
.apply_tiled_panes_layout_to_existing_panes(&layout_candidate)
.non_fatal();
}
self.tiled_panes.reapply_pane_frames();
let display_area = *self.display_area.borrow();