Make Workspace::split infallible (#50060)

Conrad Irwin created

Fixes ZED-596

Release Notes:

- Fixed a panic in editor::GoToDefinitionSplit if you managed to close
the current pane before the definitions were resolved

Change summary

crates/debugger_ui/src/session/running.rs  |  6 ++--
crates/terminal_view/src/terminal_panel.rs | 30 ++++++-------------
crates/workspace/src/pane_group.rs         | 35 +++++++++++++++--------
crates/workspace/src/workspace.rs          | 26 ++++-------------
4 files changed, 42 insertions(+), 55 deletions(-)

Detailed changes

crates/debugger_ui/src/session/running.rs 🔗

@@ -356,11 +356,11 @@ pub(crate) fn new_debugger_pane(
                     debug_assert!(_previous_subscription.is_none());
                     running
                         .panes
-                        .split(&this_pane, &new_pane, split_direction, cx)?;
-                    anyhow::Ok(new_pane)
+                        .split(&this_pane, &new_pane, split_direction, cx);
+                    new_pane
                 });
 
-                match new_pane.and_then(|r| r) {
+                match new_pane {
                     Ok(new_pane) => {
                         move_item(
                             &source,

crates/terminal_view/src/terminal_panel.rs 🔗

@@ -397,10 +397,7 @@ impl TerminalPanel {
                             };
                             panel
                                 .update_in(cx, |panel, window, cx| {
-                                    panel
-                                        .center
-                                        .split(&pane, &new_pane, direction, cx)
-                                        .log_err();
+                                    panel.center.split(&pane, &new_pane, direction, cx);
                                     window.focus(&new_pane.focus_handle(cx), cx);
                                 })
                                 .ok();
@@ -424,7 +421,7 @@ impl TerminalPanel {
                         new_pane.update(cx, |pane, cx| {
                             pane.add_item(item, true, true, None, window, cx);
                         });
-                        self.center.split(&pane, &new_pane, direction, cx).log_err();
+                        self.center.split(&pane, &new_pane, direction, cx);
                         window.focus(&new_pane.focus_handle(cx), cx);
                     }
                 };
@@ -1303,17 +1300,13 @@ pub fn new_terminal_pane(
                                             &new_pane,
                                             split_direction,
                                             cx,
-                                        )?;
-                                        anyhow::Ok(new_pane)
+                                        );
+                                        new_pane
                                     })
                                 else {
                                     return;
                                 };
 
