Added UUID based, stable workspace ID for caching on item startup. Completed first sketch of terminal persistence. Still need to debug it though....
This commit is contained in:
parent
e659823e6c
commit
a47f2ca445
20 changed files with 501 additions and 364 deletions
|
@ -206,7 +206,7 @@ impl Dock {
|
|||
cx.focus(last_active_center_pane);
|
||||
}
|
||||
cx.emit(crate::Event::DockAnchorChanged);
|
||||
workspace.serialize_workspace(None, cx);
|
||||
workspace.serialize_workspace(cx);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
|
|
|
@ -22,11 +22,8 @@ use theme::Theme;
|
|||
use util::ResultExt;
|
||||
|
||||
use crate::{
|
||||
pane,
|
||||
persistence::model::{ItemId, WorkspaceId},
|
||||
searchable::SearchableItemHandle,
|
||||
DelayedDebouncedEditAction, FollowableItemBuilders, ItemNavHistory, Pane, ToolbarItemLocation,
|
||||
Workspace,
|
||||
pane, persistence::model::ItemId, searchable::SearchableItemHandle, DelayedDebouncedEditAction,
|
||||
FollowableItemBuilders, ItemNavHistory, Pane, ToolbarItemLocation, Workspace, WorkspaceId,
|
||||
};
|
||||
|
||||
#[derive(Eq, PartialEq, Hash)]
|
||||
|
@ -52,7 +49,7 @@ pub trait Item: View {
|
|||
fn project_entry_ids(&self, cx: &AppContext) -> SmallVec<[ProjectEntryId; 3]>;
|
||||
fn is_singleton(&self, cx: &AppContext) -> bool;
|
||||
fn set_nav_history(&mut self, _: ItemNavHistory, _: &mut ViewContext<Self>);
|
||||
fn clone_on_split(&self, _: &mut ViewContext<Self>) -> Option<Self>
|
||||
fn clone_on_split(&self, _workspace_id: WorkspaceId, _: &mut ViewContext<Self>) -> Option<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
|
@ -121,7 +118,9 @@ pub trait Item: View {
|
|||
fn breadcrumbs(&self, _theme: &Theme, _cx: &AppContext) -> Option<Vec<ElementBox>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn serialized_item_kind() -> Option<&'static str>;
|
||||
|
||||
fn deserialize(
|
||||
project: ModelHandle<Project>,
|
||||
workspace: WeakViewHandle<Workspace>,
|
||||
|
@ -144,7 +143,11 @@ pub trait ItemHandle: 'static + fmt::Debug {
|
|||
fn project_entry_ids(&self, cx: &AppContext) -> SmallVec<[ProjectEntryId; 3]>;
|
||||
fn is_singleton(&self, cx: &AppContext) -> bool;
|
||||
fn boxed_clone(&self) -> Box<dyn ItemHandle>;
|
||||
fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option<Box<dyn ItemHandle>>;
|
||||
fn clone_on_split(
|
||||
&self,
|
||||
workspace_id: WorkspaceId,
|
||||
cx: &mut MutableAppContext,
|
||||
) -> Option<Box<dyn ItemHandle>>;
|
||||
fn added_to_pane(
|
||||
&self,
|
||||
workspace: &mut Workspace,
|
||||
|
@ -246,9 +249,13 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
|
|||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option<Box<dyn ItemHandle>> {
|
||||
fn clone_on_split(
|
||||
&self,
|
||||
workspace_id: WorkspaceId,
|
||||
cx: &mut MutableAppContext,
|
||||
) -> Option<Box<dyn ItemHandle>> {
|
||||
self.update(cx, |item, cx| {
|
||||
cx.add_option_view(|cx| item.clone_on_split(cx))
|
||||
cx.add_option_view(|cx| item.clone_on_split(workspace_id, cx))
|
||||
})
|
||||
.map(|handle| Box::new(handle) as Box<dyn ItemHandle>)
|
||||
}
|
||||
|
@ -812,7 +819,11 @@ pub(crate) mod test {
|
|||
self.push_to_nav_history(cx);
|
||||
}
|
||||
|
||||
fn clone_on_split(&self, _: &mut ViewContext<Self>) -> Option<Self>
|
||||
fn clone_on_split(
|
||||
&self,
|
||||
_workspace_id: WorkspaceId,
|
||||
_: &mut ViewContext<Self>,
|
||||
) -> Option<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
|
|
|
@ -2,39 +2,38 @@
|
|||
|
||||
pub mod model;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{anyhow, bail, Result, Context};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use db::connection;
|
||||
use gpui::Axis;
|
||||
use indoc::indoc;
|
||||
|
||||
|
||||
use db::sqlez::domain::Domain;
|
||||
use util::{iife, unzip_option, ResultExt};
|
||||
|
||||
use crate::dock::DockPosition;
|
||||
use crate::WorkspaceId;
|
||||
|
||||
use super::Workspace;
|
||||
|
||||
use model::{
|
||||
GroupId, PaneId, SerializedItem, SerializedPane, SerializedPaneGroup,
|
||||
SerializedWorkspace, WorkspaceId,
|
||||
GroupId, PaneId, SerializedItem, SerializedPane, SerializedPaneGroup, SerializedWorkspace,
|
||||
WorkspaceLocation,
|
||||
};
|
||||
|
||||
connection!(DB: WorkspaceDb<Workspace>);
|
||||
|
||||
|
||||
impl Domain for Workspace {
|
||||
fn name() -> &'static str {
|
||||
"workspace"
|
||||
}
|
||||
|
||||
|
||||
fn migrations() -> &'static [&'static str] {
|
||||
&[indoc! {"
|
||||
CREATE TABLE workspaces(
|
||||
workspace_id BLOB PRIMARY KEY,
|
||||
workspace_location BLOB NOT NULL UNIQUE,
|
||||
dock_visible INTEGER, -- Boolean
|
||||
dock_anchor TEXT, -- Enum: 'Bottom' / 'Right' / 'Expanded'
|
||||
dock_pane INTEGER, -- NULL indicates that we don't have a dock pane yet
|
||||
|
@ -97,21 +96,25 @@ impl WorkspaceDb {
|
|||
&self,
|
||||
worktree_roots: &[P],
|
||||
) -> Option<SerializedWorkspace> {
|
||||
let workspace_id: WorkspaceId = worktree_roots.into();
|
||||
let workspace_location: WorkspaceLocation = worktree_roots.into();
|
||||
|
||||
// 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, dock_position): (WorkspaceId, DockPosition) = iife!({
|
||||
let (workspace_id, workspace_location, dock_position): (
|
||||
WorkspaceId,
|
||||
WorkspaceLocation,
|
||||
DockPosition,
|
||||
) = iife!({
|
||||
if worktree_roots.len() == 0 {
|
||||
self.select_row(indoc! {"
|
||||
SELECT workspace_id, dock_visible, dock_anchor
|
||||
SELECT workspace_id, workspace_location, dock_visible, dock_anchor
|
||||
FROM workspaces
|
||||
ORDER BY timestamp DESC LIMIT 1"})?()?
|
||||
} else {
|
||||
self.select_row_bound(indoc! {"
|
||||
SELECT workspace_id, dock_visible, dock_anchor
|
||||
SELECT workspace_id, workspace_location, dock_visible, dock_anchor
|
||||
FROM workspaces
|
||||
WHERE workspace_id = ?"})?(&workspace_id)?
|
||||
WHERE workspace_location = ?"})?(&workspace_location)?
|
||||
}
|
||||
.context("No workspaces found")
|
||||
})
|
||||
|
@ -119,13 +122,14 @@ impl WorkspaceDb {
|
|||
.flatten()?;
|
||||
|
||||
Some(SerializedWorkspace {
|
||||
workspace_id: workspace_id.clone(),
|
||||
id: workspace_id,
|
||||
location: workspace_location.clone(),
|
||||
dock_pane: self
|
||||
.get_dock_pane(&workspace_id)
|
||||
.get_dock_pane(workspace_id)
|
||||
.context("Getting dock pane")
|
||||
.log_err()?,
|
||||
center_group: self
|
||||
.get_center_pane_group(&workspace_id)
|
||||
.get_center_pane_group(workspace_id)
|
||||
.context("Getting center group")
|
||||
.log_err()?,
|
||||
dock_position,
|
||||
|
@ -134,72 +138,61 @@ impl WorkspaceDb {
|
|||
|
||||
/// Saves a workspace using the worktree roots. Will garbage collect any workspaces
|
||||
/// that used this workspace previously
|
||||
pub fn save_workspace(
|
||||
&self,
|
||||
old_id: Option<WorkspaceId>,
|
||||
workspace: &SerializedWorkspace,
|
||||
) {
|
||||
pub fn save_workspace(&self, workspace: &SerializedWorkspace) {
|
||||
self.with_savepoint("update_worktrees", || {
|
||||
// Clear out panes and pane_groups
|
||||
self.exec_bound(indoc! {"
|
||||
UPDATE workspaces SET dock_pane = NULL WHERE workspace_id = ?1;
|
||||
DELETE FROM pane_groups WHERE workspace_id = ?1;
|
||||
DELETE FROM panes WHERE workspace_id = ?1;"})?
|
||||
(old_id.as_ref().unwrap_or(&workspace.workspace_id)).context("Clearing old panes")?;
|
||||
|
||||
if let Some(old_id) = old_id {
|
||||
self.exec_bound(indoc! {"
|
||||
UPDATE OR REPLACE workspaces
|
||||
SET workspace_id = ?,
|
||||
dock_visible = ?,
|
||||
dock_anchor = ?,
|
||||
timestamp = CURRENT_TIMESTAMP
|
||||
WHERE workspace_id = ?"})?((
|
||||
&workspace.workspace_id,
|
||||
workspace.dock_position,
|
||||
&old_id,
|
||||
)).context("Updating workspace with new worktree roots")?;
|
||||
} else {
|
||||
self.exec_bound(
|
||||
"INSERT OR REPLACE INTO workspaces(workspace_id, dock_visible, dock_anchor) VALUES (?, ?, ?)",
|
||||
)?((&workspace.workspace_id, workspace.dock_position)).context("Uodating workspace")?;
|
||||
}
|
||||
|
||||
DELETE FROM panes WHERE workspace_id = ?1;"})?(workspace.id)
|
||||
.context("Clearing old panes")?;
|
||||
|
||||
// Update or insert
|
||||
self.exec_bound(indoc! {
|
||||
"INSERT OR REPLACE INTO
|
||||
workspaces(workspace_id, workspace_location, dock_visible, dock_anchor, timestamp)
|
||||
VALUES
|
||||
(?1, ?2, ?3, ?4, CURRENT_TIMESTAMP)"
|
||||
})?((workspace.id, &workspace.location, workspace.dock_position))
|
||||
.context("Updating workspace")?;
|
||||
|
||||
// Save center pane group and dock pane
|
||||
self.save_pane_group(&workspace.workspace_id, &workspace.center_group, None).context("save pane group in save workspace")?;
|
||||
|
||||
let dock_id = self.save_pane(&workspace.workspace_id, &workspace.dock_pane, None, true).context("save pane in save workspace")?;
|
||||
|
||||
self.save_pane_group(workspace.id, &workspace.center_group, None)
|
||||
.context("save pane group in save workspace")?;
|
||||
|
||||
let dock_id = self
|
||||
.save_pane(workspace.id, &workspace.dock_pane, None, true)
|
||||
.context("save pane in save workspace")?;
|
||||
|
||||
// Complete workspace initialization
|
||||
self.exec_bound(indoc! {"
|
||||
UPDATE workspaces
|
||||
SET dock_pane = ?
|
||||
WHERE workspace_id = ?"})?((
|
||||
dock_id,
|
||||
&workspace.workspace_id,
|
||||
)).context("Finishing initialization with dock pane")?;
|
||||
WHERE workspace_id = ?"})?((dock_id, workspace.id))
|
||||
.context("Finishing initialization with dock pane")?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Update workspace with roots {:?} failed.",
|
||||
workspace.workspace_id.paths()
|
||||
"Update workspace with roots {:?} and id {:?} failed.",
|
||||
workspace.location.paths(),
|
||||
workspace.id
|
||||
)
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
|
||||
/// Returns the previous workspace ids sorted by last modified along with their opened worktree roots
|
||||
pub fn recent_workspaces(&self, limit: usize) -> Vec<Arc<Vec<PathBuf>>> {
|
||||
pub fn recent_workspaces(&self, limit: usize) -> Vec<(WorkspaceId, WorkspaceLocation)> {
|
||||
iife!({
|
||||
// TODO, upgrade anyhow: https://docs.rs/anyhow/1.0.66/anyhow/fn.Ok.html
|
||||
Ok::<_, anyhow::Error>(
|
||||
self.select_bound::<usize, WorkspaceId>(
|
||||
"SELECT workspace_id FROM workspaces ORDER BY timestamp DESC LIMIT ?",
|
||||
self.select_bound::<usize, (WorkspaceId, WorkspaceLocation)>(
|
||||
"SELECT workspace_id, workspace_location FROM workspaces ORDER BY timestamp DESC LIMIT ?",
|
||||
)?(limit)?
|
||||
.into_iter()
|
||||
.map(|id| id.paths())
|
||||
.collect::<Vec<Arc<Vec<PathBuf>>>>(),
|
||||
.collect::<Vec<(WorkspaceId, WorkspaceLocation)>>(),
|
||||
)
|
||||
})
|
||||
.log_err()
|
||||
|
@ -208,7 +201,7 @@ impl WorkspaceDb {
|
|||
|
||||
pub(crate) fn get_center_pane_group(
|
||||
&self,
|
||||
workspace_id: &WorkspaceId,
|
||||
workspace_id: WorkspaceId,
|
||||
) -> Result<SerializedPaneGroup> {
|
||||
self.get_pane_group(workspace_id, None)?
|
||||
.into_iter()
|
||||
|
@ -218,10 +211,10 @@ impl WorkspaceDb {
|
|||
|
||||
fn get_pane_group(
|
||||
&self,
|
||||
workspace_id: &WorkspaceId,
|
||||
workspace_id: WorkspaceId,
|
||||
group_id: Option<GroupId>,
|
||||
) -> Result<Vec<SerializedPaneGroup>> {
|
||||
type GroupKey<'a> = (Option<GroupId>, &'a WorkspaceId);
|
||||
type GroupKey = (Option<GroupId>, WorkspaceId);
|
||||
type GroupOrPane = (Option<GroupId>, Option<Axis>, Option<PaneId>, Option<bool>);
|
||||
self.select_bound::<GroupKey, GroupOrPane>(indoc! {"
|
||||
SELECT group_id, axis, pane_id, active
|
||||
|
@ -253,31 +246,29 @@ impl WorkspaceDb {
|
|||
if let Some((group_id, axis)) = group_id.zip(axis) {
|
||||
Ok(SerializedPaneGroup::Group {
|
||||
axis,
|
||||
children: self.get_pane_group(
|
||||
workspace_id,
|
||||
Some(group_id),
|
||||
)?,
|
||||
children: self.get_pane_group(workspace_id, Some(group_id))?,
|
||||
})
|
||||
} else if let Some((pane_id, active)) = pane_id.zip(active) {
|
||||
Ok(SerializedPaneGroup::Pane(SerializedPane::new(self.get_items( pane_id)?, active)))
|
||||
Ok(SerializedPaneGroup::Pane(SerializedPane::new(
|
||||
self.get_items(pane_id)?,
|
||||
active,
|
||||
)))
|
||||
} else {
|
||||
bail!("Pane Group Child was neither a pane group or a pane");
|
||||
}
|
||||
})
|
||||
// Filter out panes and pane groups which don't have any children or items
|
||||
.filter(|pane_group| {
|
||||
match pane_group {
|
||||
Ok(SerializedPaneGroup::Group { children, .. }) => !children.is_empty(),
|
||||
Ok(SerializedPaneGroup::Pane(pane)) => !pane.children.is_empty(),
|
||||
_ => true,
|
||||
}
|
||||
.filter(|pane_group| match pane_group {
|
||||
Ok(SerializedPaneGroup::Group { children, .. }) => !children.is_empty(),
|
||||
Ok(SerializedPaneGroup::Pane(pane)) => !pane.children.is_empty(),
|
||||
_ => true,
|
||||
})
|
||||
.collect::<Result<_>>()
|
||||
}
|
||||
|
||||
pub(crate) fn save_pane_group(
|
||||
&self,
|
||||
workspace_id: &WorkspaceId,
|
||||
workspace_id: WorkspaceId,
|
||||
pane_group: &SerializedPaneGroup,
|
||||
parent: Option<(GroupId, usize)>,
|
||||
) -> Result<()> {
|
||||
|
@ -285,26 +276,31 @@ impl WorkspaceDb {
|
|||
SerializedPaneGroup::Group { axis, children } => {
|
||||
let (parent_id, position) = unzip_option(parent);
|
||||
|
||||
let group_id = self.select_row_bound::<_, i64>(indoc!{"
|
||||
let group_id = self.select_row_bound::<_, i64>(indoc! {"
|
||||
INSERT INTO pane_groups(workspace_id, parent_group_id, position, axis)
|
||||
VALUES (?, ?, ?, ?)
|
||||
RETURNING group_id"})?
|
||||
((workspace_id, parent_id, position, *axis))?
|
||||
.ok_or_else(|| anyhow!("Couldn't retrieve group_id from inserted pane_group"))?;
|
||||
|
||||
RETURNING group_id"})?((
|
||||
workspace_id,
|
||||
parent_id,
|
||||
position,
|
||||
*axis,
|
||||
))?
|
||||
.ok_or_else(|| anyhow!("Couldn't retrieve group_id from inserted pane_group"))?;
|
||||
|
||||
for (position, group) in children.iter().enumerate() {
|
||||
self.save_pane_group(workspace_id, group, Some((group_id, position)))?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
SerializedPaneGroup::Pane(pane) => {
|
||||
self.save_pane(workspace_id, &pane, parent, false)?;
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_dock_pane(&self, workspace_id: &WorkspaceId) -> Result<SerializedPane> {
|
||||
pub(crate) fn get_dock_pane(&self, workspace_id: WorkspaceId) -> Result<SerializedPane> {
|
||||
let (pane_id, active) = self.select_row_bound(indoc! {"
|
||||
SELECT pane_id, active
|
||||
FROM panes
|
||||
|
@ -315,40 +311,35 @@ impl WorkspaceDb {
|
|||
|
||||
Ok(SerializedPane::new(
|
||||
self.get_items(pane_id).context("Reading items")?,
|
||||
active
|
||||
active,
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn save_pane(
|
||||
&self,
|
||||
workspace_id: &WorkspaceId,
|
||||
workspace_id: WorkspaceId,
|
||||
pane: &SerializedPane,
|
||||
parent: Option<(GroupId, usize)>, // None indicates BOTH dock pane AND center_pane
|
||||
dock: bool,
|
||||
) -> Result<PaneId> {
|
||||
let pane_id = self.select_row_bound::<_, i64>(indoc!{"
|
||||
let pane_id = self.select_row_bound::<_, i64>(indoc! {"
|
||||
INSERT INTO panes(workspace_id, active)
|
||||
VALUES (?, ?)
|
||||
RETURNING pane_id"},
|
||||
)?((workspace_id, pane.active))?
|
||||
RETURNING pane_id"})?((workspace_id, pane.active))?
|
||||
.ok_or_else(|| anyhow!("Could not retrieve inserted pane_id"))?;
|
||||
|
||||
|
||||
if !dock {
|
||||
let (parent_id, order) = unzip_option(parent);
|
||||
self.exec_bound(indoc! {"
|
||||
INSERT INTO center_panes(pane_id, parent_group_id, position)
|
||||
VALUES (?, ?, ?)"})?((
|
||||
pane_id, parent_id, order
|
||||
))?;
|
||||
VALUES (?, ?, ?)"})?((pane_id, parent_id, order))?;
|
||||
}
|
||||
|
||||
self.save_items(workspace_id, pane_id, &pane.children)
|
||||
.context("Saving items")?;
|
||||
|
||||
|
||||
Ok(pane_id)
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub(crate) fn get_items(&self, pane_id: PaneId) -> Result<Vec<SerializedItem>> {
|
||||
Ok(self.select_bound(indoc! {"
|
||||
|
@ -359,7 +350,7 @@ impl WorkspaceDb {
|
|||
|
||||
pub(crate) fn save_items(
|
||||
&self,
|
||||
workspace_id: &WorkspaceId,
|
||||
workspace_id: WorkspaceId,
|
||||
pane_id: PaneId,
|
||||
items: &[SerializedItem],
|
||||
) -> Result<()> {
|
||||
|
@ -376,7 +367,8 @@ impl WorkspaceDb {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use db::{open_memory_db};
|
||||
|
||||
use db::{open_memory_db, Uuid};
|
||||
use settings::DockAnchor;
|
||||
|
||||
use super::*;
|
||||
|
@ -388,15 +380,13 @@ mod tests {
|
|||
let db = WorkspaceDb(open_memory_db(Some("test_full_workspace_serialization")));
|
||||
|
||||
let dock_pane = crate::persistence::model::SerializedPane {
|
||||
|
||||
children: vec![
|
||||
SerializedItem::new("Terminal", 1),
|
||||
SerializedItem::new("Terminal", 2),
|
||||
SerializedItem::new("Terminal", 3),
|
||||
SerializedItem::new("Terminal", 4),
|
||||
|
||||
],
|
||||
active: false
|
||||
active: false,
|
||||
};
|
||||
|
||||
// -----------------
|
||||
|
@ -415,8 +405,8 @@ mod tests {
|
|||
SerializedItem::new("Terminal", 5),
|
||||
SerializedItem::new("Terminal", 6),
|
||||
],
|
||||
false)
|
||||
),
|
||||
false,
|
||||
)),
|
||||
SerializedPaneGroup::Pane(SerializedPane::new(
|
||||
vec![
|
||||
SerializedItem::new("Terminal", 7),
|
||||
|
@ -430,7 +420,6 @@ mod tests {
|
|||
vec![
|
||||
SerializedItem::new("Terminal", 9),
|
||||
SerializedItem::new("Terminal", 10),
|
||||
|
||||
],
|
||||
false,
|
||||
)),
|
||||
|
@ -438,25 +427,24 @@ mod tests {
|
|||
};
|
||||
|
||||
let workspace = SerializedWorkspace {
|
||||
workspace_id: (["/tmp", "/tmp2"]).into(),
|
||||
dock_position: DockPosition::Shown(DockAnchor::Bottom),
|
||||
id: Uuid::new(),
|
||||
location: (["/tmp", "/tmp2"]).into(),
|
||||
dock_position: DockPosition::Shown(DockAnchor::Bottom),
|
||||
center_group,
|
||||
dock_pane,
|
||||
};
|
||||
|
||||
db.save_workspace(None, &workspace);
|
||||
|
||||
db.save_workspace(&workspace);
|
||||
let round_trip_workspace = db.workspace_for_roots(&["/tmp2", "/tmp"]);
|
||||
|
||||
|
||||
assert_eq!(workspace, round_trip_workspace.unwrap());
|
||||
|
||||
// Test guaranteed duplicate IDs
|
||||
db.save_workspace(None, &workspace);
|
||||
db.save_workspace(None, &workspace);
|
||||
|
||||
db.save_workspace(&workspace);
|
||||
db.save_workspace(&workspace);
|
||||
|
||||
let round_trip_workspace = db.workspace_for_roots(&["/tmp", "/tmp2"]);
|
||||
assert_eq!(workspace, round_trip_workspace.unwrap());
|
||||
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -466,21 +454,23 @@ mod tests {
|
|||
let db = WorkspaceDb(open_memory_db(Some("test_basic_functionality")));
|
||||
|
||||
let workspace_1 = SerializedWorkspace {
|
||||
workspace_id: (["/tmp", "/tmp2"]).into(),
|
||||
id: WorkspaceId::new(),
|
||||
location: (["/tmp", "/tmp2"]).into(),
|
||||
dock_position: crate::dock::DockPosition::Shown(DockAnchor::Bottom),
|
||||
center_group: Default::default(),
|
||||
dock_pane: Default::default(),
|
||||
};
|
||||
|
||||
let mut workspace_2 = SerializedWorkspace {
|
||||
workspace_id: (["/tmp"]).into(),
|
||||
id: WorkspaceId::new(),
|
||||
location: (["/tmp"]).into(),
|
||||
dock_position: crate::dock::DockPosition::Hidden(DockAnchor::Expanded),
|
||||
center_group: Default::default(),
|
||||
dock_pane: Default::default(),
|
||||
};
|
||||
|
||||
db.save_workspace(None, &workspace_1);
|
||||
db.save_workspace(None, &workspace_2);
|
||||
db.save_workspace(&workspace_1);
|
||||
db.save_workspace(&workspace_2);
|
||||
|
||||
// Test that paths are treated as a set
|
||||
assert_eq!(
|
||||
|
@ -497,8 +487,9 @@ mod tests {
|
|||
assert_eq!(db.workspace_for_roots(&["/tmp3", "/tmp2", "/tmp4"]), None);
|
||||
|
||||
// Test 'mutate' case of updating a pre-existing id
|
||||
workspace_2.workspace_id = (["/tmp", "/tmp2"]).into();
|
||||
db.save_workspace(Some((&["/tmp"]).into()), &workspace_2);
|
||||
workspace_2.location = (["/tmp", "/tmp2"]).into();
|
||||
|
||||
db.save_workspace(&workspace_2);
|
||||
assert_eq!(
|
||||
db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
|
||||
workspace_2
|
||||
|
@ -506,33 +497,28 @@ mod tests {
|
|||
|
||||
// Test other mechanism for mutating
|
||||
let mut workspace_3 = SerializedWorkspace {
|
||||
workspace_id: (&["/tmp", "/tmp2"]).into(),
|
||||
id: WorkspaceId::new(),
|
||||
location: (&["/tmp", "/tmp2"]).into(),
|
||||
dock_position: DockPosition::Shown(DockAnchor::Right),
|
||||
center_group: Default::default(),
|
||||
dock_pane: Default::default(),
|
||||
};
|
||||
|
||||
|
||||
db.save_workspace(None, &workspace_3);
|
||||
db.save_workspace(&workspace_3);
|
||||
assert_eq!(
|
||||
db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
|
||||
workspace_3
|
||||
);
|
||||
|
||||
// Make sure that updating paths differently also works
|
||||
workspace_3.workspace_id = (["/tmp3", "/tmp4", "/tmp2"]).into();
|
||||
db.save_workspace(
|
||||
Some((&["/tmp", "/tmp2"]).into()),
|
||||
&workspace_3,
|
||||
);
|
||||
workspace_3.location = (["/tmp3", "/tmp4", "/tmp2"]).into();
|
||||
db.save_workspace(&workspace_3);
|
||||
assert_eq!(db.workspace_for_roots(&["/tmp2", "tmp"]), None);
|
||||
assert_eq!(
|
||||
db.workspace_for_roots(&["/tmp2", "/tmp3", "/tmp4"])
|
||||
.unwrap(),
|
||||
workspace_3
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
use crate::dock::DockPosition;
|
||||
|
@ -545,7 +531,8 @@ mod tests {
|
|||
center_group: &SerializedPaneGroup,
|
||||
) -> SerializedWorkspace {
|
||||
SerializedWorkspace {
|
||||
workspace_id: workspace_id.into(),
|
||||
id: WorkspaceId::new(),
|
||||
location: workspace_id.into(),
|
||||
dock_position: crate::dock::DockPosition::Hidden(DockAnchor::Right),
|
||||
center_group: center_group.clone(),
|
||||
dock_pane,
|
||||
|
@ -564,12 +551,13 @@ mod tests {
|
|||
SerializedItem::new("Terminal", 4),
|
||||
SerializedItem::new("Terminal", 2),
|
||||
SerializedItem::new("Terminal", 3),
|
||||
], false
|
||||
],
|
||||
false,
|
||||
);
|
||||
|
||||
let workspace = default_workspace(&["/tmp"], dock_pane, &Default::default());
|
||||
|
||||
db.save_workspace(None, &workspace);
|
||||
db.save_workspace(&workspace);
|
||||
|
||||
let new_workspace = db.workspace_for_roots(&["/tmp"]).unwrap();
|
||||
|
||||
|
@ -593,16 +581,20 @@ mod tests {
|
|||
SerializedPaneGroup::Group {
|
||||
axis: gpui::Axis::Vertical,
|
||||
children: vec![
|
||||
SerializedPaneGroup::Pane(SerializedPane::new(
|
||||
vec![
|
||||
SerializedItem::new("Terminal", 1),
|
||||
SerializedItem::new("Terminal", 2),
|
||||
],
|
||||
false)),
|
||||
SerializedPaneGroup::Pane(SerializedPane::new(vec![
|
||||
SerializedItem::new("Terminal", 4),
|
||||
SerializedItem::new("Terminal", 3),
|
||||
], true)),
|
||||
SerializedPaneGroup::Pane(SerializedPane::new(
|
||||
vec![
|
||||
SerializedItem::new("Terminal", 1),
|
||||
SerializedItem::new("Terminal", 2),
|
||||
],
|
||||
false,
|
||||
)),
|
||||
SerializedPaneGroup::Pane(SerializedPane::new(
|
||||
vec![
|
||||
SerializedItem::new("Terminal", 4),
|
||||
SerializedItem::new("Terminal", 3),
|
||||
],
|
||||
true,
|
||||
)),
|
||||
],
|
||||
},
|
||||
SerializedPaneGroup::Pane(SerializedPane::new(
|
||||
|
@ -610,41 +602,46 @@ mod tests {
|
|||
SerializedItem::new("Terminal", 5),
|
||||
SerializedItem::new("Terminal", 6),
|
||||
],
|
||||
false)),
|
||||
false,
|
||||
)),
|
||||
],
|
||||
};
|
||||
|
||||
let workspace = default_workspace(&["/tmp"], Default::default(), ¢er_pane);
|
||||
|
||||
db.save_workspace(None, &workspace);
|
||||
|
||||
db.save_workspace(&workspace);
|
||||
|
||||
let new_workspace = db.workspace_for_roots(&["/tmp"]).unwrap();
|
||||
|
||||
assert_eq!(workspace.center_group, new_workspace.center_group);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_cleanup_panes() {
|
||||
env_logger::try_init().ok();
|
||||
|
||||
|
||||
let db = WorkspaceDb(open_memory_db(Some("test_cleanup_panes")));
|
||||
|
||||
|
||||
let center_pane = SerializedPaneGroup::Group {
|
||||
axis: gpui::Axis::Horizontal,
|
||||
children: vec![
|
||||
SerializedPaneGroup::Group {
|
||||
axis: gpui::Axis::Vertical,
|
||||
children: vec![
|
||||
SerializedPaneGroup::Pane(SerializedPane::new(
|
||||
vec![
|
||||
SerializedItem::new("Terminal", 1),
|
||||
SerializedItem::new("Terminal", 2),
|
||||
],
|
||||
false)),
|
||||
SerializedPaneGroup::Pane(SerializedPane::new(vec![
|
||||
SerializedItem::new("Terminal", 4),
|
||||
SerializedItem::new("Terminal", 3),
|
||||
], true)),
|
||||
SerializedPaneGroup::Pane(SerializedPane::new(
|
||||
vec![
|
||||
SerializedItem::new("Terminal", 1),
|
||||
SerializedItem::new("Terminal", 2),
|
||||
],
|
||||
false,
|
||||
)),
|
||||
SerializedPaneGroup::Pane(SerializedPane::new(
|
||||
vec![
|
||||
SerializedItem::new("Terminal", 4),
|
||||
SerializedItem::new("Terminal", 3),
|
||||
],
|
||||
true,
|
||||
)),
|
||||
],
|
||||
},
|
||||
SerializedPaneGroup::Pane(SerializedPane::new(
|
||||
|
@ -652,37 +649,41 @@ mod tests {
|
|||
SerializedItem::new("Terminal", 5),
|
||||
SerializedItem::new("Terminal", 6),
|
||||
],
|
||||
false)),
|
||||
false,
|
||||
)),
|
||||
],
|
||||
};
|
||||
|
||||
let id = &["/tmp"];
|
||||
|
||||
|
||||
let mut workspace = default_workspace(id, Default::default(), ¢er_pane);
|
||||
|
||||
db.save_workspace(None, &workspace);
|
||||
|
||||
db.save_workspace(&workspace);
|
||||
|
||||
workspace.center_group = SerializedPaneGroup::Group {
|
||||
axis: gpui::Axis::Vertical,
|
||||
children: vec![
|
||||
SerializedPaneGroup::Pane(SerializedPane::new(
|
||||
vec![
|
||||
SerializedItem::new("Terminal", 1),
|
||||
SerializedItem::new("Terminal", 2),
|
||||
],
|
||||
false)),
|
||||
SerializedPaneGroup::Pane(SerializedPane::new(vec![
|
||||
SerializedItem::new("Terminal", 4),
|
||||
SerializedItem::new("Terminal", 3),
|
||||
], true)),
|
||||
SerializedPaneGroup::Pane(SerializedPane::new(
|
||||
vec![
|
||||
SerializedItem::new("Terminal", 1),
|
||||
SerializedItem::new("Terminal", 2),
|
||||
],
|
||||
false,
|
||||
)),
|
||||
SerializedPaneGroup::Pane(SerializedPane::new(
|
||||
vec![
|
||||
SerializedItem::new("Terminal", 4),
|
||||
SerializedItem::new("Terminal", 3),
|
||||
],
|
||||
true,
|
||||
)),
|
||||
],
|
||||
};
|
||||
|
||||
db.save_workspace(None, &workspace);
|
||||
|
||||
|
||||
db.save_workspace(&workspace);
|
||||
|
||||
let new_workspace = db.workspace_for_roots(id).unwrap();
|
||||
|
||||
assert_eq!(workspace.center_group, new_workspace.center_group);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,18 +16,20 @@ use project::Project;
|
|||
use settings::DockAnchor;
|
||||
use util::ResultExt;
|
||||
|
||||
use crate::{dock::DockPosition, ItemDeserializers, Member, Pane, PaneAxis, Workspace};
|
||||
use crate::{
|
||||
dock::DockPosition, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct WorkspaceId(Arc<Vec<PathBuf>>);
|
||||
pub struct WorkspaceLocation(Arc<Vec<PathBuf>>);
|
||||
|
||||
impl WorkspaceId {
|
||||
impl WorkspaceLocation {
|
||||
pub fn paths(&self) -> Arc<Vec<PathBuf>> {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: AsRef<Path>, T: IntoIterator<Item = P>> From<T> for WorkspaceId {
|
||||
impl<P: AsRef<Path>, T: IntoIterator<Item = P>> From<T> for WorkspaceLocation {
|
||||
fn from(iterator: T) -> Self {
|
||||
let mut roots = iterator
|
||||
.into_iter()
|
||||
|
@ -38,7 +40,7 @@ impl<P: AsRef<Path>, T: IntoIterator<Item = P>> From<T> for WorkspaceId {
|
|||
}
|
||||
}
|
||||
|
||||
impl Bind for &WorkspaceId {
|
||||
impl Bind for &WorkspaceLocation {
|
||||
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
|
||||
bincode::serialize(&self.0)
|
||||
.expect("Bincode serialization of paths should not fail")
|
||||
|
@ -46,16 +48,20 @@ impl Bind for &WorkspaceId {
|
|||
}
|
||||
}
|
||||
|
||||
impl Column for WorkspaceId {
|
||||
impl Column for WorkspaceLocation {
|
||||
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
|
||||
let blob = statement.column_blob(start_index)?;
|
||||
Ok((WorkspaceId(bincode::deserialize(blob)?), start_index + 1))
|
||||
Ok((
|
||||
WorkspaceLocation(bincode::deserialize(blob)?),
|
||||
start_index + 1,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct SerializedWorkspace {
|
||||
pub workspace_id: WorkspaceId,
|
||||
pub id: WorkspaceId,
|
||||
pub location: WorkspaceLocation,
|
||||
pub dock_position: DockPosition,
|
||||
pub center_group: SerializedPaneGroup,
|
||||
pub dock_pane: SerializedPane,
|
||||
|
@ -70,10 +76,11 @@ pub enum SerializedPaneGroup {
|
|||
Pane(SerializedPane),
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Default for SerializedPaneGroup {
|
||||
fn default() -> Self {
|
||||
Self::Pane(SerializedPane {
|
||||
children: Vec::new(),
|
||||
children: vec![SerializedItem::default()],
|
||||
active: false,
|
||||
})
|
||||
}
|
||||
|
@ -84,7 +91,7 @@ impl SerializedPaneGroup {
|
|||
pub(crate) async fn deserialize(
|
||||
&self,
|
||||
project: &ModelHandle<Project>,
|
||||
workspace_id: &WorkspaceId,
|
||||
workspace_id: WorkspaceId,
|
||||
workspace: &ViewHandle<Workspace>,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> (Member, Option<ViewHandle<Pane>>) {
|
||||
|
@ -136,13 +143,12 @@ impl SerializedPane {
|
|||
&self,
|
||||
project: &ModelHandle<Project>,
|
||||
pane_handle: &ViewHandle<Pane>,
|
||||
workspace_id: &WorkspaceId,
|
||||
workspace_id: WorkspaceId,
|
||||
workspace: &ViewHandle<Workspace>,
|
||||
cx: &mut AsyncAppContext,
|
||||
) {
|
||||
for item in self.children.iter() {
|
||||
let project = project.clone();
|
||||
let workspace_id = workspace_id.clone();
|
||||
let item_handle = pane_handle
|
||||
.update(cx, |_, cx| {
|
||||
if let Some(deserializer) = cx.global::<ItemDeserializers>().get(&item.kind) {
|
||||
|
@ -191,6 +197,16 @@ impl SerializedItem {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Default for SerializedItem {
|
||||
fn default() -> Self {
|
||||
SerializedItem {
|
||||
kind: Arc::from("Terminal"),
|
||||
item_id: 100000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Bind for &SerializedItem {
|
||||
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
|
||||
let next_index = statement.bind(self.kind.clone(), start_index)?;
|
||||
|
@ -231,7 +247,7 @@ mod tests {
|
|||
use db::sqlez::connection::Connection;
|
||||
use settings::DockAnchor;
|
||||
|
||||
use super::WorkspaceId;
|
||||
use super::WorkspaceLocation;
|
||||
|
||||
#[test]
|
||||
fn test_workspace_round_trips() {
|
||||
|
@ -245,7 +261,7 @@ mod tests {
|
|||
.unwrap()()
|
||||
.unwrap();
|
||||
|
||||
let workspace_id: WorkspaceId = WorkspaceId::from(&["\test2", "\test1"]);
|
||||
let workspace_id: WorkspaceLocation = WorkspaceLocation::from(&["\test2", "\test1"]);
|
||||
|
||||
db.exec_bound("INSERT INTO workspace_id_test(workspace_id, dock_anchor) VALUES (?,?)")
|
||||
.unwrap()((&workspace_id, DockAnchor::Bottom))
|
||||
|
@ -255,7 +271,10 @@ mod tests {
|
|||
db.select_row("SELECT workspace_id, dock_anchor FROM workspace_id_test LIMIT 1")
|
||||
.unwrap()()
|
||||
.unwrap(),
|
||||
Some((WorkspaceId::from(&["\test1", "\test2"]), DockAnchor::Bottom))
|
||||
Some((
|
||||
WorkspaceLocation::from(&["\test1", "\test2"]),
|
||||
DockAnchor::Bottom
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
use crate::{
|
||||
item::ItemEvent,
|
||||
persistence::model::{ItemId, WorkspaceId},
|
||||
Item, ItemNavHistory, Pane, Workspace,
|
||||
item::ItemEvent, persistence::model::ItemId, Item, ItemNavHistory, Pane, Workspace, WorkspaceId,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use call::participant::{Frame, RemoteVideoTrack};
|
||||
|
@ -148,7 +146,11 @@ impl Item for SharedScreen {
|
|||
self.nav_history = Some(history);
|
||||
}
|
||||
|
||||
fn clone_on_split(&self, cx: &mut ViewContext<Self>) -> Option<Self> {
|
||||
fn clone_on_split(
|
||||
&self,
|
||||
_workspace_id: WorkspaceId,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<Self> {
|
||||
let track = self.track.upgrade()?;
|
||||
Some(Self::new(&track, self.peer_id, self.user.clone(), cx))
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ use anyhow::{anyhow, Context, Result};
|
|||
use call::ActiveCall;
|
||||
use client::{proto, Client, PeerId, TypedEnvelope, UserStore};
|
||||
use collections::{hash_map, HashMap, HashSet};
|
||||
use db::Uuid;
|
||||
use dock::{DefaultItemFactory, Dock, ToggleDockButton};
|
||||
use drag_and_drop::DragAndDrop;
|
||||
use fs::{self, Fs};
|
||||
|
@ -45,7 +46,7 @@ use log::{error, warn};
|
|||
pub use pane::*;
|
||||
pub use pane_group::*;
|
||||
use persistence::model::SerializedItem;
|
||||
pub use persistence::model::{ItemId, WorkspaceId};
|
||||
pub use persistence::model::{ItemId, WorkspaceLocation};
|
||||
use postage::prelude::Stream;
|
||||
use project::{Project, ProjectEntryId, ProjectPath, ProjectStore, Worktree, WorktreeId};
|
||||
use serde::Deserialize;
|
||||
|
@ -128,6 +129,8 @@ pub struct OpenProjectEntryInPane {
|
|||
project_entry: ProjectEntryId,
|
||||
}
|
||||
|
||||
pub type WorkspaceId = Uuid;
|
||||
|
||||
impl_internal_actions!(
|
||||
workspace,
|
||||
[
|
||||
|
@ -530,6 +533,7 @@ pub struct Workspace {
|
|||
last_leaders_by_pane: HashMap<WeakViewHandle<Pane>, PeerId>,
|
||||
window_edited: bool,
|
||||
active_call: Option<(ModelHandle<ActiveCall>, Vec<gpui::Subscription>)>,
|
||||
database_id: WorkspaceId,
|
||||
_observe_current_user: Task<()>,
|
||||
}
|
||||
|
||||
|
@ -556,7 +560,7 @@ impl Workspace {
|
|||
project::Event::WorktreeRemoved(_) | project::Event::WorktreeAdded => {
|
||||
this.update_window_title(cx);
|
||||
// TODO: Cache workspace_id on workspace and read from it here
|
||||
this.serialize_workspace(None, cx);
|
||||
this.serialize_workspace(cx);
|
||||
}
|
||||
project::Event::DisconnectedFromHost => {
|
||||
this.update_window_edited(cx);
|
||||
|
@ -630,6 +634,12 @@ impl Workspace {
|
|||
active_call = Some((call, subscriptions));
|
||||
}
|
||||
|
||||
let id = if let Some(id) = serialized_workspace.as_ref().map(|ws| ws.id) {
|
||||
id
|
||||
} else {
|
||||
WorkspaceId::new()
|
||||
};
|
||||
|
||||
let mut this = Workspace {
|
||||
modal: None,
|
||||
weak_self: weak_handle.clone(),
|
||||
|
@ -657,6 +667,7 @@ impl Workspace {
|
|||
last_leaders_by_pane: Default::default(),
|
||||
window_edited: false,
|
||||
active_call,
|
||||
database_id: id,
|
||||
_observe_current_user,
|
||||
};
|
||||
this.project_remote_id_changed(project.read(cx).remote_id(), cx);
|
||||
|
@ -1317,7 +1328,7 @@ impl Workspace {
|
|||
pub fn add_item(&mut self, item: Box<dyn ItemHandle>, cx: &mut ViewContext<Self>) {
|
||||
let active_pane = self.active_pane().clone();
|
||||
Pane::add_item(self, &active_pane, item, true, true, None, cx);
|
||||
self.serialize_workspace(None, cx);
|
||||
self.serialize_workspace(cx);
|
||||
}
|
||||
|
||||
pub fn open_path(
|
||||
|
@ -1522,7 +1533,7 @@ impl Workspace {
|
|||
entry.remove();
|
||||
}
|
||||
}
|
||||
self.serialize_workspace(None, cx);
|
||||
self.serialize_workspace(cx);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -1544,7 +1555,7 @@ impl Workspace {
|
|||
|
||||
pane.read(cx).active_item().map(|item| {
|
||||
let new_pane = self.add_pane(cx);
|
||||
if let Some(clone) = item.clone_on_split(cx.as_mut()) {
|
||||
if let Some(clone) = item.clone_on_split(self.database_id(), cx.as_mut()) {
|
||||
Pane::add_item(self, &new_pane, clone, true, true, None, cx);
|
||||
}
|
||||
self.center.split(&pane, &new_pane, direction).unwrap();
|
||||
|
@ -2255,7 +2266,11 @@ impl Workspace {
|
|||
}
|
||||
}
|
||||
|
||||
fn workspace_id(&self, cx: &AppContext) -> WorkspaceId {
|
||||
pub fn database_id(&self) -> WorkspaceId {
|
||||
self.database_id
|
||||
}
|
||||
|
||||
fn location(&self, cx: &AppContext) -> WorkspaceLocation {
|
||||
self.project()
|
||||
.read(cx)
|
||||
.visible_worktrees(cx)
|
||||
|
@ -2275,7 +2290,7 @@ impl Workspace {
|
|||
}
|
||||
}
|
||||
|
||||
fn serialize_workspace(&self, old_id: Option<WorkspaceId>, cx: &AppContext) {
|
||||
fn serialize_workspace(&self, cx: &AppContext) {
|
||||
fn serialize_pane_handle(
|
||||
pane_handle: &ViewHandle<Pane>,
|
||||
cx: &AppContext,
|
||||
|
@ -2320,7 +2335,8 @@ impl Workspace {
|
|||
let center_group = build_serialized_pane_group(&self.center.root, cx);
|
||||
|
||||
let serialized_workspace = SerializedWorkspace {
|
||||
workspace_id: self.workspace_id(cx),
|
||||
id: self.database_id,
|
||||
location: self.location(cx),
|
||||
dock_position: self.dock.position(),
|
||||
dock_pane,
|
||||
center_group,
|
||||
|
@ -2328,7 +2344,7 @@ impl Workspace {
|
|||
|
||||
cx.background()
|
||||
.spawn(async move {
|
||||
persistence::DB.save_workspace(old_id, &serialized_workspace);
|
||||
persistence::DB.save_workspace(&serialized_workspace);
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
@ -2349,7 +2365,7 @@ impl Workspace {
|
|||
.deserialize_to(
|
||||
&project,
|
||||
&dock_pane_handle,
|
||||
&serialized_workspace.workspace_id,
|
||||
serialized_workspace.id,
|
||||
&workspace,
|
||||
&mut cx,
|
||||
)
|
||||
|
@ -2359,12 +2375,7 @@ impl Workspace {
|
|||
|
||||
let (root, active_pane) = serialized_workspace
|
||||
.center_group
|
||||
.deserialize(
|
||||
&project,
|
||||
&serialized_workspace.workspace_id,
|
||||
&workspace,
|
||||
&mut cx,
|
||||
)
|
||||
.deserialize(&project, serialized_workspace.id, &workspace, &mut cx)
|
||||
.await;
|
||||
|
||||
// Remove old panes from workspace panes list
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue