WIP: Make the item module compile again

This commit is contained in:
Antonio Scandurra 2023-10-31 13:51:42 +01:00
parent e8eea52d0f
commit 14a6199b4b
6 changed files with 478 additions and 521 deletions

View file

@ -14,7 +14,7 @@ pub use test_context::*;
use crate::{ use crate::{
current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AnyWindowHandle, current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AnyWindowHandle,
AppMetadata, AssetSource, ClipboardItem, Context, DispatchPhase, DisplayId, Executor, AppMetadata, AssetSource, ClipboardItem, Context, DispatchPhase, DisplayId, Entity, Executor,
FocusEvent, FocusHandle, FocusId, KeyBinding, Keymap, LayoutId, MainThread, MainThreadOnly, FocusEvent, FocusHandle, FocusId, KeyBinding, Keymap, LayoutId, MainThread, MainThreadOnly,
Pixels, Platform, Point, Render, SharedString, SubscriberSet, Subscription, SvgRenderer, Task, Pixels, Platform, Point, Render, SharedString, SubscriberSet, Subscription, SvgRenderer, Task,
TextStyle, TextStyleRefinement, TextSystem, View, ViewContext, Window, WindowContext, TextStyle, TextStyleRefinement, TextSystem, View, ViewContext, Window, WindowContext,
@ -694,13 +694,17 @@ impl AppContext {
self.globals_by_type.insert(global_type, lease.global); self.globals_by_type.insert(global_type, lease.global);
} }
pub fn observe_release<E: 'static>( pub fn observe_release<E, T>(
&mut self, &mut self,
handle: &Model<E>, handle: &E,
mut on_release: impl FnMut(&mut E, &mut AppContext) + Send + 'static, mut on_release: impl FnMut(&mut T, &mut AppContext) + Send + 'static,
) -> Subscription { ) -> Subscription
where
E: Entity<T>,
T: 'static,
{
self.release_listeners.insert( self.release_listeners.insert(
handle.entity_id, handle.entity_id(),
Box::new(move |entity, cx| { Box::new(move |entity, cx| {
let entity = entity.downcast_mut().expect("invalid entity type"); let entity = entity.downcast_mut().expect("invalid entity type");
on_release(entity, cx) on_release(entity, cx)

View file

@ -314,7 +314,7 @@ impl AnyView {
.map_err(|_| self) .map_err(|_| self)
} }
pub(crate) fn entity_type(&self) -> TypeId { pub fn entity_type(&self) -> TypeId {
self.0.entity_type() self.0.entity_type()
} }

View file

@ -1,88 +1,80 @@
// use crate::{ use crate::{
// pane, persistence::model::ItemId, searchable::SearchableItemHandle, FollowableItemBuilders, pane::{self, Pane},
// ItemNavHistory, Pane, ToolbarItemLocation, ViewId, Workspace, WorkspaceId, persistence::model::ItemId,
// }; searchable::SearchableItemHandle,
// use crate::{AutosaveSetting, DelayedDebouncedEditAction, WorkspaceSettings}; workspace_settings::{AutosaveSetting, WorkspaceSettings},
DelayedDebouncedEditAction, FollowableItemBuilders, ItemNavHistory, ToolbarItemLocation,
ViewId, Workspace, WorkspaceId,
};
use anyhow::Result; use anyhow::Result;
use client2::{ use client2::{
proto::{self, PeerId}, proto::{self, PeerId},
Client, Client,
}; };
use gpui2::{
AnyElement, AnyView, AppContext, EventEmitter, HighlightStyle, Model, Pixels, Point, Render,
SharedString, Task, View, ViewContext, WeakView, WindowContext,
};
use parking_lot::Mutex;
use project2::{Project, ProjectEntryId, ProjectPath};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings2::Settings; use settings2::Settings;
use smallvec::SmallVec;
use std::{
any::{Any, TypeId},
ops::Range,
path::PathBuf,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
time::Duration,
};
use theme2::Theme; use theme2::Theme;
// use client2::{
// proto::{self, PeerId},
// Client,
// };
// use gpui2::geometry::vector::Vector2F;
// use gpui2::AnyWindowHandle;
// use gpui2::{
// fonts::HighlightStyle, AnyElement, AnyViewHandle, AppContext, Model, Task, View,
// ViewContext, View, WeakViewHandle, WindowContext,
// };
// use project2::{Project, ProjectEntryId, ProjectPath};
// use schemars::JsonSchema;
// use serde_derive::{Deserialize, Serialize};
// use settings2::Setting;
// use smallvec::SmallVec;
// use std::{
// any::{Any, TypeId},
// borrow::Cow,
// cell::RefCell,
// fmt,
// ops::Range,
// path::PathBuf,
// rc::Rc,
// sync::{
// atomic::{AtomicBool, Ordering},
// Arc,
// },
// time::Duration,
// };
// use theme2::Theme;
// #[derive(Deserialize)] #[derive(Deserialize)]
// pub struct ItemSettings { pub struct ItemSettings {
// pub git_status: bool, pub git_status: bool,
// pub close_position: ClosePosition, pub close_position: ClosePosition,
// } }
// #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)] #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
// #[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
// pub enum ClosePosition { pub enum ClosePosition {
// Left, Left,
// #[default] #[default]
// Right, Right,
// } }
// impl ClosePosition { impl ClosePosition {
// pub fn right(&self) -> bool { pub fn right(&self) -> bool {
// match self { match self {
// ClosePosition::Left => false, ClosePosition::Left => false,
// ClosePosition::Right => true, ClosePosition::Right => true,
// } }
// } }
// } }
// #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)] #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
// pub struct ItemSettingsContent { pub struct ItemSettingsContent {
// git_status: Option<bool>, git_status: Option<bool>,
// close_position: Option<ClosePosition>, close_position: Option<ClosePosition>,
// } }
// impl Setting for ItemSettings { impl Settings for ItemSettings {
// const KEY: Option<&'static str> = Some("tabs"); const KEY: Option<&'static str> = Some("tabs");
// type FileContent = ItemSettingsContent; type FileContent = ItemSettingsContent;
// fn load( fn load(
// default_value: &Self::FileContent, default_value: &Self::FileContent,
// user_values: &[&Self::FileContent], user_values: &[&Self::FileContent],
// _: &gpui2::AppContext, _: &mut AppContext,
// ) -> anyhow::Result<Self> { ) -> Result<Self> {
// Self::load_via_json_merge(default_value, user_values) Self::load_via_json_merge(default_value, user_values)
// } }
// } }
#[derive(Eq, PartialEq, Hash, Debug)] #[derive(Eq, PartialEq, Hash, Debug)]
pub enum ItemEvent { pub enum ItemEvent {
@ -165,18 +157,18 @@ pub trait Item: Render + EventEmitter + Send {
false false
} }
// fn act_as_type<'a>( fn act_as_type<'a>(
// &'a self, &'a self,
// type_id: TypeId, type_id: TypeId,
// self_handle: &'a View<Self>, self_handle: &'a View<Self>,
// _: &'a AppContext, _: &'a AppContext,
// ) -> Option<&AnyViewHandle> { ) -> Option<AnyView> {
// if TypeId::of::<Self>() == type_id { if TypeId::of::<Self>() == type_id {
// Some(self_handle) Some(self_handle.clone().into_any())
// } else { } else {
// None None
// } }
// } }
fn as_searchable(&self, _: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> { fn as_searchable(&self, _: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {
None None
@ -215,35 +207,6 @@ pub trait Item: Render + EventEmitter + Send {
} }
} }
use std::{
any::Any,
cell::RefCell,
ops::Range,
path::PathBuf,
rc::Rc,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
time::Duration,
};
use gpui2::{
AnyElement, AnyView, AnyWindowHandle, AppContext, EventEmitter, HighlightStyle, Model, Pixels,
Point, Render, SharedString, Task, View, ViewContext, WeakView, WindowContext,
};
use project2::{Project, ProjectEntryId, ProjectPath};
use smallvec::SmallVec;
use crate::{
pane::{self, Pane},
persistence::model::ItemId,
searchable::SearchableItemHandle,
workspace_settings::{AutosaveSetting, WorkspaceSettings},
DelayedDebouncedEditAction, FollowableItemBuilders, ItemNavHistory, ToolbarItemLocation,
ViewId, Workspace, WorkspaceId,
};
pub trait ItemHandle: 'static + Send { pub trait ItemHandle: 'static + Send {
fn subscribe_to_item_events( fn subscribe_to_item_events(
&self, &self,
@ -275,7 +238,6 @@ pub trait ItemHandle: 'static + Send {
fn workspace_deactivated(&self, cx: &mut WindowContext); fn workspace_deactivated(&self, cx: &mut WindowContext);
fn navigate(&self, data: Box<dyn Any>, cx: &mut WindowContext) -> bool; fn navigate(&self, data: Box<dyn Any>, cx: &mut WindowContext) -> bool;
fn id(&self) -> usize; fn id(&self) -> usize;
fn window(&self) -> AnyWindowHandle;
fn to_any(&self) -> AnyView; fn to_any(&self) -> AnyView;
fn is_dirty(&self, cx: &AppContext) -> bool; fn is_dirty(&self, cx: &AppContext) -> bool;
fn has_conflict(&self, cx: &AppContext) -> bool; fn has_conflict(&self, cx: &AppContext) -> bool;
@ -288,12 +250,12 @@ pub trait ItemHandle: 'static + Send {
cx: &mut WindowContext, cx: &mut WindowContext,
) -> Task<Result<()>>; ) -> Task<Result<()>>;
fn reload(&self, project: Model<Project>, cx: &mut WindowContext) -> Task<Result<()>>; fn reload(&self, project: Model<Project>, cx: &mut WindowContext) -> Task<Result<()>>;
// fn act_as_type<'a>(&'a self, type_id: TypeId, cx: &'a AppContext) -> Option<&'a AnyViewHandle>; todo!() fn act_as_type(&self, type_id: TypeId, cx: &AppContext) -> Option<AnyView>;
fn to_followable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn FollowableItemHandle>>; fn to_followable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn FollowableItemHandle>>;
fn on_release( fn on_release(
&self, &self,
cx: &mut AppContext, cx: &mut AppContext,
callback: Box<dyn FnOnce(&mut AppContext)>, callback: Box<dyn FnOnce(&mut AppContext) + Send>,
) -> gpui2::Subscription; ) -> gpui2::Subscription;
fn to_searchable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn SearchableItemHandle>>; fn to_searchable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn SearchableItemHandle>>;
fn breadcrumb_location(&self, cx: &AppContext) -> ToolbarItemLocation; fn breadcrumb_location(&self, cx: &AppContext) -> ToolbarItemLocation;
@ -303,23 +265,21 @@ pub trait ItemHandle: 'static + Send {
fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option<Point<Pixels>>; fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option<Point<Pixels>>;
} }
pub trait WeakItemHandle: Send { pub trait WeakItemHandle: Send + Sync {
fn id(&self) -> usize; fn id(&self) -> usize;
fn window(&self) -> AnyWindowHandle;
fn upgrade(&self) -> Option<Box<dyn ItemHandle>>; fn upgrade(&self) -> Option<Box<dyn ItemHandle>>;
} }
// todo!() impl dyn ItemHandle {
// impl dyn ItemHandle { pub fn downcast<V: 'static>(&self) -> Option<View<V>> {
// pub fn downcast<T: View>(&self) -> Option<View<T>> { self.to_any().downcast().ok()
// self.as_any().clone().downcast() }
// }
// pub fn act_as<T: View>(&self, cx: &AppContext) -> Option<View<T>> { pub fn act_as<V: 'static>(&self, cx: &AppContext) -> Option<View<V>> {
// self.act_as_type(TypeId::of::<T>(), cx) self.act_as_type(TypeId::of::<V>(), cx)
// .and_then(|t| t.clone().downcast()) .and_then(|t| t.downcast().ok())
// } }
// } }
impl<T: Item> ItemHandle for View<T> { impl<T: Item> ItemHandle for View<T> {
fn subscribe_to_item_events( fn subscribe_to_item_events(
@ -438,8 +398,8 @@ impl<T: Item> ItemHandle for View<T> {
.is_none() .is_none()
{ {
let mut pending_autosave = DelayedDebouncedEditAction::new(); let mut pending_autosave = DelayedDebouncedEditAction::new();
let pending_update = Rc::new(RefCell::new(None)); let pending_update = Arc::new(Mutex::new(None));
let pending_update_scheduled = Rc::new(AtomicBool::new(false)); let pending_update_scheduled = Arc::new(AtomicBool::new(false));
let mut event_subscription = let mut event_subscription =
Some(cx.subscribe(self, move |workspace, item, event, cx| { Some(cx.subscribe(self, move |workspace, item, event, cx| {
@ -462,33 +422,31 @@ impl<T: Item> ItemHandle for View<T> {
workspace.unfollow(&pane, cx); workspace.unfollow(&pane, cx);
} }
if item.add_event_to_update_proto( if item.add_event_to_update_proto(event, &mut *pending_update.lock(), cx)
event, && !pending_update_scheduled.load(Ordering::SeqCst)
&mut *pending_update.borrow_mut(),
cx,
) && !pending_update_scheduled.load(Ordering::SeqCst)
{ {
pending_update_scheduled.store(true, Ordering::SeqCst); pending_update_scheduled.store(true, Ordering::SeqCst);
cx.after_window_update({ todo!("replace with on_next_frame?");
let pending_update = pending_update.clone(); // cx.after_window_update({
let pending_update_scheduled = pending_update_scheduled.clone(); // let pending_update = pending_update.clone();
move |this, cx| { // let pending_update_scheduled = pending_update_scheduled.clone();
pending_update_scheduled.store(false, Ordering::SeqCst); // move |this, cx| {
this.update_followers( // pending_update_scheduled.store(false, Ordering::SeqCst);
is_project_item, // this.update_followers(
proto::update_followers::Variant::UpdateView( // is_project_item,
proto::UpdateView { // proto::update_followers::Variant::UpdateView(
id: item // proto::UpdateView {
.remote_id(&this.app_state.client, cx) // id: item
.map(|id| id.to_proto()), // .remote_id(&this.app_state.client, cx)
variant: pending_update.borrow_mut().take(), // .map(|id| id.to_proto()),
leader_id, // variant: pending_update.borrow_mut().take(),
}, // leader_id,
), // },
cx, // ),
); // cx,
} // );
}); // }
// });
} }
} }
@ -525,15 +483,16 @@ impl<T: Item> ItemHandle for View<T> {
} }
})); }));
cx.observe_focus(self, move |workspace, item, focused, cx| { todo!("observe focus");
if !focused // cx.observe_focus(self, move |workspace, item, focused, cx| {
&& WorkspaceSettings::get_global(cx).autosave == AutosaveSetting::OnFocusChange // if !focused
{ // && WorkspaceSettings::get_global(cx).autosave == AutosaveSetting::OnFocusChange
Pane::autosave_item(&item, workspace.project.clone(), cx) // {
.detach_and_log_err(cx); // Pane::autosave_item(&item, workspace.project.clone(), cx)
} // .detach_and_log_err(cx);
}) // }
.detach(); // })
// .detach();
let item_id = self.id(); let item_id = self.id();
cx.observe_release(self, move |workspace, _, _| { cx.observe_release(self, move |workspace, _, _| {
@ -564,11 +523,6 @@ impl<T: Item> ItemHandle for View<T> {
self.id() self.id()
} }
fn window(&self) -> AnyWindowHandle {
todo!()
// AnyViewHandle::window(self)
}
fn to_any(&self) -> AnyView { fn to_any(&self) -> AnyView {
self.clone().into_any() self.clone().into_any()
} }
@ -602,16 +556,15 @@ impl<T: Item> ItemHandle for View<T> {
self.update(cx, |item, cx| item.reload(project, cx)) self.update(cx, |item, cx| item.reload(project, cx))
} }
// todo!() fn act_as_type<'a>(&'a self, type_id: TypeId, cx: &'a AppContext) -> Option<AnyView> {
// fn act_as_type<'a>(&'a self, type_id: TypeId, cx: &'a AppContext) -> Option<&'a AnyViewHandle> { self.read(cx).act_as_type(type_id, self, cx)
// self.read(cx).act_as_type(type_id, self, cx) }
// }
fn to_followable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn FollowableItemHandle>> { fn to_followable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn FollowableItemHandle>> {
if cx.has_global::<FollowableItemBuilders>() { if cx.has_global::<FollowableItemBuilders>() {
let builders = cx.global::<FollowableItemBuilders>(); let builders = cx.global::<FollowableItemBuilders>();
let item = self.as_any(); let item = self.to_any();
Some(builders.get(&item.view_type())?.1(item)) Some(builders.get(&item.entity_type())?.1(&item))
} else { } else {
None None
} }
@ -620,7 +573,7 @@ impl<T: Item> ItemHandle for View<T> {
fn on_release( fn on_release(
&self, &self,
cx: &mut AppContext, cx: &mut AppContext,
callback: Box<dyn FnOnce(&mut AppContext)>, callback: Box<dyn FnOnce(&mut AppContext) + Send>,
) -> gpui2::Subscription { ) -> gpui2::Subscription {
cx.observe_release(self, move |_, cx| callback(cx)) cx.observe_release(self, move |_, cx| callback(cx))
} }
@ -673,10 +626,6 @@ impl<T: Item> WeakItemHandle for WeakView<T> {
self.id() self.id()
} }
fn window(&self) -> AnyWindowHandle {
self.window()
}
fn upgrade(&self) -> Option<Box<dyn ItemHandle>> { fn upgrade(&self) -> Option<Box<dyn ItemHandle>> {
self.upgrade().map(|v| Box::new(v) as Box<dyn ItemHandle>) self.upgrade().map(|v| Box::new(v) as Box<dyn ItemHandle>)
} }

View file

@ -2,10 +2,15 @@
use crate::{ use crate::{
item::{Item, ItemHandle, WeakItemHandle}, item::{Item, ItemHandle, WeakItemHandle},
toolbar::Toolbar,
SplitDirection, Workspace, SplitDirection, Workspace,
}; };
use anyhow::Result;
use collections::{HashMap, VecDeque}; use collections::{HashMap, VecDeque};
use gpui2::{EventEmitter, Model, View, ViewContext, WeakView}; use gpui2::{
AppContext, EventEmitter, Model, Task, View, ViewContext, VisualContext, WeakView,
WindowContext,
};
use parking_lot::Mutex; use parking_lot::Mutex;
use project2::{Project, ProjectEntryId, ProjectPath}; use project2::{Project, ProjectEntryId, ProjectPath};
use serde::Deserialize; use serde::Deserialize;
@ -68,6 +73,7 @@ pub enum SaveIntent {
// pub save_intent: Option<SaveIntent>, // pub save_intent: Option<SaveIntent>,
// } // }
// todo!()
// actions!( // actions!(
// pane, // pane,
// [ // [
@ -90,8 +96,9 @@ pub enum SaveIntent {
// impl_actions!(pane, [ActivateItem, CloseActiveItem, CloseAllItems]); // impl_actions!(pane, [ActivateItem, CloseActiveItem, CloseAllItems]);
// const MAX_NAVIGATION_HISTORY_LEN: usize = 1024; const MAX_NAVIGATION_HISTORY_LEN: usize = 1024;
// todo!()
// pub fn init(cx: &mut AppContext) { // pub fn init(cx: &mut AppContext) {
// cx.add_action(Pane::toggle_zoom); // cx.add_action(Pane::toggle_zoom);
// cx.add_action(|pane: &mut Pane, action: &ActivateItem, cx| { // cx.add_action(|pane: &mut Pane, action: &ActivateItem, cx| {
@ -330,7 +337,7 @@ impl Pane {
pane: handle.clone(), pane: handle.clone(),
next_timestamp, next_timestamp,
}))), }))),
// toolbar: cx.add_view(|_| Toolbar::new()), toolbar: cx.build_view(|_| Toolbar::new()),
// tab_bar_context_menu: TabBarContextMenu { // tab_bar_context_menu: TabBarContextMenu {
// kind: TabBarContextMenuKind::New, // kind: TabBarContextMenuKind::New,
// handle: context_menu, // handle: context_menu,
@ -447,33 +454,33 @@ impl Pane {
} }
} }
// pub fn nav_history(&self) -> &NavHistory { pub fn nav_history(&self) -> &NavHistory {
// &self.nav_history &self.nav_history
// } }
// pub fn nav_history_mut(&mut self) -> &mut NavHistory { pub fn nav_history_mut(&mut self) -> &mut NavHistory {
// &mut self.nav_history &mut self.nav_history
// } }
// pub fn disable_history(&mut self) { pub fn disable_history(&mut self) {
// self.nav_history.disable(); self.nav_history.disable();
// } }
// pub fn enable_history(&mut self) { pub fn enable_history(&mut self) {
// self.nav_history.enable(); self.nav_history.enable();
// } }
// pub fn can_navigate_backward(&self) -> bool { pub fn can_navigate_backward(&self) -> bool {
// !self.nav_history.0.borrow().backward_stack.is_empty() !self.nav_history.0.lock().backward_stack.is_empty()
// } }
// pub fn can_navigate_forward(&self) -> bool { pub fn can_navigate_forward(&self) -> bool {
// !self.nav_history.0.borrow().forward_stack.is_empty() !self.nav_history.0.lock().forward_stack.is_empty()
// } }
// fn history_updated(&mut self, cx: &mut ViewContext<Self>) { fn history_updated(&mut self, cx: &mut ViewContext<Self>) {
// self.toolbar.update(cx, |_, cx| cx.notify()); self.toolbar.update(cx, |_, cx| cx.notify());
// } }
pub(crate) fn open_item( pub(crate) fn open_item(
&mut self, &mut self,
@ -736,115 +743,115 @@ impl Pane {
// )) // ))
// } // }
// pub fn close_item_by_id( pub fn close_item_by_id(
// &mut self, &mut self,
// item_id_to_close: usize, item_id_to_close: usize,
// save_intent: SaveIntent, save_intent: SaveIntent,
// cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
// ) -> Task<Result<()>> { ) -> Task<Result<()>> {
// self.close_items(cx, save_intent, move |view_id| view_id == item_id_to_close) self.close_items(cx, save_intent, move |view_id| view_id == item_id_to_close)
}
// pub fn close_inactive_items(
// &mut self,
// _: &CloseInactiveItems,
// cx: &mut ViewContext<Self>,
// ) -> Option<Task<Result<()>>> {
// if self.items.is_empty() {
// return None;
// } // }
// pub fn close_inactive_items( // let active_item_id = self.items[self.active_item_index].id();
// &mut self, // Some(self.close_items(cx, SaveIntent::Close, move |item_id| {
// _: &CloseInactiveItems, // item_id != active_item_id
// cx: &mut ViewContext<Self>, // }))
// ) -> Option<Task<Result<()>>> { // }
// if self.items.is_empty() {
// return None;
// }
// let active_item_id = self.items[self.active_item_index].id(); // pub fn close_clean_items(
// Some(self.close_items(cx, SaveIntent::Close, move |item_id| { // &mut self,
// item_id != active_item_id // _: &CloseCleanItems,
// })) // cx: &mut ViewContext<Self>,
// ) -> Option<Task<Result<()>>> {
// let item_ids: Vec<_> = self
// .items()
// .filter(|item| !item.is_dirty(cx))
// .map(|item| item.id())
// .collect();
// Some(self.close_items(cx, SaveIntent::Close, move |item_id| {
// item_ids.contains(&item_id)
// }))
// }
// pub fn close_items_to_the_left(
// &mut self,
// _: &CloseItemsToTheLeft,
// cx: &mut ViewContext<Self>,
// ) -> Option<Task<Result<()>>> {
// if self.items.is_empty() {
// return None;
// }
// let active_item_id = self.items[self.active_item_index].id();
// Some(self.close_items_to_the_left_by_id(active_item_id, cx))
// }
// pub fn close_items_to_the_left_by_id(
// &mut self,
// item_id: usize,
// cx: &mut ViewContext<Self>,
// ) -> Task<Result<()>> {
// let item_ids: Vec<_> = self
// .items()
// .take_while(|item| item.id() != item_id)
// .map(|item| item.id())
// .collect();
// self.close_items(cx, SaveIntent::Close, move |item_id| {
// item_ids.contains(&item_id)
// })
// }
// pub fn close_items_to_the_right(
// &mut self,
// _: &CloseItemsToTheRight,
// cx: &mut ViewContext<Self>,
// ) -> Option<Task<Result<()>>> {
// if self.items.is_empty() {
// return None;
// }
// let active_item_id = self.items[self.active_item_index].id();
// Some(self.close_items_to_the_right_by_id(active_item_id, cx))
// }
// pub fn close_items_to_the_right_by_id(
// &mut self,
// item_id: usize,
// cx: &mut ViewContext<Self>,
// ) -> Task<Result<()>> {
// let item_ids: Vec<_> = self
// .items()
// .rev()
// .take_while(|item| item.id() != item_id)
// .map(|item| item.id())
// .collect();
// self.close_items(cx, SaveIntent::Close, move |item_id| {
// item_ids.contains(&item_id)
// })
// }
// pub fn close_all_items(
// &mut self,
// action: &CloseAllItems,
// cx: &mut ViewContext<Self>,
// ) -> Option<Task<Result<()>>> {
// if self.items.is_empty() {
// return None;
// } // }
// pub fn close_clean_items( // Some(
// &mut self, // self.close_items(cx, action.save_intent.unwrap_or(SaveIntent::Close), |_| {
// _: &CloseCleanItems, // true
// cx: &mut ViewContext<Self>, // }),
// ) -> Option<Task<Result<()>>> { // )
// let item_ids: Vec<_> = self // }
// .items()
// .filter(|item| !item.is_dirty(cx))
// .map(|item| item.id())
// .collect();
// Some(self.close_items(cx, SaveIntent::Close, move |item_id| {
// item_ids.contains(&item_id)
// }))
// }
// pub fn close_items_to_the_left(
// &mut self,
// _: &CloseItemsToTheLeft,
// cx: &mut ViewContext<Self>,
// ) -> Option<Task<Result<()>>> {
// if self.items.is_empty() {
// return None;
// }
// let active_item_id = self.items[self.active_item_index].id();
// Some(self.close_items_to_the_left_by_id(active_item_id, cx))
// }
// pub fn close_items_to_the_left_by_id(
// &mut self,
// item_id: usize,
// cx: &mut ViewContext<Self>,
// ) -> Task<Result<()>> {
// let item_ids: Vec<_> = self
// .items()
// .take_while(|item| item.id() != item_id)
// .map(|item| item.id())
// .collect();
// self.close_items(cx, SaveIntent::Close, move |item_id| {
// item_ids.contains(&item_id)
// })
// }
// pub fn close_items_to_the_right(
// &mut self,
// _: &CloseItemsToTheRight,
// cx: &mut ViewContext<Self>,
// ) -> Option<Task<Result<()>>> {
// if self.items.is_empty() {
// return None;
// }
// let active_item_id = self.items[self.active_item_index].id();
// Some(self.close_items_to_the_right_by_id(active_item_id, cx))
// }
// pub fn close_items_to_the_right_by_id(
// &mut self,
// item_id: usize,
// cx: &mut ViewContext<Self>,
// ) -> Task<Result<()>> {
// let item_ids: Vec<_> = self
// .items()
// .rev()
// .take_while(|item| item.id() != item_id)
// .map(|item| item.id())
// .collect();
// self.close_items(cx, SaveIntent::Close, move |item_id| {
// item_ids.contains(&item_id)
// })
// }
// pub fn close_all_items(
// &mut self,
// action: &CloseAllItems,
// cx: &mut ViewContext<Self>,
// ) -> Option<Task<Result<()>>> {
// if self.items.is_empty() {
// return None;
// }
// Some(
// self.close_items(cx, action.save_intent.unwrap_or(SaveIntent::Close), |_| {
// true
// }),
// )
// }
// pub(super) fn file_names_for_prompt( // pub(super) fn file_names_for_prompt(
// items: &mut dyn Iterator<Item = &Box<dyn ItemHandle>>, // items: &mut dyn Iterator<Item = &Box<dyn ItemHandle>>,
@ -1156,28 +1163,29 @@ impl Pane {
// Ok(true) // Ok(true)
// } // }
// fn can_autosave_item(item: &dyn ItemHandle, cx: &AppContext) -> bool { fn can_autosave_item(item: &dyn ItemHandle, cx: &AppContext) -> bool {
// let is_deleted = item.project_entry_ids(cx).is_empty(); let is_deleted = item.project_entry_ids(cx).is_empty();
// item.is_dirty(cx) && !item.has_conflict(cx) && item.can_save(cx) && !is_deleted item.is_dirty(cx) && !item.has_conflict(cx) && item.can_save(cx) && !is_deleted
// } }
// pub fn autosave_item( pub fn autosave_item(
// item: &dyn ItemHandle, item: &dyn ItemHandle,
// project: Model<Project>, project: Model<Project>,
// cx: &mut WindowContext, cx: &mut WindowContext,
// ) -> Task<Result<()>> { ) -> Task<Result<()>> {
// if Self::can_autosave_item(item, cx) { if Self::can_autosave_item(item, cx) {
// item.save(project, cx) item.save(project, cx)
// } else { } else {
// Task::ready(Ok(())) Task::ready(Ok(()))
// } }
// } }
// pub fn focus_active_item(&mut self, cx: &mut ViewContext<Self>) { pub fn focus_active_item(&mut self, cx: &mut ViewContext<Self>) {
// if let Some(active_item) = self.active_item() { todo!();
// cx.focus(active_item.as_any()); // if let Some(active_item) = self.active_item() {
// } // cx.focus(active_item.as_any());
// } // }
}
// pub fn split(&mut self, direction: SplitDirection, cx: &mut ViewContext<Self>) { // pub fn split(&mut self, direction: SplitDirection, cx: &mut ViewContext<Self>) {
// cx.emit(Event::Split(direction)); // cx.emit(Event::Split(direction));
@ -1979,7 +1987,7 @@ impl NavHistory {
cx: &AppContext, cx: &AppContext,
mut f: impl FnMut(&NavigationEntry, (ProjectPath, Option<PathBuf>)), mut f: impl FnMut(&NavigationEntry, (ProjectPath, Option<PathBuf>)),
) { ) {
let borrowed_history = self.0.borrow(); let borrowed_history = self.0.lock();
borrowed_history borrowed_history
.forward_stack .forward_stack
.iter() .iter()
@ -1990,7 +1998,7 @@ impl NavHistory {
borrowed_history.paths_by_item.get(&entry.item.id()) borrowed_history.paths_by_item.get(&entry.item.id())
{ {
f(entry, project_and_abs_path.clone()); f(entry, project_and_abs_path.clone());
} else if let Some(item) = entry.item.upgrade(cx) { } else if let Some(item) = entry.item.upgrade() {
if let Some(path) = item.project_path(cx) { if let Some(path) = item.project_path(cx) {
f(entry, (path, None)); f(entry, (path, None));
} }
@ -1999,23 +2007,23 @@ impl NavHistory {
} }
pub fn set_mode(&mut self, mode: NavigationMode) { pub fn set_mode(&mut self, mode: NavigationMode) {
self.0.borrow_mut().mode = mode; self.0.lock().mode = mode;
} }
pub fn mode(&self) -> NavigationMode { pub fn mode(&self) -> NavigationMode {
self.0.borrow().mode self.0.lock().mode
} }
pub fn disable(&mut self) { pub fn disable(&mut self) {
self.0.borrow_mut().mode = NavigationMode::Disabled; self.0.lock().mode = NavigationMode::Disabled;
} }
pub fn enable(&mut self) { pub fn enable(&mut self) {
self.0.borrow_mut().mode = NavigationMode::Normal; self.0.lock().mode = NavigationMode::Normal;
} }
pub fn pop(&mut self, mode: NavigationMode, cx: &mut WindowContext) -> Option<NavigationEntry> { pub fn pop(&mut self, mode: NavigationMode, cx: &mut WindowContext) -> Option<NavigationEntry> {
let mut state = self.0.borrow_mut(); let mut state = self.0.lock();
let entry = match mode { let entry = match mode {
NavigationMode::Normal | NavigationMode::Disabled | NavigationMode::ClosingItem => { NavigationMode::Normal | NavigationMode::Disabled | NavigationMode::ClosingItem => {
return None return None
@ -2034,10 +2042,10 @@ impl NavHistory {
pub fn push<D: 'static + Any>( pub fn push<D: 'static + Any>(
&mut self, &mut self,
data: Option<D>, data: Option<D>,
item: Rc<dyn WeakItemHandle>, item: Arc<dyn WeakItemHandle>,
cx: &mut WindowContext, cx: &mut WindowContext,
) { ) {
let state = &mut *self.0.borrow_mut(); let state = &mut *self.0.lock();
match state.mode { match state.mode {
NavigationMode::Disabled => {} NavigationMode::Disabled => {}
NavigationMode::Normal | NavigationMode::ReopeningClosedItem => { NavigationMode::Normal | NavigationMode::ReopeningClosedItem => {
@ -2086,7 +2094,7 @@ impl NavHistory {
} }
pub fn remove_item(&mut self, item_id: usize) { pub fn remove_item(&mut self, item_id: usize) {
let mut state = self.0.borrow_mut(); let mut state = self.0.lock();
state.paths_by_item.remove(&item_id); state.paths_by_item.remove(&item_id);
state state
.backward_stack .backward_stack
@ -2100,19 +2108,19 @@ impl NavHistory {
} }
pub fn path_for_item(&self, item_id: usize) -> Option<(ProjectPath, Option<PathBuf>)> { pub fn path_for_item(&self, item_id: usize) -> Option<(ProjectPath, Option<PathBuf>)> {
self.0.borrow().paths_by_item.get(&item_id).cloned() self.0.lock().paths_by_item.get(&item_id).cloned()
} }
} }
// impl NavHistoryState { impl NavHistoryState {
// pub fn did_update(&self, cx: &mut WindowContext) { pub fn did_update(&self, cx: &mut WindowContext) {
// if let Some(pane) = self.pane.upgrade(cx) { if let Some(pane) = self.pane.upgrade() {
// cx.defer(move |cx| { cx.defer(move |cx| {
// pane.update(cx, |pane, cx| pane.history_updated(cx)); pane.update(cx, |pane, cx| pane.history_updated(cx));
// }); });
// } }
// } }
// } }
// pub struct PaneBackdrop<V> { // pub struct PaneBackdrop<V> {
// child_view: usize, // child_view: usize,

View file

@ -1,7 +1,7 @@
use crate::ItemHandle; use crate::ItemHandle;
use gpui2::{AppContext, EventEmitter, View, ViewContext, WindowContext}; use gpui2::{AnyView, AppContext, EventEmitter, Render, View, ViewContext, WindowContext};
pub trait ToolbarItemView: EventEmitter + Sized { pub trait ToolbarItemView: Render + EventEmitter {
fn set_active_pane_item( fn set_active_pane_item(
&mut self, &mut self,
active_pane_item: Option<&dyn crate::ItemHandle>, active_pane_item: Option<&dyn crate::ItemHandle>,
@ -22,14 +22,14 @@ pub trait ToolbarItemView: EventEmitter + Sized {
/// Number of times toolbar's height will be repeated to get the effective height. /// Number of times toolbar's height will be repeated to get the effective height.
/// Useful when multiple rows one under each other are needed. /// Useful when multiple rows one under each other are needed.
/// The rows have the same width and act as a whole when reacting to resizes and similar events. /// The rows have the same width and act as a whole when reacting to resizes and similar events.
fn row_count(&self, _cx: &ViewContext<Self>) -> usize { fn row_count(&self, _cx: &WindowContext) -> usize {
1 1
} }
} }
trait ToolbarItemViewHandle { trait ToolbarItemViewHandle: Send {
fn id(&self) -> usize; fn id(&self) -> usize;
// fn as_any(&self) -> &AnyViewHandle; todo!() fn to_any(&self) -> AnyView;
fn set_active_pane_item( fn set_active_pane_item(
&self, &self,
active_pane_item: Option<&dyn ItemHandle>, active_pane_item: Option<&dyn ItemHandle>,
@ -249,7 +249,7 @@ impl Toolbar {
pub fn item_of_type<T: ToolbarItemView>(&self) -> Option<View<T>> { pub fn item_of_type<T: ToolbarItemView>(&self) -> Option<View<T>> {
self.items self.items
.iter() .iter()
.find_map(|(item, _)| item.as_any().clone().downcast()) .find_map(|(item, _)| item.to_any().downcast().ok())
} }
pub fn hidden(&self) -> bool { pub fn hidden(&self) -> bool {
@ -262,10 +262,9 @@ impl<T: ToolbarItemView> ToolbarItemViewHandle for View<T> {
self.id() self.id()
} }
// todo!() fn to_any(&self) -> AnyView {
// fn as_any(&self) -> &AnyViewHandle { self.clone().into_any()
// self }
// }
fn set_active_pane_item( fn set_active_pane_item(
&self, &self,
@ -285,7 +284,7 @@ impl<T: ToolbarItemView> ToolbarItemViewHandle for View<T> {
} }
fn row_count(&self, cx: &WindowContext) -> usize { fn row_count(&self, cx: &WindowContext) -> usize {
self.read_with(cx, |this, cx| this.row_count(cx)) self.read(cx).row_count(cx)
} }
} }

View file

@ -36,6 +36,10 @@ use std::{
pub use toolbar::{ToolbarItemLocation, ToolbarItemView}; pub use toolbar::{ToolbarItemLocation, ToolbarItemView};
use util::ResultExt; use util::ResultExt;
use crate::persistence::model::{
DockStructure, SerializedItem, SerializedPane, SerializedPaneGroup,
};
// lazy_static! { // lazy_static! {
// static ref ZED_WINDOW_SIZE: Option<Vector2F> = env::var("ZED_WINDOW_SIZE") // static ref ZED_WINDOW_SIZE: Option<Vector2F> = env::var("ZED_WINDOW_SIZE")
// .ok() // .ok()
@ -514,9 +518,9 @@ pub struct Workspace {
// zoomed: Option<AnyWeakViewHandle>, // zoomed: Option<AnyWeakViewHandle>,
// zoomed_position: Option<DockPosition>, // zoomed_position: Option<DockPosition>,
// center: PaneGroup, // center: PaneGroup,
// left_dock: View<Dock>, left_dock: View<Dock>,
// bottom_dock: View<Dock>, bottom_dock: View<Dock>,
// right_dock: View<Dock>, right_dock: View<Dock>,
panes: Vec<View<Pane>>, panes: Vec<View<Pane>>,
panes_by_item: HashMap<usize, WeakView<Pane>>, panes_by_item: HashMap<usize, WeakView<Pane>>,
// active_pane: View<Pane>, // active_pane: View<Pane>,
@ -526,8 +530,8 @@ pub struct Workspace {
// titlebar_item: Option<AnyViewHandle>, // titlebar_item: Option<AnyViewHandle>,
// notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>, // notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>,
project: Model<Project>, project: Model<Project>,
// follower_states: HashMap<View<Pane>, FollowerState>, follower_states: HashMap<View<Pane>, FollowerState>,
// last_leaders_by_pane: HashMap<WeakView<Pane>, PeerId>, last_leaders_by_pane: HashMap<WeakView<Pane>, PeerId>,
// window_edited: bool, // window_edited: bool,
// active_call: Option<(ModelHandle<ActiveCall>, Vec<Subscription>)>, // active_call: Option<(ModelHandle<ActiveCall>, Vec<Subscription>)>,
// leader_updates_tx: mpsc::UnboundedSender<(PeerId, proto::UpdateFollowers)>, // leader_updates_tx: mpsc::UnboundedSender<(PeerId, proto::UpdateFollowers)>,
@ -2613,37 +2617,33 @@ impl Workspace {
// self.start_following(leader_id, cx) // self.start_following(leader_id, cx)
// } // }
// pub fn unfollow( pub fn unfollow(&mut self, pane: &View<Pane>, cx: &mut ViewContext<Self>) -> Option<PeerId> {
// &mut self, let state = self.follower_states.remove(pane)?;
// pane: &View<Pane>, let leader_id = state.leader_id;
// cx: &mut ViewContext<Self>, for (_, item) in state.items_by_leader_view_id {
// ) -> Option<PeerId> { item.set_leader_peer_id(None, cx);
// let state = self.follower_states.remove(pane)?; }
// let leader_id = state.leader_id;
// for (_, item) in state.items_by_leader_view_id {
// item.set_leader_peer_id(None, cx);
// }
// if self if self
// .follower_states .follower_states
// .values() .values()
// .all(|state| state.leader_id != state.leader_id) .all(|state| state.leader_id != state.leader_id)
// { {
// let project_id = self.project.read(cx).remote_id(); let project_id = self.project.read(cx).remote_id();
// let room_id = self.active_call()?.read(cx).room()?.read(cx).id(); let room_id = self.active_call()?.read(cx).room()?.read(cx).id();
// self.app_state self.app_state
// .client .client
// .send(proto::Unfollow { .send(proto::Unfollow {
// room_id, room_id,
// project_id, project_id,
// leader_id: Some(leader_id), leader_id: Some(leader_id),
// }) })
// .log_err(); .log_err();
// } }
// cx.notify(); cx.notify();
// Some(leader_id) Some(leader_id)
// } }
// pub fn is_being_followed(&self, peer_id: PeerId) -> bool { // pub fn is_being_followed(&self, peer_id: PeerId) -> bool {
// self.follower_states // self.follower_states
@ -3210,137 +3210,134 @@ impl Workspace {
// })); // }));
// } // }
// fn serialize_workspace(&self, cx: &ViewContext<Self>) { fn serialize_workspace(&self, cx: &ViewContext<Self>) {
// fn serialize_pane_handle( fn serialize_pane_handle(pane_handle: &View<Pane>, cx: &AppContext) -> SerializedPane {
// pane_handle: &View<Pane>, let (items, active) = {
// cx: &AppContext, let pane = pane_handle.read(cx);
// ) -> SerializedPane { let active_item_id = pane.active_item().map(|item| item.id());
// let (items, active) = { (
// let pane = pane_handle.read(cx); pane.items()
// let active_item_id = pane.active_item().map(|item| item.id()); .filter_map(|item_handle| {
// ( Some(SerializedItem {
// pane.items() kind: Arc::from(item_handle.serialized_item_kind()?),
// .filter_map(|item_handle| { item_id: item_handle.id(),
// Some(SerializedItem { active: Some(item_handle.id()) == active_item_id,
// kind: Arc::from(item_handle.serialized_item_kind()?), })
// item_id: item_handle.id(), })
// active: Some(item_handle.id()) == active_item_id, .collect::<Vec<_>>(),
// }) pane.has_focus(),
// }) )
// .collect::<Vec<_>>(), };
// pane.has_focus(),
// )
// };
// SerializedPane::new(items, active) SerializedPane::new(items, active)
// } }
// fn build_serialized_pane_group( fn build_serialized_pane_group(
// pane_group: &Member, pane_group: &Member,
// cx: &AppContext, cx: &AppContext,
// ) -> SerializedPaneGroup { ) -> SerializedPaneGroup {
// match pane_group { match pane_group {
// Member::Axis(PaneAxis { Member::Axis(PaneAxis {
// axis, axis,
// members, members,
// flexes, flexes,
// bounding_boxes: _, bounding_boxes: _,
// }) => SerializedPaneGroup::Group { }) => SerializedPaneGroup::Group {
// axis: *axis, axis: *axis,
// children: members children: members
// .iter() .iter()
// .map(|member| build_serialized_pane_group(member, cx)) .map(|member| build_serialized_pane_group(member, cx))
// .collect::<Vec<_>>(), .collect::<Vec<_>>(),
// flexes: Some(flexes.borrow().clone()), flexes: Some(flexes.borrow().clone()),
// }, },
// Member::Pane(pane_handle) => { Member::Pane(pane_handle) => {
// SerializedPaneGroup::Pane(serialize_pane_handle(&pane_handle, cx)) SerializedPaneGroup::Pane(serialize_pane_handle(&pane_handle, cx))
// } }
// } }
// } }
// fn build_serialized_docks(this: &Workspace, cx: &ViewContext<Workspace>) -> DockStructure { fn build_serialized_docks(this: &Workspace, cx: &ViewContext<Workspace>) -> DockStructure {
// let left_dock = this.left_dock.read(cx); let left_dock = this.left_dock.read(cx);
// let left_visible = left_dock.is_open(); let left_visible = left_dock.is_open();
// let left_active_panel = left_dock.visible_panel().and_then(|panel| { let left_active_panel = left_dock.visible_panel().and_then(|panel| {
// Some( Some(
// cx.view_ui_name(panel.as_any().window(), panel.id())? cx.view_ui_name(panel.as_any().window(), panel.id())?
// .to_string(), .to_string(),
// ) )
// }); });
// let left_dock_zoom = left_dock let left_dock_zoom = left_dock
// .visible_panel() .visible_panel()
// .map(|panel| panel.is_zoomed(cx)) .map(|panel| panel.is_zoomed(cx))
// .unwrap_or(false); .unwrap_or(false);
// let right_dock = this.right_dock.read(cx); let right_dock = this.right_dock.read(cx);
// let right_visible = right_dock.is_open(); let right_visible = right_dock.is_open();
// let right_active_panel = right_dock.visible_panel().and_then(|panel| { let right_active_panel = right_dock.visible_panel().and_then(|panel| {
// Some( Some(
// cx.view_ui_name(panel.as_any().window(), panel.id())? cx.view_ui_name(panel.as_any().window(), panel.id())?
// .to_string(), .to_string(),
// ) )
// }); });
// let right_dock_zoom = right_dock let right_dock_zoom = right_dock
// .visible_panel() .visible_panel()
// .map(|panel| panel.is_zoomed(cx)) .map(|panel| panel.is_zoomed(cx))
// .unwrap_or(false); .unwrap_or(false);
// let bottom_dock = this.bottom_dock.read(cx); let bottom_dock = this.bottom_dock.read(cx);
// let bottom_visible = bottom_dock.is_open(); let bottom_visible = bottom_dock.is_open();
// let bottom_active_panel = bottom_dock.visible_panel().and_then(|panel| { let bottom_active_panel = bottom_dock.visible_panel().and_then(|panel| {
// Some( Some(
// cx.view_ui_name(panel.as_any().window(), panel.id())? cx.view_ui_name(panel.as_any().window(), panel.id())?
// .to_string(), .to_string(),
// ) )
// }); });
// let bottom_dock_zoom = bottom_dock let bottom_dock_zoom = bottom_dock
// .visible_panel() .visible_panel()
// .map(|panel| panel.is_zoomed(cx)) .map(|panel| panel.is_zoomed(cx))
// .unwrap_or(false); .unwrap_or(false);
// DockStructure { DockStructure {
// left: DockData { left: DockData {
// visible: left_visible, visible: left_visible,
// active_panel: left_active_panel, active_panel: left_active_panel,
// zoom: left_dock_zoom, zoom: left_dock_zoom,
// }, },
// right: DockData { right: DockData {
// visible: right_visible, visible: right_visible,
// active_panel: right_active_panel, active_panel: right_active_panel,
// zoom: right_dock_zoom, zoom: right_dock_zoom,
// }, },
// bottom: DockData { bottom: DockData {
// visible: bottom_visible, visible: bottom_visible,
// active_panel: bottom_active_panel, active_panel: bottom_active_panel,
// zoom: bottom_dock_zoom, zoom: bottom_dock_zoom,
// }, },
// } }
// } }
// if let Some(location) = self.location(cx) { if let Some(location) = self.location(cx) {
// // Load bearing special case: // Load bearing special case:
// // - with_local_workspace() relies on this to not have other stuff open // - with_local_workspace() relies on this to not have other stuff open
// // when you open your log // when you open your log
// if !location.paths().is_empty() { if !location.paths().is_empty() {
// let center_group = build_serialized_pane_group(&self.center.root, cx); let center_group = build_serialized_pane_group(&self.center.root, cx);
// let docks = build_serialized_docks(self, cx); let docks = build_serialized_docks(self, cx);
// let serialized_workspace = SerializedWorkspace { let serialized_workspace = SerializedWorkspace {
// id: self.database_id, id: self.database_id,
// location, location,
// center_group, center_group,
// bounds: Default::default(), bounds: Default::default(),
// display: Default::default(), display: Default::default(),
// docks, docks,
// }; };
// cx.background() cx.background()
// .spawn(persistence::DB.save_workspace(serialized_workspace)) .spawn(persistence::DB.save_workspace(serialized_workspace))
// .detach(); .detach();
// } }
// } }
// } }
// pub(crate) fn load_workspace( // pub(crate) fn load_workspace(
// workspace: WeakView<Workspace>, // workspace: WeakView<Workspace>,