model.rs

  1use crate::{item::ItemHandle, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId};
  2use anyhow::{Context, Result};
  3use async_recursion::async_recursion;
  4use db::sqlez::{
  5    bindable::{Bind, Column, StaticColumnCount},
  6    statement::Statement,
  7};
  8use gpui::{AsyncWindowContext, Axis, Model, Task, View, WeakView, WindowBounds};
  9use project::Project;
 10use std::{
 11    path::{Path, PathBuf},
 12    sync::Arc,
 13};
 14use util::ResultExt;
 15use uuid::Uuid;
 16
 17#[derive(Debug, Clone, PartialEq, Eq)]
 18pub struct WorkspaceLocation(Arc<Vec<PathBuf>>);
 19
 20impl WorkspaceLocation {
 21    pub fn paths(&self) -> Arc<Vec<PathBuf>> {
 22        self.0.clone()
 23    }
 24}
 25
 26impl<P: AsRef<Path>, T: IntoIterator<Item = P>> From<T> for WorkspaceLocation {
 27    fn from(iterator: T) -> Self {
 28        let mut roots = iterator
 29            .into_iter()
 30            .map(|p| p.as_ref().to_path_buf())
 31            .collect::<Vec<_>>();
 32        roots.sort();
 33        Self(Arc::new(roots))
 34    }
 35}
 36
 37impl StaticColumnCount for WorkspaceLocation {}
 38impl Bind for &WorkspaceLocation {
 39    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
 40        bincode::serialize(&self.0)
 41            .expect("Bincode serialization of paths should not fail")
 42            .bind(statement, start_index)
 43    }
 44}
 45
 46impl Column for WorkspaceLocation {
 47    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
 48        let blob = statement.column_blob(start_index)?;
 49        Ok((
 50            WorkspaceLocation(bincode::deserialize(blob).context("Bincode failed")?),
 51            start_index + 1,
 52        ))
 53    }
 54}
 55
 56#[derive(Debug, PartialEq, Clone)]
 57pub struct SerializedWorkspace {
 58    pub id: WorkspaceId,
 59    pub location: WorkspaceLocation,
 60    pub center_group: SerializedPaneGroup,
 61    pub bounds: Option<WindowBounds>,
 62    pub display: Option<Uuid>,
 63    pub docks: DockStructure,
 64}
 65
 66#[derive(Debug, PartialEq, Clone, Default)]
 67pub struct DockStructure {
 68    pub(crate) left: DockData,
 69    pub(crate) right: DockData,
 70    pub(crate) bottom: DockData,
 71}
 72
 73impl Column for DockStructure {
 74    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
 75        let (left, next_index) = DockData::column(statement, start_index)?;
 76        let (right, next_index) = DockData::column(statement, next_index)?;
 77        let (bottom, next_index) = DockData::column(statement, next_index)?;
 78        Ok((
 79            DockStructure {
 80                left,
 81                right,
 82                bottom,
 83            },
 84            next_index,
 85        ))
 86    }
 87}
 88
 89impl Bind for DockStructure {
 90    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
 91        let next_index = statement.bind(&self.left, start_index)?;
 92        let next_index = statement.bind(&self.right, next_index)?;
 93        statement.bind(&self.bottom, next_index)
 94    }
 95}
 96
 97#[derive(Debug, PartialEq, Clone, Default)]
 98pub struct DockData {
 99    pub(crate) visible: bool,
100    pub(crate) active_panel: Option<String>,
101    pub(crate) zoom: bool,
102}
103
104impl Column for DockData {
105    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
106        let (visible, next_index) = Option::<bool>::column(statement, start_index)?;
107        let (active_panel, next_index) = Option::<String>::column(statement, next_index)?;
108        let (zoom, next_index) = Option::<bool>::column(statement, next_index)?;
109        Ok((
110            DockData {
111                visible: visible.unwrap_or(false),
112                active_panel,
113                zoom: zoom.unwrap_or(false),
114            },
115            next_index,
116        ))
117    }
118}
119
120impl Bind for DockData {
121    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
122        let next_index = statement.bind(&self.visible, start_index)?;
123        let next_index = statement.bind(&self.active_panel, next_index)?;
124        statement.bind(&self.zoom, next_index)
125    }
126}
127
128#[derive(Debug, PartialEq, Clone)]
129pub enum SerializedPaneGroup {
130    Group {
131        axis: Axis,
132        flexes: Option<Vec<f32>>,
133        children: Vec<SerializedPaneGroup>,
134    },
135    Pane(SerializedPane),
136}
137
138#[cfg(test)]
139impl Default for SerializedPaneGroup {
140    fn default() -> Self {
141        Self::Pane(SerializedPane {
142            children: vec![SerializedItem::default()],
143            active: false,
144        })
145    }
146}
147
148impl SerializedPaneGroup {
149    #[async_recursion(?Send)]
150    pub(crate) async fn deserialize(
151        self,
152        project: &Model<Project>,
153        workspace_id: WorkspaceId,
154        workspace: WeakView<Workspace>,
155        cx: &mut AsyncWindowContext,
156    ) -> Option<(Member, Option<View<Pane>>, Vec<Option<Box<dyn ItemHandle>>>)> {
157        match self {
158            SerializedPaneGroup::Group {
159                axis,
160                children,
161                flexes,
162            } => {
163                let mut current_active_pane = None;
164                let mut members = Vec::new();
165                let mut items = Vec::new();
166                for child in children {
167                    if let Some((new_member, active_pane, new_items)) = child
168                        .deserialize(project, workspace_id, workspace.clone(), cx)
169                        .await
170                    {
171                        members.push(new_member);
172                        items.extend(new_items);
173                        current_active_pane = current_active_pane.or(active_pane);
174                    }
175                }
176
177                if members.is_empty() {
178                    return None;
179                }
180
181                if members.len() == 1 {
182                    return Some((members.remove(0), current_active_pane, items));
183                }
184
185                Some((
186                    Member::Axis(PaneAxis::load(axis, members, flexes)),
187                    current_active_pane,
188                    items,
189                ))
190            }
191            SerializedPaneGroup::Pane(serialized_pane) => {
192                let pane = workspace
193                    .update(cx, |workspace, cx| workspace.add_pane(cx).downgrade())
194                    .log_err()?;
195                let active = serialized_pane.active;
196                let new_items = serialized_pane
197                    .deserialize_to(project, &pane, workspace_id, workspace.clone(), cx)
198                    .await
199                    .log_err()?;
200
201                if pane.update(cx, |pane, _| pane.items_len() != 0).log_err()? {
202                    let pane = pane.upgrade()?;
203                    Some((Member::Pane(pane.clone()), active.then(|| pane), new_items))
204                } else {
205                    let pane = pane.upgrade()?;
206                    workspace
207                        .update(cx, |workspace, cx| workspace.force_remove_pane(&pane, cx))
208                        .log_err()?;
209                    None
210                }
211            }
212        }
213    }
214}
215
216#[derive(Debug, PartialEq, Eq, Default, Clone)]
217pub struct SerializedPane {
218    pub(crate) active: bool,
219    pub(crate) children: Vec<SerializedItem>,
220}
221
222impl SerializedPane {
223    pub fn new(children: Vec<SerializedItem>, active: bool) -> Self {
224        SerializedPane { children, active }
225    }
226
227    pub async fn deserialize_to(
228        &self,
229        project: &Model<Project>,
230        pane: &WeakView<Pane>,
231        workspace_id: WorkspaceId,
232        workspace: WeakView<Workspace>,
233        cx: &mut AsyncWindowContext,
234    ) -> Result<Vec<Option<Box<dyn ItemHandle>>>> {
235        let mut items = Vec::new();
236        let mut active_item_index = None;
237        for (index, item) in self.children.iter().enumerate() {
238            let project = project.clone();
239            let item_handle = pane
240                .update(cx, |_, cx| {
241                    if let Some(deserializer) = cx.global::<ItemDeserializers>().get(&item.kind) {
242                        deserializer(project, workspace.clone(), workspace_id, item.item_id, cx)
243                    } else {
244                        Task::ready(Err(anyhow::anyhow!(
245                            "Deserializer does not exist for item kind: {}",
246                            item.kind
247                        )))
248                    }
249                })?
250                .await
251                .log_err();
252
253            items.push(item_handle.clone());
254
255            if let Some(item_handle) = item_handle {
256                pane.update(cx, |pane, cx| {
257                    pane.add_item(item_handle.clone(), true, true, None, cx);
258                })?;
259            }
260
261            if item.active {
262                active_item_index = Some(index);
263            }
264        }
265
266        if let Some(active_item_index) = active_item_index {
267            pane.update(cx, |pane, cx| {
268                pane.activate_item(active_item_index, false, false, cx);
269            })?;
270        }
271
272        anyhow::Ok(items)
273    }
274}
275
276pub type GroupId = i64;
277pub type PaneId = i64;
278pub type ItemId = u64;
279
280#[derive(Debug, PartialEq, Eq, Clone)]
281pub struct SerializedItem {
282    pub kind: Arc<str>,
283    pub item_id: ItemId,
284    pub active: bool,
285}
286
287impl SerializedItem {
288    pub fn new(kind: impl AsRef<str>, item_id: ItemId, active: bool) -> Self {
289        Self {
290            kind: Arc::from(kind.as_ref()),
291            item_id,
292            active,
293        }
294    }
295}
296
297#[cfg(test)]
298impl Default for SerializedItem {
299    fn default() -> Self {
300        SerializedItem {
301            kind: Arc::from("Terminal"),
302            item_id: 100000,
303            active: false,
304        }
305    }
306}
307
308impl StaticColumnCount for SerializedItem {
309    fn column_count() -> usize {
310        3
311    }
312}
313impl Bind for &SerializedItem {
314    fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
315        let next_index = statement.bind(&self.kind, start_index)?;
316        let next_index = statement.bind(&self.item_id, next_index)?;
317        statement.bind(&self.active, next_index)
318    }
319}
320
321impl Column for SerializedItem {
322    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
323        let (kind, next_index) = Arc::<str>::column(statement, start_index)?;
324        let (item_id, next_index) = ItemId::column(statement, next_index)?;
325        let (active, next_index) = bool::column(statement, next_index)?;
326        Ok((
327            SerializedItem {
328                kind,
329                item_id,
330                active,
331            },
332            next_index,
333        ))
334    }
335}