-                                let Some(new_pane) = new_pane.log_err() else {
-                                    return;
-                                };
-
                                 move_item(
                                     &source,
                                     &new_pane,
@@ -1569,15 +1562,12 @@ impl Render for TerminalPanel {
                                     _ = terminal_panel.update_in(
                                         cx,
                                         |terminal_panel, window, cx| {
-                                            terminal_panel
-                                                .center
-                                                .split(
-                                                    &terminal_panel.active_pane,
-                                                    &new_pane,
-                                                    SplitDirection::Right,
-                                                    cx,
-                                                )
-                                                .log_err();
+                                            terminal_panel.center.split(
+                                                &terminal_panel.active_pane,
+                                                &new_pane,
+                                                SplitDirection::Right,
+                                                cx,
+                                            );
                                             let new_pane = new_pane.read(cx);
                                             window.focus(&new_pane.focus_handle(cx), cx);
                                         },

crates/workspace/src/pane_group.rs 🔗

@@ -61,22 +61,33 @@ impl PaneGroup {
         new_pane: &Entity<Pane>,
         direction: SplitDirection,
         cx: &mut App,
-    ) -> Result<()> {
-        let result = match &mut self.root {
+    ) {
+        let found = match &mut self.root {
             Member::Pane(pane) => {
                 if pane == old_pane {
                     self.root = Member::new_axis(old_pane.clone(), new_pane.clone(), direction);
-                    Ok(())
+                    true
                 } else {
-                    anyhow::bail!("Pane not found");
+                    false
                 }
             }
             Member::Axis(axis) => axis.split(old_pane, new_pane, direction),
         };
-        if result.is_ok() {
-            self.mark_positions(cx);
+
+        // If the pane wasn't found, fall back to splitting the first pane in the tree.
+        if !found {
+            let first_pane = self.root.first_pane();
+            match &mut self.root {
+                Member::Pane(_) => {
+                    self.root = Member::new_axis(first_pane, new_pane.clone(), direction);
+                }
+                Member::Axis(axis) => {
+                    let _ = axis.split(&first_pane, new_pane, direction);
+                }
+            }
         }
-        result
+
+        self.mark_positions(cx);
     }
 
     pub fn bounding_box_for_pane(&self, pane: &Entity<Pane>) -> Option<Bounds<Pixels>> {
@@ -612,12 +623,12 @@ impl PaneAxis {
         old_pane: &Entity<Pane>,
         new_pane: &Entity<Pane>,
         direction: SplitDirection,
-    ) -> Result<()> {
+    ) -> bool {
         for (mut idx, member) in self.members.iter_mut().enumerate() {
             match member {
                 Member::Axis(axis) => {
-                    if axis.split(old_pane, new_pane, direction).is_ok() {
-                        return Ok(());
+                    if axis.split(old_pane, new_pane, direction) {
+                        return true;
                     }
                 }
                 Member::Pane(pane) => {
@@ -631,12 +642,12 @@ impl PaneAxis {
                             *member =
                                 Member::new_axis(old_pane.clone(), new_pane.clone(), direction);
                         }
-                        return Ok(());
+                        return true;
                     }
                 }
             }
         }
-        anyhow::bail!("Pane not found");
+        false
     }
 
     fn insert_pane(&mut self, idx: usize, new_pane: &Entity<Pane>) {

crates/workspace/src/workspace.rs 🔗

@@ -4275,14 +4275,7 @@ impl Workspace {
                     .find_pane_in_direction(direction, cx)
                     .unwrap_or_else(|| self.active_pane.clone());
                 let new_pane = self.add_pane(window, cx);
-                if self
-                    .center
-                    .split(&split_off_pane, &new_pane, direction, cx)
-                    .log_err()
-                    .is_none()
-                {
-                    return;
-                };
+                self.center.split(&split_off_pane, &new_pane, direction, cx);
                 new_pane
             }
         };
@@ -4465,14 +4458,8 @@ impl Workspace {
                     return;
                 }
                 let new_pane = self.add_pane(window, cx);
-                if self
-                    .center
-                    .split(&self.active_pane, &new_pane, action.direction, cx)
-                    .log_err()
-                    .is_none()
-                {
-                    return;
-                };
+                self.center
+                    .split(&self.active_pane, &new_pane, action.direction, cx);
                 new_pane
             }
         };
@@ -4770,8 +4757,7 @@ impl Workspace {
     ) -> Entity<Pane> {
         let new_pane = self.add_pane(window, cx);
         self.center
-            .split(&pane_to_split, &new_pane, split_direction, cx)
-            .unwrap();
+            .split(&pane_to_split, &new_pane, split_direction, cx);
         cx.notify();
         new_pane
     }
@@ -4790,7 +4776,7 @@ impl Workspace {
         new_pane.update(cx, |pane, cx| {
             pane.add_item(item, true, true, None, window, cx)
         });
-        self.center.split(&pane, &new_pane, direction, cx).unwrap();
+        self.center.split(&pane, &new_pane, direction, cx);
         cx.notify();
     }
 
@@ -4817,7 +4803,7 @@ impl Workspace {
                         pane.set_nav_history(nav_history, cx);
                         pane.add_item(clone, true, true, None, window, cx)
                     });
-                    this.center.split(&pane, &new_pane, direction, cx).unwrap();
+                    this.center.split(&pane, &new_pane, direction, cx);
                     cx.notify();
                     new_pane
                 })