This commit is contained in:
K Simmons 2022-10-20 15:07:58 -07:00 committed by Mikayla Maki
parent b48e28b555
commit 0c466f806c
10 changed files with 302 additions and 45 deletions

1
Cargo.lock generated
View file

@ -7617,6 +7617,7 @@ dependencies = [
"client", "client",
"collections", "collections",
"context_menu", "context_menu",
"db",
"drag_and_drop", "drag_and_drop",
"fs", "fs",
"futures 0.3.24", "futures 0.3.24",

View file

@ -12,6 +12,7 @@ test-support = []
[dependencies] [dependencies]
collections = { path = "../collections" } collections = { path = "../collections" }
gpui = { path = "../gpui" }
anyhow = "1.0.57" anyhow = "1.0.57"
async-trait = "0.1" async-trait = "0.1"
lazy_static = "1.4.0" lazy_static = "1.4.0"

View file

@ -1,6 +1,7 @@
mod items; mod items;
mod kvp; mod kvp;
mod migrations; mod migrations;
mod pane;
mod workspace; mod workspace;
use std::fs; use std::fs;

View file

@ -1,8 +1,17 @@
use std::{ffi::OsStr, fmt::Display, hash::Hash, os::unix::prelude::OsStrExt, path::PathBuf}; use std::{
ffi::OsStr,
fmt::Display,
hash::Hash,
os::unix::prelude::OsStrExt,
path::{Path, PathBuf},
sync::Arc,
};
use anyhow::Result; use anyhow::Result;
use collections::HashSet; use collections::HashSet;
use rusqlite::{named_params, params}; use rusqlite::{named_params, params, types::FromSql};
use crate::workspace::WorkspaceId;
use super::Db; use super::Db;
@ -62,3 +71,52 @@ CREATE TABLE editors(
FOREIGN KEY(workspace_id) REFERENCES workspace_ids(workspace_id) FOREIGN KEY(workspace_id) REFERENCES workspace_ids(workspace_id)
) STRICT; ) STRICT;
"; ";
#[derive(Debug, PartialEq, Eq)]
pub struct ItemId {
workspace_id: usize,
item_id: usize,
}
enum SerializedItemKind {
Editor,
Diagnostics,
ProjectSearch,
Terminal,
}
struct SerializedItemRow {
kind: SerializedItemKind,
item_id: usize,
path: Option<Arc<Path>>,
query: Option<String>,
}
#[derive(Debug, PartialEq, Eq)]
pub enum SerializedItem {
Editor { item_id: usize, path: Arc<Path> },
Diagnostics { item_id: usize },
ProjectSearch { item_id: usize, query: String },
Terminal { item_id: usize },
}
impl SerializedItem {
pub fn item_id(&self) -> usize {
match self {
SerializedItem::Editor { item_id, .. } => *item_id,
SerializedItem::Diagnostics { item_id } => *item_id,
SerializedItem::ProjectSearch { item_id, .. } => *item_id,
SerializedItem::Terminal { item_id } => *item_id,
}
}
}
impl Db {
pub fn get_item(&self, item_id: ItemId) -> SerializedItem {
unimplemented!()
}
pub fn save_item(&self, workspace_id: WorkspaceId, item: &SerializedItem) {}
pub fn close_item(&self, item_id: ItemId) {}
}

134
crates/db/src/pane.rs Normal file
View file

