Added center group deserialization
This commit is contained in:
parent
75d3d46b1b
commit
6530658c3e
14 changed files with 264 additions and 149 deletions
|
@ -13,10 +13,14 @@ use theme::Theme;
|
|||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct PaneGroup {
|
||||
root: Member,
|
||||
pub(crate) root: Member,
|
||||
}
|
||||
|
||||
impl PaneGroup {
|
||||
pub(crate) fn with_root(root: Member) -> Self {
|
||||
Self { root }
|
||||
}
|
||||
|
||||
pub fn new(pane: ViewHandle<Pane>) -> Self {
|
||||
Self {
|
||||
root: Member::Pane(pane),
|
||||
|
@ -85,7 +89,7 @@ impl PaneGroup {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
enum Member {
|
||||
pub(crate) enum Member {
|
||||
Axis(PaneAxis),
|
||||
Pane(ViewHandle<Pane>),
|
||||
}
|
||||
|
@ -276,9 +280,9 @@ impl Member {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
struct PaneAxis {
|
||||
axis: Axis,
|
||||
members: Vec<Member>,
|
||||
pub(crate) struct PaneAxis {
|
||||
pub axis: Axis,
|
||||
pub members: Vec<Member>,
|
||||
}
|
||||
|
||||
impl PaneAxis {
|
||||
|
|
|
@ -55,8 +55,8 @@ impl Domain for Workspace {
|
|||
CREATE TABLE panes(
|
||||
pane_id INTEGER PRIMARY KEY,
|
||||
workspace_id BLOB NOT NULL,
|
||||
parent_group_id INTEGER, -- NULL, this is a dock pane
|
||||
position INTEGER, -- NULL, this is a dock pane
|
||||
parent_group_id INTEGER, -- NULL means that this is a dock pane
|
||||
position INTEGER, -- NULL means that this is a dock pane
|
||||
FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id)
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE CASCADE,
|
||||
|
@ -164,7 +164,7 @@ impl WorkspaceDb {
|
|||
})
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Update workspace with roots {:?}",
|
||||
"Update workspace with roots {:?} failed.",
|
||||
workspace.workspace_id.paths()
|
||||
)
|
||||
})
|
||||
|
@ -196,6 +196,17 @@ impl WorkspaceDb {
|
|||
.into_iter()
|
||||
.next()
|
||||
.context("No center pane group")
|
||||
.map(|pane_group| {
|
||||
// Rewrite the special case of the root being a leaf node
|
||||
if let SerializedPaneGroup::Group { axis: Axis::Horizontal, ref children } = pane_group {
|
||||
if children.len() == 1 {
|
||||
if let Some(SerializedPaneGroup::Pane(pane)) = children.get(0) {
|
||||
return SerializedPaneGroup::Pane(pane.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
pane_group
|
||||
})
|
||||
}
|
||||
|
||||
fn get_pane_group_children<'a>(
|
||||
|
@ -242,9 +253,12 @@ impl WorkspaceDb {
|
|||
pane_group: &SerializedPaneGroup,
|
||||
parent: Option<(GroupId, usize)>,
|
||||
) -> Result<()> {
|
||||
if parent.is_none() && !matches!(pane_group, SerializedPaneGroup::Group { .. }) {
|
||||
bail!("Pane groups must have a SerializedPaneGroup::Group at the root")
|
||||
}
|
||||
// Rewrite the root node to fit with the database
|
||||
let pane_group = if parent.is_none() && matches!(pane_group, SerializedPaneGroup::Pane { .. }) {
|
||||
SerializedPaneGroup::Group { axis: Axis::Horizontal, children: vec![pane_group.clone()] }
|
||||
} else {
|
||||
pane_group.clone()
|
||||
};
|
||||
|
||||
match pane_group {
|
||||
SerializedPaneGroup::Group { axis, children } => {
|
||||
|
@ -254,7 +268,7 @@ impl WorkspaceDb {
|
|||
INSERT INTO pane_groups(workspace_id, parent_group_id, position, axis)
|
||||
VALUES (?, ?, ?, ?)
|
||||
RETURNING group_id"})?
|
||||
((workspace_id, parent_id, position, *axis))?
|
||||
((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() {
|
||||
|
@ -262,7 +276,9 @@ impl WorkspaceDb {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
SerializedPaneGroup::Pane(pane) => self.save_pane(workspace_id, pane, parent),
|
||||
SerializedPaneGroup::Pane(pane) => {
|
||||
self.save_pane(workspace_id, &pane, parent)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,7 +340,7 @@ impl WorkspaceDb {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use db::open_memory_db;
|
||||
use db::{open_memory_db, write_db_to};
|
||||
use settings::DockAnchor;
|
||||
|
||||
use super::*;
|
||||
|
@ -333,7 +349,7 @@ mod tests {
|
|||
fn test_full_workspace_serialization() {
|
||||
env_logger::try_init().ok();
|
||||
|
||||
let db = WorkspaceDb(open_memory_db("test_full_workspace_serialization"));
|
||||
let db = WorkspaceDb(open_memory_db(Some("test_full_workspace_serialization")));
|
||||
|
||||
let dock_pane = crate::persistence::model::SerializedPane {
|
||||
children: vec![
|
||||
|
@ -407,7 +423,7 @@ mod tests {
|
|||
fn test_workspace_assignment() {
|
||||
env_logger::try_init().ok();
|
||||
|
||||
let db = WorkspaceDb(open_memory_db("test_basic_functionality"));
|
||||
let db = WorkspaceDb(open_memory_db(Some("test_basic_functionality")));
|
||||
|
||||
let workspace_1 = SerializedWorkspace {
|
||||
workspace_id: (["/tmp", "/tmp2"]).into(),
|
||||
|
@ -500,7 +516,7 @@ mod tests {
|
|||
fn test_basic_dock_pane() {
|
||||
env_logger::try_init().ok();
|
||||
|
||||
let db = WorkspaceDb(open_memory_db("basic_dock_pane"));
|
||||
let db = WorkspaceDb(open_memory_db(Some("basic_dock_pane")));
|
||||
|
||||
let dock_pane = crate::persistence::model::SerializedPane {
|
||||
children: vec![
|
||||
|
@ -514,7 +530,7 @@ mod tests {
|
|||
let workspace = default_workspace(&["/tmp"], dock_pane, &Default::default());
|
||||
|
||||
db.save_workspace(None, &workspace);
|
||||
|
||||
write_db_to(&db, "dest.db").unwrap();
|
||||
let new_workspace = db.workspace_for_roots(&["/tmp"]).unwrap();
|
||||
|
||||
assert_eq!(workspace.dock_pane, new_workspace.dock_pane);
|
||||
|
@ -524,7 +540,7 @@ mod tests {
|
|||
fn test_simple_split() {
|
||||
// env_logger::try_init().ok();
|
||||
|
||||
let db = WorkspaceDb(open_memory_db("simple_split"));
|
||||
let db = WorkspaceDb(open_memory_db(Some("simple_split")));
|
||||
|
||||
// -----------------
|
||||
// | 1,2 | 5,6 |
|
||||
|
|
|
@ -5,15 +5,20 @@ use std::{
|
|||
|
||||
use anyhow::Result;
|
||||
|
||||
use gpui::Axis;
|
||||
use async_recursion::async_recursion;
|
||||
use gpui::{AsyncAppContext, Axis, ModelHandle, Task, ViewHandle};
|
||||
|
||||
use project::Project;
|
||||
use settings::DockAnchor;
|
||||
use sqlez::{
|
||||
bindable::{Bind, Column},
|
||||
statement::Statement,
|
||||
};
|
||||
use util::ResultExt;
|
||||
|
||||
use crate::dock::DockPosition;
|
||||
use crate::{
|
||||
dock::DockPosition, item::ItemHandle, ItemDeserializers, Member, Pane, PaneAxis, Workspace,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct WorkspaceId(Arc<Vec<PathBuf>>);
|
||||
|
@ -69,9 +74,42 @@ pub enum SerializedPaneGroup {
|
|||
|
||||
impl Default for SerializedPaneGroup {
|
||||
fn default() -> Self {
|
||||
Self::Group {
|
||||
axis: Axis::Horizontal,
|
||||
children: vec![Self::Pane(Default::default())],
|
||||
Self::Pane(SerializedPane {
|
||||
children: Vec::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializedPaneGroup {
|
||||
#[async_recursion(?Send)]
|
||||
pub(crate) async fn deserialize(
|
||||
&self,
|
||||
project: &ModelHandle<Project>,
|
||||
workspace_id: &WorkspaceId,
|
||||
workspace: &ViewHandle<Workspace>,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Member {
|
||||
match self {
|
||||
SerializedPaneGroup::Group { axis, children } => {
|
||||
let mut members = Vec::new();
|
||||
for child in children {
|
||||
let new_member = child
|
||||
.deserialize(project, workspace_id, workspace, cx)
|
||||
.await;
|
||||
members.push(new_member);
|
||||
}
|
||||
Member::Axis(PaneAxis {
|
||||
axis: *axis,
|
||||
members,
|
||||
})
|
||||
}
|
||||
SerializedPaneGroup::Pane(serialized_pane) => {
|
||||
let pane = workspace.update(cx, |workspace, cx| workspace.add_pane(cx));
|
||||
serialized_pane
|
||||
.deserialize_to(project, &pane, workspace_id, workspace, cx)
|
||||
.await;
|
||||
Member::Pane(pane)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -85,6 +123,44 @@ impl SerializedPane {
|
|||
pub fn new(children: Vec<SerializedItem>) -> Self {
|
||||
SerializedPane { children }
|
||||
}
|
||||
|
||||
pub async fn deserialize_to(
|
||||
&self,
|
||||
project: &ModelHandle<Project>,
|
||||
pane_handle: &ViewHandle<Pane>,
|
||||
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) {
|
||||
deserializer(
|
||||
project,
|
||||
workspace.downgrade(),
|
||||
workspace_id,
|
||||
item.item_id,
|
||||
cx,
|
||||
)
|
||||
} else {
|
||||
Task::ready(Err(anyhow::anyhow!(
|
||||
"Deserializer does not exist for item kind: {}",
|
||||
item.kind
|
||||
)))
|
||||
}
|
||||
})
|
||||
.await
|
||||
.log_err();
|
||||
if let Some(item_handle) = item_handle {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
Pane::add_item(workspace, &pane_handle, item_handle, false, false, None, cx);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type GroupId = i64;
|
||||
|
@ -150,7 +226,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_workspace_round_trips() {
|
||||
let db = Connection::open_memory("workspace_id_round_trips");
|
||||
let db = Connection::open_memory(Some("workspace_id_round_trips"));
|
||||
|
||||
db.exec(indoc::indoc! {"
|
||||
CREATE TABLE workspace_id_test(
|
||||
|
|
|
@ -58,7 +58,7 @@ use theme::{Theme, ThemeRegistry};
|
|||
pub use toolbar::{ToolbarItemLocation, ToolbarItemView};
|
||||
use util::ResultExt;
|
||||
|
||||
use crate::persistence::model::{SerializedPane, SerializedWorkspace};
|
||||
use crate::persistence::model::{SerializedPane, SerializedPaneGroup, SerializedWorkspace};
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct RemoveWorktreeFromProject(pub WorktreeId);
|
||||
|
@ -2264,27 +2264,62 @@ impl Workspace {
|
|||
.into()
|
||||
}
|
||||
|
||||
fn serialize_workspace(&self, old_id: Option<WorkspaceId>, cx: &mut MutableAppContext) {
|
||||
let dock_pane = SerializedPane {
|
||||
children: self
|
||||
.dock
|
||||
.pane()
|
||||
.read(cx)
|
||||
.items()
|
||||
.filter_map(|item_handle| {
|
||||
Some(SerializedItem {
|
||||
kind: Arc::from(item_handle.serialized_item_kind()?),
|
||||
item_id: item_handle.id(),
|
||||
fn remove_panes(&mut self, member: Member, cx: &mut ViewContext<Workspace>) {
|
||||
match member {
|
||||
Member::Axis(PaneAxis { members, .. }) => {
|
||||
for child in members.iter() {
|
||||
self.remove_panes(child.clone(), cx)
|
||||
}
|
||||
}
|
||||
Member::Pane(pane) => self.remove_pane(pane.clone(), cx),
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_workspace(&self, old_id: Option<WorkspaceId>, cx: &AppContext) {
|
||||
fn serialize_pane_handle(
|
||||
pane_handle: &ViewHandle<Pane>,
|
||||
cx: &AppContext,
|
||||
) -> SerializedPane {
|
||||
SerializedPane {
|
||||
children: pane_handle
|
||||
.read(cx)
|
||||
.items()
|
||||
.filter_map(|item_handle| {
|
||||
Some(SerializedItem {
|
||||
kind: Arc::from(item_handle.serialized_item_kind()?),
|
||||
item_id: item_handle.id(),
|
||||
})
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
};
|
||||
.collect::<Vec<_>>(),
|
||||
}
|
||||
}
|
||||
|
||||
let dock_pane = serialize_pane_handle(self.dock.pane(), cx);
|
||||
|
||||
fn build_serialized_pane_group(
|
||||
pane_group: &Member,
|
||||
cx: &AppContext,
|
||||
) -> SerializedPaneGroup {
|
||||
match pane_group {
|
||||
Member::Axis(PaneAxis { axis, members }) => SerializedPaneGroup::Group {
|
||||
axis: *axis,
|
||||
children: members
|
||||
.iter()
|
||||
.map(|member| build_serialized_pane_group(member, cx))
|
||||
.collect::<Vec<_>>(),
|
||||
},
|
||||
Member::Pane(pane_handle) => {
|
||||
SerializedPaneGroup::Pane(serialize_pane_handle(&pane_handle, cx))
|
||||
}
|
||||
}
|
||||
}
|
||||
let center_group = build_serialized_pane_group(&self.center.root, cx);
|
||||
|
||||
let serialized_workspace = SerializedWorkspace {
|
||||
workspace_id: self.workspace_id(cx),
|
||||
dock_position: self.dock.position(),
|
||||
dock_pane,
|
||||
center_group: Default::default(),
|
||||
center_group,
|
||||
};
|
||||
|
||||
cx.background()
|
||||
|
@ -2299,87 +2334,43 @@ impl Workspace {
|
|||
serialized_workspace: SerializedWorkspace,
|
||||
cx: &mut MutableAppContext,
|
||||
) {
|
||||
// fn process_splits(
|
||||
// pane_group: SerializedPaneGroup,
|
||||
// parent: Option<PaneGroup>,
|
||||
// workspace: ViewHandle<Workspace>,
|
||||
// cx: &mut AsyncAppContext,
|
||||
// ) {
|
||||
// match pane_group {
|
||||
// SerializedPaneGroup::Group { axis, children } => {
|
||||
// process_splits(pane_group, parent)
|
||||
// }
|
||||
// SerializedPaneGroup::Pane(pane) => {
|
||||
// process_pane(pane)
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
|
||||
async fn deserialize_pane(
|
||||
project: ModelHandle<Project>,
|
||||
pane: SerializedPane,
|
||||
pane_handle: ViewHandle<Pane>,
|
||||
workspace_id: WorkspaceId,
|
||||
workspace: &ViewHandle<Workspace>,
|
||||
cx: &mut AsyncAppContext,
|
||||
) {
|
||||
for item in pane.children {
|
||||
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)
|
||||
{
|
||||
deserializer(
|
||||
project,
|
||||
workspace.downgrade(),
|
||||
workspace_id,
|
||||
item.item_id,
|
||||
cx,
|
||||
)
|
||||
} else {
|
||||
Task::ready(Err(anyhow!(
|
||||
"Deserializer does not exist for item kind: {}",
|
||||
item.kind
|
||||
)))
|
||||
}
|
||||
})
|
||||
.await
|
||||
.log_err();
|
||||
|
||||
if let Some(item_handle) = item_handle {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
Pane::add_item(
|
||||
workspace,
|
||||
&pane_handle,
|
||||
item_handle,
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
cx,
|
||||
);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cx.spawn(|mut cx| async move {
|
||||
if let Some(workspace) = workspace.upgrade(&cx) {
|
||||
let (project, dock_pane_handle) = workspace.read_with(&cx, |workspace, _| {
|
||||
(workspace.project().clone(), workspace.dock_pane().clone())
|
||||
});
|
||||
deserialize_pane(
|
||||
project,
|
||||
serialized_workspace.dock_pane,
|
||||
dock_pane_handle,
|
||||
serialized_workspace.workspace_id,
|
||||
&workspace,
|
||||
&mut cx,
|
||||
)
|
||||
.await;
|
||||
|
||||
serialized_workspace
|
||||
.dock_pane
|
||||
.deserialize_to(
|
||||
&project,
|
||||
&dock_pane_handle,
|
||||
&serialized_workspace.workspace_id,
|
||||
&workspace,
|
||||
&mut cx,
|
||||
)
|
||||
.await;
|
||||
|
||||
// Traverse the splits tree and add to things
|
||||
// process_splits(serialized_workspace.center_group, None, workspace, &mut cx);
|
||||
|
||||
let root = serialized_workspace
|
||||
.center_group
|
||||
.deserialize(
|
||||
&project,
|
||||
&serialized_workspace.workspace_id,
|
||||
&workspace,
|
||||
&mut cx,
|
||||
)
|
||||
.await;
|
||||
|
||||
// Remove old panes from workspace panes list
|
||||
workspace.update(&mut cx, |workspace, cx| {
|
||||
workspace.remove_panes(workspace.center.root.clone(), cx);
|
||||
|
||||
// Swap workspace center group
|
||||
workspace.center = PaneGroup::with_root(root);
|
||||
cx.notify();
|
||||
});
|
||||
|
||||
workspace.update(&mut cx, |workspace, cx| {
|
||||
Dock::set_dock_position(workspace, serialized_workspace.dock_position, cx)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue