Moved to workspaces crate... don't feel great about it
This commit is contained in:
parent
e578f2530e
commit
a5edac312e
12 changed files with 128 additions and 97 deletions
5
Cargo.lock
generated
5
Cargo.lock
generated
|
@ -1040,6 +1040,7 @@ dependencies = [
|
||||||
"client",
|
"client",
|
||||||
"collections",
|
"collections",
|
||||||
"ctor",
|
"ctor",
|
||||||
|
"db",
|
||||||
"editor",
|
"editor",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"envy",
|
"envy",
|
||||||
|
@ -1550,7 +1551,6 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bincode",
|
|
||||||
"collections",
|
"collections",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
@ -7620,6 +7620,7 @@ name = "workspace"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"bincode",
|
||||||
"call",
|
"call",
|
||||||
"client",
|
"client",
|
||||||
"collections",
|
"collections",
|
||||||
|
@ -7629,6 +7630,7 @@ dependencies = [
|
||||||
"fs",
|
"fs",
|
||||||
"futures 0.3.25",
|
"futures 0.3.25",
|
||||||
"gpui",
|
"gpui",
|
||||||
|
"indoc",
|
||||||
"language",
|
"language",
|
||||||
"log",
|
"log",
|
||||||
"menu",
|
"menu",
|
||||||
|
@ -7639,6 +7641,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"settings",
|
"settings",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
"sqlez",
|
||||||
"theme",
|
"theme",
|
||||||
"util",
|
"util",
|
||||||
]
|
]
|
||||||
|
|
|
@ -18,6 +18,7 @@ live_kit_server = { path = "../live_kit_server" }
|
||||||
rpc = { path = "../rpc" }
|
rpc = { path = "../rpc" }
|
||||||
util = { path = "../util" }
|
util = { path = "../util" }
|
||||||
|
|
||||||
|
db = { path = "../db" }
|
||||||
anyhow = "1.0.40"
|
anyhow = "1.0.40"
|
||||||
async-trait = "0.1.50"
|
async-trait = "0.1.50"
|
||||||
async-tungstenite = "0.16"
|
async-tungstenite = "0.16"
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
db::{NewUserParams, ProjectId, SqliteTestDb as TestDb, UserId},
|
db::{Db, NewUserParams, ProjectId, UserId},
|
||||||
rpc::{Executor, Server},
|
rpc::{Executor, Server},
|
||||||
AppState,
|
AppState,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ::rpc::Peer;
|
use ::rpc::Peer;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use call::{room, ActiveCall, ParticipantLocation, Room};
|
use call::{room, ActiveCall, ParticipantLocation, Room};
|
||||||
|
@ -11,6 +12,7 @@ use client::{
|
||||||
User, UserStore, RECEIVE_TIMEOUT,
|
User, UserStore, RECEIVE_TIMEOUT,
|
||||||
};
|
};
|
||||||
use collections::{BTreeMap, HashMap, HashSet};
|
use collections::{BTreeMap, HashMap, HashSet};
|
||||||
|
use db as SqliteDb;
|
||||||
use editor::{
|
use editor::{
|
||||||
self, ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, Redo, Rename, ToOffset,
|
self, ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, Redo, Rename, ToOffset,
|
||||||
ToggleCodeActions, Undo,
|
ToggleCodeActions, Undo,
|
||||||
|
@ -5836,7 +5838,11 @@ impl TestServer {
|
||||||
|
|
||||||
Project::init(&client);
|
Project::init(&client);
|
||||||
cx.update(|cx| {
|
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);
|
call::init(client.clone(), user_store.clone(), cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,11 @@ mod db_tests;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod integration_tests;
|
mod integration_tests;
|
||||||
|
|
||||||
|
use crate::db::{Db, PostgresDb};
|
||||||
use crate::rpc::ResultExt as _;
|
use crate::rpc::ResultExt as _;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use axum::{routing::get, Router};
|
use axum::{routing::get, Router};
|
||||||
use collab::{Error, Result};
|
use collab::{Error, Result};
|
||||||
use db::DefaultDb as Db;
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{
|
use std::{
|
||||||
env::args,
|
env::args,
|
||||||
|
|
|
@ -320,7 +320,7 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use editor::Editor;
|
use editor::Editor;
|
||||||
use gpui::TestAppContext;
|
use gpui::TestAppContext;
|
||||||
use project::Project;
|
use project::{Db, Project};
|
||||||
use workspace::{AppState, Workspace};
|
use workspace::{AppState, Workspace};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -345,7 +345,7 @@ mod tests {
|
||||||
|
|
||||||
cx.update(|cx| {
|
cx.update(|cx| {
|
||||||
editor::init(cx);
|
editor::init(cx);
|
||||||
workspace::init(app_state.clone(), cx);
|
workspace::init(app_state.clone(), cx, Db::open_in_memory("test"));
|
||||||
init(cx);
|
init(cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ lazy_static = "1.4.0"
|
||||||
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
|
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
|
||||||
parking_lot = "0.11.1"
|
parking_lot = "0.11.1"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
bincode = "1.2.1"
|
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::connection::Connection;
|
use crate::connection::Connection;
|
||||||
|
|
||||||
pub trait Domain: Send + Sync + Clone {
|
pub trait Domain {
|
||||||
fn migrate(conn: &Connection) -> anyhow::Result<()>;
|
fn migrate(conn: &Connection) -> anyhow::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,10 @@ language = { path = "../language" }
|
||||||
menu = { path = "../menu" }
|
menu = { path = "../menu" }
|
||||||
project = { path = "../project" }
|
project = { path = "../project" }
|
||||||
settings = { path = "../settings" }
|
settings = { path = "../settings" }
|
||||||
|
sqlez = { path = "../sqlez" }
|
||||||
theme = { path = "../theme" }
|
theme = { path = "../theme" }
|
||||||
util = { path = "../util" }
|
util = { path = "../util" }
|
||||||
|
bincode = "1.2.1"
|
||||||
anyhow = "1.0.38"
|
anyhow = "1.0.38"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
|
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 = { version = "1.0", features = ["derive", "rc"] }
|
||||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||||
smallvec = { version = "1.6", features = ["union"] }
|
smallvec = { version = "1.6", features = ["union"] }
|
||||||
|
indoc = "1.0.4"
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
call = { path = "../call", features = ["test-support"] }
|
call = { path = "../call", features = ["test-support"] }
|
||||||
|
|
|
@ -12,6 +12,7 @@ mod status_bar;
|
||||||
mod toolbar;
|
mod toolbar;
|
||||||
mod workspace_db;
|
mod workspace_db;
|
||||||
|
|
||||||
|
use crate::workspace_db::model::SerializedWorkspace;
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use call::ActiveCall;
|
use call::ActiveCall;
|
||||||
use client::{proto, Client, PeerId, TypedEnvelope, UserStore};
|
use client::{proto, Client, PeerId, TypedEnvelope, UserStore};
|
||||||
|
@ -62,8 +63,6 @@ use theme::{Theme, ThemeRegistry};
|
||||||
pub use toolbar::{ToolbarItemLocation, ToolbarItemView};
|
pub use toolbar::{ToolbarItemLocation, ToolbarItemView};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
|
||||||
use crate::workspace_db::model;
|
|
||||||
|
|
||||||
type ProjectItemBuilders = HashMap<
|
type ProjectItemBuilders = HashMap<
|
||||||
TypeId,
|
TypeId,
|
||||||
fn(ModelHandle<Project>, AnyModelHandle, &mut ViewContext<Pane>) -> Box<dyn ItemHandle>,
|
fn(ModelHandle<Project>, AnyModelHandle, &mut ViewContext<Pane>) -> Box<dyn ItemHandle>,
|
||||||
|
@ -166,7 +165,9 @@ impl_internal_actions!(
|
||||||
);
|
);
|
||||||
impl_actions!(workspace, [ActivatePane]);
|
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);
|
pane::init(cx);
|
||||||
dock::init(cx);
|
dock::init(cx);
|
||||||
|
|
||||||
|
@ -1123,7 +1124,7 @@ enum FollowerItem {
|
||||||
|
|
||||||
impl Workspace {
|
impl Workspace {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
_serialized_workspace: Option<isize>,
|
_serialized_workspace: Option<SerializedWorkspace>,
|
||||||
project: ModelHandle<Project>,
|
project: ModelHandle<Project>,
|
||||||
dock_default_factory: DefaultItemFactory,
|
dock_default_factory: DefaultItemFactory,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
|
@ -1291,9 +1292,10 @@ impl Workspace {
|
||||||
|
|
||||||
// Use the resolved worktree roots to get the serialized_db from the database
|
// Use the resolved worktree roots to get the serialized_db from the database
|
||||||
let serialized_workspace = cx.read(|cx| {
|
let serialized_workspace = cx.read(|cx| {
|
||||||
cx.global::<Db<KeyValue>>()
|
Workspace::workspace_for_roots(
|
||||||
.open_as::<model::Workspace>()
|
cx.global::<Db<Workspace>>(),
|
||||||
.workspace_for_roots(&Vec::from_iter(worktree_roots.into_iter())[..])
|
&Vec::from_iter(worktree_roots.into_iter())[..],
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Use the serialized workspace to construct the new window
|
// Use the serialized workspace to construct the new window
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
|
|
||||||
|
use db::Db;
|
||||||
use util::{iife, unzip_option, ResultExt};
|
use util::{iife, unzip_option, ResultExt};
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
use sqlez::{domain::Domain, migrations::Migration};
|
use sqlez::{connection::Connection, domain::Domain, migrations::Migration};
|
||||||
|
|
||||||
|
use super::Workspace;
|
||||||
|
|
||||||
use self::model::{
|
use self::model::{
|
||||||
Axis, GroupId, PaneId, SerializedItem, SerializedItemKind, SerializedPane, SerializedPaneGroup,
|
Axis, GroupId, PaneId, SerializedItem, SerializedItemKind, SerializedPane, SerializedPaneGroup,
|
||||||
SerializedWorkspace, WorkspaceId,
|
SerializedWorkspace, WorkspaceId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Db;
|
|
||||||
|
|
||||||
// 1) Move all of this into Workspace crate
|
// 1) Move all of this into Workspace crate
|
||||||
// 2) Deserialize items fully
|
// 2) Deserialize items fully
|
||||||
// 3) Typed prepares (including how you expect to pull data out)
|
// 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 {
|
impl Domain for Workspace {
|
||||||
fn migrate(conn: &sqlez::connection::Connection) -> anyhow::Result<()> {
|
fn migrate(conn: &Connection) -> anyhow::Result<()> {
|
||||||
WORKSPACES_MIGRATION.run(&conn)?;
|
WORKSPACES_MIGRATION.run(&conn)?;
|
||||||
PANE_MIGRATIONS.run(&conn)?;
|
PANE_MIGRATIONS.run(&conn)?;
|
||||||
ITEM_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
|
/// 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
|
/// is empty, the most recent workspace is returned instead. If no workspace for the
|
||||||
/// passed roots is stored, returns none.
|
/// passed roots is stored, returns none.
|
||||||
pub fn workspace_for_roots<P: AsRef<Path>>(
|
pub fn workspace_for_roots<P: AsRef<Path>>(
|
||||||
&self,
|
db: &Db<Workspace>,
|
||||||
worktree_roots: &[P],
|
worktree_roots: &[P],
|
||||||
) -> Option<SerializedWorkspace> {
|
) -> Option<SerializedWorkspace> {
|
||||||
let workspace_id: WorkspaceId = worktree_roots.into();
|
let workspace_id: WorkspaceId = worktree_roots.into();
|
||||||
|
@ -95,12 +94,12 @@ impl Db<Workspace> {
|
||||||
// and we've grabbed the most recent workspace
|
// and we've grabbed the most recent workspace
|
||||||
let (workspace_id, dock_anchor, dock_visible) = iife!({
|
let (workspace_id, dock_anchor, dock_visible) = iife!({
|
||||||
if worktree_roots.len() == 0 {
|
if worktree_roots.len() == 0 {
|
||||||
self.select_row(indoc! {"
|
db.select_row(indoc! {"
|
||||||
SELECT workspace_id, dock_anchor, dock_visible
|
SELECT workspace_id, dock_anchor, dock_visible
|
||||||
FROM workspaces
|
FROM workspaces
|
||||||
ORDER BY timestamp DESC LIMIT 1"})?()?
|
ORDER BY timestamp DESC LIMIT 1"})?()?
|
||||||
} else {
|
} else {
|
||||||
self.select_row_bound(indoc! {"
|
db.select_row_bound(indoc! {"
|
||||||
SELECT workspace_id, dock_anchor, dock_visible
|
SELECT workspace_id, dock_anchor, dock_visible
|
||||||
FROM workspaces
|
FROM workspaces
|
||||||
WHERE workspace_id = ?"})?(&workspace_id)?
|
WHERE workspace_id = ?"})?(&workspace_id)?
|
||||||
|
@ -111,12 +110,10 @@ impl Db<Workspace> {
|
||||||
.flatten()?;
|
.flatten()?;
|
||||||
|
|
||||||
Some(SerializedWorkspace {
|
Some(SerializedWorkspace {
|
||||||
dock_pane: self
|
dock_pane: Workspace::get_dock_pane(&db, &workspace_id)
|
||||||
.get_dock_pane(&workspace_id)
|
|
||||||
.context("Getting dock pane")
|
.context("Getting dock pane")
|
||||||
.log_err()?,
|
.log_err()?,
|
||||||
center_group: self
|
center_group: Workspace::get_center_pane_group(&db, &workspace_id)
|
||||||
.get_center_pane_group(&workspace_id)
|
|
||||||
.context("Getting center group")
|
.context("Getting center group")
|
||||||
.log_err()?,
|
.log_err()?,
|
||||||
dock_anchor,
|
dock_anchor,
|
||||||
|
@ -127,32 +124,32 @@ impl Db<Workspace> {
|
||||||
/// Saves a workspace using the worktree roots. Will garbage collect any workspaces
|
/// Saves a workspace using the worktree roots. Will garbage collect any workspaces
|
||||||
/// that used this workspace previously
|
/// that used this workspace previously
|
||||||
pub fn save_workspace<P: AsRef<Path>>(
|
pub fn save_workspace<P: AsRef<Path>>(
|
||||||
&self,
|
db: &Db<Workspace>,
|
||||||
worktree_roots: &[P],
|
worktree_roots: &[P],
|
||||||
old_roots: Option<&[P]>,
|
old_roots: Option<&[P]>,
|
||||||
workspace: &SerializedWorkspace,
|
workspace: &SerializedWorkspace,
|
||||||
) {
|
) {
|
||||||
let workspace_id: WorkspaceId = worktree_roots.into();
|
let workspace_id: WorkspaceId = worktree_roots.into();
|
||||||
|
|
||||||
self.with_savepoint("update_worktrees", || {
|
db.with_savepoint("update_worktrees", || {
|
||||||
if let Some(old_roots) = old_roots {
|
if let Some(old_roots) = old_roots {
|
||||||
let old_id: WorkspaceId = old_roots.into();
|
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
|
// Delete any previous workspaces with the same roots. This cascades to all
|
||||||
// other tables that are based on the same roots set.
|
// other tables that are based on the same roots set.
|
||||||
// Insert new workspace into workspaces table if none were found
|
// 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 (?, ?, ?)",
|
"INSERT INTO workspaces(workspace_id, dock_anchor, dock_visible) VALUES (?, ?, ?)",
|
||||||
)?((&workspace_id, workspace.dock_anchor, workspace.dock_visible))?;
|
)?((&workspace_id, workspace.dock_anchor, workspace.dock_visible))?;
|
||||||
|
|
||||||
// Save center pane group and dock pane
|
// Save center pane group and dock pane
|
||||||
self.save_pane_group(&workspace_id, &workspace.center_group, None)?;
|
Workspace::save_pane_group(db, &workspace_id, &workspace.center_group, None)?;
|
||||||
self.save_pane(&workspace_id, &workspace.dock_pane, None)?;
|
Workspace::save_pane(db, &workspace_id, &workspace.dock_pane, None)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
@ -169,11 +166,11 @@ impl Db<Workspace> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the previous workspace ids sorted by last modified along with their opened worktree roots
|
/// 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!({
|
iife!({
|
||||||
// TODO, upgrade anyhow: https://docs.rs/anyhow/1.0.66/anyhow/fn.Ok.html
|
// TODO, upgrade anyhow: https://docs.rs/anyhow/1.0.66/anyhow/fn.Ok.html
|
||||||
Ok::<_, anyhow::Error>(
|
Ok::<_, anyhow::Error>(
|
||||||
self.select_bound::<usize, WorkspaceId>(
|
conn.select_bound::<usize, WorkspaceId>(
|
||||||
"SELECT workspace_id FROM workspaces ORDER BY timestamp DESC LIMIT ?",
|
"SELECT workspace_id FROM workspaces ORDER BY timestamp DESC LIMIT ?",
|
||||||
)?(limit)?
|
)?(limit)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -186,21 +183,21 @@ impl Db<Workspace> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_center_pane_group(
|
pub(crate) fn get_center_pane_group(
|
||||||
&self,
|
db: &Db<Workspace>,
|
||||||
workspace_id: &WorkspaceId,
|
workspace_id: &WorkspaceId,
|
||||||
) -> Result<SerializedPaneGroup> {
|
) -> Result<SerializedPaneGroup> {
|
||||||
self.get_pane_group_children(workspace_id, None)?
|
Workspace::get_pane_group_children(&db, workspace_id, None)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.next()
|
.next()
|
||||||
.context("No center pane group")
|
.context("No center pane group")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pane_group_children<'a>(
|
fn get_pane_group_children<'a>(
|
||||||
&self,
|
db: &Db<Workspace>,
|
||||||
workspace_id: &WorkspaceId,
|
workspace_id: &WorkspaceId,
|
||||||
group_id: Option<GroupId>,
|
group_id: Option<GroupId>,
|
||||||
) -> Result<Vec<SerializedPaneGroup>> {
|
) -> 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
|
SELECT group_id, axis, pane_id
|
||||||
FROM (SELECT group_id, axis, NULL as pane_id, position, parent_group_id, workspace_id
|
FROM (SELECT group_id, axis, NULL as pane_id, position, parent_group_id, workspace_id
|
||||||
FROM pane_groups
|
FROM pane_groups
|
||||||
|
@ -217,14 +214,15 @@ impl Db<Workspace> {
|
||||||
if let Some((group_id, axis)) = group_id.zip(axis) {
|
if let Some((group_id, axis)) = group_id.zip(axis) {
|
||||||
Ok(SerializedPaneGroup::Group {
|
Ok(SerializedPaneGroup::Group {
|
||||||
axis,
|
axis,
|
||||||
children: self.get_pane_group_children(
|
children: Workspace::get_pane_group_children(
|
||||||
|
db,
|
||||||
workspace_id,
|
workspace_id,
|
||||||
Some(group_id),
|
Some(group_id),
|
||||||
)?,
|
)?,
|
||||||
})
|
})
|
||||||
} else if let Some(pane_id) = pane_id {
|
} else if let Some(pane_id) = pane_id {
|
||||||
Ok(SerializedPaneGroup::Pane(SerializedPane {
|
Ok(SerializedPaneGroup::Pane(SerializedPane {
|
||||||
children: self.get_items(pane_id)?,
|
children: Workspace::get_items(db, pane_id)?,
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
bail!("Pane Group Child was neither a pane group or a pane");
|
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(
|
pub(crate) fn save_pane_group(
|
||||||
&self,
|
db: &Db<Workspace>,
|
||||||
workspace_id: &WorkspaceId,
|
workspace_id: &WorkspaceId,
|
||||||
pane_group: &SerializedPaneGroup,
|
pane_group: &SerializedPaneGroup,
|
||||||
parent: Option<(GroupId, usize)>,
|
parent: Option<(GroupId, usize)>,
|
||||||
|
@ -247,20 +245,28 @@ impl Db<Workspace> {
|
||||||
|
|
||||||
match pane_group {
|
match pane_group {
|
||||||
SerializedPaneGroup::Group { axis, children } => {
|
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))?;
|
((workspace_id, parent_id, position, *axis))?;
|
||||||
|
|
||||||
for (position, group) in children.iter().enumerate() {
|
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(())
|
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> {
|
pub(crate) fn get_dock_pane(
|
||||||
let pane_id = self.select_row_bound(indoc! {"
|
db: &Db<Workspace>,
|
||||||
|
workspace_id: &WorkspaceId,
|
||||||
|
) -> Result<SerializedPane> {
|
||||||
|
let pane_id = db.select_row_bound(indoc! {"
|
||||||
SELECT pane_id FROM panes
|
SELECT pane_id FROM panes
|
||||||
WHERE workspace_id = ? AND parent_group_id IS NULL AND position IS NULL"})?(
|
WHERE workspace_id = ? AND parent_group_id IS NULL AND position IS NULL"})?(
|
||||||
workspace_id,
|
workspace_id,
|
||||||
|
@ -268,28 +274,27 @@ impl Db<Workspace> {
|
||||||
.context("No dock pane for workspace")?;
|
.context("No dock pane for workspace")?;
|
||||||
|
|
||||||
Ok(SerializedPane::new(
|
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(
|
pub(crate) fn save_pane(
|
||||||
&self,
|
db: &Db<Workspace>,
|
||||||
workspace_id: &WorkspaceId,
|
workspace_id: &WorkspaceId,
|
||||||
pane: &SerializedPane,
|
pane: &SerializedPane,
|
||||||
parent: Option<(GroupId, usize)>,
|
parent: Option<(GroupId, usize)>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let (parent_id, order) = unzip_option(parent);
|
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 (?, ?, ?)",
|
"INSERT INTO panes(workspace_id, parent_group_id, position) VALUES (?, ?, ?)",
|
||||||
)?((workspace_id, parent_id, order))?;
|
)?((workspace_id, parent_id, order))?;
|
||||||
|
|
||||||
self.save_items(workspace_id, pane_id, &pane.children)
|
Workspace::save_items(db, workspace_id, pane_id, &pane.children).context("Saving items")
|
||||||
.context("Saving items")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_items(&self, pane_id: PaneId) -> Result<Vec<SerializedItem>> {
|
pub(crate) fn get_items(db: &Db<Workspace>, pane_id: PaneId) -> Result<Vec<SerializedItem>> {
|
||||||
Ok(self.select_bound(indoc! {"
|
Ok(db.select_bound(indoc! {"
|
||||||
SELECT item_id, kind FROM items
|
SELECT item_id, kind FROM items
|
||||||
WHERE pane_id = ?
|
WHERE pane_id = ?
|
||||||
ORDER BY position"})?(pane_id)?
|
ORDER BY position"})?(pane_id)?
|
||||||
|
@ -302,15 +307,15 @@ impl Db<Workspace> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn save_items(
|
pub(crate) fn save_items(
|
||||||
&self,
|
db: &Db<Workspace>,
|
||||||
workspace_id: &WorkspaceId,
|
workspace_id: &WorkspaceId,
|
||||||
pane_id: PaneId,
|
pane_id: PaneId,
|
||||||
items: &[SerializedItem],
|
items: &[SerializedItem],
|
||||||
) -> Result<()> {
|
) -> 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 = ?")
|
.exec_bound("DELETE FROM items WHERE workspace_id = ? AND pane_id = ? AND item_id = ?")
|
||||||
.context("Preparing deletion")?;
|
.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 (?, ?, ?, ?, ?)",
|
"INSERT INTO items(item_id, workspace_id, pane_id, kind, position) VALUES (?, ?, ?, ?, ?)",
|
||||||
).context("Preparing insertion")?;
|
).context("Preparing insertion")?;
|
||||||
for (position, item) in items.iter().enumerate() {
|
for (position, item) in items.iter().enumerate() {
|
||||||
|
@ -324,17 +329,12 @@ impl Db<Workspace> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::workspace_db::model::DockAnchor::{Bottom, Expanded, Right};
|
||||||
model::{
|
use crate::{Db, Workspace};
|
||||||
DockAnchor::{Bottom, Expanded, Right},
|
|
||||||
SerializedWorkspace,
|
|
||||||
},
|
|
||||||
Db,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_workspace_assignment() {
|
fn test_workspace_assignment() {
|
||||||
env_logger::try_init().ok();
|
// env_logger::try_init().ok();
|
||||||
|
|
||||||
let db = Db::open_in_memory("test_basic_functionality");
|
let db = Db::open_in_memory("test_basic_functionality");
|
||||||
|
|
||||||
|
@ -359,61 +359,73 @@ mod tests {
|
||||||
dock_pane: Default::default(),
|
dock_pane: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
db.save_workspace(&["/tmp", "/tmp2"], None, &workspace_1);
|
Workspace::save_workspace(&db, &["/tmp", "/tmp2"], None, &workspace_1);
|
||||||
db.save_workspace(&["/tmp"], None, &workspace_2);
|
Workspace::save_workspace(&db, &["/tmp"], None, &workspace_2);
|
||||||
|
|
||||||
db.write_to("test.db").unwrap();
|
db.write_to("test.db").unwrap();
|
||||||
|
|
||||||
// Test that paths are treated as a set
|
// Test that paths are treated as a set
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
|
Workspace::workspace_for_roots(&db, &["/tmp", "/tmp2"]).unwrap(),
|
||||||
workspace_1
|
workspace_1
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.workspace_for_roots(&["/tmp2", "/tmp"]).unwrap(),
|
Workspace::workspace_for_roots(&db, &["/tmp2", "/tmp"]).unwrap(),
|
||||||
workspace_1
|
workspace_1
|
||||||
);
|
);
|
||||||
|
|
||||||
// Make sure that other keys work
|
// Make sure that other keys work
|
||||||
assert_eq!(db.workspace_for_roots(&["/tmp"]).unwrap(), workspace_2);
|
assert_eq!(
|
||||||
assert_eq!(db.workspace_for_roots(&["/tmp3", "/tmp2", "/tmp4"]), None);
|
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
|
// 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!(
|
assert_eq!(
|
||||||
db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
|
Workspace::workspace_for_roots(&db, &["/tmp", "/tmp2"]).unwrap(),
|
||||||
workspace_2
|
workspace_2
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test other mechanism for mutating
|
// Test other mechanism for mutating
|
||||||
db.save_workspace(&["/tmp", "/tmp2"], None, &workspace_3);
|
Workspace::save_workspace(&db, &["/tmp", "/tmp2"], None, &workspace_3);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
|
Workspace::workspace_for_roots(&db, &["/tmp", "/tmp2"]).unwrap(),
|
||||||
workspace_3
|
workspace_3
|
||||||
);
|
);
|
||||||
|
|
||||||
// Make sure that updating paths differently also works
|
// Make sure that updating paths differently also works
|
||||||
db.save_workspace(
|
Workspace::save_workspace(
|
||||||
|
&db,
|
||||||
&["/tmp3", "/tmp4", "/tmp2"],
|
&["/tmp3", "/tmp4", "/tmp2"],
|
||||||
Some(&["/tmp", "/tmp2"]),
|
Some(&["/tmp", "/tmp2"]),
|
||||||
&workspace_3,
|
&workspace_3,
|
||||||
);
|
);
|
||||||
assert_eq!(db.workspace_for_roots(&["/tmp2", "tmp"]), None);
|
assert_eq!(Workspace::workspace_for_roots(&db, &["/tmp2", "tmp"]), None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.workspace_for_roots(&["/tmp2", "/tmp3", "/tmp4"])
|
Workspace::workspace_for_roots(&db, &["/tmp2", "/tmp3", "/tmp4"]).unwrap(),
|
||||||
.unwrap(),
|
|
||||||
workspace_3
|
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(
|
fn default_workspace(
|
||||||
dock_pane: SerializedPane,
|
dock_pane: SerializedPane,
|
||||||
center_group: &SerializedPaneGroup,
|
center_group: &SerializedPaneGroup,
|
||||||
) -> SerializedWorkspace {
|
) -> SerializedWorkspace {
|
||||||
SerializedWorkspace {
|
SerializedWorkspace {
|
||||||
dock_anchor: crate::model::DockAnchor::Right,
|
dock_anchor: crate::workspace_db::model::DockAnchor::Right,
|
||||||
dock_visible: false,
|
dock_visible: false,
|
||||||
center_group: center_group.clone(),
|
center_group: center_group.clone(),
|
||||||
dock_pane,
|
dock_pane,
|
||||||
|
@ -422,11 +434,11 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_basic_dock_pane() {
|
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 db = Db::open_in_memory("basic_dock_pane");
|
||||||
|
|
||||||
let dock_pane = crate::model::SerializedPane {
|
let dock_pane = crate::workspace_db::model::SerializedPane {
|
||||||
children: vec![
|
children: vec![
|
||||||
SerializedItem::Terminal { item_id: 1 },
|
SerializedItem::Terminal { item_id: 1 },
|
||||||
SerializedItem::Terminal { item_id: 4 },
|
SerializedItem::Terminal { item_id: 4 },
|
||||||
|
@ -437,16 +449,16 @@ mod tests {
|
||||||
|
|
||||||
let workspace = default_workspace(dock_pane, &Default::default());
|
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);
|
assert_eq!(workspace.dock_pane, new_workspace.dock_pane);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_simple_split() {
|
fn test_simple_split() {
|
||||||
env_logger::try_init().ok();
|
// env_logger::try_init().ok();
|
||||||
|
|
||||||
let db = Db::open_in_memory("simple_split");
|
let db = Db::open_in_memory("simple_split");
|
||||||
|
|
||||||
|
@ -456,10 +468,10 @@ mod tests {
|
||||||
// | 3,4 | |
|
// | 3,4 | |
|
||||||
// -----------------
|
// -----------------
|
||||||
let center_pane = SerializedPaneGroup::Group {
|
let center_pane = SerializedPaneGroup::Group {
|
||||||
axis: crate::model::Axis::Horizontal,
|
axis: crate::workspace_db::model::Axis::Horizontal,
|
||||||
children: vec![
|
children: vec![
|
||||||
SerializedPaneGroup::Group {
|
SerializedPaneGroup::Group {
|
||||||
axis: crate::model::Axis::Vertical,
|
axis: crate::workspace_db::model::Axis::Vertical,
|
||||||
children: vec![
|
children: vec![
|
||||||
SerializedPaneGroup::Pane(SerializedPane {
|
SerializedPaneGroup::Pane(SerializedPane {
|
||||||
children: vec![
|
children: vec![
|
||||||
|
@ -486,7 +498,7 @@ mod tests {
|
||||||
|
|
||||||
let workspace = default_workspace(Default::default(), ¢er_pane);
|
let workspace = default_workspace(Default::default(), ¢er_pane);
|
||||||
|
|
||||||
db.save_workspace(&["/tmp"], None, &workspace);
|
Workspace::save_workspace(&db, &["/tmp"], None, &workspace);
|
||||||
|
|
||||||
assert_eq!(workspace.center_group, center_pane);
|
assert_eq!(workspace.center_group, center_pane);
|
||||||
}
|
}
|
||||||
|
@ -720,7 +732,7 @@ pub mod model {
|
||||||
mod tests {
|
mod tests {
|
||||||
use sqlez::connection::Connection;
|
use sqlez::connection::Connection;
|
||||||
|
|
||||||
use crate::model::DockAnchor;
|
use crate::workspace_db::model::DockAnchor;
|
||||||
|
|
||||||
use super::WorkspaceId;
|
use super::WorkspaceId;
|
||||||
|
|
||||||
|
|
|
@ -170,7 +170,11 @@ fn main() {
|
||||||
client::ZED_SERVER_URL.clone(),
|
client::ZED_SERVER_URL.clone(),
|
||||||
cx,
|
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);
|
journal::init(app_state.clone(), cx);
|
||||||
theme_selector::init(app_state.clone(), cx);
|
theme_selector::init(app_state.clone(), cx);
|
||||||
zed::init(&app_state, cx);
|
zed::init(&app_state, cx);
|
||||||
|
|
|
@ -630,7 +630,7 @@ mod tests {
|
||||||
use gpui::{
|
use gpui::{
|
||||||
executor::Deterministic, AssetSource, MutableAppContext, TestAppContext, ViewHandle,
|
executor::Deterministic, AssetSource, MutableAppContext, TestAppContext, ViewHandle,
|
||||||
};
|
};
|
||||||
use project::{Project, ProjectPath};
|
use project::{Db, Project, ProjectPath};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
|
@ -1817,7 +1817,7 @@ mod tests {
|
||||||
state.initialize_workspace = initialize_workspace;
|
state.initialize_workspace = initialize_workspace;
|
||||||
state.build_window_options = build_window_options;
|
state.build_window_options = build_window_options;
|
||||||
call::init(app_state.client.clone(), app_state.user_store.clone(), cx);
|
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);
|
editor::init(cx);
|
||||||
pane::init(cx);
|
pane::init(cx);
|
||||||
app_state
|
app_state
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue