feat(workspace): add action for closing inactive editors on all panes (#2771)

Mikayla Maki created

using zed more and more to develop zed itself I'm finding some small qol
features missing, this is one of them
I'm very used to open two or three splits, and sometimes I want to close
everything except for the active editor, but that wasn't supported, as
the `pane::CloseInactiveItems` action only closes inactive items on the
active pane

so I've implemented it really quick, although I'm not sure it's the
right way to do this

note: I really don't like the default keybinding I've set it to, I have
this action bound to `cmd-shift-w` on all editors, but in zed is taken,
so I chose something that's free but without thinking too much about it

Release Notes:

- Added action for closing inactive editors from all panes

Change summary

assets/keymaps/default.json       |  1 
crates/workspace/src/pane.rs      |  4 +++
crates/workspace/src/workspace.rs | 41 +++++++++++++++++++++++++++++++++
3 files changed, 46 insertions(+)

Detailed changes

assets/keymaps/default.json 🔗

@@ -22,6 +22,7 @@
       "alt-cmd-right": "pane::ActivateNextItem",
       "cmd-w": "pane::CloseActiveItem",
       "alt-cmd-t": "pane::CloseInactiveItems",
+      "ctrl-alt-cmd-w": "workspace::CloseInactiveTabsAndPanes",
       "cmd-k u": "pane::CloseCleanItems",
       "cmd-k cmd-w": "pane::CloseAllItems",
       "cmd-shift-w": "workspace::CloseWindow",

crates/workspace/src/pane.rs 🔗

@@ -746,6 +746,10 @@ impl Pane {
         _: &CloseAllItems,
         cx: &mut ViewContext<Self>,
     ) -> Option<Task<Result<()>>> {
+        if self.items.is_empty() {
+            return None;
+        }
+
         Some(self.close_items(cx, move |_| true))
     }
 

crates/workspace/src/workspace.rs 🔗

@@ -122,6 +122,7 @@ actions!(
         NewFile,
         NewWindow,
         CloseWindow,
+        CloseInactiveTabsAndPanes,
         AddFolderToProject,
         Unfollow,
         Save,
@@ -240,6 +241,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
 
     cx.add_async_action(Workspace::follow_next_collaborator);
     cx.add_async_action(Workspace::close);
+    cx.add_async_action(Workspace::close_inactive_items_and_panes);
     cx.add_global_action(Workspace::close_global);
     cx.add_global_action(restart);
     cx.add_async_action(Workspace::save_all);
@@ -1671,6 +1673,45 @@ impl Workspace {
         }
     }
 
+    pub fn close_inactive_items_and_panes(
+        &mut self,
+        _: &CloseInactiveTabsAndPanes,
+        cx: &mut ViewContext<Self>,
+    ) -> Option<Task<Result<()>>> {
+        let current_pane = self.active_pane();
+
+        let mut tasks = Vec::new();
+
+        if let Some(current_pane_close) = current_pane.update(cx, |pane, cx| {
+            pane.close_inactive_items(&CloseInactiveItems, cx)
+        }) {
+            tasks.push(current_pane_close);
+        };
+
+        for pane in self.panes() {
+            if pane.id() == current_pane.id() {
+                continue;
+            }
+
+            if let Some(close_pane_items) = pane.update(cx, |pane: &mut Pane, cx| {
+                pane.close_all_items(&CloseAllItems, cx)
+            }) {
+                tasks.push(close_pane_items)
+            }
+        }
+
+        if tasks.is_empty() {
+            None
+        } else {
+            Some(cx.spawn(|_, _| async move {
+                for task in tasks {
+                    task.await?
+                }
+                Ok(())
+            }))
+        }
+    }
+
     pub fn toggle_dock(&mut self, dock_side: DockPosition, cx: &mut ViewContext<Self>) {
         let dock = match dock_side {
             DockPosition::Left => &self.left_dock,