Moved to workspaces crate... don't feel great about it

Mikayla Maki created

Change summary

Cargo.lock                                    |   5 
crates/collab/Cargo.toml                      |   1 
crates/collab/src/integration_tests.rs        |  10 
crates/collab/src/main.rs                     |   2 
crates/command_palette/src/command_palette.rs |   4 
crates/db/Cargo.toml                          |   1 
crates/sqlez/src/domain.rs                    |   2 
crates/workspace/Cargo.toml                   |   4 
crates/workspace/src/workspace.rs             |  16 +
crates/workspace/src/workspace_db.rs          | 170 +++++++++++---------
crates/zed/src/main.rs                        |   6 
crates/zed/src/zed.rs                         |   4 
12 files changed, 128 insertions(+), 97 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -1040,6 +1040,7 @@ dependencies = [
  "client",
  "collections",
  "ctor",
+ "db",
  "editor",
  "env_logger",
  "envy",
@@ -1550,7 +1551,6 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "async-trait",
- "bincode",
  "collections",
  "env_logger",
  "gpui",
@@ -7620,6 +7620,7 @@ name = "workspace"
 version = "0.1.0"
 dependencies = [
  "anyhow",
+ "bincode",
  "call",
  "client",
  "collections",
@@ -7629,6 +7630,7 @@ dependencies = [
  "fs",
  "futures 0.3.25",
  "gpui",
+ "indoc",
  "language",
  "log",
  "menu",
@@ -7639,6 +7641,7 @@ dependencies = [
  "serde_json",
  "settings",
  "smallvec",
+ "sqlez",
  "theme",
  "util",
 ]

crates/collab/Cargo.toml 🔗

@@ -18,6 +18,7 @@ live_kit_server = { path = "../live_kit_server" }
 rpc = { path = "../rpc" }
 util = { path = "../util" }
 
+db = { path = "../db" }
 anyhow = "1.0.40"
 async-trait = "0.1.50"
 async-tungstenite = "0.16"

crates/collab/src/integration_tests.rs 🔗

@@ -1,8 +1,9 @@
 use crate::{
-    db::{NewUserParams, ProjectId, SqliteTestDb as TestDb, UserId},
+    db::{Db, NewUserParams, ProjectId, UserId},
     rpc::{Executor, Server},
     AppState,
 };
+
 use ::rpc::Peer;
 use anyhow::anyhow;
 use call::{room, ActiveCall, ParticipantLocation, Room};
@@ -11,6 +12,7 @@ use client::{
     User, UserStore, RECEIVE_TIMEOUT,
 };
 use collections::{BTreeMap, HashMap, HashSet};
+use db as SqliteDb;
 use editor::{
     self, ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, Redo, Rename, ToOffset,
     ToggleCodeActions, Undo,
@@ -5836,7 +5838,11 @@ impl TestServer {
 
         Project::init(&client);
         cx.update(|cx| {
-            workspace::init(app_state.clone(), cx);
+            workspace::init(
+                app_state.clone(),
+                cx,
+                SqliteDb::open_in_memory("integration tests"),
+            );
             call::init(client.clone(), user_store.clone(), cx);
         });
 

crates/collab/src/main.rs 🔗

@@ -9,11 +9,11 @@ mod db_tests;
 #[cfg(test)]
 mod integration_tests;
 
+use crate::db::{Db, PostgresDb};
 use crate::rpc::ResultExt as _;
 use anyhow::anyhow;
 use axum::{routing::get, Router};
 use collab::{Error, Result};
-use db::DefaultDb as Db;
 use serde::Deserialize;
 use std::{
     env::args,

crates/command_palette/src/command_palette.rs 🔗

@@ -320,7 +320,7 @@ mod tests {
     use super::*;
     use editor::Editor;
     use gpui::TestAppContext;
-    use project::Project;
+    use project::{Db, Project};
     use workspace::{AppState, Workspace};
 
     #[test]
@@ -345,7 +345,7 @@ mod tests {
 
         cx.update(|cx| {
             editor::init(cx);
-            workspace::init(app_state.clone(), cx);
+            workspace::init(app_state.clone(), cx, Db::open_in_memory("test"));
             init(cx);
         });
 

crates/db/Cargo.toml 🔗

@@ -22,7 +22,6 @@ lazy_static = "1.4.0"
 log = { version = "0.4.16", features = ["kv_unstable_serde"] }
 parking_lot = "0.11.1"
 serde = { version = "1.0", features = ["derive"] }
-bincode = "1.2.1"
 
 
 [dev-dependencies]

crates/sqlez/src/domain.rs 🔗

@@ -1,6 +1,6 @@
 use crate::connection::Connection;
 
-pub trait Domain: Send + Sync + Clone {
+pub trait Domain {
     fn migrate(conn: &Connection) -> anyhow::Result<()>;
 }
 

crates/workspace/Cargo.toml 🔗

@@ -30,8 +30,10 @@ language = { path = "../language" }
 menu = { path = "../menu" }
 project = { path = "../project" }
 settings = { path = "../settings" }
+sqlez = { path = "../sqlez" }
 theme = { path = "../theme" }
 util = { path = "../util" }
+bincode = "1.2.1"
 anyhow = "1.0.38"
 futures = "0.3"
 log = { version = "0.4.16", features = ["kv_unstable_serde"] }
@@ -40,6 +42,8 @@ postage = { version = "0.4.1", features = ["futures-traits"] }
 serde = { version = "1.0", features = ["derive", "rc"] }
 serde_json = { version = "1.0", features = ["preserve_order"] }
 smallvec = { version = "1.6", features = ["union"] }
+indoc = "1.0.4"
+
 
 [dev-dependencies]
 call = { path = "../call", features = ["test-support"] }

crates/workspace/src/workspace.rs 🔗

@@ -12,6 +12,7 @@ mod status_bar;
 mod toolbar;
 mod workspace_db;
 
+use crate::workspace_db::model::SerializedWorkspace;
 use anyhow::{anyhow, Context, Result};
 use call::ActiveCall;
 use client::{proto, Client, PeerId, TypedEnvelope, UserStore};
@@ -62,8 +63,6 @@ use theme::{Theme, ThemeRegistry};
 pub use toolbar::{ToolbarItemLocation, ToolbarItemView};
 use util::ResultExt;
 
-use crate::workspace_db::model;
-
 type ProjectItemBuilders = HashMap<
     TypeId,
     fn(ModelHandle<Project>, AnyModelHandle, &mut ViewContext<Pane>) -> Box<dyn ItemHandle>,
@@ -166,7 +165,9 @@ impl_internal_actions!(
 );
 impl_actions!(workspace, [ActivatePane]);
 
-pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
+pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext, db: Db<Workspace>) {
+    cx.set_global(db);
+
     pane::init(cx);
     dock::init(cx);
 
@@ -1123,7 +1124,7 @@ enum FollowerItem {
 
 impl Workspace {
     pub fn new(
-        _serialized_workspace: Option<isize>,
+        _serialized_workspace: Option<SerializedWorkspace>,
         project: ModelHandle<Project>,
         dock_default_factory: DefaultItemFactory,
         cx: &mut ViewContext<Self>,
@@ -1291,9 +1292,10 @@ impl Workspace {
 
             // Use the resolved worktree roots to get the serialized_db from the database
             let serialized_workspace = cx.read(|cx| {
-                cx.global::<Db<KeyValue>>()
-                    .open_as::<model::Workspace>()
-                    .workspace_for_roots(&Vec::from_iter(worktree_roots.into_iter())[..])
+                Workspace::workspace_for_roots(
+                    cx.global::<Db<Workspace>>(),
+                    &Vec::from_iter(worktree_roots.into_iter())[..],
+                )
             });
 
             // Use the serialized workspace to construct the new window

crates/workspace/src/workspace_db.rs 🔗

@@ -1,18 +1,20 @@
 use anyhow::{bail, Context, Result};
+
+use db::Db;
 use util::{iife, unzip_option, ResultExt};
 
 use std::path::{Path, PathBuf};
 
 use indoc::indoc;
-use sqlez::{domain::Domain, migrations::Migration};
+use sqlez::{connection::Connection, domain::Domain, migrations::Migration};
+
+use super::Workspace;
 
 use self::model::{
     Axis, GroupId, PaneId, SerializedItem, SerializedItemKind, SerializedPane, SerializedPaneGroup,
     SerializedWorkspace, WorkspaceId,
 };
 
-use super::Db;
-
 // 1) Move all of this into Workspace crate
 // 2) Deserialize items fully
 // 3) Typed prepares (including how you expect to pull data out)
@@ -70,23 +72,20 @@ pub(crate) const ITEM_MIGRATIONS: Migration = Migration::new(
     "}],
 );
 
-#[derive(Clone)]
-pub enum Workspace {}
-
 impl Domain for Workspace {
-    fn migrate(conn: &sqlez::connection::Connection) -> anyhow::Result<()> {
+    fn migrate(conn: &Connection) -> anyhow::Result<()> {
         WORKSPACES_MIGRATION.run(&conn)?;
         PANE_MIGRATIONS.run(&conn)?;
         ITEM_MIGRATIONS.run(&conn)
     }
 }
 
-impl Db<Workspace> {
+impl Workspace {
     /// Returns a serialized workspace for the given worktree_roots. If the passed array
     /// is empty, the most recent workspace is returned instead. If no workspace for the
     /// passed roots is stored, returns none.
     pub fn workspace_for_roots<P: AsRef<Path>>(
-        &self,
+        db: &Db<Workspace>,
         worktree_roots: &[P],
     ) -> Option<SerializedWorkspace> {
         let workspace_id: WorkspaceId = worktree_roots.into();
@@ -95,12 +94,12 @@ impl Db<Workspace> {
         // and we've grabbed the most recent workspace
         let (workspace_id, dock_anchor, dock_visible) = iife!({
             if worktree_roots.len() == 0 {
-                self.select_row(indoc! {"
+                db.select_row(indoc! {"
                         SELECT workspace_id, dock_anchor, dock_visible 
                         FROM workspaces 
                         ORDER BY timestamp DESC LIMIT 1"})?()?
             } else {
-                self.select_row_bound(indoc! {"
+                db.select_row_bound(indoc! {"
                         SELECT workspace_id, dock_anchor, dock_visible 
                         FROM workspaces 
                         WHERE workspace_id = ?"})?(&workspace_id)?
@@ -111,12 +110,10 @@ impl Db<Workspace> {
         .flatten()?;
 
         Some(SerializedWorkspace {
-            dock_pane: self
-                .get_dock_pane(&workspace_id)
+            dock_pane: Workspace::get_dock_pane(&db, &workspace_id)
                 .context("Getting dock pane")
                 .log_err()?,
-            center_group: self
-                .get_center_pane_group(&workspace_id)
+            center_group: Workspace::get_center_pane_group(&db, &workspace_id)
                 .context("Getting center group")
                 .log_err()?,
             dock_anchor,
@@ -127,32 +124,32 @@ impl Db<Workspace> {
     /// Saves a workspace using the worktree roots. Will garbage collect any workspaces
     /// that used this workspace previously
     pub fn save_workspace<P: AsRef<Path>>(
-        &self,
+        db: &Db<Workspace>,
         worktree_roots: &[P],
         old_roots: Option<&[P]>,
         workspace: &SerializedWorkspace,
     ) {
         let workspace_id: WorkspaceId = worktree_roots.into();
 
-        self.with_savepoint("update_worktrees", || {
+        db.with_savepoint("update_worktrees", || {
             if let Some(old_roots) = old_roots {
                 let old_id: WorkspaceId = old_roots.into();
 
-                self.exec_bound("DELETE FROM WORKSPACES WHERE workspace_id = ?")?(&old_id)?;
+                db.exec_bound("DELETE FROM WORKSPACES WHERE workspace_id = ?")?(&old_id)?;
             }
 
             // Delete any previous workspaces with the same roots. This cascades to all
             // other tables that are based on the same roots set.
             // Insert new workspace into workspaces table if none were found
-            self.exec_bound("DELETE FROM workspaces WHERE workspace_id = ?;")?(&workspace_id)?;
+            db.exec_bound("DELETE FROM workspaces WHERE workspace_id = ?;")?(&workspace_id)?;
 
-            self.exec_bound(
+            db.exec_bound(
                 "INSERT INTO workspaces(workspace_id, dock_anchor, dock_visible) VALUES (?, ?, ?)",
             )?((&workspace_id, workspace.dock_anchor, workspace.dock_visible))?;
 
             // Save center pane group and dock pane
-            self.save_pane_group(&workspace_id, &workspace.center_group, None)?;
-            self.save_pane(&workspace_id, &workspace.dock_pane, None)?;
+            Workspace::save_pane_group(db, &workspace_id, &workspace.center_group, None)?;
+            Workspace::save_pane(db, &workspace_id, &workspace.dock_pane, None)?;
 
             Ok(())
         })
@@ -169,11 +166,11 @@ impl Db<Workspace> {
     }
 
     /// Returns the previous workspace ids sorted by last modified along with their opened worktree roots
-    pub fn recent_workspaces(&self, limit: usize) -> Vec<Vec<PathBuf>> {
+    pub fn recent_workspaces(conn: &Connection, limit: usize) -> Vec<Vec<PathBuf>> {
         iife!({
             // TODO, upgrade anyhow: https://docs.rs/anyhow/1.0.66/anyhow/fn.Ok.html
             Ok::<_, anyhow::Error>(
-                self.select_bound::<usize, WorkspaceId>(
+                conn.select_bound::<usize, WorkspaceId>(
                     "SELECT workspace_id FROM workspaces ORDER BY timestamp DESC LIMIT ?",
                 )?(limit)?
                 .into_iter()
@@ -186,21 +183,21 @@ impl Db<Workspace> {
     }
 
     pub(crate) fn get_center_pane_group(
-        &self,
+        db: &Db<Workspace>,
         workspace_id: &WorkspaceId,
     ) -> Result<SerializedPaneGroup> {
-        self.get_pane_group_children(workspace_id, None)?
+        Workspace::get_pane_group_children(&db, workspace_id, None)?
             .into_iter()
             .next()
             .context("No center pane group")
     }
 
     fn get_pane_group_children<'a>(
-        &self,
+        db: &Db<Workspace>,
         workspace_id: &WorkspaceId,
         group_id: Option<GroupId>,
     ) -> Result<Vec<SerializedPaneGroup>> {
-        self.select_bound::<(Option<GroupId>, &WorkspaceId), (Option<GroupId>, Option<Axis>, Option<PaneId>)>(indoc! {"
+        db.select_bound::<(Option<GroupId>, &WorkspaceId), (Option<GroupId>, Option<Axis>, Option<PaneId>)>(indoc! {"
             SELECT group_id, axis, pane_id
                 FROM (SELECT group_id, axis, NULL as pane_id, position,  parent_group_id, workspace_id
                 FROM pane_groups
@@ -217,14 +214,15 @@ impl Db<Workspace> {
                 if let Some((group_id, axis)) = group_id.zip(axis) {
                     Ok(SerializedPaneGroup::Group {
                         axis,
-                        children: self.get_pane_group_children(
+                        children: Workspace::get_pane_group_children(
+                            db,
                             workspace_id,
                             Some(group_id),
                         )?,
                     })
                 } else if let Some(pane_id) = pane_id {
                     Ok(SerializedPaneGroup::Pane(SerializedPane {
-                        children: self.get_items(pane_id)?,
+                        children: Workspace::get_items(db, pane_id)?,
                     }))
                 } else {
                     bail!("Pane Group Child was neither a pane group or a pane");
@@ -234,7 +232,7 @@ impl Db<Workspace> {
     }
 
     pub(crate) fn save_pane_group(
-        &self,
+        db: &Db<Workspace>,
         workspace_id: &WorkspaceId,
         pane_group: &SerializedPaneGroup,
         parent: Option<(GroupId, usize)>,
@@ -247,20 +245,28 @@ impl Db<Workspace> {
 
         match pane_group {
             SerializedPaneGroup::Group { axis, children } => {
-                let parent_id = self.insert_bound("INSERT INTO pane_groups(workspace_id, parent_group_id, position, axis) VALUES (?, ?, ?, ?)")?
+                let parent_id = db.insert_bound("INSERT INTO pane_groups(workspace_id, parent_group_id, position, axis) VALUES (?, ?, ?, ?)")?
                     ((workspace_id, parent_id, position, *axis))?;
 
                 for (position, group) in children.iter().enumerate() {
-                    self.save_pane_group(workspace_id, group, Some((parent_id, position)))?
+                    Workspace::save_pane_group(
+                        db,
+                        workspace_id,
+                        group,
+                        Some((parent_id, position)),
+                    )?
                 }
                 Ok(())
             }
-            SerializedPaneGroup::Pane(pane) => self.save_pane(workspace_id, pane, parent),
+            SerializedPaneGroup::Pane(pane) => Workspace::save_pane(db, workspace_id, pane, parent),
         }
     }
 
-    pub(crate) fn get_dock_pane(&self, workspace_id: &WorkspaceId) -> Result<SerializedPane> {
-        let pane_id = self.select_row_bound(indoc! {"
+    pub(crate) fn get_dock_pane(
+        db: &Db<Workspace>,
+        workspace_id: &WorkspaceId,
+    ) -> Result<SerializedPane> {
+        let pane_id = db.select_row_bound(indoc! {"
                 SELECT pane_id FROM panes 
                 WHERE workspace_id = ? AND parent_group_id IS NULL AND position IS NULL"})?(
             workspace_id,
@@ -268,28 +274,27 @@ impl Db<Workspace> {
         .context("No dock pane for workspace")?;
 
         Ok(SerializedPane::new(
-            self.get_items(pane_id).context("Reading items")?,
+            Workspace::get_items(db, pane_id).context("Reading items")?,
         ))
     }
 
     pub(crate) fn save_pane(
-        &self,
+        db: &Db<Workspace>,
         workspace_id: &WorkspaceId,
         pane: &SerializedPane,
         parent: Option<(GroupId, usize)>,
     ) -> Result<()> {
         let (parent_id, order) = unzip_option(parent);
 
-        let pane_id = self.insert_bound(
+        let pane_id = db.insert_bound(
             "INSERT INTO panes(workspace_id, parent_group_id, position) VALUES (?, ?, ?)",
         )?((workspace_id, parent_id, order))?;
 
-        self.save_items(workspace_id, pane_id, &pane.children)
-            .context("Saving items")
+        Workspace::save_items(db, workspace_id, pane_id, &pane.children).context("Saving items")
     }
 
-    pub(crate) fn get_items(&self, pane_id: PaneId) -> Result<Vec<SerializedItem>> {
-        Ok(self.select_bound(indoc! {"
+    pub(crate) fn get_items(db: &Db<Workspace>, pane_id: PaneId) -> Result<Vec<SerializedItem>> {
+        Ok(db.select_bound(indoc! {"
                 SELECT item_id, kind FROM items
                 WHERE pane_id = ?
                 ORDER BY position"})?(pane_id)?
@@ -302,15 +307,15 @@ impl Db<Workspace> {
     }
 
     pub(crate) fn save_items(
-        &self,
+        db: &Db<Workspace>,
         workspace_id: &WorkspaceId,
         pane_id: PaneId,
         items: &[SerializedItem],
     ) -> Result<()> {
-        let mut delete_old = self
+        let mut delete_old = db
             .exec_bound("DELETE FROM items WHERE workspace_id = ? AND pane_id = ? AND item_id = ?")
             .context("Preparing deletion")?;
-        let mut insert_new = self.exec_bound(
+        let mut insert_new = db.exec_bound(
             "INSERT INTO items(item_id, workspace_id, pane_id, kind, position) VALUES (?, ?, ?, ?, ?)",
         ).context("Preparing insertion")?;
         for (position, item) in items.iter().enumerate() {
@@ -324,17 +329,12 @@ impl Db<Workspace> {
 
 #[cfg(test)]
 mod tests {
-    use crate::{
-        model::{
-            DockAnchor::{Bottom, Expanded, Right},
-            SerializedWorkspace,
-        },
-        Db,
-    };
+    use crate::workspace_db::model::DockAnchor::{Bottom, Expanded, Right};
+    use crate::{Db, Workspace};
 
     #[test]
     fn test_workspace_assignment() {
-        env_logger::try_init().ok();
+        // env_logger::try_init().ok();
 
         let db = Db::open_in_memory("test_basic_functionality");
 
@@ -359,61 +359,73 @@ mod tests {
             dock_pane: Default::default(),
         };
 
-        db.save_workspace(&["/tmp", "/tmp2"], None, &workspace_1);
-        db.save_workspace(&["/tmp"], None, &workspace_2);
+        Workspace::save_workspace(&db, &["/tmp", "/tmp2"], None, &workspace_1);
+        Workspace::save_workspace(&db, &["/tmp"], None, &workspace_2);
 
         db.write_to("test.db").unwrap();
 
         // Test that paths are treated as a set
         assert_eq!(
-            db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
+            Workspace::workspace_for_roots(&db, &["/tmp", "/tmp2"]).unwrap(),
             workspace_1
         );
         assert_eq!(
-            db.workspace_for_roots(&["/tmp2", "/tmp"]).unwrap(),
+            Workspace::workspace_for_roots(&db, &["/tmp2", "/tmp"]).unwrap(),
             workspace_1
         );
 
         // Make sure that other keys work
-        assert_eq!(db.workspace_for_roots(&["/tmp"]).unwrap(), workspace_2);
-        assert_eq!(db.workspace_for_roots(&["/tmp3", "/tmp2", "/tmp4"]), None);
+        assert_eq!(
+            Workspace::workspace_for_roots(&db, &["/tmp"]).unwrap(),
+            workspace_2
+        );
+        assert_eq!(
+            Workspace::workspace_for_roots(&db, &["/tmp3", "/tmp2", "/tmp4"]),
+            None
+        );
 
         // Test 'mutate' case of updating a pre-existing id
-        db.save_workspace(&["/tmp", "/tmp2"], Some(&["/tmp", "/tmp2"]), &workspace_2);
+        Workspace::save_workspace(
+            &db,
+            &["/tmp", "/tmp2"],
+            Some(&["/tmp", "/tmp2"]),
+            &workspace_2,
+        );
         assert_eq!(
-            db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
+            Workspace::workspace_for_roots(&db, &["/tmp", "/tmp2"]).unwrap(),
             workspace_2
         );
 
         // Test other mechanism for mutating
-        db.save_workspace(&["/tmp", "/tmp2"], None, &workspace_3);
+        Workspace::save_workspace(&db, &["/tmp", "/tmp2"], None, &workspace_3);
         assert_eq!(
-            db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
+            Workspace::workspace_for_roots(&db, &["/tmp", "/tmp2"]).unwrap(),
             workspace_3
         );
 
         // Make sure that updating paths differently also works
-        db.save_workspace(
+        Workspace::save_workspace(
+            &db,
             &["/tmp3", "/tmp4", "/tmp2"],
             Some(&["/tmp", "/tmp2"]),
             &workspace_3,
         );
-        assert_eq!(db.workspace_for_roots(&["/tmp2", "tmp"]), None);
+        assert_eq!(Workspace::workspace_for_roots(&db, &["/tmp2", "tmp"]), None);
         assert_eq!(
-            db.workspace_for_roots(&["/tmp2", "/tmp3", "/tmp4"])
-                .unwrap(),
+            Workspace::workspace_for_roots(&db, &["/tmp2", "/tmp3", "/tmp4"]).unwrap(),
             workspace_3
         );
     }
 
-    use crate::model::{SerializedItem, SerializedPane, SerializedPaneGroup};
+    use crate::workspace_db::model::SerializedWorkspace;
+    use crate::workspace_db::model::{SerializedItem, SerializedPane, SerializedPaneGroup};
 
     fn default_workspace(
         dock_pane: SerializedPane,
         center_group: &SerializedPaneGroup,
     ) -> SerializedWorkspace {
         SerializedWorkspace {
-            dock_anchor: crate::model::DockAnchor::Right,
+            dock_anchor: crate::workspace_db::model::DockAnchor::Right,
             dock_visible: false,
             center_group: center_group.clone(),
             dock_pane,
@@ -422,11 +434,11 @@ mod tests {
 
     #[test]
     fn test_basic_dock_pane() {
-        env_logger::try_init().ok();
+        // env_logger::try_init().ok();
 
         let db = Db::open_in_memory("basic_dock_pane");
 
-        let dock_pane = crate::model::SerializedPane {
+        let dock_pane = crate::workspace_db::model::SerializedPane {
             children: vec![
                 SerializedItem::Terminal { item_id: 1 },
                 SerializedItem::Terminal { item_id: 4 },
@@ -437,16 +449,16 @@ mod tests {
 
         let workspace = default_workspace(dock_pane, &Default::default());
 
-        db.save_workspace(&["/tmp"], None, &workspace);
+        Workspace::save_workspace(&db, &["/tmp"], None, &workspace);
 
-        let new_workspace = db.workspace_for_roots(&["/tmp"]).unwrap();
+        let new_workspace = Workspace::workspace_for_roots(&db, &["/tmp"]).unwrap();
 
         assert_eq!(workspace.dock_pane, new_workspace.dock_pane);
     }
 
     #[test]
     fn test_simple_split() {
-        env_logger::try_init().ok();
+        // env_logger::try_init().ok();
 
         let db = Db::open_in_memory("simple_split");
 
@@ -456,10 +468,10 @@ mod tests {
         //  | 3,4   |       |
         //  -----------------
         let center_pane = SerializedPaneGroup::Group {
-            axis: crate::model::Axis::Horizontal,
+            axis: crate::workspace_db::model::Axis::Horizontal,
             children: vec![
                 SerializedPaneGroup::Group {
-                    axis: crate::model::Axis::Vertical,
+                    axis: crate::workspace_db::model::Axis::Vertical,
                     children: vec![
                         SerializedPaneGroup::Pane(SerializedPane {
                             children: vec![
@@ -486,7 +498,7 @@ mod tests {
 
         let workspace = default_workspace(Default::default(), &center_pane);
 
-        db.save_workspace(&["/tmp"], None, &workspace);
+        Workspace::save_workspace(&db, &["/tmp"], None, &workspace);
 
         assert_eq!(workspace.center_group, center_pane);
     }
@@ -720,7 +732,7 @@ pub mod model {
     mod tests {
         use sqlez::connection::Connection;
 
-        use crate::model::DockAnchor;
+        use crate::workspace_db::model::DockAnchor;
 
         use super::WorkspaceId;
 

crates/zed/src/main.rs 🔗

@@ -170,7 +170,11 @@ fn main() {
             client::ZED_SERVER_URL.clone(),
             cx,
         );
-        workspace::init(app_state.clone(), cx);
+
+        let workspace_db = cx.global::<Db<project::KeyValue>>().open_as::<Workspace>();
+
+        workspace::init(app_state.clone(), cx, workspace_db);
+
         journal::init(app_state.clone(), cx);
         theme_selector::init(app_state.clone(), cx);
         zed::init(&app_state, cx);

crates/zed/src/zed.rs 🔗

@@ -630,7 +630,7 @@ mod tests {
     use gpui::{
         executor::Deterministic, AssetSource, MutableAppContext, TestAppContext, ViewHandle,
     };
-    use project::{Project, ProjectPath};
+    use project::{Db, Project, ProjectPath};
     use serde_json::json;
     use std::{
         collections::HashSet,
@@ -1817,7 +1817,7 @@ mod tests {
             state.initialize_workspace = initialize_workspace;
             state.build_window_options = build_window_options;
             call::init(app_state.client.clone(), app_state.user_store.clone(), cx);
-            workspace::init(app_state.clone(), cx);
+            workspace::init(app_state.clone(), cx, Db::open_in_memory("test"));
             editor::init(cx);
             pane::init(cx);
             app_state