From 89d8bb1425be55627b038b05a7357946d3ddc9d5 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 17 May 2023 17:34:20 -0700 Subject: [PATCH] WIP: Add persistence to new docks --- crates/gpui/src/platform.rs | 8 +-- crates/sqlez/src/bindable.rs | 2 +- crates/sqlez/src/statement.rs | 6 +- crates/sqlez/src/typed_statements.rs | 6 +- crates/workspace/src/persistence.rs | 52 +++++++++++++++-- crates/workspace/src/persistence/model.rs | 65 +++++++++++++++++++++- crates/workspace/src/workspace.rs | 68 +++++++++++++++++++++-- 7 files changed, 181 insertions(+), 26 deletions(-) diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index ec301939f7..8fbcda02a3 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -222,21 +222,21 @@ impl Bind for WindowBounds { fn bind(&self, statement: &Statement, start_index: i32) -> Result { let (region, next_index) = match self { WindowBounds::Fullscreen => { - let next_index = statement.bind("Fullscreen", start_index)?; + let next_index = statement.bind(&"Fullscreen", start_index)?; (None, next_index) } WindowBounds::Maximized => { - let next_index = statement.bind("Maximized", start_index)?; + let next_index = statement.bind(&"Maximized", start_index)?; (None, next_index) } WindowBounds::Fixed(region) => { - let next_index = statement.bind("Fixed", start_index)?; + let next_index = statement.bind(&"Fixed", start_index)?; (Some(*region), next_index) } }; statement.bind( - region.map(|region| { + ®ion.map(|region| { ( region.min_x(), region.min_y(), diff --git a/crates/sqlez/src/bindable.rs b/crates/sqlez/src/bindable.rs index 86d69afe5f..4c874c4585 100644 --- a/crates/sqlez/src/bindable.rs +++ b/crates/sqlez/src/bindable.rs @@ -27,7 +27,7 @@ impl StaticColumnCount for bool {} impl Bind for bool { fn bind(&self, statement: &Statement, start_index: i32) -> Result { statement - .bind(self.then_some(1).unwrap_or(0), start_index) + .bind(&self.then_some(1).unwrap_or(0), start_index) .with_context(|| format!("Failed to bind bool at index {start_index}")) } } diff --git a/crates/sqlez/src/statement.rs b/crates/sqlez/src/statement.rs index 69d5685ba0..de0ad626a5 100644 --- a/crates/sqlez/src/statement.rs +++ b/crates/sqlez/src/statement.rs @@ -236,7 +236,7 @@ impl<'a> Statement<'a> { Ok(str::from_utf8(slice)?) } - pub fn bind(&self, value: T, index: i32) -> Result { + pub fn bind(&self, value: &T, index: i32) -> Result { debug_assert!(index > 0); Ok(value.bind(self, index)?) } @@ -258,7 +258,7 @@ impl<'a> Statement<'a> { } } - pub fn with_bindings(&mut self, bindings: impl Bind) -> Result<&mut Self> { + pub fn with_bindings(&mut self, bindings: &impl Bind) -> Result<&mut Self> { self.bind(bindings, 1)?; Ok(self) } @@ -464,7 +464,7 @@ mod test { connection .exec(indoc! {" CREATE TABLE texts ( - text TEXT + text TEXT )"}) .unwrap()() .unwrap(); diff --git a/crates/sqlez/src/typed_statements.rs b/crates/sqlez/src/typed_statements.rs index 488ee27c0c..d7f25cde51 100644 --- a/crates/sqlez/src/typed_statements.rs +++ b/crates/sqlez/src/typed_statements.rs @@ -29,7 +29,7 @@ impl Connection { query: &str, ) -> Result Result<()>> { let mut statement = Statement::prepare(self, query)?; - Ok(move |bindings| statement.with_bindings(bindings)?.exec()) + Ok(move |bindings| statement.with_bindings(&bindings)?.exec()) } /// Prepare a statement which has no bindings and returns a `Vec`. @@ -55,7 +55,7 @@ impl Connection { query: &str, ) -> Result Result>> { let mut statement = Statement::prepare(self, query)?; - Ok(move |bindings| statement.with_bindings(bindings)?.rows::()) + Ok(move |bindings| statement.with_bindings(&bindings)?.rows::()) } /// Prepare a statement that selects a single row from the database. @@ -87,7 +87,7 @@ impl Connection { let mut statement = Statement::prepare(self, query)?; Ok(move |bindings| { statement - .with_bindings(bindings) + .with_bindings(&bindings) .context("Bindings failed")? .maybe_row::() .context("Maybe row failed") diff --git a/crates/workspace/src/persistence.rs b/crates/workspace/src/persistence.rs index 3621a4e0d9..f5d8c56a46 100644 --- a/crates/workspace/src/persistence.rs +++ b/crates/workspace/src/persistence.rs @@ -18,6 +18,9 @@ use model::{ WorkspaceLocation, }; +use self::model::DockStructure; + + define_connection! { // Current schema shape using pseudo-rust syntax: // @@ -151,6 +154,15 @@ define_connection! { INSERT INTO workspaces_2 SELECT * FROM workspaces; DROP TABLE workspaces; ALTER TABLE workspaces_2 RENAME TO workspaces; + ), + // Add panels related information + sql!( + ALTER TABLE workspaces ADD COLUMN left_dock_visible INTEGER; //bool + ALTER TABLE workspaces ADD COLUMN left_dock_size REAL; + ALTER TABLE workspaces ADD COLUMN right_dock_visible INTEGER; //bool + ALTER TABLE workspaces ADD COLUMN right_dock_size REAL; + ALTER TABLE workspaces ADD COLUMN bottom_dock_visible INTEGER; //bool + ALTER TABLE workspaces ADD COLUMN bottom_dock_size REAL; )]; } @@ -166,12 +178,13 @@ impl WorkspaceDb { // Note that we re-assign the workspace_id here in case it's empty // and we've grabbed the most recent workspace - let (workspace_id, workspace_location, left_sidebar_open, bounds, display): ( + let (workspace_id, workspace_location, left_sidebar_open, bounds, display, docks): ( WorkspaceId, WorkspaceLocation, bool, Option, Option, + DockStructure ) = self .select_row_bound(sql! { SELECT @@ -183,7 +196,13 @@ impl WorkspaceDb { window_y, window_width, window_height, - display + display, + left_dock_visible, + left_dock_size, + right_dock_visible, + right_dock_size, + bottom_dock_visible, + bottom_dock_size FROM workspaces WHERE workspace_location = ? }) @@ -202,6 +221,7 @@ impl WorkspaceDb { left_sidebar_open, bounds, display, + docks }) } @@ -227,15 +247,27 @@ impl WorkspaceDb { workspace_id, workspace_location, left_sidebar_open, + left_dock_visible, + left_dock_size, + right_dock_visible, + right_dock_size, + bottom_dock_visible, + bottom_dock_size, timestamp ) - VALUES (?1, ?2, ?3, CURRENT_TIMESTAMP) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, CURRENT_TIMESTAMP) ON CONFLICT DO UPDATE SET workspace_location = ?2, left_sidebar_open = ?3, + left_dock_visible = ?4, + left_dock_size = ?5, + right_dock_visible = ?6, + right_dock_size = ?7, + bottom_dock_visible = ?8, + bottom_dock_size = ?9, timestamp = CURRENT_TIMESTAMP - ))?((workspace.id, &workspace.location)) + ))?((workspace.id, &workspace.location, workspace.left_sidebar_open, workspace.docks)) .context("Updating workspace")?; // Save center pane group @@ -549,19 +581,22 @@ mod tests { let mut workspace_1 = SerializedWorkspace { id: 1, location: (["/tmp", "/tmp2"]).into(), - center_group: Default::default(), left_sidebar_open: true, + center_group: Default::default(), bounds: Default::default(), display: Default::default(), + docks: Default::default() }; let mut _workspace_2 = SerializedWorkspace { id: 2, location: (["/tmp"]).into(), - center_group: Default::default(), left_sidebar_open: false, + center_group: Default::default(), bounds: Default::default(), display: Default::default(), + docks: Default::default() + }; db.save_workspace(workspace_1.clone()).await; @@ -659,6 +694,7 @@ mod tests { left_sidebar_open: true, bounds: Default::default(), display: Default::default(), + docks: Default::default() }; db.save_workspace(workspace.clone()).await; @@ -687,6 +723,7 @@ mod tests { left_sidebar_open: true, bounds: Default::default(), display: Default::default(), + docks: Default::default() }; let mut workspace_2 = SerializedWorkspace { @@ -696,6 +733,7 @@ mod tests { left_sidebar_open: false, bounds: Default::default(), display: Default::default(), + docks: Default::default() }; db.save_workspace(workspace_1.clone()).await; @@ -732,6 +770,7 @@ mod tests { left_sidebar_open: false, bounds: Default::default(), display: Default::default(), + docks: Default::default() }; db.save_workspace(workspace_3.clone()).await; @@ -765,6 +804,7 @@ mod tests { left_sidebar_open: true, bounds: Default::default(), display: Default::default(), + docks: Default::default() } } diff --git a/crates/workspace/src/persistence/model.rs b/crates/workspace/src/persistence/model.rs index 19da782fb6..9d997fcfad 100644 --- a/crates/workspace/src/persistence/model.rs +++ b/crates/workspace/src/persistence/model.rs @@ -63,6 +63,65 @@ pub struct SerializedWorkspace { pub left_sidebar_open: bool, pub bounds: Option, pub display: Option, + pub docks: DockStructure, +} + +#[derive(Debug, PartialEq, Clone, Default)] +pub struct DockStructure { + pub(crate) left: DockData, + pub(crate) right: DockData, + pub(crate) bottom: DockData, +} + +impl Column for DockStructure { + fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> { + let (left, next_index) = DockData::column(statement, start_index)?; + let (right, next_index) = DockData::column(statement, next_index)?; + let (bottom, next_index) = DockData::column(statement, next_index)?; + Ok(( + DockStructure { + left, + right, + bottom, + }, + next_index, + )) + } +} + +impl Bind for DockStructure { + fn bind(&self, statement: &Statement, start_index: i32) -> Result { + let next_index = statement.bind(&self.left, start_index)?; + let next_index = statement.bind(&self.right, next_index)?; + statement.bind(&self.bottom, next_index) + } +} + +#[derive(Debug, PartialEq, Clone, Default)] +pub struct DockData { + pub(crate) visible: bool, + pub(crate) size: Option, +} + +impl Column for DockData { + fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> { + let (visible, next_index) = Option::::column(statement, start_index)?; + let (size, next_index) = Option::::column(statement, next_index)?; + Ok(( + DockData { + visible: visible.unwrap_or(false), + size, + }, + next_index, + )) + } +} + +impl Bind for DockData { + fn bind(&self, statement: &Statement, start_index: i32) -> Result { + let next_index = statement.bind(&self.visible, start_index)?; + statement.bind(&self.size, next_index) + } } #[derive(Debug, PartialEq, Eq, Clone)] @@ -251,9 +310,9 @@ impl StaticColumnCount for SerializedItem { } impl Bind for &SerializedItem { fn bind(&self, statement: &Statement, start_index: i32) -> Result { - let next_index = statement.bind(self.kind.clone(), start_index)?; - let next_index = statement.bind(self.item_id, next_index)?; - statement.bind(self.active, next_index) + let next_index = statement.bind(&self.kind, start_index)?; + let next_index = statement.bind(&self.item_id, next_index)?; + statement.bind(&self.active, next_index) } } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index e9fc2866aa..6cb9f66edb 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -58,7 +58,9 @@ use std::{ use crate::{ notifications::simple_message_notification::MessageNotification, - persistence::model::{SerializedPane, SerializedPaneGroup, SerializedWorkspace}, + persistence::model::{ + DockData, DockStructure, SerializedPane, SerializedPaneGroup, SerializedWorkspace, + }, }; use dock::{Dock, DockPosition, Panel, PanelButtons, PanelHandle, TogglePanel}; use lazy_static::lazy_static; @@ -2575,12 +2577,51 @@ impl Workspace { } } + fn build_serialized_docks(this: &Workspace, cx: &AppContext) -> DockStructure { + let left_dock = this.left_dock.read(cx); + let left_visible = left_dock.is_open(); + let left_size = left_dock + .active_panel() + .map(|panel| left_dock.panel_size(panel.as_ref())) + .flatten(); + + let right_dock = this.right_dock.read(cx); + let right_visible = right_dock.is_open(); + let right_size = right_dock + .active_panel() + .map(|panel| right_dock.panel_size(panel.as_ref())) + .flatten(); + + let bottom_dock = this.bottom_dock.read(cx); + let bottom_visible = bottom_dock.is_open(); + let bottom_size = bottom_dock + .active_panel() + .map(|panel| bottom_dock.panel_size(panel.as_ref())) + .flatten(); + + DockStructure { + left: DockData { + visible: left_visible, + size: left_size, + }, + right: DockData { + visible: right_visible, + size: right_size, + }, + bottom: DockData { + visible: bottom_visible, + size: bottom_size, + }, + } + } + if let Some(location) = self.location(cx) { // Load bearing special case: // - with_local_workspace() relies on this to not have other stuff open // when you open your log if !location.paths().is_empty() { let center_group = build_serialized_pane_group(&self.center.root, cx); + let docks = build_serialized_docks(self, cx); let serialized_workspace = SerializedWorkspace { id: self.database_id, @@ -2589,6 +2630,7 @@ impl Workspace { left_sidebar_open: self.left_dock.read(cx).is_open(), bounds: Default::default(), display: Default::default(), + docks, }; cx.background() @@ -2642,11 +2684,25 @@ impl Workspace { } } - if workspace.left_dock().read(cx).is_open() - != serialized_workspace.left_sidebar_open - { - workspace.toggle_dock(DockPosition::Left, cx); - } + let docks = serialized_workspace.docks; + workspace.left_dock.update(cx, |dock, cx| { + dock.set_open(docks.left.visible, cx); + if let Some(size) = docks.left.size { + dock.resize_active_panel(size, cx); + } + }); + workspace.right_dock.update(cx, |dock, cx| { + dock.set_open(docks.right.visible, cx); + if let Some(size) = docks.right.size { + dock.resize_active_panel(size, cx); + } + }); + workspace.bottom_dock.update(cx, |dock, cx| { + dock.set_open(docks.bottom.visible, cx); + if let Some(size) = docks.bottom.size { + dock.resize_active_panel(size, cx); + } + }); cx.notify(); })?;