Merge pull request #2361 from zed-industries/add-close-items-to-left-and-right

Joseph T. Lyons created

Add close items to left and right

Change summary

crates/workspace/src/pane.rs | 129 +++++++++++++++++++++++++++----------
1 file changed, 93 insertions(+), 36 deletions(-)

Detailed changes

crates/workspace/src/pane.rs 🔗

@@ -46,6 +46,8 @@ actions!(
         CloseActiveItem,
         CloseInactiveItems,
         CloseCleanItems,
+        CloseItemsToTheLeft,
+        CloseItemsToTheRight,
         CloseAllItems,
         ReopenClosedItem,
         SplitLeft,
@@ -122,6 +124,8 @@ pub fn init(cx: &mut MutableAppContext) {
     cx.add_async_action(Pane::close_active_item);
     cx.add_async_action(Pane::close_inactive_items);
     cx.add_async_action(Pane::close_clean_items);
+    cx.add_async_action(Pane::close_items_to_the_left);
+    cx.add_async_action(Pane::close_items_to_the_right);
     cx.add_async_action(Pane::close_all_items);
     cx.add_async_action(|workspace: &mut Workspace, action: &CloseItem, cx| {
         let pane = action.pane.upgrade(cx)?;
@@ -261,13 +265,6 @@ pub enum ReorderBehavior {
     MoveToIndex(usize),
 }
 
-enum ItemType {
-    Active,
-    Inactive,
-    Clean,
-    All,
-}
-
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 enum TabBarContextMenuKind {
     New,
@@ -642,7 +639,7 @@ impl Pane {
         self.items.len()
     }
 
-    pub fn items(&self) -> impl Iterator<Item = &Box<dyn ItemHandle>> {
+    pub fn items(&self) -> impl Iterator<Item = &Box<dyn ItemHandle>> + DoubleEndedIterator {
         self.items.iter()
     }
 
@@ -741,7 +738,18 @@ impl Pane {
         _: &CloseActiveItem,
         cx: &mut ViewContext<Workspace>,
     ) -> Option<Task<Result<()>>> {
-        Self::close_main(workspace, ItemType::Active, cx)
+        let pane_handle = workspace.active_pane().clone();
+        let pane = pane_handle.read(cx);
+        let active_item_id = pane.items[pane.active_item_index].id();
+
+        let task = Self::close_items(workspace, pane_handle, cx, move |item_id| {
+            item_id == active_item_id
+        });
+
+        Some(cx.foreground().spawn(async move {
+            task.await?;
+            Ok(())
+        }))
     }
 
     pub fn close_inactive_items(
@@ -749,54 +757,103 @@ impl Pane {
         _: &CloseInactiveItems,
         cx: &mut ViewContext<Workspace>,
     ) -> Option<Task<Result<()>>> {
-        Self::close_main(workspace, ItemType::Inactive, cx)
+        let pane_handle = workspace.active_pane().clone();
+        let pane = pane_handle.read(cx);
+        let active_item_id = pane.items[pane.active_item_index].id();
+
+        let task = Self::close_items(workspace, pane_handle, cx, move |item_id| {
+            item_id != active_item_id
+        });
+
+        Some(cx.foreground().spawn(async move {
+            task.await?;
+            Ok(())
+        }))
     }
 
-    pub fn close_all_items(
+    pub fn close_clean_items(
         workspace: &mut Workspace,
-        _: &CloseAllItems,
+        _: &CloseCleanItems,
         cx: &mut ViewContext<Workspace>,
     ) -> Option<Task<Result<()>>> {
-        Self::close_main(workspace, ItemType::All, cx)
+        let pane_handle = workspace.active_pane().clone();
+        let pane = pane_handle.read(cx);
+
+        let item_ids: Vec<_> = pane
+            .items()
+            .filter(|item| !item.is_dirty(cx))
+            .map(|item| item.id())
+            .collect();
+
+        let task = Self::close_items(workspace, pane_handle, cx, move |item_id| {
+            item_ids.contains(&item_id)
+        });
+
+        Some(cx.foreground().spawn(async move {
+            task.await?;
+            Ok(())
+        }))
     }
 
-    pub fn close_clean_items(
+    pub fn close_items_to_the_left(
         workspace: &mut Workspace,
-        _: &CloseCleanItems,
+        _: &CloseItemsToTheLeft,
         cx: &mut ViewContext<Workspace>,
     ) -> Option<Task<Result<()>>> {
-        Self::close_main(workspace, ItemType::Clean, cx)
+        let pane_handle = workspace.active_pane().clone();
+        let pane = pane_handle.read(cx);
+        let active_item_id = pane.items[pane.active_item_index].id();
+
+        let item_ids: Vec<_> = pane
+            .items()
+            .take_while(|item| item.id() != active_item_id)
+            .map(|item| item.id())
+            .collect();
+
+        let task = Self::close_items(workspace, pane_handle, cx, move |item_id| {
+            item_ids.contains(&item_id)
+        });
+
+        Some(cx.foreground().spawn(async move {
+            task.await?;
+            Ok(())
+        }))
     }
 
-    fn close_main(
+    pub fn close_items_to_the_right(
         workspace: &mut Workspace,
-        close_item_type: ItemType,
+        _: &CloseItemsToTheRight,
         cx: &mut ViewContext<Workspace>,
     ) -> Option<Task<Result<()>>> {
         let pane_handle = workspace.active_pane().clone();
         let pane = pane_handle.read(cx);
-        if pane.items.is_empty() {
-            return None;
-        }
-
         let active_item_id = pane.items[pane.active_item_index].id();
-        let clean_item_ids: Vec<_> = pane
+
+        let item_ids: Vec<_> = pane
             .items()
-            .filter(|item| !item.is_dirty(cx))
+            .rev()
+            .take_while(|item| item.id() != active_item_id)
             .map(|item| item.id())
             .collect();
-        let task =
-            Self::close_items(
-                workspace,
-                pane_handle,
-                cx,
-                move |item_id| match close_item_type {
-                    ItemType::Active => item_id == active_item_id,
-                    ItemType::Inactive => item_id != active_item_id,
-                    ItemType::Clean => clean_item_ids.contains(&item_id),
-                    ItemType::All => true,
-                },
-            );
+
+        let task = Self::close_items(workspace, pane_handle, cx, move |item_id| {
+            item_ids.contains(&item_id)
+        });
+
+        Some(cx.foreground().spawn(async move {
+            task.await?;
+            Ok(())
+        }))
+    }
+
+    pub fn close_all_items(
+        workspace: &mut Workspace,
+        _: &CloseAllItems,
+        cx: &mut ViewContext<Workspace>,
+    ) -> Option<Task<Result<()>>> {
+        let pane_handle = workspace.active_pane().clone();
+
+        let task = Self::close_items(workspace, pane_handle, cx, move |_| true);
 
         Some(cx.foreground().spawn(async move {
             task.await?;