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}