use super::{SerializedAxis, SerializedWindowBounds}; use crate::{ Member, Pane, PaneAxis, SerializableItemRegistry, Workspace, WorkspaceId, item::ItemHandle, path_list::PathList, }; use anyhow::Result; use async_recursion::async_recursion; use collections::IndexSet; use db::sqlez::{ bindable::{Bind, Column, StaticColumnCount}, statement::Statement, }; use gpui::{AsyncWindowContext, Entity, WeakEntity}; use language::{Toolchain, ToolchainScope}; use project::{Project, debugger::breakpoint_store::SourceBreakpoint}; use remote::RemoteConnectionOptions; use std::{ collections::BTreeMap, path::{Path, PathBuf}, sync::Arc, }; use util::ResultExt; use uuid::Uuid; #[derive( Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, serde::Serialize, serde::Deserialize, )] pub(crate) struct RemoteConnectionId(pub u64); #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub(crate) enum RemoteConnectionKind { Ssh, Wsl, } #[derive(Debug, PartialEq, Clone)] pub enum SerializedWorkspaceLocation { Local, Remote(RemoteConnectionOptions), } impl SerializedWorkspaceLocation { /// Get sorted paths pub fn sorted_paths(&self) -> Arc> { unimplemented!() } } #[derive(Debug, PartialEq, Clone)] pub(crate) struct SerializedWorkspace { pub(crate) id: WorkspaceId, pub(crate) location: SerializedWorkspaceLocation, pub(crate) paths: PathList, pub(crate) center_group: SerializedPaneGroup, pub(crate) window_bounds: Option, pub(crate) centered_layout: bool, pub(crate) display: Option, pub(crate) docks: DockStructure, pub(crate) session_id: Option, pub(crate) breakpoints: BTreeMap, Vec>, pub(crate) user_toolchains: BTreeMap>, pub(crate) window_id: Option, } #[derive(Debug, PartialEq, Clone, Default)] pub struct DockStructure { pub(crate) left: DockData, pub(crate) right: DockData, pub(crate) bottom: DockData, } impl RemoteConnectionKind { pub(crate) fn serialize(&self) -> &'static str { match self { RemoteConnectionKind::Ssh => "ssh", RemoteConnectionKind::Wsl => "wsl", } } pub(crate) fn deserialize(text: &str) -> Option { match text { "ssh" => Some(Self::Ssh), "wsl" => Some(Self::Wsl), _ => None, } } } impl Column for DockStructure { fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> { let (left, next_index) = DockData::column(statement, start_index)?; let (right, next_index) = DockData::column(statement, next_index)?; let (bottom, next_index) = DockData::column(statement, next_index)?; Ok(( DockStructure { left, right, bottom, }, next_index, )) } } impl Bind for DockStructure { fn bind(&self, statement: &Statement, start_index: i32) -> Result { let next_index = statement.bind(&self.left, start_index)?; let next_index = statement.bind(&self.right, next_index)?; statement.bind(&self.bottom, next_index) } } #[derive(Debug, PartialEq, Clone, Default)] pub struct DockData { pub(crate) visible: bool, pub(crate) active_panel: Option, pub(crate) zoom: bool, } impl Column for DockData { fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> { let (visible, next_index) = Option::::column(statement, start_index)?; let (active_panel, next_index) = Option::::column(statement, next_index)?; let (zoom, next_index) = Option::::column(statement, next_index)?; Ok(( DockData { visible: visible.unwrap_or(false), active_panel, zoom: zoom.unwrap_or(false), }, next_index, )) } } impl Bind for DockData { fn bind(&self, statement: &Statement, start_index: i32) -> Result { let next_index = statement.bind(&self.visible, start_index)?; let next_index = statement.bind(&self.active_panel, next_index)?; statement.bind(&self.zoom, next_index) } } #[derive(Debug, PartialEq, Clone)] pub(crate) enum SerializedPaneGroup { Group { axis: SerializedAxis, flexes: Option>, children: Vec, }, Pane(SerializedPane), } #[cfg(test)] impl Default for SerializedPaneGroup { fn default() -> Self { Self::Pane(SerializedPane { children: vec![SerializedItem::default()], active: false, pinned_count: 0, }) } } impl SerializedPaneGroup { #[async_recursion(?Send)] pub(crate) async fn deserialize( self, project: &Entity, workspace_id: WorkspaceId, workspace: WeakEntity, cx: &mut AsyncWindowContext, ) -> Option<( Member, Option>, Vec>>, )> { match self { SerializedPaneGroup::Group { axis, children, flexes, } => { let mut current_active_pane = None; let mut members = Vec::new(); let mut items = Vec::new(); for child in children { if let Some((new_member, active_pane, new_items)) = child .deserialize(project, workspace_id, workspace.clone(), cx) .await { members.push(new_member); items.extend(new_items); current_active_pane = current_active_pane.or(active_pane); } } if members.is_empty() { return None; } if members.len() == 1 { return Some((members.remove(0), current_active_pane, items)); } Some(( Member::Axis(PaneAxis::load(axis.0, members, flexes)), current_active_pane, items, )) } SerializedPaneGroup::Pane(serialized_pane) => { let pane = workspace .update_in(cx, |workspace, window, cx| { workspace.add_pane(window, cx).downgrade() }) .log_err()?; let active = serialized_pane.active; let new_items = serialized_pane .deserialize_to(project, &pane, workspace_id, workspace.clone(), cx) .await .log_err()?; if pane .read_with(cx, |pane, _| pane.items_len() != 0) .log_err()? { let pane = pane.upgrade()?; Some(( Member::Pane(pane.clone()), active.then_some(pane), new_items, )) } else { let pane = pane.upgrade()?; workspace .update_in(cx, |workspace, window, cx| { workspace.force_remove_pane(&pane, &None, window, cx) }) .log_err()?; None } } } } } #[derive(Debug, PartialEq, Eq, Default, Clone)] pub struct SerializedPane { pub(crate) active: bool, pub(crate) children: Vec, pub(crate) pinned_count: usize, } impl SerializedPane { pub fn new(children: Vec, active: bool, pinned_count: usize) -> Self { SerializedPane { children, active, pinned_count, } } pub async fn deserialize_to( &self, project: &Entity, pane: &WeakEntity, workspace_id: WorkspaceId, workspace: WeakEntity, cx: &mut AsyncWindowContext, ) -> Result>>> { let mut item_tasks = Vec::new(); let mut active_item_index = None; let mut preview_item_index = None; for (index, item) in self.children.iter().enumerate() { let project = project.clone(); item_tasks.push(pane.update_in(cx, |_, window, cx| { SerializableItemRegistry::deserialize( &item.kind, project, workspace.clone(), workspace_id, item.item_id, window, cx, ) })?); if item.active { active_item_index = Some(index); } if item.preview { preview_item_index = Some(index); } } let mut items = Vec::new(); for item_handle in futures::future::join_all(item_tasks).await { let item_handle = item_handle.log_err(); items.push(item_handle.clone()); if let Some(item_handle) = item_handle { pane.update_in(cx, |pane, window, cx| { pane.add_item(item_handle.clone(), true, true, None, window, cx); })?; } } if let Some(active_item_index) = active_item_index { pane.update_in(cx, |pane, window, cx| { pane.activate_item(active_item_index, false, false, window, cx); })?; } if let Some(preview_item_index) = preview_item_index { pane.update(cx, |pane, cx| { if let Some(item) = pane.item_for_index(preview_item_index) { pane.set_preview_item_id(Some(item.item_id()), cx); } })?; } pane.update(cx, |pane, _| { pane.set_pinned_count(self.pinned_count.min(items.len())); })?; anyhow::Ok(items) } } pub type GroupId = i64; pub type PaneId = i64; pub type ItemId = u64; #[derive(Debug, PartialEq, Eq, Clone)] pub struct SerializedItem { pub kind: Arc, pub item_id: ItemId, pub active: bool, pub preview: bool, } impl SerializedItem { pub fn new(kind: impl AsRef, item_id: ItemId, active: bool, preview: bool) -> Self { Self { kind: Arc::from(kind.as_ref()), item_id, active, preview, } } } #[cfg(test)] impl Default for SerializedItem { fn default() -> Self { SerializedItem { kind: Arc::from("Terminal"), item_id: 100000, active: false, preview: false, } } } impl StaticColumnCount for SerializedItem { fn column_count() -> usize { 4 } } impl Bind for &SerializedItem { fn bind(&self, statement: &Statement, start_index: i32) -> Result { let next_index = statement.bind(&self.kind, start_index)?; let next_index = statement.bind(&self.item_id, next_index)?; let next_index = statement.bind(&self.active, next_index)?; statement.bind(&self.preview, next_index) } } impl Column for SerializedItem { fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> { let (kind, next_index) = Arc::::column(statement, start_index)?; let (item_id, next_index) = ItemId::column(statement, next_index)?; let (active, next_index) = bool::column(statement, next_index)?; let (preview, next_index) = bool::column(statement, next_index)?; Ok(( SerializedItem { kind, item_id, active, preview, }, next_index, )) } }