pane.rs

  1use gpui::Axis;
  2
  3use crate::{items::ItemId, workspace::WorkspaceId};
  4
  5use super::Db;
  6
  7// We have an many-branched, unbalanced tree with three types:
  8// Pane Groups
  9// Panes
 10// Items
 11
 12// The root is always a Pane Group
 13// Pane Groups can have 0 (or more) Panes and/or Pane Groups as children
 14// Panes can have 0 or more items as children
 15// Panes can be their own root
 16// Items cannot have children
 17// References pointing down is hard (SQL doesn't like arrays)
 18// References pointing up is easy (1-1 item / parent relationship) but is harder to query
 19//
 20
 21#[derive(Debug, PartialEq, Eq, Copy, Clone)]
 22pub struct PaneId {
 23    workspace_id: WorkspaceId,
 24    pane_id: usize,
 25}
 26
 27#[derive(Debug, PartialEq, Eq, Copy, Clone)]
 28pub struct PaneGroupId {
 29    workspace_id: WorkspaceId,
 30    group_id: usize,
 31}
 32
 33impl PaneGroupId {
 34    pub fn root(workspace_id: WorkspaceId) -> Self {
 35        Self {
 36            workspace_id,
 37            group_id: 0,
 38        }
 39    }
 40}
 41
 42#[derive(Debug, PartialEq, Eq)]
 43pub struct SerializedPaneGroup {
 44    group_id: PaneGroupId,
 45    axis: Axis,
 46    children: Vec<PaneGroupChild>,
 47}
 48
 49impl SerializedPaneGroup {
 50    pub fn empty_root(workspace_id: WorkspaceId) -> Self {
 51        Self {
 52            group_id: PaneGroupId::root(workspace_id),
 53            axis: Default::default(),
 54            children: Default::default(),
 55        }
 56    }
 57}
 58
 59struct PaneGroupChildRow {
 60    child_pane_id: Option<usize>,
 61    child_group_id: Option<usize>,
 62    index: usize,
 63}
 64
 65#[derive(Debug, PartialEq, Eq)]
 66pub enum PaneGroupChild {
 67    Pane(SerializedPane),
 68    Group(SerializedPaneGroup),
 69}
 70
 71#[derive(Debug, PartialEq, Eq)]
 72pub struct SerializedPane {
 73    pane_id: PaneId,
 74    children: Vec<ItemId>,
 75}
 76
 77pub(crate) const PANE_M_1: &str = "
 78CREATE TABLE dock_panes(
 79    dock_pane_id INTEGER PRIMARY KEY,
 80    workspace_id INTEGER NOT NULL,
 81    anchor_position TEXT NOT NULL, -- Enum: 'Bottom' / 'Right' / 'Expanded'
 82    shown INTEGER NOT NULL, -- Boolean
 83    FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE
 84) STRICT;
 85
 86CREATE TABLE pane_groups(
 87    group_id INTEGER PRIMARY KEY,
 88    workspace_id INTEGER NOT NULL,
 89    parent_group INTEGER, -- NULL indicates that this is a root node
 90    axis TEXT NOT NULL, -- Enum:  'Vertical' / 'Horizontal'
 91    FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE,
 92    FOREIGN KEY(parent_group) REFERENCES pane_groups(group_id) ON DELETE CASCADE
 93) STRICT;
 94
 95CREATE TABLE grouped_panes(
 96    pane_id INTEGER PRIMARY KEY,
 97    workspace_id INTEGER NOT NULL,
 98    group_id INTEGER NOT NULL,
 99    idx INTEGER NOT NULL,
100    FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE,
101    FOREIGN KEY(group_id) REFERENCES pane_groups(group_id) ON DELETE CASCADE
102) STRICT;
103
104CREATE TABLE items(
105    item_id INTEGER PRIMARY KEY,
106    workspace_id INTEGER NOT NULL,
107    kind TEXT NOT NULL,
108    FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE
109) STRICT;
110
111CREATE TABLE group_items(
112    workspace_id INTEGER NOT NULL,
113    pane_id INTEGER NOT NULL,
114    item_id INTEGER NOT NULL,
115    idx INTEGER NOT NULL,
116    PRIMARY KEY (workspace_id, pane_id, item_id)
117    FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE,
118    FOREIGN KEY(pane_id) REFERENCES grouped_panes(pane_id) ON DELETE CASCADE,
119    FOREIGN KEY(item_id) REFERENCES items(item_id) ON DELETE CASCADE
120) STRICT;
121
122CREATE TABLE dock_items(
123    workspace_id INTEGER NOT NULL,
124    dock_pane_id INTEGER NOT NULL,
125    item_id INTEGER NOT NULL,
126    idx INTEGER NOT NULL,
127    PRIMARY KEY (workspace_id, dock_pane_id, item_id)
128    FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE,
129    FOREIGN KEY(dock_pane_id) REFERENCES dock_panes(dock_pane_id) ON DELETE CASCADE,
130    FOREIGN KEY(item_id) REFERENCES items(item_id)ON DELETE CASCADE
131) STRICT;
132";
133
134#[derive(Default, Debug)]
135pub enum DockAnchor {
136    #[default]
137    Bottom,
138    Right,
139    Expanded,
140}
141
142#[derive(Default, Debug)]
143pub struct SerializedDockPane {
144    pub workspace: WorkspaceId,
145    pub anchor_position: DockAnchor,
146    pub shown: bool,
147}
148
149impl Db {
150    pub fn get_pane_group(&self, pane_group_id: PaneGroupId) -> SerializedPaneGroup {
151        let axis = self.get_pane_group_axis(pane_group_id);
152        let mut children: Vec<(usize, PaneGroupChild)> = Vec::new();
153        for child_row in self.get_pane_group_children(pane_group_id) {
154            if let Some(child_pane_id) = child_row.child_pane_id {
155                children.push((
156                    child_row.index,
157                    PaneGroupChild::Pane(self.get_pane(PaneId {
158                        workspace_id: pane_group_id.workspace_id,
159                        pane_id: child_pane_id,
160                    })),
161                ));
162            } else if let Some(child_group_id) = child_row.child_group_id {
163                children.push((
164                    child_row.index,
165                    PaneGroupChild::Group(self.get_pane_group(PaneGroupId {
166                        workspace_id: pane_group_id.workspace_id,
167                        group_id: child_group_id,
168                    })),
169                ));
170            }
171        }
172        children.sort_by_key(|(index, _)| *index);
173
174        SerializedPaneGroup {
175            group_id: pane_group_id,
176            axis,
177            children: children.into_iter().map(|(_, child)| child).collect(),
178        }
179    }
180
181    fn get_pane_group_children(
182        &self,
183        _pane_group_id: PaneGroupId,
184    ) -> impl Iterator<Item = PaneGroupChildRow> {
185        Vec::new().into_iter()
186    }
187
188    fn get_pane_group_axis(&self, _pane_group_id: PaneGroupId) -> Axis {
189        unimplemented!();
190    }
191
192    pub fn save_pane_splits(&self, _center_pane_group: SerializedPaneGroup) {
193        // Delete the center pane group for this workspace and any of its children
194        // Generate new pane group IDs as we go through
195        // insert them
196        // Items garbage collect themselves when dropped
197    }
198
199    pub(crate) fn get_pane(&self, _pane_id: PaneId) -> SerializedPane {
200        unimplemented!();
201    }
202
203    pub fn get_dock_pane(&self, _workspace: WorkspaceId) -> Option<SerializedDockPane> {
204        unimplemented!()
205    }
206
207    pub fn save_dock_pane(&self, _dock_pane: SerializedDockPane) {}
208}
209
210#[cfg(test)]
211mod tests {
212
213    use crate::Db;
214
215    use super::{DockAnchor, SerializedDockPane};
216
217    #[test]
218    fn test_basic_dock_pane() {
219        let db = Db::open_in_memory();
220
221        let workspace = db.workspace_for_roots(&["/tmp"]);
222
223        db.save_dock_pane(SerializedDockPane {
224            workspace: workspace.workspace_id,
225            anchor_position: DockAnchor::Expanded,
226            shown: true,
227        });
228
229        let _new_workspace = db.workspace_for_roots(&["/tmp"]);
230    }
231}