diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 6adcf27bd1aa18f6f96c1f2433861cdce8e38e09..d78b230dd91b2cf5dc0d16cc59311745b27d61b1 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -10,7 +10,7 @@ use gpui::{ use settings::{settings_file::SettingsFile, Settings}; use workspace::{ - item::Item, open_new, dock::DockPosition, AppState, PaneBackdrop, Welcome, Workspace, + dock::DockPosition, item::Item, open_new, AppState, PaneBackdrop, Welcome, Workspace, WorkspaceId, }; diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 82d8d404259bf73d88e7d0f9fd6a0fbd59449bc4..5320a4c652cd05b99a82a243828f0434fb5f5044 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -202,6 +202,8 @@ impl Dock { if panel_ix == self.active_panel_index { self.active_panel_index = 0; self.set_open(false, cx); + } else if panel_ix < self.active_panel_index { + self.active_panel_index -= 1; } self.panel_entries.remove(panel_ix); cx.notify(); @@ -228,7 +230,9 @@ impl Dock { pub fn active_panel(&self) -> Option<&Rc> { if self.is_open { - self.panel_entries.get(self.active_panel_index).map(|entry| &entry.panel) + self.panel_entries + .get(self.active_panel_index) + .map(|entry| &entry.panel) } else { None } @@ -416,3 +420,68 @@ impl StatusItemView for PanelButtons { ) { } } + +#[cfg(test)] +pub(crate) mod test { + use super::*; + use gpui::Entity; + + pub enum TestPanelEvent { + PositionChanged, + Activated, + Closed, + } + + pub struct TestPanel { + pub position: DockPosition, + } + + impl Entity for TestPanel { + type Event = TestPanelEvent; + } + + impl View for TestPanel { + fn ui_name() -> &'static str { + "TestPanel" + } + + fn render(&mut self, _: &mut ViewContext<'_, '_, Self>) -> AnyElement { + Empty::new().into_any() + } + } + + impl Panel for TestPanel { + fn position(&self, _: &gpui::WindowContext) -> super::DockPosition { + self.position + } + + fn position_is_valid(&self, _: super::DockPosition) -> bool { + true + } + + fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext) { + self.position = position; + cx.emit(TestPanelEvent::PositionChanged); + } + + fn icon_path(&self) -> &'static str { + "icons/test_panel.svg" + } + + fn icon_tooltip(&self) -> String { + "Test Panel".into() + } + + fn should_change_position_on_event(event: &Self::Event) -> bool { + matches!(event, TestPanelEvent::PositionChanged) + } + + fn should_activate_on_event(&self, event: &Self::Event, _: &gpui::AppContext) -> bool { + matches!(event, TestPanelEvent::Activated) + } + + fn should_close_on_event(&self, event: &Self::Event, _: &gpui::AppContext) -> bool { + matches!(event, TestPanelEvent::Closed) + } + } +} diff --git a/crates/workspace/src/persistence.rs b/crates/workspace/src/persistence.rs index 3b7d0ecb8701c4b974781f9ef0bb9e8a123156d3..2ea99581d219b95e331430740af161bbd641056c 100644 --- a/crates/workspace/src/persistence.rs +++ b/crates/workspace/src/persistence.rs @@ -214,10 +214,7 @@ impl WorkspaceDb { workspace_location = ?2, left_sidebar_open = ?3, timestamp = CURRENT_TIMESTAMP - ))?(( - workspace.id, - &workspace.location, - )) + ))?((workspace.id, &workspace.location)) .context("Updating workspace")?; // Save center pane group @@ -454,7 +451,6 @@ impl WorkspaceDb { #[cfg(test)] mod tests { - use db::open_test_db; use super::*; diff --git a/crates/workspace/src/persistence/model.rs b/crates/workspace/src/persistence/model.rs index f946ebf9de81eab14ca9d5e51c2f773c9ed79c97..19da782fb6840a9a39d500db2355ca666154c7a7 100644 --- a/crates/workspace/src/persistence/model.rs +++ b/crates/workspace/src/persistence/model.rs @@ -1,6 +1,4 @@ -use crate::{ - ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId, -}; +use crate::{ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId}; use anyhow::{anyhow, Context, Result}; use async_recursion::async_recursion; use db::sqlez::{ diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index cf89ed43c75c3e648f86ded942d4d803e4ab521f..791d0d0a44c319abe9db1f87eea139efbf82ccc1 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -859,7 +859,7 @@ impl Workspace { was_visible = dock.is_open() && dock .active_panel() - .map_or(false, |item| item.as_any().is::()); + .map_or(false, |active_panel| active_panel.id() == panel.id()); dock.remove_panel(&panel, cx); }); dock = match panel.read(cx).position(cx) { @@ -2688,7 +2688,11 @@ impl View for Workspace { .flex(1., true), ) .with_children( - if self.bottom_dock.read(cx).active_panel().is_some() + if self + .bottom_dock + .read(cx) + .active_panel() + .is_some() { Some(ChildView::new(&self.bottom_dock, cx)) } else { @@ -3074,7 +3078,10 @@ fn parse_pixel_position_env_var(value: &str) -> Option { mod tests { use std::{cell::RefCell, rc::Rc}; - use crate::item::test::{TestItem, TestItemEvent, TestProjectItem}; + use crate::{ + dock::test::TestPanel, + item::test::{TestItem, TestItemEvent, TestProjectItem}, + }; use super::*; use fs::FakeFs; @@ -3644,4 +3651,89 @@ mod tests { assert!(pane.can_navigate_forward()); }); } + + #[gpui::test] + async fn test_panels(deterministic: Arc, cx: &mut gpui::TestAppContext) { + deterministic.forbid_parking(); + Settings::test_async(cx); + let fs = FakeFs::new(cx.background()); + + let project = Project::test(fs, [], cx).await; + let (_window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); + + let (panel_1, panel_2) = workspace.update(cx, |workspace, cx| { + // Add panel_1 on the left, panel_2 on the right. + let panel_1 = cx.add_view(|_| TestPanel { + position: DockPosition::Left, + }); + workspace.add_panel(panel_1.clone(), cx); + workspace + .left_dock() + .update(cx, |left_dock, cx| left_dock.set_open(true, cx)); + let panel_2 = cx.add_view(|_| TestPanel { + position: DockPosition::Right, + }); + workspace.add_panel(panel_2.clone(), cx); + workspace + .right_dock() + .update(cx, |right_dock, cx| right_dock.set_open(true, cx)); + + assert_eq!( + workspace.left_dock().read(cx).active_panel().unwrap().id(), + panel_1.id() + ); + assert_eq!( + workspace.right_dock().read(cx).active_panel().unwrap().id(), + panel_2.id() + ); + + (panel_1, panel_2) + }); + + // Move panel_1 to the right + panel_1.update(cx, |panel_1, cx| { + panel_1.set_position(DockPosition::Right, cx) + }); + + workspace.update(cx, |workspace, cx| { + // Since panel_1 was visible on the left, it should now be visible now that it's been moved to the right. + // Since it was the only panel on the left, the left dock should now be closed. + assert!(!workspace.left_dock().read(cx).is_open()); + assert!(workspace.left_dock().read(cx).active_panel().is_none()); + assert_eq!( + workspace.right_dock().read(cx).active_panel().unwrap().id(), + panel_1.id() + ); + + // Now we move panel_2 to the left + panel_2.set_position(DockPosition::Left, cx); + }); + + workspace.update(cx, |workspace, cx| { + // Since panel_2 was not visible on the right, we don't open the left dock. + assert!(!workspace.left_dock().read(cx).is_open()); + // And the right dock is unaffected in it's displaying of panel_1 + assert!(workspace.right_dock().read(cx).is_open()); + assert_eq!( + workspace.right_dock().read(cx).active_panel().unwrap().id(), + panel_1.id() + ); + }); + + // Move panel_1 back to the left + panel_1.update(cx, |panel_1, cx| { + panel_1.set_position(DockPosition::Left, cx) + }); + + workspace.update(cx, |workspace, cx| { + // Since panel_1 was visible on the right, we open the left dock and make panel_1 active. + assert!(workspace.left_dock().read(cx).is_open()); + assert_eq!( + workspace.left_dock().read(cx).active_panel().unwrap().id(), + panel_1.id() + ); + // And right the dock should be closed as it no longer has any panels. + assert!(!workspace.right_dock().read(cx).is_open()); + }); + } } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index ff969a8c7597d8accae7ceb93cffa0751012405e..362b714a9274cdc6d0448b2d1320b7482f23bb40 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -52,8 +52,7 @@ use staff_mode::StaffMode; use theme::ThemeRegistry; use util::{channel::RELEASE_CHANNEL, paths, ResultExt, TryFutureExt}; use workspace::{ - item::ItemHandle, notifications::NotifyResultExt, AppState, OpenSettings, - Workspace, + item::ItemHandle, notifications::NotifyResultExt, AppState, OpenSettings, Workspace, }; use zed::{self, build_window_options, initialize_workspace, languages, menus};