This commit is contained in:
Antonio Scandurra 2023-10-30 16:43:01 +01:00
parent d4d9fcc88c
commit 89bcbe3eeb
8 changed files with 1504 additions and 1493 deletions

View file

@ -8,6 +8,7 @@ use client2::{
proto::{self, PeerId, ViewId}, proto::{self, PeerId, ViewId},
Client, Client,
}; };
use settings2::Settings;
use theme2::Theme; use theme2::Theme;
// use client2::{ // use client2::{
// proto::{self, PeerId}, // proto::{self, PeerId},
@ -16,8 +17,8 @@ use theme2::Theme;
// use gpui2::geometry::vector::Vector2F; // use gpui2::geometry::vector::Vector2F;
// use gpui2::AnyWindowHandle; // use gpui2::AnyWindowHandle;
// use gpui2::{ // use gpui2::{
// fonts::HighlightStyle, AnyElement, AnyViewHandle, AppContext, ModelHandle, Task, View, // fonts::HighlightStyle, AnyElement, AnyViewHandle, AppContext, Handle, Task, View,
// ViewContext, ViewHandle, WeakViewHandle, WindowContext, // ViewContext, View, WeakViewHandle, WindowContext,
// }; // };
// use project2::{Project, ProjectEntryId, ProjectPath}; // use project2::{Project, ProjectEntryId, ProjectPath};
// use schemars::JsonSchema; // use schemars::JsonSchema;
@ -97,7 +98,7 @@ pub struct BreadcrumbText {
pub highlights: Option<Vec<(Range<usize>, HighlightStyle)>>, pub highlights: Option<Vec<(Range<usize>, HighlightStyle)>>,
} }
pub trait Item: EventEmitter { pub trait Item: EventEmitter + Sized {
// fn deactivated(&mut self, _: &mut ViewContext<Self>) {} // fn deactivated(&mut self, _: &mut ViewContext<Self>) {}
// fn workspace_deactivated(&mut self, _: &mut ViewContext<Self>) {} // fn workspace_deactivated(&mut self, _: &mut ViewContext<Self>) {}
// fn navigate(&mut self, _: Box<dyn Any>, _: &mut ViewContext<Self>) -> bool { // fn navigate(&mut self, _: Box<dyn Any>, _: &mut ViewContext<Self>) -> bool {
@ -138,14 +139,14 @@ pub trait Item: EventEmitter {
// } // }
// fn save( // fn save(
// &mut self, // &mut self,
// _project: ModelHandle<Project>, // _project: Handle<Project>,
// _cx: &mut ViewContext<Self>, // _cx: &mut ViewContext<Self>,
// ) -> Task<Result<()>> { // ) -> Task<Result<()>> {
// unimplemented!("save() must be implemented if can_save() returns true") // unimplemented!("save() must be implemented if can_save() returns true")
// } // }
// fn save_as( // fn save_as(
// &mut self, // &mut self,
// _project: ModelHandle<Project>, // _project: Handle<Project>,
// _abs_path: PathBuf, // _abs_path: PathBuf,
// _cx: &mut ViewContext<Self>, // _cx: &mut ViewContext<Self>,
// ) -> Task<Result<()>> { // ) -> Task<Result<()>> {
@ -153,7 +154,7 @@ pub trait Item: EventEmitter {
// } // }
// fn reload( // fn reload(
// &mut self, // &mut self,
// _project: ModelHandle<Project>, // _project: Handle<Project>,
// _cx: &mut ViewContext<Self>, // _cx: &mut ViewContext<Self>,
// ) -> Task<Result<()>> { // ) -> Task<Result<()>> {
// unimplemented!("reload() must be implemented if can_save() returns true") // unimplemented!("reload() must be implemented if can_save() returns true")
@ -171,7 +172,7 @@ pub trait Item: EventEmitter {
// fn act_as_type<'a>( // fn act_as_type<'a>(
// &'a self, // &'a self,
// type_id: TypeId, // type_id: TypeId,
// self_handle: &'a ViewHandle<Self>, // self_handle: &'a View<Self>,
// _: &'a AppContext, // _: &'a AppContext,
// ) -> Option<&AnyViewHandle> { // ) -> Option<&AnyViewHandle> {
// if TypeId::of::<Self>() == type_id { // if TypeId::of::<Self>() == type_id {
@ -181,7 +182,7 @@ pub trait Item: EventEmitter {
// } // }
// } // }
// fn as_searchable(&self, _: &ViewHandle<Self>) -> Option<Box<dyn SearchableItemHandle>> { // fn as_searchable(&self, _: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {
// None // None
// } // }
@ -200,12 +201,12 @@ pub trait Item: EventEmitter {
// } // }
// fn deserialize( // fn deserialize(
// _project: ModelHandle<Project>, // _project: Handle<Project>,
// _workspace: WeakViewHandle<Workspace>, // _workspace: WeakViewHandle<Workspace>,
// _workspace_id: WorkspaceId, // _workspace_id: WorkspaceId,
// _item_id: ItemId, // _item_id: ItemId,
// _cx: &mut ViewContext<Pane>, // _cx: &mut ViewContext<Pane>,
// ) -> Task<Result<ViewHandle<Self>>> { // ) -> Task<Result<View<Self>>> {
// unimplemented!( // unimplemented!(
// "deserialize() must be implemented if serialized_item_kind() returns Some(_)" // "deserialize() must be implemented if serialized_item_kind() returns Some(_)"
// ) // )
@ -218,27 +219,36 @@ pub trait Item: EventEmitter {
// } // }
} }
use core::fmt;
use std::{ use std::{
any::{Any, TypeId}, any::Any,
borrow::Cow, borrow::Cow,
cell::RefCell,
ops::Range, ops::Range,
path::PathBuf, path::PathBuf,
sync::Arc, rc::Rc,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
time::Duration,
}; };
use gpui2::{ use gpui2::{
AnyElement, AnyView, AnyWindowHandle, AppContext, EventEmitter, Handle, HighlightStyle, Pixels, AnyElement, AnyWindowHandle, AppContext, EventEmitter, Handle, HighlightStyle, Pixels, Point,
Point, Task, View, ViewContext, WindowContext, Task, View, ViewContext, WindowContext,
}; };
use project2::{Project, ProjectEntryId, ProjectPath}; use project2::{Project, ProjectEntryId, ProjectPath};
use smallvec::SmallVec; use smallvec::SmallVec;
use crate::{ use crate::{
pane::Pane, searchable::SearchableItemHandle, ToolbarItemLocation, Workspace, WorkspaceId, pane::{self, Pane},
searchable::SearchableItemHandle,
workspace_settings::{AutosaveSetting, WorkspaceSettings},
DelayedDebouncedEditAction, FollowableItemBuilders, ToolbarItemLocation, Workspace,
WorkspaceId,
}; };
pub trait ItemHandle: 'static + fmt::Debug + Send { pub trait ItemHandle: 'static + Send {
fn subscribe_to_item_events( fn subscribe_to_item_events(
&self, &self,
cx: &mut WindowContext, cx: &mut WindowContext,
@ -305,355 +315,347 @@ pub trait WeakItemHandle {
// todo!() // todo!()
// impl dyn ItemHandle { // impl dyn ItemHandle {
// pub fn downcast<T: View>(&self) -> Option<ViewHandle<T>> { // pub fn downcast<T: View>(&self) -> Option<View<T>> {
// self.as_any().clone().downcast() // self.as_any().clone().downcast()
// } // }
// pub fn act_as<T: View>(&self, cx: &AppContext) -> Option<ViewHandle<T>> { // pub fn act_as<T: View>(&self, cx: &AppContext) -> Option<View<T>> {
// self.act_as_type(TypeId::of::<T>(), cx) // self.act_as_type(TypeId::of::<T>(), cx)
// .and_then(|t| t.clone().downcast()) // .and_then(|t| t.clone().downcast())
// } // }
// } // }
// impl<T: Item> ItemHandle for ViewHandle<T> { impl<T: Item> ItemHandle for View<T> {
// fn subscribe_to_item_events( fn subscribe_to_item_events(
// &self, &self,
// cx: &mut WindowContext, cx: &mut WindowContext,
// handler: Box<dyn Fn(ItemEvent, &mut WindowContext)>, handler: Box<dyn Fn(ItemEvent, &mut WindowContext)>,
// ) -> gpui2::Subscription { ) -> gpui2::Subscription {
// cx.subscribe(self, move |_, event, cx| { cx.subscribe(self, move |_, event, cx| {
// for item_event in T::to_item_events(event) { for item_event in T::to_item_events(event) {
// handler(item_event, cx) handler(item_event, cx)
// } }
// }) })
// } }
// fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option<Cow<'a, str>> { fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option<Cow<'a, str>> {
// self.read(cx).tab_tooltip_text(cx) self.read(cx).tab_tooltip_text(cx)
// } }
// fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option<Cow<'a, str>> { fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option<Cow<'a, str>> {
// self.read(cx).tab_description(detail, cx) self.read(cx).tab_description(detail, cx)
// } }
// fn tab_content( fn tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Pane> {
// &self, self.read(cx).tab_content(detail, cx)
// detail: Option<usize>, }
// style: &theme2::Tab,
// cx: &AppContext,
// ) -> AnyElement<Pane> {
// self.read(cx).tab_content(detail, style, cx)
// }
// fn dragged_tab_content( fn dragged_tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Workspace> {
// &self, self.read(cx).tab_content(detail, cx)
// detail: Option<usize>, }
// style: &theme2::Tab,
// cx: &AppContext,
// ) -> AnyElement<Workspace> {
// self.read(cx).tab_content(detail, style, cx)
// }
// fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> { fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
// let this = self.read(cx); let this = self.read(cx);
// let mut result = None; let mut result = None;
// if this.is_singleton(cx) { if this.is_singleton(cx) {
// this.for_each_project_item(cx, &mut |_, item| { this.for_each_project_item(cx, &mut |_, item| {
// result = item.project_path(cx); result = item.project_path(cx);
// }); });
// } }
// result result
// } }
// fn project_entry_ids(&self, cx: &AppContext) -> SmallVec<[ProjectEntryId; 3]> { fn project_entry_ids(&self, cx: &AppContext) -> SmallVec<[ProjectEntryId; 3]> {
// let mut result = SmallVec::new(); let mut result = SmallVec::new();
// self.read(cx).for_each_project_item(cx, &mut |_, item| { self.read(cx).for_each_project_item(cx, &mut |_, item| {
// if let Some(id) = item.entry_id(cx) { if let Some(id) = item.entry_id(cx) {
// result.push(id); result.push(id);
// } }
// }); });
// result result
// } }
// fn project_item_model_ids(&self, cx: &AppContext) -> SmallVec<[usize; 3]> { fn project_item_model_ids(&self, cx: &AppContext) -> SmallVec<[usize; 3]> {
// let mut result = SmallVec::new(); let mut result = SmallVec::new();
// self.read(cx).for_each_project_item(cx, &mut |id, _| { self.read(cx).for_each_project_item(cx, &mut |id, _| {
// result.push(id); result.push(id);
// }); });
// result result
// } }
// fn for_each_project_item( fn for_each_project_item(
// &self, &self,
// cx: &AppContext, cx: &AppContext,
// f: &mut dyn FnMut(usize, &dyn project2::Item), f: &mut dyn FnMut(usize, &dyn project2::Item),
// ) { ) {
// self.read(cx).for_each_project_item(cx, f) self.read(cx).for_each_project_item(cx, f)
// } }
// fn is_singleton(&self, cx: &AppContext) -> bool { fn is_singleton(&self, cx: &AppContext) -> bool {
// self.read(cx).is_singleton(cx) self.read(cx).is_singleton(cx)
// } }
// fn boxed_clone(&self) -> Box<dyn ItemHandle> { fn boxed_clone(&self) -> Box<dyn ItemHandle> {
// Box::new(self.clone()) Box::new(self.clone())
// } }
// fn clone_on_split( fn clone_on_split(
// &self, &self,
// workspace_id: WorkspaceId, workspace_id: WorkspaceId,
// cx: &mut WindowContext, cx: &mut WindowContext,
// ) -> Option<Box<dyn ItemHandle>> { ) -> Option<Box<dyn ItemHandle>> {
// self.update(cx, |item, cx| { self.update(cx, |item, cx| {
// cx.add_option_view(|cx| item.clone_on_split(workspace_id, cx)) cx.add_option_view(|cx| item.clone_on_split(workspace_id, cx))
// }) })
// .map(|handle| Box::new(handle) as Box<dyn ItemHandle>) .map(|handle| Box::new(handle) as Box<dyn ItemHandle>)
// } }
// fn added_to_pane( fn added_to_pane(
// &self, &self,
// workspace: &mut Workspace, workspace: &mut Workspace,
// pane: ViewHandle<Pane>, pane: View<Pane>,
// cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
// ) { ) {
// let history = pane.read(cx).nav_history_for_item(self); let history = pane.read(cx).nav_history_for_item(self);
// self.update(cx, |this, cx| { self.update(cx, |this, cx| {
// this.set_nav_history(history, cx); this.set_nav_history(history, cx);
// this.added_to_workspace(workspace, cx); this.added_to_workspace(workspace, cx);
// }); });
// if let Some(followed_item) = self.to_followable_item_handle(cx) { if let Some(followed_item) = self.to_followable_item_handle(cx) {
// if let Some(message) = followed_item.to_state_proto(cx) { if let Some(message) = followed_item.to_state_proto(cx) {
// workspace.update_followers( workspace.update_followers(
// followed_item.is_project_item(cx), followed_item.is_project_item(cx),
// proto::update_followers::Variant::CreateView(proto::View { proto::update_followers::Variant::CreateView(proto::View {
// id: followed_item id: followed_item
// .remote_id(&workspace.app_state.client, cx) .remote_id(&workspace.app_state.client, cx)
// .map(|id| id.to_proto()), .map(|id| id.to_proto()),
// variant: Some(message), variant: Some(message),
// leader_id: workspace.leader_for_pane(&pane), leader_id: workspace.leader_for_pane(&pane),
// }), }),
// cx, cx,
// ); );
// } }
// } }
// if workspace if workspace
// .panes_by_item .panes_by_item
// .insert(self.id(), pane.downgrade()) .insert(self.id(), pane.downgrade())
// .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 = Rc::new(RefCell::new(None));
// let pending_update_scheduled = Rc::new(AtomicBool::new(false)); let pending_update_scheduled = Rc::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| {
// let pane = if let Some(pane) = workspace let pane = if let Some(pane) = workspace
// .panes_by_item .panes_by_item
// .get(&item.id()) .get(&item.id())
// .and_then(|pane| pane.upgrade(cx)) .and_then(|pane| pane.upgrade(cx))
// { {
// pane pane
// } else { } else {
// log::error!("unexpected item event after pane was dropped"); log::error!("unexpected item event after pane was dropped");
// return; return;
// }; };
// if let Some(item) = item.to_followable_item_handle(cx) { if let Some(item) = item.to_followable_item_handle(cx) {
// let is_project_item = item.is_project_item(cx); let is_project_item = item.is_project_item(cx);
// let leader_id = workspace.leader_for_pane(&pane); let leader_id = workspace.leader_for_pane(&pane);
// if leader_id.is_some() && item.should_unfollow_on_event(event, cx) { if leader_id.is_some() && item.should_unfollow_on_event(event, cx) {
// workspace.unfollow(&pane, cx); workspace.unfollow(&pane, cx);
// } }
// if item.add_event_to_update_proto( if item.add_event_to_update_proto(
// event, event,
// &mut *pending_update.borrow_mut(), &mut *pending_update.borrow_mut(),
// cx, cx,
// ) && !pending_update_scheduled.load(Ordering::SeqCst) ) && !pending_update_scheduled.load(Ordering::SeqCst)
// { {
// pending_update_scheduled.store(true, Ordering::SeqCst); pending_update_scheduled.store(true, Ordering::SeqCst);
// cx.after_window_update({ cx.after_window_update({
// let pending_update = pending_update.clone(); let pending_update = pending_update.clone();
// let pending_update_scheduled = pending_update_scheduled.clone(); let pending_update_scheduled = pending_update_scheduled.clone();
// move |this, cx| { move |this, cx| {
// pending_update_scheduled.store(false, Ordering::SeqCst); pending_update_scheduled.store(false, Ordering::SeqCst);
// this.update_followers( this.update_followers(
// is_project_item, is_project_item,
// proto::update_followers::Variant::UpdateView( proto::update_followers::Variant::UpdateView(
// proto::UpdateView { proto::UpdateView {
// id: item id: item
// .remote_id(&this.app_state.client, cx) .remote_id(&this.app_state.client, cx)
// .map(|id| id.to_proto()), .map(|id| id.to_proto()),
// variant: pending_update.borrow_mut().take(), variant: pending_update.borrow_mut().take(),
// leader_id, leader_id,
// }, },
// ), ),
// cx, cx,
// ); );
// } }
// }); });
// } }
// } }
// for item_event in T::to_item_events(event).into_iter() { for item_event in T::to_item_events(event).into_iter() {
// match item_event { match item_event {
// ItemEvent::CloseItem => { ItemEvent::CloseItem => {
// pane.update(cx, |pane, cx| { pane.update(cx, |pane, cx| {
// pane.close_item_by_id(item.id(), crate::SaveIntent::Close, cx) pane.close_item_by_id(item.id(), crate::SaveIntent::Close, cx)
// }) })
// .detach_and_log_err(cx); .detach_and_log_err(cx);
// return; return;
// } }
// ItemEvent::UpdateTab => { ItemEvent::UpdateTab => {
// pane.update(cx, |_, cx| { pane.update(cx, |_, cx| {
// cx.emit(pane::Event::ChangeItemTitle); cx.emit(pane::Event::ChangeItemTitle);
// cx.notify(); cx.notify();
// }); });
// } }
// ItemEvent::Edit => { ItemEvent::Edit => {
// let autosave = settings2::get::<WorkspaceSettings>(cx).autosave; let autosave = WorkspaceSettings::get_global(cx).autosave;
// if let AutosaveSetting::AfterDelay { milliseconds } = autosave { if let AutosaveSetting::AfterDelay { milliseconds } = autosave {
// let delay = Duration::from_millis(milliseconds); let delay = Duration::from_millis(milliseconds);
// let item = item.clone(); let item = item.clone();
// pending_autosave.fire_new(delay, cx, move |workspace, cx| { pending_autosave.fire_new(delay, cx, move |workspace, cx| {
// Pane::autosave_item(&item, workspace.project().clone(), cx) Pane::autosave_item(&item, workspace.project().clone(), cx)
// }); });
// } }
// } }
// _ => {} _ => {}
// } }
// } }
// })); }));
// cx.observe_focus(self, move |workspace, item, focused, cx| { cx.observe_focus(self, move |workspace, item, focused, cx| {
// if !focused if !focused
// && settings2::get::<WorkspaceSettings>(cx).autosave && WorkspaceSettings::get_global(cx).autosave == AutosaveSetting::OnFocusChange
// == AutosaveSetting::OnFocusChange {
// { Pane::autosave_item(&item, workspace.project.clone(), cx)
// Pane::autosave_item(&item, workspace.project.clone(), cx) .detach_and_log_err(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, _, _| {
// workspace.panes_by_item.remove(&item_id); workspace.panes_by_item.remove(&item_id);
// event_subscription.take(); event_subscription.take();
// }) })
// .detach(); .detach();
// } }
// cx.defer(|workspace, cx| { cx.defer(|workspace, cx| {
// workspace.serialize_workspace(cx); workspace.serialize_workspace(cx);
// }); });
// } }
// fn deactivated(&self, cx: &mut WindowContext) { fn deactivated(&self, cx: &mut WindowContext) {
// self.update(cx, |this, cx| this.deactivated(cx)); self.update(cx, |this, cx| this.deactivated(cx));
// } }
// fn workspace_deactivated(&self, cx: &mut WindowContext) { fn workspace_deactivated(&self, cx: &mut WindowContext) {
// self.update(cx, |this, cx| this.workspace_deactivated(cx)); self.update(cx, |this, cx| this.workspace_deactivated(cx));
// } }
// fn navigate(&self, data: Box<dyn Any>, cx: &mut WindowContext) -> bool { fn navigate(&self, data: Box<dyn Any>, cx: &mut WindowContext) -> bool {
// self.update(cx, |this, cx| this.navigate(data, cx)) self.update(cx, |this, cx| this.navigate(data, cx))
// } }
// fn id(&self) -> usize { fn id(&self) -> usize {
// self.id() self.id()
// } }
// fn window(&self) -> AnyWindowHandle { fn window(&self) -> AnyWindowHandle {
// AnyViewHandle::window(self) todo!()
// } // AnyViewHandle::window(self)
}
// fn as_any(&self) -> &AnyViewHandle { // todo!()
// self // fn as_any(&self) -> &AnyViewHandle {
// } // self
// }
// fn is_dirty(&self, cx: &AppContext) -> bool { fn is_dirty(&self, cx: &AppContext) -> bool {
// self.read(cx).is_dirty(cx) self.read(cx).is_dirty(cx)
// } }
// fn has_conflict(&self, cx: &AppContext) -> bool { fn has_conflict(&self, cx: &AppContext) -> bool {
// self.read(cx).has_conflict(cx) self.read(cx).has_conflict(cx)
// } }
// fn can_save(&self, cx: &AppContext) -> bool { fn can_save(&self, cx: &AppContext) -> bool {
// self.read(cx).can_save(cx) self.read(cx).can_save(cx)
// } }
// fn save(&self, project: ModelHandle<Project>, cx: &mut WindowContext) -> Task<Result<()>> { fn save(&self, project: Handle<Project>, cx: &mut WindowContext) -> Task<Result<()>> {
// self.update(cx, |item, cx| item.save(project, cx)) self.update(cx, |item, cx| item.save(project, cx))
// } }
// fn save_as( fn save_as(
// &self, &self,
// project: ModelHandle<Project>, project: Handle<Project>,
// abs_path: PathBuf, abs_path: PathBuf,
// cx: &mut WindowContext, cx: &mut WindowContext,
// ) -> Task<anyhow::Result<()>> { ) -> Task<anyhow::Result<()>> {
// self.update(cx, |item, cx| item.save_as(project, abs_path, cx)) self.update(cx, |item, cx| item.save_as(project, abs_path, cx))
// } }
// fn reload(&self, project: ModelHandle<Project>, cx: &mut WindowContext) -> Task<Result<()>> { fn reload(&self, project: Handle<Project>, cx: &mut WindowContext) -> Task<Result<()>> {
// self.update(cx, |item, cx| item.reload(project, cx)) self.update(cx, |item, cx| item.reload(project, cx))
// } }
// fn act_as_type<'a>(&'a self, type_id: TypeId, cx: &'a AppContext) -> Option<&'a AnyViewHandle> { // todo!()
// self.read(cx).act_as_type(type_id, self, cx) // 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)
// }
// 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.as_any();
// Some(builders.get(&item.view_type())?.1(item)) Some(builders.get(&item.view_type())?.1(item))
// } else { } else {
// None None
// } }
// } }
// 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)>,
// ) -> gpui2::Subscription { ) -> gpui2::Subscription {
// cx.observe_release(self, move |_, cx| callback(cx)) cx.observe_release(self, move |_, cx| callback(cx))
// } }
// fn to_searchable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn SearchableItemHandle>> { fn to_searchable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn SearchableItemHandle>> {
// self.read(cx).as_searchable(self) self.read(cx).as_searchable(self)
// } }
// fn breadcrumb_location(&self, cx: &AppContext) -> ToolbarItemLocation { fn breadcrumb_location(&self, cx: &AppContext) -> ToolbarItemLocation {
// self.read(cx).breadcrumb_location() self.read(cx).breadcrumb_location()
// } }
// fn breadcrumbs(&self, theme: &Theme, cx: &AppContext) -> Option<Vec<BreadcrumbText>> { fn breadcrumbs(&self, theme: &Theme, cx: &AppContext) -> Option<Vec<BreadcrumbText>> {
// self.read(cx).breadcrumbs(theme, cx) self.read(cx).breadcrumbs(theme, cx)
// } }
// fn serialized_item_kind(&self) -> Option<&'static str> { fn serialized_item_kind(&self) -> Option<&'static str> {
// T::serialized_item_kind() T::serialized_item_kind()
// } }
// fn show_toolbar(&self, cx: &AppContext) -> bool { fn show_toolbar(&self, cx: &AppContext) -> bool {
// self.read(cx).show_toolbar() self.read(cx).show_toolbar()
// } }
// fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option<Vector2F> { fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option<Point<Pixels>> {
// self.read(cx).pixel_position_of_cursor(cx) self.read(cx).pixel_position_of_cursor(cx)
// } }
// } }
// impl From<Box<dyn ItemHandle>> for AnyViewHandle { // impl From<Box<dyn ItemHandle>> for AnyViewHandle {
// fn from(val: Box<dyn ItemHandle>) -> Self { // fn from(val: Box<dyn ItemHandle>) -> Self {
@ -747,7 +749,7 @@ pub trait FollowableItemHandle: ItemHandle {
fn is_project_item(&self, cx: &AppContext) -> bool; fn is_project_item(&self, cx: &AppContext) -> bool;
} }
// impl<T: FollowableItem> FollowableItemHandle for ViewHandle<T> { // impl<T: FollowableItem> FollowableItemHandle for View<T> {
// fn remote_id(&self, client: &Arc<Client>, cx: &AppContext) -> Option<ViewId> { // fn remote_id(&self, client: &Arc<Client>, cx: &AppContext) -> Option<ViewId> {
// self.read(cx).remote_id().or_else(|| { // self.read(cx).remote_id().or_else(|| {
// client.peer_id().map(|creator| ViewId { // client.peer_id().map(|creator| ViewId {
@ -780,7 +782,7 @@ pub trait FollowableItemHandle: ItemHandle {
// fn apply_update_proto( // fn apply_update_proto(
// &self, // &self,
// project: &ModelHandle<Project>, // project: &Handle<Project>,
// message: proto::update_view::Variant, // message: proto::update_view::Variant,
// cx: &mut WindowContext, // cx: &mut WindowContext,
// ) -> Task<Result<()>> { // ) -> Task<Result<()>> {
@ -805,8 +807,8 @@ pub trait FollowableItemHandle: ItemHandle {
// use super::{Item, ItemEvent}; // use super::{Item, ItemEvent};
// use crate::{ItemId, ItemNavHistory, Pane, Workspace, WorkspaceId}; // use crate::{ItemId, ItemNavHistory, Pane, Workspace, WorkspaceId};
// use gpui2::{ // use gpui2::{
// elements::Empty, AnyElement, AppContext, Element, Entity, ModelHandle, Task, View, // elements::Empty, AnyElement, AppContext, Element, Entity, Handle, Task, View,
// ViewContext, ViewHandle, WeakViewHandle, // ViewContext, View, WeakViewHandle,
// }; // };
// use project2::{Project, ProjectEntryId, ProjectPath, WorktreeId}; // use project2::{Project, ProjectEntryId, ProjectPath, WorktreeId};
// use smallvec::SmallVec; // use smallvec::SmallVec;
@ -827,7 +829,7 @@ pub trait FollowableItemHandle: ItemHandle {
// pub is_dirty: bool, // pub is_dirty: bool,
// pub is_singleton: bool, // pub is_singleton: bool,
// pub has_conflict: bool, // pub has_conflict: bool,
// pub project_items: Vec<ModelHandle<TestProjectItem>>, // pub project_items: Vec<Handle<TestProjectItem>>,
// pub nav_history: Option<ItemNavHistory>, // pub nav_history: Option<ItemNavHistory>,
// pub tab_descriptions: Option<Vec<&'static str>>, // pub tab_descriptions: Option<Vec<&'static str>>,
// pub tab_detail: Cell<Option<usize>>, // pub tab_detail: Cell<Option<usize>>,
@ -872,7 +874,7 @@ pub trait FollowableItemHandle: ItemHandle {
// } // }
// impl TestProjectItem { // impl TestProjectItem {
// pub fn new(id: u64, path: &str, cx: &mut AppContext) -> ModelHandle<Self> { // pub fn new(id: u64, path: &str, cx: &mut AppContext) -> Handle<Self> {
// let entry_id = Some(ProjectEntryId::from_proto(id)); // let entry_id = Some(ProjectEntryId::from_proto(id));
// let project_path = Some(ProjectPath { // let project_path = Some(ProjectPath {
// worktree_id: WorktreeId::from_usize(0), // worktree_id: WorktreeId::from_usize(0),
@ -884,7 +886,7 @@ pub trait FollowableItemHandle: ItemHandle {
// }) // })
// } // }
// pub fn new_untitled(cx: &mut AppContext) -> ModelHandle<Self> { // pub fn new_untitled(cx: &mut AppContext) -> Handle<Self> {
// cx.add_model(|_| Self { // cx.add_model(|_| Self {
// project_path: None, // project_path: None,
// entry_id: None, // entry_id: None,
@ -937,7 +939,7 @@ pub trait FollowableItemHandle: ItemHandle {
// self // self
// } // }
// pub fn with_project_items(mut self, items: &[ModelHandle<TestProjectItem>]) -> Self { // pub fn with_project_items(mut self, items: &[Handle<TestProjectItem>]) -> Self {
// self.project_items.clear(); // self.project_items.clear();
// self.project_items.extend(items.iter().cloned()); // self.project_items.extend(items.iter().cloned());
// self // self
@ -1048,7 +1050,7 @@ pub trait FollowableItemHandle: ItemHandle {
// fn save( // fn save(
// &mut self, // &mut self,
// _: ModelHandle<Project>, // _: Handle<Project>,
// _: &mut ViewContext<Self>, // _: &mut ViewContext<Self>,
// ) -> Task<anyhow::Result<()>> { // ) -> Task<anyhow::Result<()>> {
// self.save_count += 1; // self.save_count += 1;
@ -1058,7 +1060,7 @@ pub trait FollowableItemHandle: ItemHandle {
// fn save_as( // fn save_as(
// &mut self, // &mut self,
// _: ModelHandle<Project>, // _: Handle<Project>,
// _: std::path::PathBuf, // _: std::path::PathBuf,
// _: &mut ViewContext<Self>, // _: &mut ViewContext<Self>,
// ) -> Task<anyhow::Result<()>> { // ) -> Task<anyhow::Result<()>> {
@ -1069,7 +1071,7 @@ pub trait FollowableItemHandle: ItemHandle {
// fn reload( // fn reload(
// &mut self, // &mut self,
// _: ModelHandle<Project>, // _: Handle<Project>,
// _: &mut ViewContext<Self>, // _: &mut ViewContext<Self>,
// ) -> Task<anyhow::Result<()>> { // ) -> Task<anyhow::Result<()>> {
// self.reload_count += 1; // self.reload_count += 1;
@ -1086,12 +1088,12 @@ pub trait FollowableItemHandle: ItemHandle {
// } // }
// fn deserialize( // fn deserialize(
// _project: ModelHandle<Project>, // _project: Handle<Project>,
// _workspace: WeakViewHandle<Workspace>, // _workspace: WeakViewHandle<Workspace>,
// workspace_id: WorkspaceId, // workspace_id: WorkspaceId,
// _item_id: ItemId, // _item_id: ItemId,
// cx: &mut ViewContext<Pane>, // cx: &mut ViewContext<Pane>,
// ) -> Task<anyhow::Result<ViewHandle<Self>>> { // ) -> Task<anyhow::Result<View<Self>>> {
// let view = cx.add_view(|_cx| Self::new_deserialized(workspace_id)); // let view = cx.add_view(|_cx| Self::new_deserialized(workspace_id));
// Task::Ready(Some(anyhow::Ok(view))) // Task::Ready(Some(anyhow::Ok(view)))
// } // }

View file

@ -29,7 +29,7 @@
// WindowContext, // WindowContext,
// }; // };
// use project2::{Project, ProjectEntryId, ProjectPath}; // use project2::{Project, ProjectEntryId, ProjectPath};
// use serde::Deserialize; use serde::Deserialize;
// use std::{ // use std::{
// any::Any, // any::Any,
// cell::RefCell, // cell::RefCell,
@ -44,24 +44,24 @@
// use theme2::{Theme, ThemeSettings}; // use theme2::{Theme, ThemeSettings};
// use util::truncate_and_remove_front; // use util::truncate_and_remove_front;
// #[derive(PartialEq, Clone, Copy, Deserialize, Debug)] #[derive(PartialEq, Clone, Copy, Deserialize, Debug)]
// #[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
// pub enum SaveIntent { pub enum SaveIntent {
// /// write all files (even if unchanged) /// write all files (even if unchanged)
// /// prompt before overwriting on-disk changes /// prompt before overwriting on-disk changes
// Save, Save,
// /// write any files that have local changes /// write any files that have local changes
// /// prompt before overwriting on-disk changes /// prompt before overwriting on-disk changes
// SaveAll, SaveAll,
// /// always prompt for a new path /// always prompt for a new path
// SaveAs, SaveAs,
// /// prompt "you have unsaved changes" before writing /// prompt "you have unsaved changes" before writing
// Close, Close,
// /// write all dirty files, don't prompt on conflict /// write all dirty files, don't prompt on conflict
// Overwrite, Overwrite,
// /// skip all save-related behavior /// skip all save-related behavior
// Skip, Skip,
// } }
// #[derive(Clone, Deserialize, PartialEq)] // #[derive(Clone, Deserialize, PartialEq)]
// pub struct ActivateItem(pub usize); // pub struct ActivateItem(pub usize);
@ -159,7 +159,10 @@ pub enum Event {
ZoomOut, ZoomOut,
} }
use crate::item::{ItemHandle, WeakItemHandle}; use crate::{
item::{ItemHandle, WeakItemHandle},
SplitDirection,
};
use collections::{HashMap, VecDeque}; use collections::{HashMap, VecDeque};
use gpui2::{Handle, ViewContext, WeakView}; use gpui2::{Handle, ViewContext, WeakView};
use project2::{Project, ProjectEntryId, ProjectPath}; use project2::{Project, ProjectEntryId, ProjectPath};

File diff suppressed because it is too large Load diff

View file

@ -5,13 +5,13 @@ pub mod model;
use std::path::Path; use std::path::Path;
use anyhow::{anyhow, bail, Context, Result}; use anyhow::{anyhow, bail, Context, Result};
use db::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql}; use db2::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql};
use gpui::{platform::WindowBounds, Axis}; use gpui2::WindowBounds;
use util::{unzip_option, ResultExt}; use util::{unzip_option, ResultExt};
use uuid::Uuid; use uuid::Uuid;
use crate::WorkspaceId; use crate::{Axis, WorkspaceId};
use model::{ use model::{
GroupId, PaneId, SerializedItem, SerializedPane, SerializedPaneGroup, SerializedWorkspace, GroupId, PaneId, SerializedItem, SerializedPane, SerializedPaneGroup, SerializedWorkspace,
@ -549,424 +549,425 @@ impl WorkspaceDb {
} }
} }
#[cfg(test)] // todo!()
mod tests { // #[cfg(test)]
use super::*; // mod tests {
use db::open_test_db; // use super::*;
// use db::open_test_db;
#[gpui::test] // #[gpui::test]
async fn test_next_id_stability() { // async fn test_next_id_stability() {
env_logger::try_init().ok(); // env_logger::try_init().ok();
let db = WorkspaceDb(open_test_db("test_next_id_stability").await); // let db = WorkspaceDb(open_test_db("test_next_id_stability").await);
db.write(|conn| { // db.write(|conn| {
conn.migrate( // conn.migrate(
"test_table", // "test_table",
&[sql!( // &[sql!(
CREATE TABLE test_table( // CREATE TABLE test_table(
text TEXT, // text TEXT,
workspace_id INTEGER, // workspace_id INTEGER,
FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) // FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id)
ON DELETE CASCADE // ON DELETE CASCADE
) STRICT; // ) STRICT;
)], // )],
) // )
.unwrap(); // .unwrap();
}) // })
.await; // .await;
let id = db.next_id().await.unwrap(); // let id = db.next_id().await.unwrap();
// Assert the empty row got inserted // // Assert the empty row got inserted
assert_eq!( // assert_eq!(
Some(id), // Some(id),
db.select_row_bound::<WorkspaceId, WorkspaceId>(sql!( // db.select_row_bound::<WorkspaceId, WorkspaceId>(sql!(
SELECT workspace_id FROM workspaces WHERE workspace_id = ? // SELECT workspace_id FROM workspaces WHERE workspace_id = ?
)) // ))
.unwrap()(id) // .unwrap()(id)
.unwrap() // .unwrap()
); // );
db.write(move |conn| { // db.write(move |conn| {
conn.exec_bound(sql!(INSERT INTO test_table(text, workspace_id) VALUES (?, ?))) // conn.exec_bound(sql!(INSERT INTO test_table(text, workspace_id) VALUES (?, ?)))
.unwrap()(("test-text-1", id)) // .unwrap()(("test-text-1", id))
.unwrap() // .unwrap()
}) // })
.await; // .await;
let test_text_1 = db // let test_text_1 = db
.select_row_bound::<_, String>(sql!(SELECT text FROM test_table WHERE workspace_id = ?)) // .select_row_bound::<_, String>(sql!(SELECT text FROM test_table WHERE workspace_id = ?))
.unwrap()(1) // .unwrap()(1)
.unwrap() // .unwrap()
.unwrap(); // .unwrap();
assert_eq!(test_text_1, "test-text-1"); // assert_eq!(test_text_1, "test-text-1");
} // }
#[gpui::test] // #[gpui::test]
async fn test_workspace_id_stability() { // async fn test_workspace_id_stability() {
env_logger::try_init().ok(); // env_logger::try_init().ok();
let db = WorkspaceDb(open_test_db("test_workspace_id_stability").await); // let db = WorkspaceDb(open_test_db("test_workspace_id_stability").await);
db.write(|conn| { // db.write(|conn| {
conn.migrate( // conn.migrate(
"test_table", // "test_table",
&[sql!( // &[sql!(
CREATE TABLE test_table( // CREATE TABLE test_table(
text TEXT, // text TEXT,
workspace_id INTEGER, // workspace_id INTEGER,
FOREIGN KEY(workspace_id) // FOREIGN KEY(workspace_id)
REFERENCES workspaces(workspace_id) // REFERENCES workspaces(workspace_id)
ON DELETE CASCADE // ON DELETE CASCADE
) STRICT;)], // ) STRICT;)],
) // )
}) // })
.await // .await
.unwrap(); // .unwrap();
let mut workspace_1 = SerializedWorkspace { // let mut workspace_1 = SerializedWorkspace {
id: 1, // id: 1,
location: (["/tmp", "/tmp2"]).into(), // location: (["/tmp", "/tmp2"]).into(),
center_group: Default::default(), // center_group: Default::default(),
bounds: Default::default(), // bounds: Default::default(),
display: Default::default(), // display: Default::default(),
docks: Default::default(), // docks: Default::default(),
}; // };
let workspace_2 = SerializedWorkspace { // let workspace_2 = SerializedWorkspace {
id: 2, // id: 2,
location: (["/tmp"]).into(), // location: (["/tmp"]).into(),
center_group: Default::default(), // center_group: Default::default(),
bounds: Default::default(), // bounds: Default::default(),
display: Default::default(), // display: Default::default(),
docks: Default::default(), // docks: Default::default(),
}; // };
db.save_workspace(workspace_1.clone()).await; // db.save_workspace(workspace_1.clone()).await;
db.write(|conn| { // db.write(|conn| {
conn.exec_bound(sql!(INSERT INTO test_table(text, workspace_id) VALUES (?, ?))) // conn.exec_bound(sql!(INSERT INTO test_table(text, workspace_id) VALUES (?, ?)))
.unwrap()(("test-text-1", 1)) // .unwrap()(("test-text-1", 1))
.unwrap(); // .unwrap();
}) // })
.await; // .await;
db.save_workspace(workspace_2.clone()).await; // db.save_workspace(workspace_2.clone()).await;
db.write(|conn| { // db.write(|conn| {
conn.exec_bound(sql!(INSERT INTO test_table(text, workspace_id) VALUES (?, ?))) // conn.exec_bound(sql!(INSERT INTO test_table(text, workspace_id) VALUES (?, ?)))
.unwrap()(("test-text-2", 2)) // .unwrap()(("test-text-2", 2))
.unwrap(); // .unwrap();
}) // })
.await; // .await;
workspace_1.location = (["/tmp", "/tmp3"]).into(); // workspace_1.location = (["/tmp", "/tmp3"]).into();
db.save_workspace(workspace_1.clone()).await; // db.save_workspace(workspace_1.clone()).await;
db.save_workspace(workspace_1).await; // db.save_workspace(workspace_1).await;
db.save_workspace(workspace_2).await; // db.save_workspace(workspace_2).await;
let test_text_2 = db // let test_text_2 = db
.select_row_bound::<_, String>(sql!(SELECT text FROM test_table WHERE workspace_id = ?)) // .select_row_bound::<_, String>(sql!(SELECT text FROM test_table WHERE workspace_id = ?))
.unwrap()(2) // .unwrap()(2)
.unwrap() // .unwrap()
.unwrap(); // .unwrap();
assert_eq!(test_text_2, "test-text-2"); // assert_eq!(test_text_2, "test-text-2");
let test_text_1 = db // let test_text_1 = db
.select_row_bound::<_, String>(sql!(SELECT text FROM test_table WHERE workspace_id = ?)) // .select_row_bound::<_, String>(sql!(SELECT text FROM test_table WHERE workspace_id = ?))
.unwrap()(1) // .unwrap()(1)
.unwrap() // .unwrap()
.unwrap(); // .unwrap();
assert_eq!(test_text_1, "test-text-1"); // assert_eq!(test_text_1, "test-text-1");
} // }
fn group(axis: gpui::Axis, children: Vec<SerializedPaneGroup>) -> SerializedPaneGroup { // fn group(axis: gpui::Axis, children: Vec<SerializedPaneGroup>) -> SerializedPaneGroup {
SerializedPaneGroup::Group { // SerializedPaneGroup::Group {
axis, // axis,
flexes: None, // flexes: None,
children, // children,
} // }
} // }
#[gpui::test] // #[gpui::test]
async fn test_full_workspace_serialization() { // async fn test_full_workspace_serialization() {
env_logger::try_init().ok(); // env_logger::try_init().ok();
let db = WorkspaceDb(open_test_db("test_full_workspace_serialization").await); // let db = WorkspaceDb(open_test_db("test_full_workspace_serialization").await);
// ----------------- // // -----------------
// | 1,2 | 5,6 | // // | 1,2 | 5,6 |
// | - - - | | // // | - - - | |
// | 3,4 | | // // | 3,4 | |
// ----------------- // // -----------------
let center_group = group( // let center_group = group(
gpui::Axis::Horizontal, // gpui::Axis::Horizontal,
vec![ // vec![
group( // group(
gpui::Axis::Vertical, // gpui::Axis::Vertical,
vec![ // vec![
SerializedPaneGroup::Pane(SerializedPane::new( // SerializedPaneGroup::Pane(SerializedPane::new(
vec![ // vec![
SerializedItem::new("Terminal", 5, false), // SerializedItem::new("Terminal", 5, false),
SerializedItem::new("Terminal", 6, true), // SerializedItem::new("Terminal", 6, true),
], // ],
false, // false,
)), // )),
SerializedPaneGroup::Pane(SerializedPane::new( // SerializedPaneGroup::Pane(SerializedPane::new(
vec![ // vec![
SerializedItem::new("Terminal", 7, true), // SerializedItem::new("Terminal", 7, true),
SerializedItem::new("Terminal", 8, false), // SerializedItem::new("Terminal", 8, false),
], // ],
false, // false,
)), // )),
], // ],
), // ),
SerializedPaneGroup::Pane(SerializedPane::new( // SerializedPaneGroup::Pane(SerializedPane::new(
vec![ // vec![
SerializedItem::new("Terminal", 9, false), // SerializedItem::new("Terminal", 9, false),
SerializedItem::new("Terminal", 10, true), // SerializedItem::new("Terminal", 10, true),
], // ],
false, // false,
)), // )),
], // ],
); // );
let workspace = SerializedWorkspace { // let workspace = SerializedWorkspace {
id: 5, // id: 5,
location: (["/tmp", "/tmp2"]).into(), // location: (["/tmp", "/tmp2"]).into(),
center_group, // center_group,
bounds: Default::default(), // bounds: Default::default(),
display: Default::default(), // display: Default::default(),
docks: Default::default(), // docks: Default::default(),
}; // };
db.save_workspace(workspace.clone()).await; // db.save_workspace(workspace.clone()).await;
let round_trip_workspace = db.workspace_for_roots(&["/tmp2", "/tmp"]); // let round_trip_workspace = db.workspace_for_roots(&["/tmp2", "/tmp"]);
assert_eq!(workspace, round_trip_workspace.unwrap()); // assert_eq!(workspace, round_trip_workspace.unwrap());
// Test guaranteed duplicate IDs // // Test guaranteed duplicate IDs
db.save_workspace(workspace.clone()).await; // db.save_workspace(workspace.clone()).await;
db.save_workspace(workspace.clone()).await; // db.save_workspace(workspace.clone()).await;
let round_trip_workspace = db.workspace_for_roots(&["/tmp", "/tmp2"]); // let round_trip_workspace = db.workspace_for_roots(&["/tmp", "/tmp2"]);
assert_eq!(workspace, round_trip_workspace.unwrap()); // assert_eq!(workspace, round_trip_workspace.unwrap());
} // }
#[gpui::test] // #[gpui::test]
async fn test_workspace_assignment() { // async fn test_workspace_assignment() {
env_logger::try_init().ok(); // env_logger::try_init().ok();
let db = WorkspaceDb(open_test_db("test_basic_functionality").await); // let db = WorkspaceDb(open_test_db("test_basic_functionality").await);
let workspace_1 = SerializedWorkspace { // let workspace_1 = SerializedWorkspace {
id: 1, // id: 1,
location: (["/tmp", "/tmp2"]).into(), // location: (["/tmp", "/tmp2"]).into(),
center_group: Default::default(), // center_group: Default::default(),
bounds: Default::default(), // bounds: Default::default(),
display: Default::default(), // display: Default::default(),
docks: Default::default(), // docks: Default::default(),
}; // };
let mut workspace_2 = SerializedWorkspace { // let mut workspace_2 = SerializedWorkspace {
id: 2, // id: 2,
location: (["/tmp"]).into(), // location: (["/tmp"]).into(),
center_group: Default::default(), // center_group: Default::default(),
bounds: Default::default(), // bounds: Default::default(),
display: Default::default(), // display: Default::default(),
docks: Default::default(), // docks: Default::default(),
}; // };
db.save_workspace(workspace_1.clone()).await; // db.save_workspace(workspace_1.clone()).await;
db.save_workspace(workspace_2.clone()).await; // db.save_workspace(workspace_2.clone()).await;
// Test that paths are treated as a set // // Test that paths are treated as a set
assert_eq!( // assert_eq!(
db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(), // db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
workspace_1 // workspace_1
); // );
assert_eq!( // assert_eq!(
db.workspace_for_roots(&["/tmp2", "/tmp"]).unwrap(), // db.workspace_for_roots(&["/tmp2", "/tmp"]).unwrap(),
workspace_1 // workspace_1
); // );
// Make sure that other keys work // // Make sure that other keys work
assert_eq!(db.workspace_for_roots(&["/tmp"]).unwrap(), workspace_2); // assert_eq!(db.workspace_for_roots(&["/tmp"]).unwrap(), workspace_2);
assert_eq!(db.workspace_for_roots(&["/tmp3", "/tmp2", "/tmp4"]), None); // assert_eq!(db.workspace_for_roots(&["/tmp3", "/tmp2", "/tmp4"]), None);
// Test 'mutate' case of updating a pre-existing id // // Test 'mutate' case of updating a pre-existing id
workspace_2.location = (["/tmp", "/tmp2"]).into(); // workspace_2.location = (["/tmp", "/tmp2"]).into();
db.save_workspace(workspace_2.clone()).await; // db.save_workspace(workspace_2.clone()).await;
assert_eq!( // assert_eq!(
db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(), // db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
workspace_2 // workspace_2
); // );
// Test other mechanism for mutating // // Test other mechanism for mutating
let mut workspace_3 = SerializedWorkspace { // let mut workspace_3 = SerializedWorkspace {
id: 3, // id: 3,
location: (&["/tmp", "/tmp2"]).into(), // location: (&["/tmp", "/tmp2"]).into(),
center_group: Default::default(), // center_group: Default::default(),
bounds: Default::default(), // bounds: Default::default(),
display: Default::default(), // display: Default::default(),
docks: Default::default(), // docks: Default::default(),
}; // };
db.save_workspace(workspace_3.clone()).await; // db.save_workspace(workspace_3.clone()).await;
assert_eq!( // assert_eq!(
db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(), // db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
workspace_3 // workspace_3
); // );
// Make sure that updating paths differently also works // // Make sure that updating paths differently also works
workspace_3.location = (["/tmp3", "/tmp4", "/tmp2"]).into(); // workspace_3.location = (["/tmp3", "/tmp4", "/tmp2"]).into();
db.save_workspace(workspace_3.clone()).await; // db.save_workspace(workspace_3.clone()).await;
assert_eq!(db.workspace_for_roots(&["/tmp2", "tmp"]), None); // assert_eq!(db.workspace_for_roots(&["/tmp2", "tmp"]), None);
assert_eq!( // assert_eq!(
db.workspace_for_roots(&["/tmp2", "/tmp3", "/tmp4"]) // db.workspace_for_roots(&["/tmp2", "/tmp3", "/tmp4"])
.unwrap(), // .unwrap(),
workspace_3 // workspace_3
); // );
} // }
use crate::persistence::model::SerializedWorkspace; // use crate::persistence::model::SerializedWorkspace;
use crate::persistence::model::{SerializedItem, SerializedPane, SerializedPaneGroup}; // use crate::persistence::model::{SerializedItem, SerializedPane, SerializedPaneGroup};
fn default_workspace<P: AsRef<Path>>( // fn default_workspace<P: AsRef<Path>>(
workspace_id: &[P], // workspace_id: &[P],
center_group: &SerializedPaneGroup, // center_group: &SerializedPaneGroup,
) -> SerializedWorkspace { // ) -> SerializedWorkspace {
SerializedWorkspace { // SerializedWorkspace {
id: 4, // id: 4,
location: workspace_id.into(), // location: workspace_id.into(),
center_group: center_group.clone(), // center_group: center_group.clone(),
bounds: Default::default(), // bounds: Default::default(),
display: Default::default(), // display: Default::default(),
docks: Default::default(), // docks: Default::default(),
} // }
} // }
#[gpui::test] // #[gpui::test]
async fn test_simple_split() { // async fn test_simple_split() {
env_logger::try_init().ok(); // env_logger::try_init().ok();
let db = WorkspaceDb(open_test_db("simple_split").await); // let db = WorkspaceDb(open_test_db("simple_split").await);
// ----------------- // // -----------------
// | 1,2 | 5,6 | // // | 1,2 | 5,6 |
// | - - - | | // // | - - - | |
// | 3,4 | | // // | 3,4 | |
// ----------------- // // -----------------
let center_pane = group( // let center_pane = group(
gpui::Axis::Horizontal, // gpui::Axis::Horizontal,
vec![ // vec![
group( // group(
gpui::Axis::Vertical, // gpui::Axis::Vertical,
vec![ // vec![
SerializedPaneGroup::Pane(SerializedPane::new( // SerializedPaneGroup::Pane(SerializedPane::new(
vec![ // vec![
SerializedItem::new("Terminal", 1, false), // SerializedItem::new("Terminal", 1, false),
SerializedItem::new("Terminal", 2, true), // SerializedItem::new("Terminal", 2, true),
], // ],
false, // false,
)), // )),
SerializedPaneGroup::Pane(SerializedPane::new( // SerializedPaneGroup::Pane(SerializedPane::new(
vec![ // vec![
SerializedItem::new("Terminal", 4, false), // SerializedItem::new("Terminal", 4, false),
SerializedItem::new("Terminal", 3, true), // SerializedItem::new("Terminal", 3, true),
], // ],
true, // true,
)), // )),
], // ],
), // ),
SerializedPaneGroup::Pane(SerializedPane::new( // SerializedPaneGroup::Pane(SerializedPane::new(
vec![ // vec![
SerializedItem::new("Terminal", 5, true), // SerializedItem::new("Terminal", 5, true),
SerializedItem::new("Terminal", 6, false), // SerializedItem::new("Terminal", 6, false),
], // ],
false, // false,
)), // )),
], // ],
); // );
let workspace = default_workspace(&["/tmp"], &center_pane); // let workspace = default_workspace(&["/tmp"], &center_pane);
db.save_workspace(workspace.clone()).await; // db.save_workspace(workspace.clone()).await;
let new_workspace = db.workspace_for_roots(&["/tmp"]).unwrap(); // let new_workspace = db.workspace_for_roots(&["/tmp"]).unwrap();
assert_eq!(workspace.center_group, new_workspace.center_group); // assert_eq!(workspace.center_group, new_workspace.center_group);
} // }
#[gpui::test] // #[gpui::test]
async fn test_cleanup_panes() { // async fn test_cleanup_panes() {
env_logger::try_init().ok(); // env_logger::try_init().ok();
let db = WorkspaceDb(open_test_db("test_cleanup_panes").await); // let db = WorkspaceDb(open_test_db("test_cleanup_panes").await);
let center_pane = group( // let center_pane = group(
gpui::Axis::Horizontal, // gpui::Axis::Horizontal,
vec![ // vec![
group( // group(
gpui::Axis::Vertical, // gpui::Axis::Vertical,
vec![ // vec![
SerializedPaneGroup::Pane(SerializedPane::new( // SerializedPaneGroup::Pane(SerializedPane::new(
vec![ // vec![
SerializedItem::new("Terminal", 1, false), // SerializedItem::new("Terminal", 1, false),
SerializedItem::new("Terminal", 2, true), // SerializedItem::new("Terminal", 2, true),
], // ],
false, // false,
)), // )),
SerializedPaneGroup::Pane(SerializedPane::new( // SerializedPaneGroup::Pane(SerializedPane::new(
vec![ // vec![
SerializedItem::new("Terminal", 4, false), // SerializedItem::new("Terminal", 4, false),
SerializedItem::new("Terminal", 3, true), // SerializedItem::new("Terminal", 3, true),
], // ],
true, // true,
)), // )),
], // ],
), // ),
SerializedPaneGroup::Pane(SerializedPane::new( // SerializedPaneGroup::Pane(SerializedPane::new(
vec![ // vec![
SerializedItem::new("Terminal", 5, false), // SerializedItem::new("Terminal", 5, false),
SerializedItem::new("Terminal", 6, true), // SerializedItem::new("Terminal", 6, true),
], // ],
false, // false,
)), // )),
], // ],
); // );
let id = &["/tmp"]; // let id = &["/tmp"];
let mut workspace = default_workspace(id, &center_pane); // let mut workspace = default_workspace(id, &center_pane);
db.save_workspace(workspace.clone()).await; // db.save_workspace(workspace.clone()).await;
workspace.center_group = group( // workspace.center_group = group(
gpui::Axis::Vertical, // gpui::Axis::Vertical,
vec![ // vec![
SerializedPaneGroup::Pane(SerializedPane::new( // SerializedPaneGroup::Pane(SerializedPane::new(
vec![ // vec![
SerializedItem::new("Terminal", 1, false), // SerializedItem::new("Terminal", 1, false),
SerializedItem::new("Terminal", 2, true), // SerializedItem::new("Terminal", 2, true),
], // ],
false, // false,
)), // )),
SerializedPaneGroup::Pane(SerializedPane::new( // SerializedPaneGroup::Pane(SerializedPane::new(
vec![ // vec![
SerializedItem::new("Terminal", 4, true), // SerializedItem::new("Terminal", 4, true),
SerializedItem::new("Terminal", 3, false), // SerializedItem::new("Terminal", 3, false),
], // ],
true, // true,
)), // )),
], // ],
); // );
db.save_workspace(workspace.clone()).await; // db.save_workspace(workspace.clone()).await;
let new_workspace = db.workspace_for_roots(id).unwrap(); // let new_workspace = db.workspace_for_roots(id).unwrap();
assert_eq!(workspace.center_group, new_workspace.center_group); // assert_eq!(workspace.center_group, new_workspace.center_group);
} // }
} // }

View file

@ -1,14 +1,14 @@
use crate::{item::ItemHandle, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId}; use crate::{
item::ItemHandle, Axis, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId,
};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use async_recursion::async_recursion; use async_recursion::async_recursion;
use db::sqlez::{ use db2::sqlez::{
bindable::{Bind, Column, StaticColumnCount}, bindable::{Bind, Column, StaticColumnCount},
statement::Statement, statement::Statement,
}; };
use gpui::{ use gpui2::{AsyncAppContext, Handle, Task, View, WeakView, WindowBounds};
platform::WindowBounds, AsyncAppContext, Axis, ModelHandle, Task, ViewHandle, WeakViewHandle, use project2::Project;
};
use project::Project;
use std::{ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc, sync::Arc,
@ -151,15 +151,11 @@ impl SerializedPaneGroup {
#[async_recursion(?Send)] #[async_recursion(?Send)]
pub(crate) async fn deserialize( pub(crate) async fn deserialize(
self, self,
project: &ModelHandle<Project>, project: &Handle<Project>,
workspace_id: WorkspaceId, workspace_id: WorkspaceId,
workspace: &WeakViewHandle<Workspace>, workspace: &WeakView<Workspace>,
cx: &mut AsyncAppContext, cx: &mut AsyncAppContext,
) -> Option<( ) -> Option<(Member, Option<View<Pane>>, Vec<Option<Box<dyn ItemHandle>>>)> {
Member,
Option<ViewHandle<Pane>>,
Vec<Option<Box<dyn ItemHandle>>>,
)> {
match self { match self {
SerializedPaneGroup::Group { SerializedPaneGroup::Group {
axis, axis,
@ -208,10 +204,10 @@ impl SerializedPaneGroup {
.read_with(cx, |pane, _| pane.items_len() != 0) .read_with(cx, |pane, _| pane.items_len() != 0)
.log_err()? .log_err()?
{ {
let pane = pane.upgrade(cx)?; let pane = pane.upgrade()?;
Some((Member::Pane(pane.clone()), active.then(|| pane), new_items)) Some((Member::Pane(pane.clone()), active.then(|| pane), new_items))
} else { } else {
let pane = pane.upgrade(cx)?; let pane = pane.upgrade()?;
workspace workspace
.update(cx, |workspace, cx| workspace.force_remove_pane(&pane, cx)) .update(cx, |workspace, cx| workspace.force_remove_pane(&pane, cx))
.log_err()?; .log_err()?;
@ -235,10 +231,10 @@ impl SerializedPane {
pub async fn deserialize_to( pub async fn deserialize_to(
&self, &self,
project: &ModelHandle<Project>, project: &Handle<Project>,
pane: &WeakViewHandle<Pane>, pane: &WeakView<Pane>,
workspace_id: WorkspaceId, workspace_id: WorkspaceId,
workspace: &WeakViewHandle<Workspace>, workspace: &WeakView<Workspace>,
cx: &mut AsyncAppContext, cx: &mut AsyncAppContext,
) -> Result<Vec<Option<Box<dyn ItemHandle>>>> { ) -> Result<Vec<Option<Box<dyn ItemHandle>>>> {
let mut items = Vec::new(); let mut items = Vec::new();

View file

@ -1,10 +1,7 @@
use crate::ItemHandle; use crate::ItemHandle;
use gpui::{ use gpui2::{AppContext, EventEmitter, View, ViewContext, WindowContext};
elements::*, AnyElement, AnyViewHandle, AppContext, Entity, View, ViewContext, ViewHandle,
WindowContext,
};
pub trait ToolbarItemView: View { pub trait ToolbarItemView: EventEmitter + Sized {
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>,
@ -32,7 +29,7 @@ pub trait ToolbarItemView: View {
trait ToolbarItemViewHandle { trait ToolbarItemViewHandle {
fn id(&self) -> usize; fn id(&self) -> usize;
fn as_any(&self) -> &AnyViewHandle; // fn as_any(&self) -> &AnyViewHandle; todo!()
fn set_active_pane_item( fn set_active_pane_item(
&self, &self,
active_pane_item: Option<&dyn ItemHandle>, active_pane_item: Option<&dyn ItemHandle>,
@ -57,84 +54,81 @@ pub struct Toolbar {
items: Vec<(Box<dyn ToolbarItemViewHandle>, ToolbarItemLocation)>, items: Vec<(Box<dyn ToolbarItemViewHandle>, ToolbarItemLocation)>,
} }
impl Entity for Toolbar { // todo!()
type Event = (); // impl View for Toolbar {
} // fn ui_name() -> &'static str {
// "Toolbar"
// }
impl View for Toolbar { // fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
fn ui_name() -> &'static str { // let theme = &theme::current(cx).workspace.toolbar;
"Toolbar"
}
fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> { // let mut primary_left_items = Vec::new();
let theme = &theme::current(cx).workspace.toolbar; // let mut primary_right_items = Vec::new();
// let mut secondary_item = None;
// let spacing = theme.item_spacing;
// let mut primary_items_row_count = 1;
let mut primary_left_items = Vec::new(); // for (item, position) in &self.items {
let mut primary_right_items = Vec::new(); // match *position {
let mut secondary_item = None; // ToolbarItemLocation::Hidden => {}
let spacing = theme.item_spacing;
let mut primary_items_row_count = 1;
for (item, position) in &self.items { // ToolbarItemLocation::PrimaryLeft { flex } => {
match *position { // primary_items_row_count = primary_items_row_count.max(item.row_count(cx));
ToolbarItemLocation::Hidden => {} // let left_item = ChildView::new(item.as_any(), cx).aligned();
// if let Some((flex, expanded)) = flex {
// primary_left_items.push(left_item.flex(flex, expanded).into_any());
// } else {
// primary_left_items.push(left_item.into_any());
// }
// }
ToolbarItemLocation::PrimaryLeft { flex } => { // ToolbarItemLocation::PrimaryRight { flex } => {
primary_items_row_count = primary_items_row_count.max(item.row_count(cx)); // primary_items_row_count = primary_items_row_count.max(item.row_count(cx));
let left_item = ChildView::new(item.as_any(), cx).aligned(); // let right_item = ChildView::new(item.as_any(), cx).aligned().flex_float();
if let Some((flex, expanded)) = flex { // if let Some((flex, expanded)) = flex {
primary_left_items.push(left_item.flex(flex, expanded).into_any()); // primary_right_items.push(right_item.flex(flex, expanded).into_any());
} else { // } else {
primary_left_items.push(left_item.into_any()); // primary_right_items.push(right_item.into_any());
} // }
} // }
ToolbarItemLocation::PrimaryRight { flex } => { // ToolbarItemLocation::Secondary => {
primary_items_row_count = primary_items_row_count.max(item.row_count(cx)); // secondary_item = Some(
let right_item = ChildView::new(item.as_any(), cx).aligned().flex_float(); // ChildView::new(item.as_any(), cx)
if let Some((flex, expanded)) = flex { // .constrained()
primary_right_items.push(right_item.flex(flex, expanded).into_any()); // .with_height(theme.height * item.row_count(cx) as f32)
} else { // .into_any(),
primary_right_items.push(right_item.into_any()); // );
} // }
} // }
// }
ToolbarItemLocation::Secondary => { // let container_style = theme.container;
secondary_item = Some( // let height = theme.height * primary_items_row_count as f32;
ChildView::new(item.as_any(), cx)
.constrained()
.with_height(theme.height * item.row_count(cx) as f32)
.into_any(),
);
}
}
}
let container_style = theme.container; // let mut primary_items = Flex::row().with_spacing(spacing);
let height = theme.height * primary_items_row_count as f32; // primary_items.extend(primary_left_items);
// primary_items.extend(primary_right_items);
let mut primary_items = Flex::row().with_spacing(spacing); // let mut toolbar = Flex::column();
primary_items.extend(primary_left_items); // if !primary_items.is_empty() {
primary_items.extend(primary_right_items); // toolbar.add_child(primary_items.constrained().with_height(height));
// }
// if let Some(secondary_item) = secondary_item {
// toolbar.add_child(secondary_item);
// }
let mut toolbar = Flex::column(); // if toolbar.is_empty() {
if !primary_items.is_empty() { // toolbar.into_any_named("toolbar")
toolbar.add_child(primary_items.constrained().with_height(height)); // } else {
} // toolbar
if let Some(secondary_item) = secondary_item { // .contained()
toolbar.add_child(secondary_item); // .with_style(container_style)
} // .into_any_named("toolbar")
// }
if toolbar.is_empty() { // }
toolbar.into_any_named("toolbar") // }
} else {
toolbar
.contained()
.with_style(container_style)
.into_any_named("toolbar")
}
}
}
// <<<<<<< HEAD // <<<<<<< HEAD
// ======= // =======
@ -206,7 +200,7 @@ impl Toolbar {
cx.notify(); cx.notify();
} }
pub fn add_item<T>(&mut self, item: ViewHandle<T>, cx: &mut ViewContext<Self>) pub fn add_item<T>(&mut self, item: View<T>, cx: &mut ViewContext<Self>)
where where
T: 'static + ToolbarItemView, T: 'static + ToolbarItemView,
{ {
@ -252,7 +246,7 @@ impl Toolbar {
} }
} }
pub fn item_of_type<T: ToolbarItemView>(&self) -> Option<ViewHandle<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.as_any().clone().downcast())
@ -263,14 +257,15 @@ impl Toolbar {
} }
} }
impl<T: ToolbarItemView> ToolbarItemViewHandle for ViewHandle<T> { impl<T: ToolbarItemView> ToolbarItemViewHandle for View<T> {
fn id(&self) -> usize { fn id(&self) -> usize {
self.id() self.id()
} }
fn as_any(&self) -> &AnyViewHandle { // todo!()
self // fn as_any(&self) -> &AnyViewHandle {
} // self
// }
fn set_active_pane_item( fn set_active_pane_item(
&self, &self,
@ -294,8 +289,9 @@ impl<T: ToolbarItemView> ToolbarItemViewHandle for ViewHandle<T> {
} }
} }
impl From<&dyn ToolbarItemViewHandle> for AnyViewHandle { // todo!()
fn from(val: &dyn ToolbarItemViewHandle) -> Self { // impl From<&dyn ToolbarItemViewHandle> for AnyViewHandle {
val.as_any().clone() // fn from(val: &dyn ToolbarItemViewHandle) -> Self {
} // val.as_any().clone()
} // }
// }

View file

@ -3,12 +3,12 @@ pub mod item;
// pub mod notifications; // pub mod notifications;
pub mod pane; pub mod pane;
pub mod pane_group; pub mod pane_group;
// mod persistence; mod persistence;
pub mod searchable; pub mod searchable;
// pub mod shared_screen; // pub mod shared_screen;
// mod status_bar; // mod status_bar;
mod toolbar; mod toolbar;
// mod workspace_settings; mod workspace_settings;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
// use call2::ActiveCall; // use call2::ActiveCall;
@ -36,13 +36,14 @@ use anyhow::{anyhow, Result};
// }, // },
// AnyModelHandle, AnyViewHandle, AnyWeakViewHandle, AnyWindowHandle, AppContext, AsyncAppContext, // AnyModelHandle, AnyViewHandle, AnyWeakViewHandle, AnyWindowHandle, AppContext, AsyncAppContext,
// Entity, ModelContext, ModelHandle, SizeConstraint, Subscription, Task, View, ViewContext, // Entity, ModelContext, ModelHandle, SizeConstraint, Subscription, Task, View, ViewContext,
// ViewHandle, WeakViewHandle, WindowContext, WindowHandle, // View, WeakViewHandle, WindowContext, WindowHandle,
// }; // };
// use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem}; // use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem};
// use itertools::Itertools; // use itertools::Itertools;
// use language2::{LanguageRegistry, Rope}; // use language2::{LanguageRegistry, Rope};
// use node_runtime::NodeRuntime;// // // use node_runtime::NodeRuntime;// //
use futures::channel::oneshot;
// use crate::{ // use crate::{
// notifications::{simple_message_notification::MessageNotification, NotificationTracker}, // notifications::{simple_message_notification::MessageNotification, NotificationTracker},
// persistence::model::{ // persistence::model::{
@ -91,7 +92,7 @@ pub use toolbar::{ToolbarItemLocation, ToolbarItemView};
// fn has_focus(&self, cx: &WindowContext) -> bool; // fn has_focus(&self, cx: &WindowContext) -> bool;
// } // }
// impl<T: Modal> ModalHandle for ViewHandle<T> { // impl<T: Modal> ModalHandle for View<T> {
// fn as_any(&self) -> &AnyViewHandle { // fn as_any(&self) -> &AnyViewHandle {
// self // self
// } // }
@ -376,61 +377,61 @@ pub fn register_project_item<I: ProjectItem>(cx: &mut AppContext) {
}); });
} }
// type FollowableItemBuilder = fn( type FollowableItemBuilder = fn(
// ViewHandle<Pane>, View<Pane>,
// ViewHandle<Workspace>, View<Workspace>,
// ViewId, ViewId,
// &mut Option<proto::view::Variant>, &mut Option<proto::view::Variant>,
// &mut AppContext, &mut AppContext,
// ) -> Option<Task<Result<Box<dyn FollowableItemHandle>>>>; ) -> Option<Task<Result<Box<dyn FollowableItemHandle>>>>;
// type FollowableItemBuilders = HashMap< type FollowableItemBuilders = HashMap<
// TypeId, TypeId,
// ( (
// FollowableItemBuilder, FollowableItemBuilder,
// fn(&AnyViewHandle) -> Box<dyn FollowableItemHandle>, fn(&AnyView) -> Box<dyn FollowableItemHandle>,
// ), ),
// >; >;
// pub fn register_followable_item<I: FollowableItem>(cx: &mut AppContext) { pub fn register_followable_item<I: FollowableItem>(cx: &mut AppContext) {
// cx.update_default_global(|builders: &mut FollowableItemBuilders, _| { cx.update_default_global(|builders: &mut FollowableItemBuilders, _| {
// builders.insert( builders.insert(
// TypeId::of::<I>(), TypeId::of::<I>(),
// ( (
// |pane, workspace, id, state, cx| { |pane, workspace, id, state, cx| {
// I::from_state_proto(pane, workspace, id, state, cx).map(|task| { I::from_state_proto(pane, workspace, id, state, cx).map(|task| {
// cx.foreground() cx.foreground()
// .spawn(async move { Ok(Box::new(task.await?) as Box<_>) }) .spawn(async move { Ok(Box::new(task.await?) as Box<_>) })
// }) })
// }, },
// |this| Box::new(this.clone().downcast::<I>().unwrap()), |this| Box::new(this.clone().downcast::<I>().unwrap()),
// ), ),
// ); );
// }); });
// } }
// type ItemDeserializers = HashMap< type ItemDeserializers = HashMap<
// Arc<str>, Arc<str>,
// fn( fn(
// ModelHandle<Project>, Handle<Project>,
// WeakViewHandle<Workspace>, WeakView<Workspace>,
// WorkspaceId, WorkspaceId,
// ItemId, ItemId,
// &mut ViewContext<Pane>, &mut ViewContext<Pane>,
// ) -> Task<Result<Box<dyn ItemHandle>>>, ) -> Task<Result<Box<dyn ItemHandle>>>,
// >; >;
// pub fn register_deserializable_item<I: Item>(cx: &mut AppContext) { pub fn register_deserializable_item<I: Item>(cx: &mut AppContext) {
// cx.update_default_global(|deserializers: &mut ItemDeserializers, _cx| { cx.update_default_global(|deserializers: &mut ItemDeserializers, _cx| {
// if let Some(serialized_item_kind) = I::serialized_item_kind() { if let Some(serialized_item_kind) = I::serialized_item_kind() {
// deserializers.insert( deserializers.insert(
// Arc::from(serialized_item_kind), Arc::from(serialized_item_kind),
// |project, workspace, workspace_id, item_id, cx| { |project, workspace, workspace_id, item_id, cx| {
// let task = I::deserialize(project, workspace, workspace_id, item_id, cx); let task = I::deserialize(project, workspace, workspace_id, item_id, cx);
// cx.foreground() cx.foreground()
// .spawn(async { Ok(Box::new(task.await?) as Box<_>) }) .spawn(async { Ok(Box::new(task.await?) as Box<_>) })
// }, },
// ); );
// } }
// }); });
// } }
pub struct AppState { pub struct AppState {
pub languages: Arc<LanguageRegistry>, pub languages: Arc<LanguageRegistry>,
@ -493,54 +494,54 @@ struct Follower {
// } // }
// } // }
// struct DelayedDebouncedEditAction { struct DelayedDebouncedEditAction {
// task: Option<Task<()>>, task: Option<Task<()>>,
// cancel_channel: Option<oneshot::Sender<()>>, cancel_channel: Option<oneshot::Sender<()>>,
// } }
// impl DelayedDebouncedEditAction { impl DelayedDebouncedEditAction {
// fn new() -> DelayedDebouncedEditAction { fn new() -> DelayedDebouncedEditAction {
// DelayedDebouncedEditAction { DelayedDebouncedEditAction {
// task: None, task: None,
// cancel_channel: None, cancel_channel: None,
// } }
// } }
// fn fire_new<F>(&mut self, delay: Duration, cx: &mut ViewContext<Workspace>, func: F) fn fire_new<F>(&mut self, delay: Duration, cx: &mut ViewContext<Workspace>, func: F)
// where where
// F: 'static + FnOnce(&mut Workspace, &mut ViewContext<Workspace>) -> Task<Result<()>>, F: 'static + FnOnce(&mut Workspace, &mut ViewContext<Workspace>) -> Task<Result<()>>,
// { {
// if let Some(channel) = self.cancel_channel.take() { if let Some(channel) = self.cancel_channel.take() {
// _ = channel.send(()); _ = channel.send(());
// } }
// let (sender, mut receiver) = oneshot::channel::<()>(); let (sender, mut receiver) = oneshot::channel::<()>();
// self.cancel_channel = Some(sender); self.cancel_channel = Some(sender);
// let previous_task = self.task.take(); let previous_task = self.task.take();
// self.task = Some(cx.spawn(|workspace, mut cx| async move { self.task = Some(cx.spawn(|workspace, mut cx| async move {
// let mut timer = cx.background().timer(delay).fuse(); let mut timer = cx.background().timer(delay).fuse();
// if let Some(previous_task) = previous_task { if let Some(previous_task) = previous_task {
// previous_task.await; previous_task.await;
// } }
// futures::select_biased! { futures::select_biased! {
// _ = receiver => return, _ = receiver => return,
// _ = timer => {} _ = timer => {}
// } }
// if let Some(result) = workspace if let Some(result) = workspace
// .update(&mut cx, |workspace, cx| (func)(workspace, cx)) .update(&mut cx, |workspace, cx| (func)(workspace, cx))
// .log_err() .log_err()
// { {
// result.await.log_err(); result.await.log_err();
// } }
// })); }));
// } }
// } }
// pub enum Event { // pub enum Event {
// PaneAdded(ViewHandle<Pane>), // PaneAdded(View<Pane>),
// ContactRequestedJoin(u64), // ContactRequestedJoin(u64),
// } // }
@ -550,19 +551,19 @@ pub struct Workspace {
// zoomed: Option<AnyWeakViewHandle>, // zoomed: Option<AnyWeakViewHandle>,
// zoomed_position: Option<DockPosition>, // zoomed_position: Option<DockPosition>,
// center: PaneGroup, // center: PaneGroup,
// left_dock: ViewHandle<Dock>, // left_dock: View<Dock>,
// bottom_dock: ViewHandle<Dock>, // bottom_dock: View<Dock>,
// right_dock: ViewHandle<Dock>, // right_dock: View<Dock>,
panes: Vec<View<Pane>>, panes: Vec<View<Pane>>,
// panes_by_item: HashMap<usize, WeakViewHandle<Pane>>, // panes_by_item: HashMap<usize, WeakViewHandle<Pane>>,
// active_pane: ViewHandle<Pane>, // active_pane: View<Pane>,
last_active_center_pane: Option<WeakView<Pane>>, last_active_center_pane: Option<WeakView<Pane>>,
// last_active_view_id: Option<proto::ViewId>, // last_active_view_id: Option<proto::ViewId>,
// status_bar: ViewHandle<StatusBar>, // status_bar: View<StatusBar>,
// titlebar_item: Option<AnyViewHandle>, // titlebar_item: Option<AnyViewHandle>,
// notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>, // notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>,
project: Handle<Project>, project: Handle<Project>,
// follower_states: HashMap<ViewHandle<Pane>, FollowerState>, // follower_states: HashMap<View<Pane>, FollowerState>,
// last_leaders_by_pane: HashMap<WeakViewHandle<Pane>, PeerId>, // last_leaders_by_pane: HashMap<WeakViewHandle<Pane>, PeerId>,
// window_edited: bool, // window_edited: bool,
// active_call: Option<(ModelHandle<ActiveCall>, Vec<Subscription>)>, // active_call: Option<(ModelHandle<ActiveCall>, Vec<Subscription>)>,
@ -930,19 +931,19 @@ impl Workspace {
// self.weak_self.clone() // self.weak_self.clone()
// } // }
// pub fn left_dock(&self) -> &ViewHandle<Dock> { // pub fn left_dock(&self) -> &View<Dock> {
// &self.left_dock // &self.left_dock
// } // }
// pub fn bottom_dock(&self) -> &ViewHandle<Dock> { // pub fn bottom_dock(&self) -> &View<Dock> {
// &self.bottom_dock // &self.bottom_dock
// } // }
// pub fn right_dock(&self) -> &ViewHandle<Dock> { // pub fn right_dock(&self) -> &View<Dock> {
// &self.right_dock // &self.right_dock
// } // }
// pub fn add_panel<T: Panel>(&mut self, panel: ViewHandle<T>, cx: &mut ViewContext<Self>) // pub fn add_panel<T: Panel>(&mut self, panel: View<T>, cx: &mut ViewContext<Self>)
// where // where
// T::Event: std::fmt::Debug, // T::Event: std::fmt::Debug,
// { // {
@ -951,12 +952,12 @@ impl Workspace {
// pub fn add_panel_with_extra_event_handler<T: Panel, F>( // pub fn add_panel_with_extra_event_handler<T: Panel, F>(
// &mut self, // &mut self,
// panel: ViewHandle<T>, // panel: View<T>,
// cx: &mut ViewContext<Self>, // cx: &mut ViewContext<Self>,
// handler: F, // handler: F,
// ) where // ) where
// T::Event: std::fmt::Debug, // T::Event: std::fmt::Debug,
// F: Fn(&mut Self, &ViewHandle<T>, &T::Event, &mut ViewContext<Self>) + 'static, // F: Fn(&mut Self, &View<T>, &T::Event, &mut ViewContext<Self>) + 'static,
// { // {
// let dock = match panel.position(cx) { // let dock = match panel.position(cx) {
// DockPosition::Left => &self.left_dock, // DockPosition::Left => &self.left_dock,
@ -1033,7 +1034,7 @@ impl Workspace {
// dock.update(cx, |dock, cx| dock.add_panel(panel, cx)); // dock.update(cx, |dock, cx| dock.add_panel(panel, cx));
// } // }
// pub fn status_bar(&self) -> &ViewHandle<StatusBar> { // pub fn status_bar(&self) -> &View<StatusBar> {
// &self.status_bar // &self.status_bar
// } // }
@ -1617,10 +1618,10 @@ impl Workspace {
// &mut self, // &mut self,
// cx: &mut ViewContext<Self>, // cx: &mut ViewContext<Self>,
// add_view: F, // add_view: F,
// ) -> Option<ViewHandle<V>> // ) -> Option<View<V>>
// where // where
// V: 'static + Modal, // V: 'static + Modal,
// F: FnOnce(&mut Self, &mut ViewContext<Self>) -> ViewHandle<V>, // F: FnOnce(&mut Self, &mut ViewContext<Self>) -> View<V>,
// { // {
// cx.notify(); // cx.notify();
// // Whatever modal was visible is getting clobbered. If its the same type as V, then return // // Whatever modal was visible is getting clobbered. If its the same type as V, then return
@ -1649,7 +1650,7 @@ impl Workspace {
// } // }
// } // }
// pub fn modal<V: 'static + View>(&self) -> Option<ViewHandle<V>> { // pub fn modal<V: 'static + View>(&self) -> Option<View<V>> {
// self.modal // self.modal
// .as_ref() // .as_ref()
// .and_then(|modal| modal.view.as_any().clone().downcast::<V>()) // .and_then(|modal| modal.view.as_any().clone().downcast::<V>())
@ -1676,14 +1677,14 @@ impl Workspace {
// self.panes.iter().flat_map(|pane| pane.read(cx).items()) // self.panes.iter().flat_map(|pane| pane.read(cx).items())
// } // }
// pub fn item_of_type<T: Item>(&self, cx: &AppContext) -> Option<ViewHandle<T>> { // pub fn item_of_type<T: Item>(&self, cx: &AppContext) -> Option<View<T>> {
// self.items_of_type(cx).max_by_key(|item| item.id()) // self.items_of_type(cx).max_by_key(|item| item.id())
// } // }
// pub fn items_of_type<'a, T: Item>( // pub fn items_of_type<'a, T: Item>(
// &'a self, // &'a self,
// cx: &'a AppContext, // cx: &'a AppContext,
// ) -> impl 'a + Iterator<Item = ViewHandle<T>> { // ) -> impl 'a + Iterator<Item = View<T>> {
// self.panes // self.panes
// .iter() // .iter()
// .flat_map(|pane| pane.read(cx).items_of_type()) // .flat_map(|pane| pane.read(cx).items_of_type())
@ -1834,7 +1835,7 @@ impl Workspace {
// } // }
// /// Transfer focus to the panel of the given type. // /// Transfer focus to the panel of the given type.
// pub fn focus_panel<T: Panel>(&mut self, cx: &mut ViewContext<Self>) -> Option<ViewHandle<T>> { // pub fn focus_panel<T: Panel>(&mut self, cx: &mut ViewContext<Self>) -> Option<View<T>> {
// self.focus_or_unfocus_panel::<T>(cx, |_, _| true)? // self.focus_or_unfocus_panel::<T>(cx, |_, _| true)?
// .as_any() // .as_any()
// .clone() // .clone()
@ -1888,7 +1889,7 @@ impl Workspace {
// None // None
// } // }
// pub fn panel<T: Panel>(&self, cx: &WindowContext) -> Option<ViewHandle<T>> { // pub fn panel<T: Panel>(&self, cx: &WindowContext) -> Option<View<T>> {
// for dock in [&self.left_dock, &self.bottom_dock, &self.right_dock] { // for dock in [&self.left_dock, &self.bottom_dock, &self.right_dock] {
// let dock = dock.read(cx); // let dock = dock.read(cx);
// if let Some(panel) = dock.panel::<T>() { // if let Some(panel) = dock.panel::<T>() {
@ -1956,7 +1957,7 @@ impl Workspace {
// cx.notify(); // cx.notify();
// } // }
// fn add_pane(&mut self, cx: &mut ViewContext<Self>) -> ViewHandle<Pane> { // fn add_pane(&mut self, cx: &mut ViewContext<Self>) -> View<Pane> {
// let pane = cx.add_view(|cx| { // let pane = cx.add_view(|cx| {
// Pane::new( // Pane::new(
// self.weak_handle(), // self.weak_handle(),
@ -2138,7 +2139,7 @@ impl Workspace {
// &mut self, // &mut self,
// project_item: ModelHandle<T::Item>, // project_item: ModelHandle<T::Item>,
// cx: &mut ViewContext<Self>, // cx: &mut ViewContext<Self>,
// ) -> ViewHandle<T> // ) -> View<T>
// where // where
// T: ProjectItem, // T: ProjectItem,
// { // {
@ -2162,7 +2163,7 @@ impl Workspace {
// &mut self, // &mut self,
// project_item: ModelHandle<T::Item>, // project_item: ModelHandle<T::Item>,
// cx: &mut ViewContext<Self>, // cx: &mut ViewContext<Self>,
// ) -> ViewHandle<T> // ) -> View<T>
// where // where
// T: ProjectItem, // T: ProjectItem,
// { // {
@ -2259,7 +2260,7 @@ impl Workspace {
// &mut self, // &mut self,
// direction: SplitDirection, // direction: SplitDirection,
// cx: &mut ViewContext<Self>, // cx: &mut ViewContext<Self>,
// ) -> Option<&ViewHandle<Pane>> { // ) -> Option<&View<Pane>> {
// let Some(bounding_box) = self.center.bounding_box_for_pane(&self.active_pane) else { // let Some(bounding_box) = self.center.bounding_box_for_pane(&self.active_pane) else {
// return None; // return None;
// }; // };
@ -2280,7 +2281,7 @@ impl Workspace {
// self.center.pane_at_pixel_position(target) // self.center.pane_at_pixel_position(target)
// } // }
// fn handle_pane_focused(&mut self, pane: ViewHandle<Pane>, cx: &mut ViewContext<Self>) { // fn handle_pane_focused(&mut self, pane: View<Pane>, cx: &mut ViewContext<Self>) {
// if self.active_pane != pane { // if self.active_pane != pane {
// self.active_pane = pane.clone(); // self.active_pane = pane.clone();
// self.status_bar.update(cx, |status_bar, cx| { // self.status_bar.update(cx, |status_bar, cx| {
@ -2304,7 +2305,7 @@ impl Workspace {
// fn handle_pane_event( // fn handle_pane_event(
// &mut self, // &mut self,
// pane: ViewHandle<Pane>, // pane: View<Pane>,
// event: &pane::Event, // event: &pane::Event,
// cx: &mut ViewContext<Self>, // cx: &mut ViewContext<Self>,
// ) { // ) {
@ -2363,10 +2364,10 @@ impl Workspace {
// pub fn split_pane( // pub fn split_pane(
// &mut self, // &mut self,
// pane_to_split: ViewHandle<Pane>, // pane_to_split: View<Pane>,
// split_direction: SplitDirection, // split_direction: SplitDirection,
// cx: &mut ViewContext<Self>, // cx: &mut ViewContext<Self>,
// ) -> ViewHandle<Pane> { // ) -> View<Pane> {
// let new_pane = self.add_pane(cx); // let new_pane = self.add_pane(cx);
// self.center // self.center
// .split(&pane_to_split, &new_pane, split_direction) // .split(&pane_to_split, &new_pane, split_direction)
@ -2377,10 +2378,10 @@ impl Workspace {
// pub fn split_and_clone( // pub fn split_and_clone(
// &mut self, // &mut self,
// pane: ViewHandle<Pane>, // pane: View<Pane>,
// direction: SplitDirection, // direction: SplitDirection,
// cx: &mut ViewContext<Self>, // cx: &mut ViewContext<Self>,
// ) -> Option<ViewHandle<Pane>> { // ) -> Option<View<Pane>> {
// let item = pane.read(cx).active_item()?; // let item = pane.read(cx).active_item()?;
// let maybe_pane_handle = if let Some(clone) = item.clone_on_split(self.database_id(), cx) { // let maybe_pane_handle = if let Some(clone) = item.clone_on_split(self.database_id(), cx) {
// let new_pane = self.add_pane(cx); // let new_pane = self.add_pane(cx);
@ -2440,8 +2441,8 @@ impl Workspace {
// pub fn move_item( // pub fn move_item(
// &mut self, // &mut self,
// source: ViewHandle<Pane>, // source: View<Pane>,
// destination: ViewHandle<Pane>, // destination: View<Pane>,
// item_id_to_move: usize, // item_id_to_move: usize,
// destination_index: usize, // destination_index: usize,
// cx: &mut ViewContext<Self>, // cx: &mut ViewContext<Self>,
@ -2473,7 +2474,7 @@ impl Workspace {
// }); // });
// } // }
// fn remove_pane(&mut self, pane: ViewHandle<Pane>, cx: &mut ViewContext<Self>) { // fn remove_pane(&mut self, pane: View<Pane>, cx: &mut ViewContext<Self>) {
// if self.center.remove(&pane).unwrap() { // if self.center.remove(&pane).unwrap() {
// self.force_remove_pane(&pane, cx); // self.force_remove_pane(&pane, cx);
// self.unfollow(&pane, cx); // self.unfollow(&pane, cx);
@ -2488,11 +2489,11 @@ impl Workspace {
// } // }
// } // }
// pub fn panes(&self) -> &[ViewHandle<Pane>] { // pub fn panes(&self) -> &[View<Pane>] {
// &self.panes // &self.panes
// } // }
// pub fn active_pane(&self) -> &ViewHandle<Pane> { // pub fn active_pane(&self) -> &View<Pane> {
// &self.active_pane // &self.active_pane
// } // }
@ -2651,7 +2652,7 @@ impl Workspace {
// pub fn unfollow( // pub fn unfollow(
// &mut self, // &mut self,
// pane: &ViewHandle<Pane>, // pane: &View<Pane>,
// cx: &mut ViewContext<Self>, // cx: &mut ViewContext<Self>,
// ) -> Option<PeerId> { // ) -> Option<PeerId> {
// let state = self.follower_states.remove(pane)?; // let state = self.follower_states.remove(pane)?;
@ -2959,7 +2960,7 @@ impl Workspace {
// async fn add_views_from_leader( // async fn add_views_from_leader(
// this: WeakViewHandle<Self>, // this: WeakViewHandle<Self>,
// leader_id: PeerId, // leader_id: PeerId,
// panes: Vec<ViewHandle<Pane>>, // panes: Vec<View<Pane>>,
// views: Vec<proto::View>, // views: Vec<proto::View>,
// cx: &mut AsyncAppContext, // cx: &mut AsyncAppContext,
// ) -> Result<()> { // ) -> Result<()> {
@ -3060,7 +3061,7 @@ impl Workspace {
// }) // })
// } // }
// pub fn leader_for_pane(&self, pane: &ViewHandle<Pane>) -> Option<PeerId> { // pub fn leader_for_pane(&self, pane: &View<Pane>) -> Option<PeerId> {
// self.follower_states.get(pane).map(|state| state.leader_id) // self.follower_states.get(pane).map(|state| state.leader_id)
// } // }
@ -3133,9 +3134,9 @@ impl Workspace {
// fn shared_screen_for_peer( // fn shared_screen_for_peer(
// &self, // &self,
// peer_id: PeerId, // peer_id: PeerId,
// pane: &ViewHandle<Pane>, // pane: &View<Pane>,
// cx: &mut ViewContext<Self>, // cx: &mut ViewContext<Self>,
// ) -> Option<ViewHandle<SharedScreen>> { // ) -> Option<View<SharedScreen>> {
// let call = self.active_call()?; // let call = self.active_call()?;
// let room = call.read(cx).room()?.read(cx); // let room = call.read(cx).room()?.read(cx);
// let participant = room.remote_participant_for_peer_id(peer_id)?; // let participant = room.remote_participant_for_peer_id(peer_id)?;
@ -3229,7 +3230,7 @@ impl Workspace {
// } // }
// } // }
// fn force_remove_pane(&mut self, pane: &ViewHandle<Pane>, cx: &mut ViewContext<Workspace>) { // fn force_remove_pane(&mut self, pane: &View<Pane>, cx: &mut ViewContext<Workspace>) {
// self.panes.retain(|p| p != pane); // self.panes.retain(|p| p != pane);
// cx.focus(self.panes.last().unwrap()); // cx.focus(self.panes.last().unwrap());
// if self.last_active_center_pane == Some(pane.downgrade()) { // if self.last_active_center_pane == Some(pane.downgrade()) {
@ -3248,7 +3249,7 @@ 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: &ViewHandle<Pane>, // pane_handle: &View<Pane>,
// cx: &AppContext, // cx: &AppContext,
// ) -> SerializedPane { // ) -> SerializedPane {
// let (items, active) = { // let (items, active) = {
@ -4075,7 +4076,7 @@ impl Workspace {
// fn file_project_paths(&self, cx: &AppContext) -> Vec<ProjectPath>; // fn file_project_paths(&self, cx: &AppContext) -> Vec<ProjectPath>;
// } // }
// impl WorkspaceHandle for ViewHandle<Workspace> { // impl WorkspaceHandle for View<Workspace> {
// fn file_project_paths(&self, cx: &AppContext) -> Vec<ProjectPath> { // fn file_project_paths(&self, cx: &AppContext) -> Vec<ProjectPath> {
// self.read(cx) // self.read(cx)
// .worktrees(cx) // .worktrees(cx)
@ -4320,13 +4321,16 @@ pub async fn activate_workspace_for_project(
// None // None
// } // }
use client2::{proto::PeerId, Client, UserStore}; use client2::{
proto::{self, PeerId, ViewId},
Client, UserStore,
};
use collections::{HashMap, HashSet}; use collections::{HashMap, HashSet};
use gpui2::{ use gpui2::{
AnyHandle, AppContext, AsyncAppContext, DisplayId, Handle, MainThread, Task, View, ViewContext, AnyHandle, AnyView, AppContext, AsyncAppContext, DisplayId, Handle, MainThread, Task, View,
WeakHandle, WeakView, WindowBounds, WindowHandle, WindowOptions, ViewContext, WeakHandle, WeakView, WindowBounds, WindowHandle, WindowOptions,
}; };
use item::{ItemHandle, ProjectItem}; use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem};
use language2::LanguageRegistry; use language2::LanguageRegistry;
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use project2::{Project, ProjectEntryId, ProjectPath, Worktree}; use project2::{Project, ProjectEntryId, ProjectPath, Worktree};
@ -4334,6 +4338,7 @@ use std::{
any::TypeId, any::TypeId,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc, sync::Arc,
time::Duration,
}; };
use util::ResultExt; use util::ResultExt;

View file

@ -1,6 +1,6 @@
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use settings::Setting; use settings2::Settings;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct WorkspaceSettings { pub struct WorkspaceSettings {
@ -41,7 +41,7 @@ pub enum GitGutterSetting {
Hide, Hide,
} }
impl Setting for WorkspaceSettings { impl Settings for WorkspaceSettings {
const KEY: Option<&'static str> = None; const KEY: Option<&'static str> = None;
type FileContent = WorkspaceSettingsContent; type FileContent = WorkspaceSettingsContent;
@ -49,7 +49,7 @@ impl Setting for WorkspaceSettings {
fn load( fn load(
default_value: &Self::FileContent, default_value: &Self::FileContent,
user_values: &[&Self::FileContent], user_values: &[&Self::FileContent],
_: &gpui::AppContext, _: &gpui2::AppContext,
) -> anyhow::Result<Self> { ) -> anyhow::Result<Self> {
Self::load_via_json_merge(default_value, user_values) Self::load_via_json_merge(default_value, user_values)
} }