@ -0,0 +1,134 @@
use gpui::Axis;
use crate::{items::ItemId, workspace::WorkspaceId};
use super::Db;
pub(crate) const PANE_M_1: &str = "
CREATE TABLE pane_groups(
workspace_id INTEGER,
group_id INTEGER,
axis STRING NOT NULL, -- 'Vertical' / 'Horizontal'
PRIMARY KEY (workspace_id, group_id)
) STRICT;
CREATE TABLE pane_group_children(
workspace_id INTEGER,
group_id INTEGER,
child_pane_id INTEGER, -- Nullable
child_group_id INTEGER, -- Nullable
index INTEGER,
PRIMARY KEY (workspace_id, group_id)
) STRICT;
CREATE TABLE pane_items(
workspace_id INTEGER,
pane_id INTEGER,
item_id INTEGER, -- Array
index INTEGER,
KEY (workspace_id, pane_id)
) STRICT;
";
#[derive(Debug, PartialEq, Eq)]
pub struct PaneId {
workspace_id: WorkspaceId,
pane_id: usize,
}
#[derive(Debug, PartialEq, Eq)]
pub struct PaneGroupId {
workspace_id: WorkspaceId,
group_id: usize,
}
impl PaneGroupId {
pub(crate) fn root(workspace_id: WorkspaceId) -> Self {
Self {
workspace_id,
group_id: 0,
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct SerializedPaneGroup {
group_id: PaneGroupId,
axis: Axis,
children: Vec<PaneGroupChild>,
}
struct PaneGroupChildRow {
child_pane_id: Option<usize>,
child_group_id: Option<usize>,
index: usize,
}
#[derive(Debug, PartialEq, Eq)]
pub enum PaneGroupChild {
Pane(SerializedPane),
Group(SerializedPaneGroup),
}
#[derive(Debug, PartialEq, Eq)]
pub struct SerializedPane {
pane_id: PaneId,
children: Vec<ItemId>,
}
impl Db {
pub(crate) fn get_pane_group(&self, pane_group_id: PaneGroupId) -> SerializedPaneGroup {
let axis = self.get_pane_group_axis(pane_group_id);
let mut children: Vec<(usize, PaneGroupChild)> = Vec::new();
for child_row in self.get_pane_group_children(pane_group_id) {
if let Some(child_pane_id) = child_row.child_pane_id {
children.push((
child_row.index,
PaneGroupChild::Pane(self.get_pane(PaneId {
workspace_id: pane_group_id.workspace_id,
pane_id: child_pane_id,
})),
));
} else if let Some(child_group_id) = child_row.child_group_id {
children.push((
child_row.index,
PaneGroupChild::Group(self.get_pane_group(PaneGroupId {
workspace_id: pane_group_id.workspace_id,
group_id: child_group_id,
})),
));
}
}
children.sort_by_key(|(index, _)| index);
SerializedPaneGroup {
group_id: pane_group_id,
axis,
children: children.into_iter().map(|(_, child)| child).collect(),
}
}
pub fn get_pane_group_children(
&self,
pane_group_id: PaneGroupId,
) -> impl Iterator<Item = PaneGroupChildRow> {
unimplemented!()
}
pub fn get_pane_group_axis(&self, pane_group_id: PaneGroupId) -> Axis {
unimplemented!();
}
pub fn save_center_pane_group(&self, center_pane_group: SerializedPaneGroup) {
// Delete the center pane group for this workspace and any of its children
// Generate new pane group IDs as we go through
// insert them
// Items garbage collect themselves when dropped
}
pub(crate) fn get_pane(&self, pane_id: PaneId) -> SerializedPane {
unimplemented!();
}
pub fn save_pane(&self, pane: SerializedPane) {}
}

View file

@ -1,5 +1,7 @@
use std::{path::Path, sync::Arc}; use std::{path::Path, sync::Arc};
use crate::pane::{PaneGroupId, PaneId, SerializedPane, SerializedPaneGroup};
use super::Db; use super::Db;
pub(crate) const WORKSPACE_M_1: &str = " pub(crate) const WORKSPACE_M_1: &str = "
@ -17,28 +19,6 @@ CREATE TABLE worktree_roots(
workspace_id INTEGER NOT NULL, workspace_id INTEGER NOT NULL,
FOREIGN KEY(workspace_id) REFERENCES workspace_ids(workspace_id) FOREIGN KEY(workspace_id) REFERENCES workspace_ids(workspace_id)
) STRICT; ) STRICT;
CREATE TABLE pane_groups(
workspace_id INTEGER,
group_id INTEGER,
split_direction STRING, -- 'Vertical' / 'Horizontal' /
PRIMARY KEY (workspace_id, group_id)
) STRICT;
CREATE TABLE pane_group_children(
workspace_id INTEGER,
group_id INTEGER,
child_pane_id INTEGER, -- Nullable
child_group_id INTEGER, -- Nullable
PRIMARY KEY (workspace_id, group_id)
) STRICT;
CREATE TABLE pane_items(
workspace_id INTEGER,
pane_id INTEGER,
item_id INTEGER, -- Array
PRIMARY KEY (workspace_id, pane_id)
) STRICT;
"; ";
// Zed stores items with ids which are a combination of a view id during a given run and a workspace id. This // Zed stores items with ids which are a combination of a view id during a given run and a workspace id. This
@ -52,18 +32,65 @@ CREATE TABLE pane_items(
// Case 4: Starting Zed with multiple project folders // Case 4: Starting Zed with multiple project folders
// > Zed ~/projects/Zed ~/projects/Zed.dev // > Zed ~/projects/Zed ~/projects/Zed.dev
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct WorkspaceId(usize); pub struct WorkspaceId(usize);
struct WorkspaceRow {
pub workspace_id: WorkspaceId,
pub center_group_id: PaneGroupId,
pub dock_pane_id: PaneId,
}
pub struct SerializedWorkspace {
pub workspace_id: WorkspaceId,
pub center_group: SerializedPaneGroup,
pub dock_pane: Option<SerializedPane>,
}
impl Db { impl Db {
/// Finds or creates a workspace id for the given set of worktree roots. If the passed worktree roots is empty, return the /// Finds or creates a workspace id for the given set of worktree roots. If the passed worktree roots is empty, return the
/// the last workspace id /// the last workspace id
pub fn workspace_id(&self, worktree_roots: &[Arc<Path>]) -> WorkspaceId { pub fn workspace_for_worktree_roots(
&self,
worktree_roots: &[Arc<Path>],
) -> SerializedWorkspace {
// Find the workspace id which is uniquely identified by this set of paths return it if found // Find the workspace id which is uniquely identified by this set of paths return it if found
// Otherwise: if let Some(workspace_id) = self.workspace_id(worktree_roots) {
// Find the max workspace_id and increment it as our new workspace id let workspace_row = self.get_workspace_row(workspace_id);
// Store in the worktrees table the mapping from this new id to the set of worktree roots let center_group = self.get_pane_group(workspace_row.center_group_id);
unimplemented!(); let dock_pane = self.get_pane(workspace_row.dock_pane_id);
SerializedWorkspace {
workspace_id,
center_group,
dock_pane: Some(dock_pane),
}
} else {
let workspace_id = self.get_next_workspace_id();
let center_group = SerializedPaneGroup {
group_id: PaneGroupId::root(workspace_id),
axis: Default::default(),
children: Default::default(),
};
SerializedWorkspace {
workspace_id,
center_group,
dock_pane: None,
}
}
}
fn get_next_workspace_id(&self) -> WorkspaceId {
unimplemented!()
}
fn workspace_id(&self, worktree_roots: &[Arc<Path>]) -> Option<WorkspaceId> {
unimplemented!()
}
fn get_workspace_row(&self, workspace_id: WorkspaceId) -> WorkspaceRow {
unimplemented!()
} }
/// Updates the open paths for the given workspace id. Will garbage collect items from /// Updates the open paths for the given workspace id. Will garbage collect items from
@ -80,16 +107,12 @@ impl Db {
unimplemented!(); unimplemented!();
} }
/// Returns the previous workspace ids sorted by last modified /// Returns the previous workspace ids sorted by last modified along with their opened worktree roots
pub fn recent_workspaces(&self) -> Vec<(WorkspaceId, Vec<Arc<Path>>)> { pub fn recent_workspaces(&self) -> Vec<(WorkspaceId, Vec<Arc<Path>>)> {
// Return all the workspace ids and their associated paths ordered by the access timestamp // Return all the workspace ids and their associated paths ordered by the access timestamp
//ORDER BY timestamps //ORDER BY timestamps
unimplemented!(); unimplemented!();
} }
pub fn center_pane(&self, workspace: WorkspaceId) -> SerializedPaneGroup {}
pub fn dock_pane(&self, workspace: WorkspaceId) -> SerializedPane {}
} }
#[cfg(test)] #[cfg(test)]
@ -104,6 +127,42 @@ mod tests {
use super::WorkspaceId; use super::WorkspaceId;
fn arc_path(path: &'static str) -> Arc<Path> {
PathBuf::from(path).into()
}
fn test_detect_workspace_id() {
let data = &[
(WorkspaceId(1), vec![arc_path("/tmp")]),
(WorkspaceId(2), vec![arc_path("/tmp"), arc_path("/tmp2")]),
(
WorkspaceId(3),
vec![arc_path("/tmp"), arc_path("/tmp2"), arc_path("/tmp3")],
),
];
let db = Db::open_in_memory();
for (workspace_id, entries) in data {
db.update_worktree_roots(workspace_id, entries); //??
}
assert_eq!(None, db.workspace_id(&[arc_path("/tmp2")]));
assert_eq!(
None,
db.workspace_id(&[arc_path("/tmp2"), arc_path("/tmp3")])
);
assert_eq!(Some(WorkspaceId(1)), db.workspace_id(&[arc_path("/tmp")]));
assert_eq!(
Some(WorkspaceId(2)),
db.workspace_id(&[arc_path("/tmp"), arc_path("/tmp2")])
);
assert_eq!(
Some(WorkspaceId(3)),
db.workspace_id(&[arc_path("/tmp"), arc_path("/tmp2"), arc_path("/tmp3")])
);
}
fn test_tricky_overlapping_updates() { fn test_tricky_overlapping_updates() {
// DB state: // DB state:
// (/tree) -> ID: 1 // (/tree) -> ID: 1
@ -117,10 +176,6 @@ mod tests {
// (/tree2, /tree3) -> ID: 2 // (/tree2, /tree3) -> ID: 2
// Get rid of 3 for garbage collection // Get rid of 3 for garbage collection
fn arc_path(path: &'static str) -> Arc<Path> {
PathBuf::from(path).into()
}
let data = &[ let data = &[
(WorkspaceId(1), vec![arc_path("/tmp")]), (WorkspaceId(1), vec![arc_path("/tmp")]),
(WorkspaceId(2), vec![arc_path("/tmp"), arc_path("/tmp2")]), (WorkspaceId(2), vec![arc_path("/tmp"), arc_path("/tmp2")]),
@ -131,18 +186,18 @@ mod tests {
for (workspace_id, entries) in data { for (workspace_id, entries) in data {
db.update_worktree_roots(workspace_id, entries); //?? db.update_worktree_roots(workspace_id, entries); //??
assert_eq!(&db.workspace_id(&[]), workspace_id) assert_eq!(&db.workspace_id(&[]), &Some(*workspace_id))
} }
for (workspace_id, entries) in data { for (workspace_id, entries) in data {
assert_eq!(&db.workspace_id(entries.as_slice()), workspace_id); assert_eq!(&db.workspace_id(entries.as_slice()), &Some(*workspace_id));
} }
db.update_worktree_roots(&WorkspaceId(2), &[arc_path("/tmp2")]); db.update_worktree_roots(&WorkspaceId(2), &[arc_path("/tmp2")]);
// todo!(); // make sure that 3 got garbage collected // todo!(); // make sure that 3 got garbage collected
assert_eq!(db.workspace_id(&[arc_path("/tmp2")]), WorkspaceId(2)); assert_eq!(db.workspace_id(&[arc_path("/tmp2")]), Some(WorkspaceId(2)));
assert_eq!(db.workspace_id(&[arc_path("/tmp")]), WorkspaceId(1)); assert_eq!(db.workspace_id(&[arc_path("/tmp")]), Some(WorkspaceId(1)));
let recent_workspaces = db.recent_workspaces(); let recent_workspaces = db.recent_workspaces();
assert_eq!(recent_workspaces.get(0).unwrap().0, WorkspaceId(2)); assert_eq!(recent_workspaces.get(0).unwrap().0, WorkspaceId(2));

View file

@ -863,8 +863,9 @@ pub struct DebugContext<'a> {
pub app: &'a AppContext, pub app: &'a AppContext,
} }
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum Axis { pub enum Axis {
#[default]
Horizontal, Horizontal,
Vertical, Vertical,
} }

View file

@ -18,6 +18,7 @@ test-support = [
] ]
[dependencies] [dependencies]
db = { path = "../db" }
call = { path = "../call" } call = { path = "../call" }
client = { path = "../client" } client = { path = "../client" }
collections = { path = "../collections" } collections = { path = "../collections" }

View file

@ -137,7 +137,11 @@ pub struct Dock {
} }
impl Dock { impl Dock {
pub fn new(cx: &mut ViewContext<Workspace>, default_item_factory: DefaultItemFactory) -> Self { pub fn new(
serialized_pane: SerializedPane,
default_item_factory: DefaultItemFactory,
cx: &mut ViewContext<Workspace>,
) -> Self {
let anchor = cx.global::<Settings>().default_dock_anchor; let anchor = cx.global::<Settings>().default_dock_anchor;
let pane = cx.add_view(|cx| Pane::new(Some(anchor), cx)); let pane = cx.add_view(|cx| Pane::new(Some(anchor), cx));
pane.update(cx, |pane, cx| { pane.update(cx, |pane, cx| {

View file

@ -1110,6 +1110,7 @@ enum FollowerItem {
impl Workspace { impl Workspace {
pub fn new( pub fn new(
serialized_workspace: SerializedWorkspace,
project: ModelHandle<Project>, project: ModelHandle<Project>,
dock_default_factory: DefaultItemFactory, dock_default_factory: DefaultItemFactory,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,