mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-07 20:39:04 +03:00
WIP
This commit is contained in:
parent
b48e28b555
commit
0c466f806c
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -7617,6 +7617,7 @@ dependencies = [
|
||||
"client",
|
||||
"collections",
|
||||
"context_menu",
|
||||
"db",
|
||||
"drag_and_drop",
|
||||
"fs",
|
||||
"futures 0.3.24",
|
||||
|
@ -12,6 +12,7 @@ test-support = []
|
||||
|
||||
[dependencies]
|
||||
collections = { path = "../collections" }
|
||||
gpui = { path = "../gpui" }
|
||||
anyhow = "1.0.57"
|
||||
async-trait = "0.1"
|
||||
lazy_static = "1.4.0"
|
||||
|
@ -1,6 +1,7 @@
|
||||
mod items;
|
||||
mod kvp;
|
||||
mod migrations;
|
||||
mod pane;
|
||||
mod workspace;
|
||||
|
||||
use std::fs;
|
||||
|
@ -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 collections::HashSet;
|
||||
use rusqlite::{named_params, params};
|
||||
use rusqlite::{named_params, params, types::FromSql};
|
||||
|
||||
use crate::workspace::WorkspaceId;
|
||||
|
||||
use super::Db;
|
||||
|
||||
@ -62,3 +71,52 @@ CREATE TABLE editors(
|
||||
FOREIGN KEY(workspace_id) REFERENCES workspace_ids(workspace_id)
|
||||
) 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
134
crates/db/src/pane.rs
Normal 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) {}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
use std::{path::Path, sync::Arc};
|
||||
|
||||
use crate::pane::{PaneGroupId, PaneId, SerializedPane, SerializedPaneGroup};
|
||||
|
||||
use super::Db;
|
||||
|
||||
pub(crate) const WORKSPACE_M_1: &str = "
|
||||
@ -17,28 +19,6 @@ CREATE TABLE worktree_roots(
|
||||
workspace_id INTEGER NOT NULL,
|
||||
FOREIGN KEY(workspace_id) REFERENCES workspace_ids(workspace_id)
|
||||
) 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
|
||||
@ -52,18 +32,65 @@ CREATE TABLE pane_items(
|
||||
// Case 4: Starting Zed with multiple project folders
|
||||
// > Zed ~/projects/Zed ~/projects/Zed.dev
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
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 {
|
||||
/// 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
|
||||
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
|
||||
// Otherwise:
|
||||
// Find the max workspace_id and increment it as our new workspace id
|
||||
// Store in the worktrees table the mapping from this new id to the set of worktree roots
|
||||
unimplemented!();
|
||||
if let Some(workspace_id) = self.workspace_id(worktree_roots) {
|
||||
let workspace_row = self.get_workspace_row(workspace_id);
|
||||
let center_group = self.get_pane_group(workspace_row.center_group_id);
|
||||
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
|
||||
@ -80,16 +107,12 @@ impl Db {
|
||||
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>>)> {
|
||||
// Return all the workspace ids and their associated paths ordered by the access timestamp
|
||||
//ORDER BY timestamps
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
pub fn center_pane(&self, workspace: WorkspaceId) -> SerializedPaneGroup {}
|
||||
|
||||
pub fn dock_pane(&self, workspace: WorkspaceId) -> SerializedPane {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -104,6 +127,42 @@ mod tests {
|
||||
|
||||
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() {
|
||||
// DB state:
|
||||
// (/tree) -> ID: 1
|
||||
@ -117,10 +176,6 @@ mod tests {
|
||||
// (/tree2, /tree3) -> ID: 2
|
||||
// Get rid of 3 for garbage collection
|
||||
|
||||
fn arc_path(path: &'static str) -> Arc<Path> {
|
||||
PathBuf::from(path).into()
|
||||
}
|
||||
|
||||
let data = &[
|
||||
(WorkspaceId(1), vec![arc_path("/tmp")]),
|
||||
(WorkspaceId(2), vec![arc_path("/tmp"), arc_path("/tmp2")]),
|
||||
@ -131,18 +186,18 @@ mod tests {
|
||||
|
||||
for (workspace_id, entries) in data {
|
||||
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 {
|
||||
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")]);
|
||||
// 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("/tmp")]), WorkspaceId(1));
|
||||
assert_eq!(db.workspace_id(&[arc_path("/tmp2")]), Some(WorkspaceId(2)));
|
||||
assert_eq!(db.workspace_id(&[arc_path("/tmp")]), Some(WorkspaceId(1)));
|
||||
|
||||
let recent_workspaces = db.recent_workspaces();
|
||||
assert_eq!(recent_workspaces.get(0).unwrap().0, WorkspaceId(2));
|
||||
|
@ -863,8 +863,9 @@ pub struct DebugContext<'a> {
|
||||
pub app: &'a AppContext,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
pub enum Axis {
|
||||
#[default]
|
||||
Horizontal,
|
||||
Vertical,
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ test-support = [
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
db = { path = "../db" }
|
||||
call = { path = "../call" }
|
||||
client = { path = "../client" }
|
||||
collections = { path = "../collections" }
|
||||
|
@ -137,7 +137,11 @@ pub struct 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 pane = cx.add_view(|cx| Pane::new(Some(anchor), cx));
|
||||
pane.update(cx, |pane, cx| {
|
||||
|
@ -1110,6 +1110,7 @@ enum FollowerItem {
|
||||
|
||||
impl Workspace {
|
||||
pub fn new(
|
||||
serialized_workspace: SerializedWorkspace,
|
||||
project: ModelHandle<Project>,
|
||||
dock_default_factory: DefaultItemFactory,
|
||||
cx: &mut ViewContext<Self>,
|
||||
|
Loading…
Reference in New Issue
Block a user