Don't close panel on event unless active; add tests

Nathan Sobo created

Change summary

crates/project_panel/src/project_panel.rs |  4 +-
crates/workspace/src/dock.rs              | 12 ++++--
crates/workspace/src/workspace.rs         | 48 +++++++++++++++++++++---
3 files changed, 52 insertions(+), 12 deletions(-)

Detailed changes

crates/project_panel/src/project_panel.rs 🔗

@@ -12,8 +12,8 @@ use gpui::{
     geometry::vector::Vector2F,
     keymap_matcher::KeymapContext,
     platform::{CursorStyle, MouseButton, PromptLevel},
-    AnyElement, AppContext, Axis, ClipboardItem, Element, Entity, ModelHandle, Task, View,
-    ViewContext, ViewHandle, WeakViewHandle,
+    AnyElement, AppContext, ClipboardItem, Element, Entity, ModelHandle, Task, View, ViewContext,
+    ViewHandle, WeakViewHandle,
 };
 use menu::{Confirm, SelectNext, SelectPrev};
 use project::{Entry, EntryKind, Project, ProjectEntryId, ProjectPath, Worktree, WorktreeId};

crates/workspace/src/dock.rs 🔗

@@ -180,16 +180,20 @@ impl Dock {
     pub fn add_panel<T: Panel>(&mut self, panel: ViewHandle<T>, cx: &mut ViewContext<Self>) {
         let subscriptions = [
             cx.observe(&panel, |_, _, cx| cx.notify()),
-            cx.subscribe(&panel, |this, view, event, cx| {
-                if view.read(cx).should_activate_on_event(event, cx) {
+            cx.subscribe(&panel, |this, panel, event, cx| {
+                if panel.read(cx).should_activate_on_event(event, cx) {
                     if let Some(ix) = this
                         .panel_entries
                         .iter()
-                        .position(|entry| entry.panel.id() == view.id())
+                        .position(|entry| entry.panel.id() == panel.id())
                     {
+                        this.set_open(true, cx);
                         this.activate_panel(ix, cx);
+                        cx.focus(&panel);
                     }
-                } else if view.read(cx).should_close_on_event(event, cx) {
+                } else if panel.read(cx).should_close_on_event(event, cx)
+                    && this.active_panel().map_or(false, |p| p.id() == panel.id())
+                {
                     this.set_open(false, cx);
                 }
             }),

crates/workspace/src/workspace.rs 🔗

@@ -3091,7 +3091,7 @@ mod tests {
     use std::{cell::RefCell, rc::Rc};
 
     use crate::{
-        dock::test::TestPanel,
+        dock::test::{TestPanel, TestPanelEvent},
         item::test::{TestItem, TestItemEvent, TestProjectItem},
     };
 
@@ -3767,14 +3767,50 @@ mod tests {
             assert!(!workspace.left_dock().read(cx).is_open());
             // The bottom dock is sized based on the panel's default size,
             // since the panel orientation changed from vertical to horizontal.
+            let bottom_dock = workspace.bottom_dock();
             assert_eq!(
-                workspace
-                    .bottom_dock()
-                    .read(cx)
-                    .active_panel_size()
-                    .unwrap(),
+                bottom_dock.read(cx).active_panel_size().unwrap(),
                 panel_1.default_size(cx),
             );
+            // Close bottom dock and move panel_1 back to the left.
+            bottom_dock.update(cx, |bottom_dock, cx| bottom_dock.set_open(false, cx));
+            panel_1.set_position(DockPosition::Left, cx);
+        });
+
+        // Emit activated event on panel 1
+        panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::Activated));
+
+        // Now the left dock is open and panel_1 is active and focused.
+        workspace.read_with(cx, |workspace, cx| {
+            let left_dock = workspace.left_dock();
+            assert!(left_dock.read(cx).is_open());
+            assert_eq!(
+                left_dock.read(cx).active_panel().unwrap().id(),
+                panel_1.id()
+            );
+            assert!(panel_1.is_focused(cx));
+        });
+
+        // Emit closed event on panel 2, which is not active
+        panel_2.update(cx, |_, cx| cx.emit(TestPanelEvent::Closed));
+
+        // Wo don't close the left dock, because panel_2 wasn't the active panel
+        workspace.read_with(cx, |workspace, cx| {
+            let left_dock = workspace.left_dock();
+            assert!(left_dock.read(cx).is_open());
+            assert_eq!(
+                left_dock.read(cx).active_panel().unwrap().id(),
+                panel_1.id()
+            );
+        });
+
+        // Emit closed event on panel 1, which is active
+        panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::Closed));
+
+        // Now the left dock is closed, because panel_1 was the active panel
+        workspace.read_with(cx, |workspace, cx| {
+            let left_dock = workspace.left_dock();
+            assert!(!left_dock.read(cx).is_open());
         });
     }
 }