Detailed changes
@@ -8,6 +8,7 @@ use client2::{
proto::{self, PeerId, ViewId},
Client,
};
+use settings2::Settings;
use theme2::Theme;
// use client2::{
// proto::{self, PeerId},
@@ -16,8 +17,8 @@ use theme2::Theme;
// use gpui2::geometry::vector::Vector2F;
// use gpui2::AnyWindowHandle;
// use gpui2::{
-// fonts::HighlightStyle, AnyElement, AnyViewHandle, AppContext, ModelHandle, Task, View,
-// ViewContext, ViewHandle, WeakViewHandle, WindowContext,
+// fonts::HighlightStyle, AnyElement, AnyViewHandle, AppContext, Handle, Task, View,
+// ViewContext, View, WeakViewHandle, WindowContext,
// };
// use project2::{Project, ProjectEntryId, ProjectPath};
// use schemars::JsonSchema;
@@ -97,7 +98,7 @@ pub struct BreadcrumbText {
pub highlights: Option<Vec<(Range<usize>, HighlightStyle)>>,
}
-pub trait Item: EventEmitter {
+pub trait Item: EventEmitter + Sized {
// fn 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 {
@@ -138,14 +139,14 @@ pub trait Item: EventEmitter {
// }
// fn save(
// &mut self,
- // _project: ModelHandle<Project>,
+ // _project: Handle<Project>,
// _cx: &mut ViewContext<Self>,
// ) -> Task<Result<()>> {
// unimplemented!("save() must be implemented if can_save() returns true")
// }
// fn save_as(
// &mut self,
- // _project: ModelHandle<Project>,
+ // _project: Handle<Project>,
// _abs_path: PathBuf,
// _cx: &mut ViewContext<Self>,
// ) -> Task<Result<()>> {
@@ -153,7 +154,7 @@ pub trait Item: EventEmitter {
// }
// fn reload(
// &mut self,
- // _project: ModelHandle<Project>,
+ // _project: Handle<Project>,
// _cx: &mut ViewContext<Self>,
// ) -> Task<Result<()>> {
// unimplemented!("reload() must be implemented if can_save() returns true")
@@ -171,7 +172,7 @@ pub trait Item: EventEmitter {
// fn act_as_type<'a>(
// &'a self,
// type_id: TypeId,
- // self_handle: &'a ViewHandle<Self>,
+ // self_handle: &'a View<Self>,
// _: &'a AppContext,
// ) -> Option<&AnyViewHandle> {
// 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
// }
@@ -200,12 +201,12 @@ pub trait Item: EventEmitter {
// }
// fn deserialize(
- // _project: ModelHandle<Project>,
+ // _project: Handle<Project>,
// _workspace: WeakViewHandle<Workspace>,
// _workspace_id: WorkspaceId,
// _item_id: ItemId,
// _cx: &mut ViewContext<Pane>,
- // ) -> Task<Result<ViewHandle<Self>>> {
+ // ) -> Task<Result<View<Self>>> {
// unimplemented!(
// "deserialize() must be implemented if serialized_item_kind() returns Some(_)"
// )
@@ -218,27 +219,36 @@ pub trait Item: EventEmitter {
// }
}
-use core::fmt;
use std::{
- any::{Any, TypeId},
+ any::Any,
borrow::Cow,
+ cell::RefCell,
ops::Range,
path::PathBuf,
- sync::Arc,
+ rc::Rc,
+ sync::{
+ atomic::{AtomicBool, Ordering},
+ Arc,
+ },
+ time::Duration,
};
use gpui2::{
- AnyElement, AnyView, AnyWindowHandle, AppContext, EventEmitter, Handle, HighlightStyle, Pixels,
- Point, Task, View, ViewContext, WindowContext,
+ AnyElement, AnyWindowHandle, AppContext, EventEmitter, Handle, HighlightStyle, Pixels, Point,
+ Task, View, ViewContext, WindowContext,
};
use project2::{Project, ProjectEntryId, ProjectPath};
use smallvec::SmallVec;
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(
&self,
cx: &mut WindowContext,
@@ -305,355 +315,347 @@ pub trait WeakItemHandle {
// todo!()
// 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()
// }
-// 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)
// .and_then(|t| t.clone().downcast())
// }
// }
-// impl<T: Item> ItemHandle for ViewHandle<T> {
-// fn subscribe_to_item_events(
-// &self,
-// cx: &mut WindowContext,
-// handler: Box<dyn Fn(ItemEvent, &mut WindowContext)>,
-// ) -> gpui2::Subscription {
-// cx.subscribe(self, move |_, event, cx| {
-// for item_event in T::to_item_events(event) {
-// handler(item_event, cx)
-// }
-// })
-// }
-
-// fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option<Cow<'a, str>> {
-// self.read(cx).tab_tooltip_text(cx)
-// }
-
-// fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option<Cow<'a, str>> {
-// self.read(cx).tab_description(detail, cx)
-// }
-
-// fn tab_content(
-// &self,
-// detail: Option<usize>,
-// style: &theme2::Tab,
-// cx: &AppContext,
-// ) -> AnyElement<Pane> {
-// self.read(cx).tab_content(detail, style, cx)
-// }
-
-// fn dragged_tab_content(
-// &self,
-// detail: Option<usize>,
-// style: &theme2::Tab,
-// cx: &AppContext,
-// ) -> AnyElement<Workspace> {
-// self.read(cx).tab_content(detail, style, cx)
-// }
+impl<T: Item> ItemHandle for View<T> {
+ fn subscribe_to_item_events(
+ &self,
+ cx: &mut WindowContext,
+ handler: Box<dyn Fn(ItemEvent, &mut WindowContext)>,
+ ) -> gpui2::Subscription {
+ cx.subscribe(self, move |_, event, cx| {
+ for item_event in T::to_item_events(event) {
+ handler(item_event, cx)
+ }
+ })
+ }
-// fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
-// let this = self.read(cx);
-// let mut result = None;
-// if this.is_singleton(cx) {
-// this.for_each_project_item(cx, &mut |_, item| {
-// result = item.project_path(cx);
-// });
-// }
-// result
-// }
+ fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option<Cow<'a, str>> {
+ self.read(cx).tab_tooltip_text(cx)
+ }
-// fn project_entry_ids(&self, cx: &AppContext) -> SmallVec<[ProjectEntryId; 3]> {
-// let mut result = SmallVec::new();
-// self.read(cx).for_each_project_item(cx, &mut |_, item| {
-// if let Some(id) = item.entry_id(cx) {
-// result.push(id);
-// }
-// });
-// result
-// }
+ fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option<Cow<'a, str>> {
+ self.read(cx).tab_description(detail, cx)
+ }
-// fn project_item_model_ids(&self, cx: &AppContext) -> SmallVec<[usize; 3]> {
-// let mut result = SmallVec::new();
-// self.read(cx).for_each_project_item(cx, &mut |id, _| {
-// result.push(id);
-// });
-// result
-// }
+ fn tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Pane> {
+ self.read(cx).tab_content(detail, cx)
+ }
-// fn for_each_project_item(
-// &self,
-// cx: &AppContext,
-// f: &mut dyn FnMut(usize, &dyn project2::Item),
-// ) {
-// self.read(cx).for_each_project_item(cx, f)
-// }
+ fn dragged_tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Workspace> {
+ self.read(cx).tab_content(detail, cx)
+ }
-// fn is_singleton(&self, cx: &AppContext) -> bool {
-// self.read(cx).is_singleton(cx)
-// }
+ fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
+ let this = self.read(cx);
+ let mut result = None;
+ if this.is_singleton(cx) {
+ this.for_each_project_item(cx, &mut |_, item| {
+ result = item.project_path(cx);
+ });
+ }
+ result
+ }
-// fn boxed_clone(&self) -> Box<dyn ItemHandle> {
-// Box::new(self.clone())
-// }
+ fn project_entry_ids(&self, cx: &AppContext) -> SmallVec<[ProjectEntryId; 3]> {
+ let mut result = SmallVec::new();
+ self.read(cx).for_each_project_item(cx, &mut |_, item| {
+ if let Some(id) = item.entry_id(cx) {
+ result.push(id);
+ }
+ });
+ result
+ }
-// fn clone_on_split(
-// &self,
-// workspace_id: WorkspaceId,
-// cx: &mut WindowContext,
-// ) -> Option<Box<dyn ItemHandle>> {
-// self.update(cx, |item, cx| {
-// cx.add_option_view(|cx| item.clone_on_split(workspace_id, cx))
-// })
-// .map(|handle| Box::new(handle) as Box<dyn ItemHandle>)
-// }
+ fn project_item_model_ids(&self, cx: &AppContext) -> SmallVec<[usize; 3]> {
+ let mut result = SmallVec::new();
+ self.read(cx).for_each_project_item(cx, &mut |id, _| {
+ result.push(id);
+ });
+ result
+ }
-// fn added_to_pane(
-// &self,
-// workspace: &mut Workspace,
-// pane: ViewHandle<Pane>,
-// cx: &mut ViewContext<Workspace>,
-// ) {
-// let history = pane.read(cx).nav_history_for_item(self);
-// self.update(cx, |this, cx| {
-// this.set_nav_history(history, cx);
-// this.added_to_workspace(workspace, cx);
-// });
-
-// if let Some(followed_item) = self.to_followable_item_handle(cx) {
-// if let Some(message) = followed_item.to_state_proto(cx) {
-// workspace.update_followers(
-// followed_item.is_project_item(cx),
-// proto::update_followers::Variant::CreateView(proto::View {
-// id: followed_item
-// .remote_id(&workspace.app_state.client, cx)
-// .map(|id| id.to_proto()),
-// variant: Some(message),
-// leader_id: workspace.leader_for_pane(&pane),
-// }),
-// cx,
-// );
-// }
-// }
+ fn for_each_project_item(
+ &self,
+ cx: &AppContext,
+ f: &mut dyn FnMut(usize, &dyn project2::Item),
+ ) {
+ self.read(cx).for_each_project_item(cx, f)
+ }
-// if workspace
-// .panes_by_item
-// .insert(self.id(), pane.downgrade())
-// .is_none()
-// {
-// let mut pending_autosave = DelayedDebouncedEditAction::new();
-// let pending_update = Rc::new(RefCell::new(None));
-// let pending_update_scheduled = Rc::new(AtomicBool::new(false));
-
-// let mut event_subscription =
-// Some(cx.subscribe(self, move |workspace, item, event, cx| {
-// let pane = if let Some(pane) = workspace
-// .panes_by_item
-// .get(&item.id())
-// .and_then(|pane| pane.upgrade(cx))
-// {
-// pane
-// } else {
-// log::error!("unexpected item event after pane was dropped");
-// return;
-// };
-
-// if let Some(item) = item.to_followable_item_handle(cx) {
-// let is_project_item = item.is_project_item(cx);
-// let leader_id = workspace.leader_for_pane(&pane);
-
-// if leader_id.is_some() && item.should_unfollow_on_event(event, cx) {
-// workspace.unfollow(&pane, cx);
-// }
-
-// if item.add_event_to_update_proto(
-// event,
-// &mut *pending_update.borrow_mut(),
-// cx,
-// ) && !pending_update_scheduled.load(Ordering::SeqCst)
-// {
-// pending_update_scheduled.store(true, Ordering::SeqCst);
-// cx.after_window_update({
-// let pending_update = pending_update.clone();
-// let pending_update_scheduled = pending_update_scheduled.clone();
-// move |this, cx| {
-// pending_update_scheduled.store(false, Ordering::SeqCst);
-// this.update_followers(
-// is_project_item,
-// proto::update_followers::Variant::UpdateView(
-// proto::UpdateView {
-// id: item
-// .remote_id(&this.app_state.client, cx)
-// .map(|id| id.to_proto()),
-// variant: pending_update.borrow_mut().take(),
-// leader_id,
-// },
-// ),
-// cx,
-// );
-// }
-// });
-// }
-// }
-
-// for item_event in T::to_item_events(event).into_iter() {
-// match item_event {
-// ItemEvent::CloseItem => {
-// pane.update(cx, |pane, cx| {
-// pane.close_item_by_id(item.id(), crate::SaveIntent::Close, cx)
-// })
-// .detach_and_log_err(cx);
-// return;
-// }
-
-// ItemEvent::UpdateTab => {
-// pane.update(cx, |_, cx| {
-// cx.emit(pane::Event::ChangeItemTitle);
-// cx.notify();
-// });
-// }
-
-// ItemEvent::Edit => {
-// let autosave = settings2::get::<WorkspaceSettings>(cx).autosave;
-// if let AutosaveSetting::AfterDelay { milliseconds } = autosave {
-// let delay = Duration::from_millis(milliseconds);
-// let item = item.clone();
-// pending_autosave.fire_new(delay, cx, move |workspace, cx| {
-// Pane::autosave_item(&item, workspace.project().clone(), cx)
-// });
-// }
-// }
-
-// _ => {}
-// }
-// }
-// }));
-
-// cx.observe_focus(self, move |workspace, item, focused, cx| {
-// if !focused
-// && settings2::get::<WorkspaceSettings>(cx).autosave
-// == AutosaveSetting::OnFocusChange
-// {
-// Pane::autosave_item(&item, workspace.project.clone(), cx)
-// .detach_and_log_err(cx);
-// }
-// })
-// .detach();
+ fn is_singleton(&self, cx: &AppContext) -> bool {
+ self.read(cx).is_singleton(cx)
+ }
-// let item_id = self.id();
-// cx.observe_release(self, move |workspace, _, _| {
-// workspace.panes_by_item.remove(&item_id);
-// event_subscription.take();
-// })
-// .detach();
-// }
+ fn boxed_clone(&self) -> Box<dyn ItemHandle> {
+ Box::new(self.clone())
+ }
-// cx.defer(|workspace, cx| {
-// workspace.serialize_workspace(cx);
-// });
-// }
+ fn clone_on_split(
+ &self,
+ workspace_id: WorkspaceId,
+ cx: &mut WindowContext,
+ ) -> Option<Box<dyn ItemHandle>> {
+ self.update(cx, |item, cx| {
+ cx.add_option_view(|cx| item.clone_on_split(workspace_id, cx))
+ })
+ .map(|handle| Box::new(handle) as Box<dyn ItemHandle>)
+ }
-// fn deactivated(&self, cx: &mut WindowContext) {
-// self.update(cx, |this, cx| this.deactivated(cx));
-// }
+ fn added_to_pane(
+ &self,
+ workspace: &mut Workspace,
+ pane: View<Pane>,
+ cx: &mut ViewContext<Workspace>,
+ ) {
+ let history = pane.read(cx).nav_history_for_item(self);
+ self.update(cx, |this, cx| {
+ this.set_nav_history(history, cx);
+ this.added_to_workspace(workspace, cx);
+ });
+
+ if let Some(followed_item) = self.to_followable_item_handle(cx) {
+ if let Some(message) = followed_item.to_state_proto(cx) {
+ workspace.update_followers(
+ followed_item.is_project_item(cx),
+ proto::update_followers::Variant::CreateView(proto::View {
+ id: followed_item
+ .remote_id(&workspace.app_state.client, cx)
+ .map(|id| id.to_proto()),
+ variant: Some(message),
+ leader_id: workspace.leader_for_pane(&pane),
+ }),
+ cx,
+ );
+ }
+ }
+
+ if workspace
+ .panes_by_item
+ .insert(self.id(), pane.downgrade())
+ .is_none()
+ {
+ let mut pending_autosave = DelayedDebouncedEditAction::new();
+ let pending_update = Rc::new(RefCell::new(None));
+ let pending_update_scheduled = Rc::new(AtomicBool::new(false));
+
+ let mut event_subscription =
+ Some(cx.subscribe(self, move |workspace, item, event, cx| {
+ let pane = if let Some(pane) = workspace
+ .panes_by_item
+ .get(&item.id())
+ .and_then(|pane| pane.upgrade(cx))
+ {
+ pane
+ } else {
+ log::error!("unexpected item event after pane was dropped");
+ return;
+ };
+
+ if let Some(item) = item.to_followable_item_handle(cx) {
+ let is_project_item = item.is_project_item(cx);
+ let leader_id = workspace.leader_for_pane(&pane);
+
+ if leader_id.is_some() && item.should_unfollow_on_event(event, cx) {
+ workspace.unfollow(&pane, cx);
+ }
+
+ if item.add_event_to_update_proto(
+ event,
+ &mut *pending_update.borrow_mut(),
+ cx,
+ ) && !pending_update_scheduled.load(Ordering::SeqCst)
+ {
+ pending_update_scheduled.store(true, Ordering::SeqCst);
+ cx.after_window_update({
+ let pending_update = pending_update.clone();
+ let pending_update_scheduled = pending_update_scheduled.clone();
+ move |this, cx| {
+ pending_update_scheduled.store(false, Ordering::SeqCst);
+ this.update_followers(
+ is_project_item,
+ proto::update_followers::Variant::UpdateView(
+ proto::UpdateView {
+ id: item
+ .remote_id(&this.app_state.client, cx)
+ .map(|id| id.to_proto()),
+ variant: pending_update.borrow_mut().take(),
+ leader_id,
+ },
+ ),
+ cx,
+ );
+ }
+ });
+ }
+ }
+
+ for item_event in T::to_item_events(event).into_iter() {
+ match item_event {
+ ItemEvent::CloseItem => {
+ pane.update(cx, |pane, cx| {
+ pane.close_item_by_id(item.id(), crate::SaveIntent::Close, cx)
+ })
+ .detach_and_log_err(cx);
+ return;
+ }
+
+ ItemEvent::UpdateTab => {
+ pane.update(cx, |_, cx| {
+ cx.emit(pane::Event::ChangeItemTitle);
+ cx.notify();
+ });
+ }
+
+ ItemEvent::Edit => {
+ let autosave = WorkspaceSettings::get_global(cx).autosave;
+ if let AutosaveSetting::AfterDelay { milliseconds } = autosave {
+ let delay = Duration::from_millis(milliseconds);
+ let item = item.clone();
+ pending_autosave.fire_new(delay, cx, move |workspace, cx| {
+ Pane::autosave_item(&item, workspace.project().clone(), cx)
+ });
+ }
+ }
+
+ _ => {}
+ }
+ }
+ }));
+
+ cx.observe_focus(self, move |workspace, item, focused, cx| {
+ if !focused
+ && WorkspaceSettings::get_global(cx).autosave == AutosaveSetting::OnFocusChange
+ {
+ Pane::autosave_item(&item, workspace.project.clone(), cx)
+ .detach_and_log_err(cx);
+ }
+ })
+ .detach();
+
+ let item_id = self.id();
+ cx.observe_release(self, move |workspace, _, _| {
+ workspace.panes_by_item.remove(&item_id);
+ event_subscription.take();
+ })
+ .detach();
+ }
+
+ cx.defer(|workspace, cx| {
+ workspace.serialize_workspace(cx);
+ });
+ }
-// fn workspace_deactivated(&self, cx: &mut WindowContext) {
-// self.update(cx, |this, cx| this.workspace_deactivated(cx));
-// }
+ fn deactivated(&self, cx: &mut WindowContext) {
+ self.update(cx, |this, cx| this.deactivated(cx));
+ }
-// fn navigate(&self, data: Box<dyn Any>, cx: &mut WindowContext) -> bool {
-// self.update(cx, |this, cx| this.navigate(data, cx))
-// }
+ fn workspace_deactivated(&self, cx: &mut WindowContext) {
+ self.update(cx, |this, cx| this.workspace_deactivated(cx));
+ }
-// fn id(&self) -> usize {
-// self.id()
-// }
+ fn navigate(&self, data: Box<dyn Any>, cx: &mut WindowContext) -> bool {
+ self.update(cx, |this, cx| this.navigate(data, cx))
+ }
-// fn window(&self) -> AnyWindowHandle {
-// AnyViewHandle::window(self)
-// }
+ fn id(&self) -> usize {
+ self.id()
+ }
-// fn as_any(&self) -> &AnyViewHandle {
-// self
-// }
+ fn window(&self) -> AnyWindowHandle {
+ todo!()
+ // AnyViewHandle::window(self)
+ }
-// fn is_dirty(&self, cx: &AppContext) -> bool {
-// self.read(cx).is_dirty(cx)
-// }
+ // todo!()
+ // fn as_any(&self) -> &AnyViewHandle {
+ // self
+ // }
-// fn has_conflict(&self, cx: &AppContext) -> bool {
-// self.read(cx).has_conflict(cx)
-// }
+ fn is_dirty(&self, cx: &AppContext) -> bool {
+ self.read(cx).is_dirty(cx)
+ }
-// fn can_save(&self, cx: &AppContext) -> bool {
-// self.read(cx).can_save(cx)
-// }
+ fn has_conflict(&self, cx: &AppContext) -> bool {
+ self.read(cx).has_conflict(cx)
+ }
-// fn save(&self, project: ModelHandle<Project>, cx: &mut WindowContext) -> Task<Result<()>> {
-// self.update(cx, |item, cx| item.save(project, cx))
-// }
+ fn can_save(&self, cx: &AppContext) -> bool {
+ self.read(cx).can_save(cx)
+ }
-// fn save_as(
-// &self,
-// project: ModelHandle<Project>,
-// abs_path: PathBuf,
-// cx: &mut WindowContext,
-// ) -> Task<anyhow::Result<()>> {
-// self.update(cx, |item, cx| item.save_as(project, abs_path, cx))
-// }
+ fn save(&self, project: Handle<Project>, cx: &mut WindowContext) -> Task<Result<()>> {
+ self.update(cx, |item, cx| item.save(project, cx))
+ }
-// fn reload(&self, project: ModelHandle<Project>, cx: &mut WindowContext) -> Task<Result<()>> {
-// self.update(cx, |item, cx| item.reload(project, cx))
-// }
+ fn save_as(
+ &self,
+ project: Handle<Project>,
+ abs_path: PathBuf,
+ cx: &mut WindowContext,
+ ) -> Task<anyhow::Result<()>> {
+ self.update(cx, |item, cx| item.save_as(project, abs_path, 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 reload(&self, project: Handle<Project>, cx: &mut WindowContext) -> Task<Result<()>> {
+ self.update(cx, |item, cx| item.reload(project, cx))
+ }
-// fn to_followable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn FollowableItemHandle>> {
-// if cx.has_global::<FollowableItemBuilders>() {
-// let builders = cx.global::<FollowableItemBuilders>();
-// let item = self.as_any();
-// Some(builders.get(&item.view_type())?.1(item))
-// } else {
-// None
-// }
-// }
+ // todo!()
+ // 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>> {
+ if cx.has_global::<FollowableItemBuilders>() {
+ let builders = cx.global::<FollowableItemBuilders>();
+ let item = self.as_any();
+ Some(builders.get(&item.view_type())?.1(item))
+ } else {
+ None
+ }
+ }
-// fn on_release(
-// &self,
-// cx: &mut AppContext,
-// callback: Box<dyn FnOnce(&mut AppContext)>,
-// ) -> gpui2::Subscription {
-// cx.observe_release(self, move |_, cx| callback(cx))
-// }
+ fn on_release(
+ &self,
+ cx: &mut AppContext,
+ callback: Box<dyn FnOnce(&mut AppContext)>,
+ ) -> gpui2::Subscription {
+ cx.observe_release(self, move |_, cx| callback(cx))
+ }
-// fn to_searchable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn SearchableItemHandle>> {
-// self.read(cx).as_searchable(self)
-// }
+ fn to_searchable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn SearchableItemHandle>> {
+ self.read(cx).as_searchable(self)
+ }
-// fn breadcrumb_location(&self, cx: &AppContext) -> ToolbarItemLocation {
-// self.read(cx).breadcrumb_location()
-// }
+ fn breadcrumb_location(&self, cx: &AppContext) -> ToolbarItemLocation {
+ self.read(cx).breadcrumb_location()
+ }
-// fn breadcrumbs(&self, theme: &Theme, cx: &AppContext) -> Option<Vec<BreadcrumbText>> {
-// self.read(cx).breadcrumbs(theme, cx)
-// }
+ fn breadcrumbs(&self, theme: &Theme, cx: &AppContext) -> Option<Vec<BreadcrumbText>> {
+ self.read(cx).breadcrumbs(theme, cx)
+ }
-// fn serialized_item_kind(&self) -> Option<&'static str> {
-// T::serialized_item_kind()
-// }
+ fn serialized_item_kind(&self) -> Option<&'static str> {
+ T::serialized_item_kind()
+ }
-// fn show_toolbar(&self, cx: &AppContext) -> bool {
-// self.read(cx).show_toolbar()
-// }
+ fn show_toolbar(&self, cx: &AppContext) -> bool {
+ self.read(cx).show_toolbar()
+ }
-// fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option<Vector2F> {
-// self.read(cx).pixel_position_of_cursor(cx)
-// }
-// }
+ fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option<Point<Pixels>> {
+ self.read(cx).pixel_position_of_cursor(cx)
+ }
+}
// impl From<Box<dyn ItemHandle>> for AnyViewHandle {
// fn from(val: Box<dyn ItemHandle>) -> Self {
@@ -747,7 +749,7 @@ pub trait FollowableItemHandle: ItemHandle {
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> {
// self.read(cx).remote_id().or_else(|| {
// client.peer_id().map(|creator| ViewId {
@@ -780,7 +782,7 @@ pub trait FollowableItemHandle: ItemHandle {
// fn apply_update_proto(
// &self,
-// project: &ModelHandle<Project>,
+// project: &Handle<Project>,
// message: proto::update_view::Variant,
// cx: &mut WindowContext,
// ) -> Task<Result<()>> {
@@ -805,8 +807,8 @@ pub trait FollowableItemHandle: ItemHandle {
// use super::{Item, ItemEvent};
// use crate::{ItemId, ItemNavHistory, Pane, Workspace, WorkspaceId};
// use gpui2::{
-// elements::Empty, AnyElement, AppContext, Element, Entity, ModelHandle, Task, View,
-// ViewContext, ViewHandle, WeakViewHandle,
+// elements::Empty, AnyElement, AppContext, Element, Entity, Handle, Task, View,
+// ViewContext, View, WeakViewHandle,
// };
// use project2::{Project, ProjectEntryId, ProjectPath, WorktreeId};
// use smallvec::SmallVec;
@@ -827,7 +829,7 @@ pub trait FollowableItemHandle: ItemHandle {
// pub is_dirty: bool,
// pub is_singleton: bool,
// pub has_conflict: bool,
-// pub project_items: Vec<ModelHandle<TestProjectItem>>,
+// pub project_items: Vec<Handle<TestProjectItem>>,
// pub nav_history: Option<ItemNavHistory>,
// pub tab_descriptions: Option<Vec<&'static str>>,
// pub tab_detail: Cell<Option<usize>>,
@@ -872,7 +874,7 @@ pub trait FollowableItemHandle: ItemHandle {
// }
// 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 project_path = Some(ProjectPath {
// 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 {
// project_path: None,
// entry_id: None,
@@ -937,7 +939,7 @@ pub trait FollowableItemHandle: ItemHandle {
// 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.extend(items.iter().cloned());
// self
@@ -1048,7 +1050,7 @@ pub trait FollowableItemHandle: ItemHandle {
// fn save(
// &mut self,
-// _: ModelHandle<Project>,
+// _: Handle<Project>,
// _: &mut ViewContext<Self>,
// ) -> Task<anyhow::Result<()>> {
// self.save_count += 1;
@@ -1058,7 +1060,7 @@ pub trait FollowableItemHandle: ItemHandle {
// fn save_as(
// &mut self,
-// _: ModelHandle<Project>,
+// _: Handle<Project>,
// _: std::path::PathBuf,
// _: &mut ViewContext<Self>,
// ) -> Task<anyhow::Result<()>> {
@@ -1069,7 +1071,7 @@ pub trait FollowableItemHandle: ItemHandle {
// fn reload(
// &mut self,
-// _: ModelHandle<Project>,
+// _: Handle<Project>,
// _: &mut ViewContext<Self>,
// ) -> Task<anyhow::Result<()>> {
// self.reload_count += 1;
@@ -1086,12 +1088,12 @@ pub trait FollowableItemHandle: ItemHandle {
// }
// fn deserialize(
-// _project: ModelHandle<Project>,
+// _project: Handle<Project>,
// _workspace: WeakViewHandle<Workspace>,
// workspace_id: WorkspaceId,
// _item_id: ItemId,
// 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));
// Task::Ready(Some(anyhow::Ok(view)))
// }
@@ -29,7 +29,7 @@
// WindowContext,
// };
// use project2::{Project, ProjectEntryId, ProjectPath};
-// use serde::Deserialize;
+use serde::Deserialize;
// use std::{
// any::Any,
// cell::RefCell,
@@ -44,24 +44,24 @@
// use theme2::{Theme, ThemeSettings};
// use util::truncate_and_remove_front;
-// #[derive(PartialEq, Clone, Copy, Deserialize, Debug)]
-// #[serde(rename_all = "camelCase")]
-// pub enum SaveIntent {
-// /// write all files (even if unchanged)
-// /// prompt before overwriting on-disk changes
-// Save,
-// /// write any files that have local changes
-// /// prompt before overwriting on-disk changes
-// SaveAll,
-// /// always prompt for a new path
-// SaveAs,
-// /// prompt "you have unsaved changes" before writing
-// Close,
-// /// write all dirty files, don't prompt on conflict
-// Overwrite,
-// /// skip all save-related behavior
-// Skip,
-// }
+#[derive(PartialEq, Clone, Copy, Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub enum SaveIntent {
+ /// write all files (even if unchanged)
+ /// prompt before overwriting on-disk changes
+ Save,
+ /// write any files that have local changes
+ /// prompt before overwriting on-disk changes
+ SaveAll,
+ /// always prompt for a new path
+ SaveAs,
+ /// prompt "you have unsaved changes" before writing
+ Close,
+ /// write all dirty files, don't prompt on conflict
+ Overwrite,
+ /// skip all save-related behavior
+ Skip,
+}
// #[derive(Clone, Deserialize, PartialEq)]
// pub struct ActivateItem(pub usize);
@@ -159,7 +159,10 @@ pub enum Event {
ZoomOut,
}
-use crate::item::{ItemHandle, WeakItemHandle};
+use crate::{
+ item::{ItemHandle, WeakItemHandle},
+ SplitDirection,
+};
use collections::{HashMap, VecDeque};
use gpui2::{Handle, ViewContext, WeakView};
use project2::{Project, ProjectEntryId, ProjectPath};
@@ -1,8 +1,8 @@
-use crate::{pane_group::element::PaneAxisElement, AppState, FollowerState, Pane, Workspace};
+use crate::{AppState, FollowerState, Pane, Workspace};
use anyhow::{anyhow, Result};
-use call2::{ActiveCall, ParticipantLocation};
+use call2::ActiveCall;
use collections::HashMap;
-use gpui2::{Bounds, Handle, Pixels, Point, View, ViewContext};
+use gpui2::{size, AnyElement, AnyView, Bounds, Handle, Pixels, Point, View, ViewContext};
use project2::Project;
use serde::Deserialize;
use std::{cell::RefCell, rc::Rc, sync::Arc};
@@ -12,7 +12,7 @@ const HANDLE_HITBOX_SIZE: f32 = 4.0;
const HORIZONTAL_MIN_SIZE: f32 = 80.;
const VERTICAL_MIN_SIZE: f32 = 100.;
-enum Axis {
+pub enum Axis {
Vertical,
Horizontal,
}
@@ -96,7 +96,7 @@ impl PaneGroup {
follower_states: &HashMap<View<Pane>, FollowerState>,
active_call: Option<&Handle<ActiveCall>>,
active_pane: &View<Pane>,
- zoomed: Option<&AnyViewHandle>,
+ zoomed: Option<&AnyView>,
app_state: &Arc<AppState>,
cx: &mut ViewContext<Workspace>,
) -> AnyElement<Workspace> {
@@ -159,136 +159,138 @@ impl Member {
follower_states: &HashMap<View<Pane>, FollowerState>,
active_call: Option<&Handle<ActiveCall>>,
active_pane: &View<Pane>,
- zoomed: Option<&AnyViewHandle>,
+ zoomed: Option<&AnyView>,
app_state: &Arc<AppState>,
cx: &mut ViewContext<Workspace>,
) -> AnyElement<Workspace> {
- enum FollowIntoExternalProject {}
-
- match self {
- Member::Pane(pane) => {
- let pane_element = if Some(&**pane) == zoomed {
- Empty::new().into_any()
- } else {
- ChildView::new(pane, cx).into_any()
- };
-
- let leader = follower_states.get(pane).and_then(|state| {
- let room = active_call?.read(cx).room()?.read(cx);
- room.remote_participant_for_peer_id(state.leader_id)
- });
-
- let mut leader_border = Border::default();
- let mut leader_status_box = None;
- if let Some(leader) = &leader {
- let leader_color = theme
- .editor
- .selection_style_for_room_participant(leader.participant_index.0)
- .cursor;
- leader_border = Border::all(theme.workspace.leader_border_width, leader_color);
- leader_border
- .color
- .fade_out(1. - theme.workspace.leader_border_opacity);
- leader_border.overlay = true;
-
- leader_status_box = match leader.location {
- ParticipantLocation::SharedProject {
- project_id: leader_project_id,
- } => {
- if Some(leader_project_id) == project.read(cx).remote_id() {
- None
- } else {
- let leader_user = leader.user.clone();
- let leader_user_id = leader.user.id;
- Some(
- MouseEventHandler::new::<FollowIntoExternalProject, _>(
- pane.id(),
- cx,
- |_, _| {
- Label::new(
- format!(
- "Follow {} to their active project",
- leader_user.github_login,
- ),
- theme
- .workspace
- .external_location_message
- .text
- .clone(),
- )
- .contained()
- .with_style(
- theme.workspace.external_location_message.container,
- )
- },
- )
- .with_cursor_style(CursorStyle::PointingHand)
- .on_click(MouseButton::Left, move |_, this, cx| {
- crate::join_remote_project(
- leader_project_id,
- leader_user_id,
- this.app_state().clone(),
- cx,
- )
- .detach_and_log_err(cx);
- })
- .aligned()
- .bottom()
- .right()
- .into_any(),
- )
- }
- }
- ParticipantLocation::UnsharedProject => Some(
- Label::new(
- format!(
- "{} is viewing an unshared Zed project",
- leader.user.github_login
- ),
- theme.workspace.external_location_message.text.clone(),
- )
- .contained()
- .with_style(theme.workspace.external_location_message.container)
- .aligned()
- .bottom()
- .right()
- .into_any(),
- ),
- ParticipantLocation::External => Some(
- Label::new(
- format!(
- "{} is viewing a window outside of Zed",
- leader.user.github_login
- ),
- theme.workspace.external_location_message.text.clone(),
- )
- .contained()
- .with_style(theme.workspace.external_location_message.container)
- .aligned()
- .bottom()
- .right()
- .into_any(),
- ),
- };
- }
-
- Stack::new()
- .with_child(pane_element.contained().with_border(leader_border))
- .with_children(leader_status_box)
- .into_any()
- }
- Member::Axis(axis) => axis.render(
- project,
- basis + 1,
- theme,
- follower_states,
- active_call,
- active_pane,
- zoomed,
- app_state,
- cx,
- ),
- }
+ todo!()
+
+ // enum FollowIntoExternalProject {}
+
+ // match self {
+ // Member::Pane(pane) => {
+ // let pane_element = if Some(&**pane) == zoomed {
+ // Empty::new().into_any()
+ // } else {
+ // ChildView::new(pane, cx).into_any()
+ // };
+
+ // let leader = follower_states.get(pane).and_then(|state| {
+ // let room = active_call?.read(cx).room()?.read(cx);
+ // room.remote_participant_for_peer_id(state.leader_id)
+ // });
+
+ // let mut leader_border = Border::default();
+ // let mut leader_status_box = None;
+ // if let Some(leader) = &leader {
+ // let leader_color = theme
+ // .editor
+ // .selection_style_for_room_participant(leader.participant_index.0)
+ // .cursor;
+ // leader_border = Border::all(theme.workspace.leader_border_width, leader_color);
+ // leader_border
+ // .color
+ // .fade_out(1. - theme.workspace.leader_border_opacity);
+ // leader_border.overlay = true;
+
+ // leader_status_box = match leader.location {
+ // ParticipantLocation::SharedProject {
+ // project_id: leader_project_id,
+ // } => {
+ // if Some(leader_project_id) == project.read(cx).remote_id() {
+ // None
+ // } else {
+ // let leader_user = leader.user.clone();
+ // let leader_user_id = leader.user.id;
+ // Some(
+ // MouseEventHandler::new::<FollowIntoExternalProject, _>(
+ // pane.id(),
+ // cx,
+ // |_, _| {
+ // Label::new(
+ // format!(
+ // "Follow {} to their active project",
+ // leader_user.github_login,
+ // ),
+ // theme
+ // .workspace
+ // .external_location_message
+ // .text
+ // .clone(),
+ // )
+ // .contained()
+ // .with_style(
+ // theme.workspace.external_location_message.container,
+ // )
+ // },
+ // )
+ // .with_cursor_style(CursorStyle::PointingHand)
+ // .on_click(MouseButton::Left, move |_, this, cx| {
+ // crate::join_remote_project(
+ // leader_project_id,
+ // leader_user_id,
+ // this.app_state().clone(),
+ // cx,
+ // )
+ // .detach_and_log_err(cx);
+ // })
+ // .aligned()
+ // .bottom()
+ // .right()
+ // .into_any(),
+ // )
+ // }
+ // }
+ // ParticipantLocation::UnsharedProject => Some(
+ // Label::new(
+ // format!(
+ // "{} is viewing an unshared Zed project",
+ // leader.user.github_login
+ // ),
+ // theme.workspace.external_location_message.text.clone(),
+ // )
+ // .contained()
+ // .with_style(theme.workspace.external_location_message.container)
+ // .aligned()
+ // .bottom()
+ // .right()
+ // .into_any(),
+ // ),
+ // ParticipantLocation::External => Some(
+ // Label::new(
+ // format!(
+ // "{} is viewing a window outside of Zed",
+ // leader.user.github_login
+ // ),
+ // theme.workspace.external_location_message.text.clone(),
+ // )
+ // .contained()
+ // .with_style(theme.workspace.external_location_message.container)
+ // .aligned()
+ // .bottom()
+ // .right()
+ // .into_any(),
+ // ),
+ // };
+ // }
+
+ // Stack::new()
+ // .with_child(pane_element.contained().with_border(leader_border))
+ // .with_children(leader_status_box)
+ // .into_any()
+ // }
+ // Member::Axis(axis) => axis.render(
+ // project,
+ // basis + 1,
+ // theme,
+ // follower_states,
+ // active_call,
+ // active_pane,
+ // zoomed,
+ // app_state,
+ // cx,
+ // ),
+ // }
}
fn collect_panes<'a>(&'a self, panes: &mut Vec<&'a View<Pane>>) {
@@ -308,7 +310,7 @@ pub(crate) struct PaneAxis {
pub axis: Axis,
pub members: Vec<Member>,
pub flexes: Rc<RefCell<Vec<f32>>>,
- pub bounding_boxes: Rc<RefCell<Vec<Option<RectF>>>>,
+ pub bounding_boxes: Rc<RefCell<Vec<Option<Bounds<Pixels>>>>>,
}
impl PaneAxis {
@@ -428,7 +430,7 @@ impl PaneAxis {
}
}
- fn bounding_box_for_pane(&self, pane: &View<Pane>) -> Option<RectF> {
+ fn bounding_box_for_pane(&self, pane: &View<Pane>) -> Option<Bounds<Pixels>> {
debug_assert!(self.members.len() == self.bounding_boxes.borrow().len());
for (idx, member) in self.members.iter().enumerate() {
@@ -448,14 +450,14 @@ impl PaneAxis {
None
}
- fn pane_at_pixel_position(&self, coordinate: Vector2F) -> Option<&View<Pane>> {
+ fn pane_at_pixel_position(&self, coordinate: Point<Pixels>) -> Option<&View<Pane>> {
debug_assert!(self.members.len() == self.bounding_boxes.borrow().len());
let bounding_boxes = self.bounding_boxes.borrow();
for (idx, member) in self.members.iter().enumerate() {
if let Some(coordinates) = bounding_boxes[idx] {
- if coordinates.contains_point(coordinate) {
+ if coordinates.contains_point(&coordinate) {
return match member {
Member::Pane(found) => Some(found),
Member::Axis(axis) => axis.pane_at_pixel_position(coordinate),
@@ -474,59 +476,60 @@ impl PaneAxis {
follower_states: &HashMap<View<Pane>, FollowerState>,
active_call: Option<&Handle<ActiveCall>>,
active_pane: &View<Pane>,
- zoomed: Option<&AnyViewHandle>,
+ zoomed: Option<&AnyView>,
app_state: &Arc<AppState>,
cx: &mut ViewContext<Workspace>,
) -> AnyElement<Workspace> {
debug_assert!(self.members.len() == self.flexes.borrow().len());
- let mut pane_axis = PaneAxisElement::new(
- self.axis,
- basis,
- self.flexes.clone(),
- self.bounding_boxes.clone(),
- );
- let mut active_pane_ix = None;
-
- let mut members = self.members.iter().enumerate().peekable();
- while let Some((ix, member)) = members.next() {
- let last = members.peek().is_none();
-
- if member.contains(active_pane) {
- active_pane_ix = Some(ix);
- }
-
- let mut member = member.render(
- project,
- (basis + ix) * 10,
- theme,
- follower_states,
- active_call,
- active_pane,
- zoomed,
- app_state,
- cx,
- );
-
- if !last {
- let mut border = theme.workspace.pane_divider;
- border.left = false;
- border.right = false;
- border.top = false;
- border.bottom = false;
-
- match self.axis {
- Axis::Vertical => border.bottom = true,
- Axis::Horizontal => border.right = true,
- }
-
- member = member.contained().with_border(border).into_any();
- }
-
- pane_axis = pane_axis.with_child(member.into_any());
- }
- pane_axis.set_active_pane(active_pane_ix);
- pane_axis.into_any()
+ todo!()
+ // let mut pane_axis = PaneAxisElement::new(
+ // self.axis,
+ // basis,
+ // self.flexes.clone(),
+ // self.bounding_boxes.clone(),
+ // );
+ // let mut active_pane_ix = None;
+
+ // let mut members = self.members.iter().enumerate().peekable();
+ // while let Some((ix, member)) = members.next() {
+ // let last = members.peek().is_none();
+
+ // if member.contains(active_pane) {
+ // active_pane_ix = Some(ix);
+ // }
+
+ // let mut member = member.render(
+ // project,
+ // (basis + ix) * 10,
+ // theme,
+ // follower_states,
+ // active_call,
+ // active_pane,
+ // zoomed,
+ // app_state,
+ // cx,
+ // );
+
+ // if !last {
+ // let mut border = theme.workspace.pane_divider;
+ // border.left = false;
+ // border.right = false;
+ // border.top = false;
+ // border.bottom = false;
+
+ // match self.axis {
+ // Axis::Vertical => border.bottom = true,
+ // Axis::Horizontal => border.right = true,
+ // }
+
+ // member = member.contained().with_border(border).into_any();
+ // }
+
+ // pane_axis = pane_axis.with_child(member.into_any());
+ // }
+ // pane_axis.set_active_pane(active_pane_ix);
+ // pane_axis.into_any()
}
}
@@ -543,7 +546,7 @@ impl SplitDirection {
[Self::Up, Self::Down, Self::Left, Self::Right]
}
- pub fn edge(&self, rect: RectF) -> f32 {
+ pub fn edge(&self, rect: Bounds<Pixels>) -> f32 {
match self {
Self::Up => rect.min_y(),
Self::Down => rect.max_y(),
@@ -552,19 +555,24 @@ impl SplitDirection {
}
}
- // Returns a new rectangle which shares an edge in SplitDirection and has `size` along SplitDirection
- pub fn along_edge(&self, rect: RectF, size: f32) -> RectF {
+ pub fn along_edge(&self, bounds: Bounds<Pixels>, length: Pixels) -> Bounds<Pixels> {
match self {
- Self::Up => RectF::new(rect.origin(), Vector2F::new(rect.width(), size)),
- Self::Down => RectF::new(
- rect.lower_left() - Vector2F::new(0., size),
- Vector2F::new(rect.width(), size),
- ),
- Self::Left => RectF::new(rect.origin(), Vector2F::new(size, rect.height())),
- Self::Right => RectF::new(
- rect.upper_right() - Vector2F::new(size, 0.),
- Vector2F::new(size, rect.height()),
- ),
+ Self::Up => Bounds {
+ origin: bounds.origin(),
+ size: size(bounds.width(), length),
+ },
+ Self::Down => Bounds {
+ origin: size(bounds.min_x(), bounds.max_y() - length),
+ size: size(bounds.width(), length),
+ },
+ Self::Left => Bounds {
+ origin: bounds.origin(),
+ size: size(length, bounds.height()),
+ },
+ Self::Right => Bounds {
+ origin: size(bounds.max_x() - length, bounds.min_y()),
+ size: size(length, bounds.height()),
+ },
}
}
@@ -583,403 +591,403 @@ impl SplitDirection {
}
}
-mod element {
- use std::{cell::RefCell, iter::from_fn, ops::Range, rc::Rc};
-
- use gpui::{
- geometry::{
- rect::RectF,
- vector::{vec2f, Vector2F},
- },
- json::{self, ToJson},
- platform::{CursorStyle, MouseButton},
- scene::MouseDrag,
- AnyElement, Axis, CursorRegion, Element, EventContext, MouseRegion, RectFExt,
- SizeConstraint, Vector2FExt, ViewContext,
- };
-
- use crate::{
- pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE},
- Workspace, WorkspaceSettings,
- };
-
- pub struct PaneAxisElement {
- axis: Axis,
- basis: usize,
- active_pane_ix: Option<usize>,
- flexes: Rc<RefCell<Vec<f32>>>,
- children: Vec<AnyElement<Workspace>>,
- bounding_boxes: Rc<RefCell<Vec<Option<RectF>>>>,
- }
-
- impl PaneAxisElement {
- pub fn new(
- axis: Axis,
- basis: usize,
- flexes: Rc<RefCell<Vec<f32>>>,
- bounding_boxes: Rc<RefCell<Vec<Option<RectF>>>>,
- ) -> Self {
- Self {
- axis,
- basis,
- flexes,
- bounding_boxes,
- active_pane_ix: None,
- children: Default::default(),
- }
- }
-
- pub fn set_active_pane(&mut self, active_pane_ix: Option<usize>) {
- self.active_pane_ix = active_pane_ix;
- }
-
- fn layout_children(
- &mut self,
- active_pane_magnification: f32,
- constraint: SizeConstraint,
- remaining_space: &mut f32,
- remaining_flex: &mut f32,
- cross_axis_max: &mut f32,
- view: &mut Workspace,
- cx: &mut ViewContext<Workspace>,
- ) {
- let flexes = self.flexes.borrow();
- let cross_axis = self.axis.invert();
- for (ix, child) in self.children.iter_mut().enumerate() {
- let flex = if active_pane_magnification != 1. {
- if let Some(active_pane_ix) = self.active_pane_ix {
- if ix == active_pane_ix {
- active_pane_magnification
- } else {
- 1.
- }
- } else {
- 1.
- }
- } else {
- flexes[ix]
- };
-
- let child_size = if *remaining_flex == 0.0 {
- *remaining_space
- } else {
- let space_per_flex = *remaining_space / *remaining_flex;
- space_per_flex * flex
- };
-
- let child_constraint = match self.axis {
- Axis::Horizontal => SizeConstraint::new(
- vec2f(child_size, constraint.min.y()),
- vec2f(child_size, constraint.max.y()),
- ),
- Axis::Vertical => SizeConstraint::new(
- vec2f(constraint.min.x(), child_size),
- vec2f(constraint.max.x(), child_size),
- ),
- };
- let child_size = child.layout(child_constraint, view, cx);
- *remaining_space -= child_size.along(self.axis);
- *remaining_flex -= flex;
- *cross_axis_max = cross_axis_max.max(child_size.along(cross_axis));
- }
- }
-
- fn handle_resize(
- flexes: Rc<RefCell<Vec<f32>>>,
- axis: Axis,
- preceding_ix: usize,
- child_start: Vector2F,
- drag_bounds: RectF,
- ) -> impl Fn(MouseDrag, &mut Workspace, &mut EventContext<Workspace>) {
- let size = move |ix, flexes: &[f32]| {
- drag_bounds.length_along(axis) * (flexes[ix] / flexes.len() as f32)
- };
-
- move |drag, workspace: &mut Workspace, cx| {
- if drag.end {
- // TODO: Clear cascading resize state
- return;
- }
- let min_size = match axis {
- Axis::Horizontal => HORIZONTAL_MIN_SIZE,
- Axis::Vertical => VERTICAL_MIN_SIZE,
- };
- let mut flexes = flexes.borrow_mut();
-
- // Don't allow resizing to less than the minimum size, if elements are already too small
- if min_size - 1. > size(preceding_ix, flexes.as_slice()) {
- return;
- }
-
- let mut proposed_current_pixel_change = (drag.position - child_start).along(axis)
- - size(preceding_ix, flexes.as_slice());
-
- let flex_changes = |pixel_dx, target_ix, next: isize, flexes: &[f32]| {
- let flex_change = pixel_dx / drag_bounds.length_along(axis);
- let current_target_flex = flexes[target_ix] + flex_change;
- let next_target_flex =
- flexes[(target_ix as isize + next) as usize] - flex_change;
- (current_target_flex, next_target_flex)
- };
-
- let mut successors = from_fn({
- let forward = proposed_current_pixel_change > 0.;
- let mut ix_offset = 0;
- let len = flexes.len();
- move || {
- let result = if forward {
- (preceding_ix + 1 + ix_offset < len).then(|| preceding_ix + ix_offset)
- } else {
- (preceding_ix as isize - ix_offset as isize >= 0)
- .then(|| preceding_ix - ix_offset)
- };
-
- ix_offset += 1;
-
- result
- }
- });
-
- while proposed_current_pixel_change.abs() > 0. {
- let Some(current_ix) = successors.next() else {
- break;
- };
-
- let next_target_size = f32::max(
- size(current_ix + 1, flexes.as_slice()) - proposed_current_pixel_change,
- min_size,
- );
-
- let current_target_size = f32::max(
- size(current_ix, flexes.as_slice())
- + size(current_ix + 1, flexes.as_slice())
- - next_target_size,
- min_size,
- );
-
- let current_pixel_change =
- current_target_size - size(current_ix, flexes.as_slice());
-
- let (current_target_flex, next_target_flex) =
- flex_changes(current_pixel_change, current_ix, 1, flexes.as_slice());
-
- flexes[current_ix] = current_target_flex;
- flexes[current_ix + 1] = next_target_flex;
-
- proposed_current_pixel_change -= current_pixel_change;
- }
-
- workspace.schedule_serialize(cx);
- cx.notify();
- }
- }
- }
-
- impl Extend<AnyElement<Workspace>> for PaneAxisElement {
- fn extend<T: IntoIterator<Item = AnyElement<Workspace>>>(&mut self, children: T) {
- self.children.extend(children);
- }
- }
-
- impl Element<Workspace> for PaneAxisElement {
- type LayoutState = f32;
- type PaintState = ();
-
- fn layout(
- &mut self,
- constraint: SizeConstraint,
- view: &mut Workspace,
- cx: &mut ViewContext<Workspace>,
- ) -> (Vector2F, Self::LayoutState) {
- debug_assert!(self.children.len() == self.flexes.borrow().len());
-
- let active_pane_magnification =
- settings::get::<WorkspaceSettings>(cx).active_pane_magnification;
-
- let mut remaining_flex = 0.;
-
- if active_pane_magnification != 1. {
- let active_pane_flex = self
- .active_pane_ix
- .map(|_| active_pane_magnification)
- .unwrap_or(1.);
- remaining_flex += self.children.len() as f32 - 1. + active_pane_flex;
- } else {
- for flex in self.flexes.borrow().iter() {
- remaining_flex += flex;
- }
- }
-
- let mut cross_axis_max: f32 = 0.0;
- let mut remaining_space = constraint.max_along(self.axis);
-
- if remaining_space.is_infinite() {
- panic!("flex contains flexible children but has an infinite constraint along the flex axis");
- }
-
- self.layout_children(
- active_pane_magnification,
- constraint,
- &mut remaining_space,
- &mut remaining_flex,
- &mut cross_axis_max,
- view,
- cx,
- );
-
- let mut size = match self.axis {
- Axis::Horizontal => vec2f(constraint.max.x() - remaining_space, cross_axis_max),
- Axis::Vertical => vec2f(cross_axis_max, constraint.max.y() - remaining_space),
- };
-
- if constraint.min.x().is_finite() {
- size.set_x(size.x().max(constraint.min.x()));
- }
- if constraint.min.y().is_finite() {
- size.set_y(size.y().max(constraint.min.y()));
- }
-
- if size.x() > constraint.max.x() {
- size.set_x(constraint.max.x());
- }
- if size.y() > constraint.max.y() {
- size.set_y(constraint.max.y());
- }
-
- (size, remaining_space)
- }
-
- fn paint(
- &mut self,
- bounds: RectF,
- visible_bounds: RectF,
- remaining_space: &mut Self::LayoutState,
- view: &mut Workspace,
- cx: &mut ViewContext<Workspace>,
- ) -> Self::PaintState {
- let can_resize = settings::get::<WorkspaceSettings>(cx).active_pane_magnification == 1.;
- let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
-
- let overflowing = *remaining_space < 0.;
- if overflowing {
- cx.scene().push_layer(Some(visible_bounds));
- }
-
- let mut child_origin = bounds.origin();
-
- let mut bounding_boxes = self.bounding_boxes.borrow_mut();
- bounding_boxes.clear();
-
- let mut children_iter = self.children.iter_mut().enumerate().peekable();
- while let Some((ix, child)) = children_iter.next() {
- let child_start = child_origin.clone();
- child.paint(child_origin, visible_bounds, view, cx);
-
- bounding_boxes.push(Some(RectF::new(child_origin, child.size())));
-
- match self.axis {
- Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0),
- Axis::Vertical => child_origin += vec2f(0.0, child.size().y()),
- }
-
- if can_resize && children_iter.peek().is_some() {
- cx.scene().push_stacking_context(None, None);
-
- let handle_origin = match self.axis {
- Axis::Horizontal => child_origin - vec2f(HANDLE_HITBOX_SIZE / 2., 0.0),
- Axis::Vertical => child_origin - vec2f(0.0, HANDLE_HITBOX_SIZE / 2.),
- };
-
- let handle_bounds = match self.axis {
- Axis::Horizontal => RectF::new(
- handle_origin,
- vec2f(HANDLE_HITBOX_SIZE, visible_bounds.height()),
- ),
- Axis::Vertical => RectF::new(
- handle_origin,
- vec2f(visible_bounds.width(), HANDLE_HITBOX_SIZE),
- ),
- };
-
- let style = match self.axis {
- Axis::Horizontal => CursorStyle::ResizeLeftRight,
- Axis::Vertical => CursorStyle::ResizeUpDown,
- };
-
- cx.scene().push_cursor_region(CursorRegion {
- bounds: handle_bounds,
- style,
- });
-
- enum ResizeHandle {}
- let mut mouse_region = MouseRegion::new::<ResizeHandle>(
- cx.view_id(),
- self.basis + ix,
- handle_bounds,
- );
- mouse_region = mouse_region
- .on_drag(
- MouseButton::Left,
- Self::handle_resize(
- self.flexes.clone(),
- self.axis,
- ix,
- child_start,
- visible_bounds.clone(),
- ),
- )
- .on_click(MouseButton::Left, {
- let flexes = self.flexes.clone();
- move |e, v: &mut Workspace, cx| {
- if e.click_count >= 2 {
- let mut borrow = flexes.borrow_mut();
- *borrow = vec![1.; borrow.len()];
- v.schedule_serialize(cx);
- cx.notify();
- }
- }
- });
- cx.scene().push_mouse_region(mouse_region);
-
- cx.scene().pop_stacking_context();
- }
- }
-
- if overflowing {
- cx.scene().pop_layer();
- }
- }
-
- fn rect_for_text_range(
- &self,
- range_utf16: Range<usize>,
- _: RectF,
- _: RectF,
- _: &Self::LayoutState,
- _: &Self::PaintState,
- view: &Workspace,
- cx: &ViewContext<Workspace>,
- ) -> Option<RectF> {
- self.children
- .iter()
- .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx))
- }
-
- fn debug(
- &self,
- bounds: RectF,
- _: &Self::LayoutState,
- _: &Self::PaintState,
- view: &Workspace,
- cx: &ViewContext<Workspace>,
- ) -> json::Value {
- serde_json::json!({
- "type": "PaneAxis",
- "bounds": bounds.to_json(),
- "axis": self.axis.to_json(),
- "flexes": *self.flexes.borrow(),
- "children": self.children.iter().map(|child| child.debug(view, cx)).collect::<Vec<json::Value>>()
- })
- }
- }
-}
+// mod element {
+// // use std::{cell::RefCell, iter::from_fn, ops::Range, rc::Rc};
+
+// // use gpui::{
+// // geometry::{
+// // rect::Bounds<Pixels>,
+// // vector::{vec2f, Vector2F},
+// // },
+// // json::{self, ToJson},
+// // platform::{CursorStyle, MouseButton},
+// // scene::MouseDrag,
+// // AnyElement, Axis, CursorRegion, Element, EventContext, MouseRegion, Bounds<Pixels>Ext,
+// // SizeConstraint, Vector2FExt, ViewContext,
+// // };
+
+// use crate::{
+// pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE},
+// Workspace, WorkspaceSettings,
+// };
+
+// pub struct PaneAxisElement {
+// axis: Axis,
+// basis: usize,
+// active_pane_ix: Option<usize>,
+// flexes: Rc<RefCell<Vec<f32>>>,
+// children: Vec<AnyElement<Workspace>>,
+// bounding_boxes: Rc<RefCell<Vec<Option<Bounds<Pixels>>>>>,
+// }
+
+// impl PaneAxisElement {
+// pub fn new(
+// axis: Axis,
+// basis: usize,
+// flexes: Rc<RefCell<Vec<f32>>>,
+// bounding_boxes: Rc<RefCell<Vec<Option<Bounds<Pixels>>>>>,
+// ) -> Self {
+// Self {
+// axis,
+// basis,
+// flexes,
+// bounding_boxes,
+// active_pane_ix: None,
+// children: Default::default(),
+// }
+// }
+
+// pub fn set_active_pane(&mut self, active_pane_ix: Option<usize>) {
+// self.active_pane_ix = active_pane_ix;
+// }
+
+// fn layout_children(
+// &mut self,
+// active_pane_magnification: f32,
+// constraint: SizeConstraint,
+// remaining_space: &mut f32,
+// remaining_flex: &mut f32,
+// cross_axis_max: &mut f32,
+// view: &mut Workspace,
+// cx: &mut ViewContext<Workspace>,
+// ) {
+// let flexes = self.flexes.borrow();
+// let cross_axis = self.axis.invert();
+// for (ix, child) in self.children.iter_mut().enumerate() {
+// let flex = if active_pane_magnification != 1. {
+// if let Some(active_pane_ix) = self.active_pane_ix {
+// if ix == active_pane_ix {
+// active_pane_magnification
+// } else {
+// 1.
+// }
+// } else {
+// 1.
+// }
+// } else {
+// flexes[ix]
+// };
+
+// let child_size = if *remaining_flex == 0.0 {
+// *remaining_space
+// } else {
+// let space_per_flex = *remaining_space / *remaining_flex;
+// space_per_flex * flex
+// };
+
+// let child_constraint = match self.axis {
+// Axis::Horizontal => SizeConstraint::new(
+// vec2f(child_size, constraint.min.y()),
+// vec2f(child_size, constraint.max.y()),
+// ),
+// Axis::Vertical => SizeConstraint::new(
+// vec2f(constraint.min.x(), child_size),
+// vec2f(constraint.max.x(), child_size),
+// ),
+// };
+// let child_size = child.layout(child_constraint, view, cx);
+// *remaining_space -= child_size.along(self.axis);
+// *remaining_flex -= flex;
+// *cross_axis_max = cross_axis_max.max(child_size.along(cross_axis));
+// }
+// }
+
+// fn handle_resize(
+// flexes: Rc<RefCell<Vec<f32>>>,
+// axis: Axis,
+// preceding_ix: usize,
+// child_start: Vector2F,
+// drag_bounds: Bounds<Pixels>,
+// ) -> impl Fn(MouseDrag, &mut Workspace, &mut EventContext<Workspace>) {
+// let size = move |ix, flexes: &[f32]| {
+// drag_bounds.length_along(axis) * (flexes[ix] / flexes.len() as f32)
+// };
+
+// move |drag, workspace: &mut Workspace, cx| {
+// if drag.end {
+// // TODO: Clear cascading resize state
+// return;
+// }
+// let min_size = match axis {
+// Axis::Horizontal => HORIZONTAL_MIN_SIZE,
+// Axis::Vertical => VERTICAL_MIN_SIZE,
+// };
+// let mut flexes = flexes.borrow_mut();
+
+// // Don't allow resizing to less than the minimum size, if elements are already too small
+// if min_size - 1. > size(preceding_ix, flexes.as_slice()) {
+// return;
+// }
+
+// let mut proposed_current_pixel_change = (drag.position - child_start).along(axis)
+// - size(preceding_ix, flexes.as_slice());
+
+// let flex_changes = |pixel_dx, target_ix, next: isize, flexes: &[f32]| {
+// let flex_change = pixel_dx / drag_bounds.length_along(axis);
+// let current_target_flex = flexes[target_ix] + flex_change;
+// let next_target_flex =
+// flexes[(target_ix as isize + next) as usize] - flex_change;
+// (current_target_flex, next_target_flex)
+// };
+
+// let mut successors = from_fn({
+// let forward = proposed_current_pixel_change > 0.;
+// let mut ix_offset = 0;
+// let len = flexes.len();
+// move || {
+// let result = if forward {
+// (preceding_ix + 1 + ix_offset < len).then(|| preceding_ix + ix_offset)
+// } else {
+// (preceding_ix as isize - ix_offset as isize >= 0)
+// .then(|| preceding_ix - ix_offset)
+// };
+
+// ix_offset += 1;
+
+// result
+// }
+// });
+
+// while proposed_current_pixel_change.abs() > 0. {
+// let Some(current_ix) = successors.next() else {
+// break;
+// };
+
+// let next_target_size = f32::max(
+// size(current_ix + 1, flexes.as_slice()) - proposed_current_pixel_change,
+// min_size,
+// );
+
+// let current_target_size = f32::max(
+// size(current_ix, flexes.as_slice())
+// + size(current_ix + 1, flexes.as_slice())
+// - next_target_size,
+// min_size,
+// );
+
+// let current_pixel_change =
+// current_target_size - size(current_ix, flexes.as_slice());
+
+// let (current_target_flex, next_target_flex) =
+// flex_changes(current_pixel_change, current_ix, 1, flexes.as_slice());
+
+// flexes[current_ix] = current_target_flex;
+// flexes[current_ix + 1] = next_target_flex;
+
+// proposed_current_pixel_change -= current_pixel_change;
+// }
+
+// workspace.schedule_serialize(cx);
+// cx.notify();
+// }
+// }
+// }
+
+// impl Extend<AnyElement<Workspace>> for PaneAxisElement {
+// fn extend<T: IntoIterator<Item = AnyElement<Workspace>>>(&mut self, children: T) {
+// self.children.extend(children);
+// }
+// }
+
+// impl Element<Workspace> for PaneAxisElement {
+// type LayoutState = f32;
+// type PaintState = ();
+
+// fn layout(
+// &mut self,
+// constraint: SizeConstraint,
+// view: &mut Workspace,
+// cx: &mut ViewContext<Workspace>,
+// ) -> (Vector2F, Self::LayoutState) {
+// debug_assert!(self.children.len() == self.flexes.borrow().len());
+
+// let active_pane_magnification =
+// settings::get::<WorkspaceSettings>(cx).active_pane_magnification;
+
+// let mut remaining_flex = 0.;
+
+// if active_pane_magnification != 1. {
+// let active_pane_flex = self
+// .active_pane_ix
+// .map(|_| active_pane_magnification)
+// .unwrap_or(1.);
+// remaining_flex += self.children.len() as f32 - 1. + active_pane_flex;
+// } else {
+// for flex in self.flexes.borrow().iter() {
+// remaining_flex += flex;
+// }
+// }
+
+// let mut cross_axis_max: f32 = 0.0;
+// let mut remaining_space = constraint.max_along(self.axis);
+
+// if remaining_space.is_infinite() {
+// panic!("flex contains flexible children but has an infinite constraint along the flex axis");
+// }
+
+// self.layout_children(
+// active_pane_magnification,
+// constraint,
+// &mut remaining_space,
+// &mut remaining_flex,
+// &mut cross_axis_max,
+// view,
+// cx,
+// );
+
+// let mut size = match self.axis {
+// Axis::Horizontal => vec2f(constraint.max.x() - remaining_space, cross_axis_max),
+// Axis::Vertical => vec2f(cross_axis_max, constraint.max.y() - remaining_space),
+// };
+
+// if constraint.min.x().is_finite() {
+// size.set_x(size.x().max(constraint.min.x()));
+// }
+// if constraint.min.y().is_finite() {
+// size.set_y(size.y().max(constraint.min.y()));
+// }
+
+// if size.x() > constraint.max.x() {
+// size.set_x(constraint.max.x());
+// }
+// if size.y() > constraint.max.y() {
+// size.set_y(constraint.max.y());
+// }
+
+// (size, remaining_space)
+// }
+
+// fn paint(
+// &mut self,
+// bounds: Bounds<Pixels>,
+// visible_bounds: Bounds<Pixels>,
+// remaining_space: &mut Self::LayoutState,
+// view: &mut Workspace,
+// cx: &mut ViewContext<Workspace>,
+// ) -> Self::PaintState {
+// let can_resize = settings::get::<WorkspaceSettings>(cx).active_pane_magnification == 1.;
+// let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
+
+// let overflowing = *remaining_space < 0.;
+// if overflowing {
+// cx.scene().push_layer(Some(visible_bounds));
+// }
+
+// let mut child_origin = bounds.origin();
+
+// let mut bounding_boxes = self.bounding_boxes.borrow_mut();
+// bounding_boxes.clear();
+
+// let mut children_iter = self.children.iter_mut().enumerate().peekable();
+// while let Some((ix, child)) = children_iter.next() {
+// let child_start = child_origin.clone();
+// child.paint(child_origin, visible_bounds, view, cx);
+
+// bounding_boxes.push(Some(Bounds<Pixels>::new(child_origin, child.size())));
+
+// match self.axis {
+// Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0),
+// Axis::Vertical => child_origin += vec2f(0.0, child.size().y()),
+// }
+
+// if can_resize && children_iter.peek().is_some() {
+// cx.scene().push_stacking_context(None, None);
+
+// let handle_origin = match self.axis {
+// Axis::Horizontal => child_origin - vec2f(HANDLE_HITBOX_SIZE / 2., 0.0),
+// Axis::Vertical => child_origin - vec2f(0.0, HANDLE_HITBOX_SIZE / 2.),
+// };
+
+// let handle_bounds = match self.axis {
+// Axis::Horizontal => Bounds<Pixels>::new(
+// handle_origin,
+// vec2f(HANDLE_HITBOX_SIZE, visible_bounds.height()),
+// ),
+// Axis::Vertical => Bounds<Pixels>::new(
+// handle_origin,
+// vec2f(visible_bounds.width(), HANDLE_HITBOX_SIZE),
+// ),
+// };
+
+// let style = match self.axis {
+// Axis::Horizontal => CursorStyle::ResizeLeftRight,
+// Axis::Vertical => CursorStyle::ResizeUpDown,
+// };
+
+// cx.scene().push_cursor_region(CursorRegion {
+// bounds: handle_bounds,
+// style,
+// });
+
+// enum ResizeHandle {}
+// let mut mouse_region = MouseRegion::new::<ResizeHandle>(
+// cx.view_id(),
+// self.basis + ix,
+// handle_bounds,
+// );
+// mouse_region = mouse_region
+// .on_drag(
+// MouseButton::Left,
+// Self::handle_resize(
+// self.flexes.clone(),
+// self.axis,
+// ix,
+// child_start,
+// visible_bounds.clone(),
+// ),
+// )
+// .on_click(MouseButton::Left, {
+// let flexes = self.flexes.clone();
+// move |e, v: &mut Workspace, cx| {
+// if e.click_count >= 2 {
+// let mut borrow = flexes.borrow_mut();
+// *borrow = vec![1.; borrow.len()];
+// v.schedule_serialize(cx);
+// cx.notify();
+// }
+// }
+// });
+// cx.scene().push_mouse_region(mouse_region);
+
+// cx.scene().pop_stacking_context();
+// }
+// }
+
+// if overflowing {
+// cx.scene().pop_layer();
+// }
+// }
+
+// fn rect_for_text_range(
+// &self,
+// range_utf16: Range<usize>,
+// _: Bounds<Pixels>,
+// _: Bounds<Pixels>,
+// _: &Self::LayoutState,
+// _: &Self::PaintState,
+// view: &Workspace,
+// cx: &ViewContext<Workspace>,
+// ) -> Option<Bounds<Pixels>> {
+// self.children
+// .iter()
+// .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx))
+// }
+
+// fn debug(
+// &self,
+// bounds: Bounds<Pixels>,
+// _: &Self::LayoutState,
+// _: &Self::PaintState,
+// view: &Workspace,
+// cx: &ViewContext<Workspace>,
+// ) -> json::Value {
+// serde_json::json!({
+// "type": "PaneAxis",
+// "bounds": bounds.to_json(),
+// "axis": self.axis.to_json(),
+// "flexes": *self.flexes.borrow(),
+// "children": self.children.iter().map(|child| child.debug(view, cx)).collect::<Vec<json::Value>>()
+// })
+// }
+// }
+// }
@@ -5,13 +5,13 @@ pub mod model;
use std::path::Path;
use anyhow::{anyhow, bail, Context, Result};
-use db::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql};
-use gpui::{platform::WindowBounds, Axis};
+use db2::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql};
+use gpui2::WindowBounds;
use util::{unzip_option, ResultExt};
use uuid::Uuid;
-use crate::WorkspaceId;
+use crate::{Axis, WorkspaceId};
use model::{
GroupId, PaneId, SerializedItem, SerializedPane, SerializedPaneGroup, SerializedWorkspace,
@@ -549,424 +549,425 @@ impl WorkspaceDb {
}
}
-#[cfg(test)]
-mod tests {
- use super::*;
- use db::open_test_db;
-
- #[gpui::test]
- async fn test_next_id_stability() {
- env_logger::try_init().ok();
-
- let db = WorkspaceDb(open_test_db("test_next_id_stability").await);
-
- db.write(|conn| {
- conn.migrate(
- "test_table",
- &[sql!(
- CREATE TABLE test_table(
- text TEXT,
- workspace_id INTEGER,
- FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id)
- ON DELETE CASCADE
- ) STRICT;
- )],
- )
- .unwrap();
- })
- .await;
-
- let id = db.next_id().await.unwrap();
- // Assert the empty row got inserted
- assert_eq!(
- Some(id),
- db.select_row_bound::<WorkspaceId, WorkspaceId>(sql!(
- SELECT workspace_id FROM workspaces WHERE workspace_id = ?
- ))
- .unwrap()(id)
- .unwrap()
- );
-
- db.write(move |conn| {
- conn.exec_bound(sql!(INSERT INTO test_table(text, workspace_id) VALUES (?, ?)))
- .unwrap()(("test-text-1", id))
- .unwrap()
- })
- .await;
-
- let test_text_1 = db
- .select_row_bound::<_, String>(sql!(SELECT text FROM test_table WHERE workspace_id = ?))
- .unwrap()(1)
- .unwrap()
- .unwrap();
- assert_eq!(test_text_1, "test-text-1");
- }
-
- #[gpui::test]
- async fn test_workspace_id_stability() {
- env_logger::try_init().ok();
-
- let db = WorkspaceDb(open_test_db("test_workspace_id_stability").await);
-
- db.write(|conn| {
- conn.migrate(
- "test_table",
- &[sql!(
- CREATE TABLE test_table(
- text TEXT,
- workspace_id INTEGER,
- FOREIGN KEY(workspace_id)
- REFERENCES workspaces(workspace_id)
- ON DELETE CASCADE
- ) STRICT;)],
- )
- })
- .await
- .unwrap();
-
- let mut workspace_1 = SerializedWorkspace {
- id: 1,
- location: (["/tmp", "/tmp2"]).into(),
- center_group: Default::default(),
- bounds: Default::default(),
- display: Default::default(),
- docks: Default::default(),
- };
-
- let workspace_2 = SerializedWorkspace {
- id: 2,
- location: (["/tmp"]).into(),
- center_group: Default::default(),
- bounds: Default::default(),
- display: Default::default(),
- docks: Default::default(),
- };
-
- db.save_workspace(workspace_1.clone()).await;
-
- db.write(|conn| {
- conn.exec_bound(sql!(INSERT INTO test_table(text, workspace_id) VALUES (?, ?)))
- .unwrap()(("test-text-1", 1))
- .unwrap();
- })
- .await;
-
- db.save_workspace(workspace_2.clone()).await;
-
- db.write(|conn| {
- conn.exec_bound(sql!(INSERT INTO test_table(text, workspace_id) VALUES (?, ?)))
- .unwrap()(("test-text-2", 2))
- .unwrap();
- })
- .await;
-
- workspace_1.location = (["/tmp", "/tmp3"]).into();
- db.save_workspace(workspace_1.clone()).await;
- db.save_workspace(workspace_1).await;
- db.save_workspace(workspace_2).await;
-
- let test_text_2 = db
- .select_row_bound::<_, String>(sql!(SELECT text FROM test_table WHERE workspace_id = ?))
- .unwrap()(2)
- .unwrap()
- .unwrap();
- assert_eq!(test_text_2, "test-text-2");
-
- let test_text_1 = db
- .select_row_bound::<_, String>(sql!(SELECT text FROM test_table WHERE workspace_id = ?))
- .unwrap()(1)
- .unwrap()
- .unwrap();
- assert_eq!(test_text_1, "test-text-1");
- }
-
- fn group(axis: gpui::Axis, children: Vec<SerializedPaneGroup>) -> SerializedPaneGroup {
- SerializedPaneGroup::Group {
- axis,
- flexes: None,
- children,
- }
- }
-
- #[gpui::test]
- async fn test_full_workspace_serialization() {
- env_logger::try_init().ok();
-
- let db = WorkspaceDb(open_test_db("test_full_workspace_serialization").await);
-
- // -----------------
- // | 1,2 | 5,6 |
- // | - - - | |
- // | 3,4 | |
- // -----------------
- let center_group = group(
- gpui::Axis::Horizontal,
- vec![
- group(
- gpui::Axis::Vertical,
- vec![
- SerializedPaneGroup::Pane(SerializedPane::new(
- vec![
- SerializedItem::new("Terminal", 5, false),
- SerializedItem::new("Terminal", 6, true),
- ],
- false,
- )),
- SerializedPaneGroup::Pane(SerializedPane::new(
- vec![
- SerializedItem::new("Terminal", 7, true),
- SerializedItem::new("Terminal", 8, false),
- ],
- false,
- )),
- ],
- ),
- SerializedPaneGroup::Pane(SerializedPane::new(
- vec![
- SerializedItem::new("Terminal", 9, false),
- SerializedItem::new("Terminal", 10, true),
- ],
- false,
- )),
- ],
- );
-
- let workspace = SerializedWorkspace {
- id: 5,
- location: (["/tmp", "/tmp2"]).into(),
- center_group,
- bounds: Default::default(),
- display: Default::default(),
- docks: Default::default(),
- };
-
- db.save_workspace(workspace.clone()).await;
- let round_trip_workspace = db.workspace_for_roots(&["/tmp2", "/tmp"]);
-
- assert_eq!(workspace, round_trip_workspace.unwrap());
-
- // Test guaranteed duplicate IDs
- db.save_workspace(workspace.clone()).await;
- db.save_workspace(workspace.clone()).await;
-
- let round_trip_workspace = db.workspace_for_roots(&["/tmp", "/tmp2"]);
- assert_eq!(workspace, round_trip_workspace.unwrap());
- }
-
- #[gpui::test]
- async fn test_workspace_assignment() {
- env_logger::try_init().ok();
-
- let db = WorkspaceDb(open_test_db("test_basic_functionality").await);
-
- let workspace_1 = SerializedWorkspace {
- id: 1,
- location: (["/tmp", "/tmp2"]).into(),
- center_group: Default::default(),
- bounds: Default::default(),
- display: Default::default(),
- docks: Default::default(),
- };
-
- let mut workspace_2 = SerializedWorkspace {
- id: 2,
- location: (["/tmp"]).into(),
- center_group: Default::default(),
- bounds: Default::default(),
- display: Default::default(),
- docks: Default::default(),
- };
-
- db.save_workspace(workspace_1.clone()).await;
- db.save_workspace(workspace_2.clone()).await;
-
- // Test that paths are treated as a set
- assert_eq!(
- db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
- workspace_1
- );
- assert_eq!(
- db.workspace_for_roots(&["/tmp2", "/tmp"]).unwrap(),
- workspace_1
- );
-
- // Make sure that other keys work
- assert_eq!(db.workspace_for_roots(&["/tmp"]).unwrap(), workspace_2);
- assert_eq!(db.workspace_for_roots(&["/tmp3", "/tmp2", "/tmp4"]), None);
-
- // Test 'mutate' case of updating a pre-existing id
- workspace_2.location = (["/tmp", "/tmp2"]).into();
-
- db.save_workspace(workspace_2.clone()).await;
- assert_eq!(
- db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
- workspace_2
- );
-
- // Test other mechanism for mutating
- let mut workspace_3 = SerializedWorkspace {
- id: 3,
- location: (&["/tmp", "/tmp2"]).into(),
- center_group: Default::default(),
- bounds: Default::default(),
- display: Default::default(),
- docks: Default::default(),
- };
-
- db.save_workspace(workspace_3.clone()).await;
- assert_eq!(
- db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
- workspace_3
- );
-
- // Make sure that updating paths differently also works
- workspace_3.location = (["/tmp3", "/tmp4", "/tmp2"]).into();
- db.save_workspace(workspace_3.clone()).await;
- assert_eq!(db.workspace_for_roots(&["/tmp2", "tmp"]), None);
- assert_eq!(
- db.workspace_for_roots(&["/tmp2", "/tmp3", "/tmp4"])
- .unwrap(),
- workspace_3
- );
- }
-
- use crate::persistence::model::SerializedWorkspace;
- use crate::persistence::model::{SerializedItem, SerializedPane, SerializedPaneGroup};
-
- fn default_workspace<P: AsRef<Path>>(
- workspace_id: &[P],
- center_group: &SerializedPaneGroup,
- ) -> SerializedWorkspace {
- SerializedWorkspace {
- id: 4,
- location: workspace_id.into(),
- center_group: center_group.clone(),
- bounds: Default::default(),
- display: Default::default(),
- docks: Default::default(),
- }
- }
-
- #[gpui::test]
- async fn test_simple_split() {
- env_logger::try_init().ok();
-
- let db = WorkspaceDb(open_test_db("simple_split").await);
-
- // -----------------
- // | 1,2 | 5,6 |
- // | - - - | |
- // | 3,4 | |
- // -----------------
- let center_pane = group(
- gpui::Axis::Horizontal,
- vec![
- group(
- gpui::Axis::Vertical,
- vec![
- SerializedPaneGroup::Pane(SerializedPane::new(
- vec![
- SerializedItem::new("Terminal", 1, false),
- SerializedItem::new("Terminal", 2, true),
- ],
- false,
- )),
- SerializedPaneGroup::Pane(SerializedPane::new(
- vec![
- SerializedItem::new("Terminal", 4, false),
- SerializedItem::new("Terminal", 3, true),
- ],
- true,
- )),
- ],
- ),
- SerializedPaneGroup::Pane(SerializedPane::new(
- vec![
- SerializedItem::new("Terminal", 5, true),
- SerializedItem::new("Terminal", 6, false),
- ],
- false,
- )),
- ],
- );
-
- let workspace = default_workspace(&["/tmp"], ¢er_pane);
-
- db.save_workspace(workspace.clone()).await;
-
- let new_workspace = db.workspace_for_roots(&["/tmp"]).unwrap();
-
- assert_eq!(workspace.center_group, new_workspace.center_group);
- }
-
- #[gpui::test]
- async fn test_cleanup_panes() {
- env_logger::try_init().ok();
-
- let db = WorkspaceDb(open_test_db("test_cleanup_panes").await);
-
- let center_pane = group(
- gpui::Axis::Horizontal,
- vec![
- group(
- gpui::Axis::Vertical,
- vec![
- SerializedPaneGroup::Pane(SerializedPane::new(
- vec![
- SerializedItem::new("Terminal", 1, false),
- SerializedItem::new("Terminal", 2, true),
- ],
- false,
- )),
- SerializedPaneGroup::Pane(SerializedPane::new(
- vec![
- SerializedItem::new("Terminal", 4, false),
- SerializedItem::new("Terminal", 3, true),
- ],
- true,
- )),
- ],
- ),
- SerializedPaneGroup::Pane(SerializedPane::new(
- vec![
- SerializedItem::new("Terminal", 5, false),
- SerializedItem::new("Terminal", 6, true),
- ],
- false,
- )),
- ],
- );
-
- let id = &["/tmp"];
-
- let mut workspace = default_workspace(id, ¢er_pane);
-
- db.save_workspace(workspace.clone()).await;
-
- workspace.center_group = group(
- gpui::Axis::Vertical,
- vec![
- SerializedPaneGroup::Pane(SerializedPane::new(
- vec![
- SerializedItem::new("Terminal", 1, false),
- SerializedItem::new("Terminal", 2, true),
- ],
- false,
- )),
- SerializedPaneGroup::Pane(SerializedPane::new(
- vec![
- SerializedItem::new("Terminal", 4, true),
- SerializedItem::new("Terminal", 3, false),
- ],
- true,
- )),
- ],
- );
-
- db.save_workspace(workspace.clone()).await;
-
- let new_workspace = db.workspace_for_roots(id).unwrap();
-
- assert_eq!(workspace.center_group, new_workspace.center_group);
- }
-}
+// todo!()
+// #[cfg(test)]
+// mod tests {
+// use super::*;
+// use db::open_test_db;
+
+// #[gpui::test]
+// async fn test_next_id_stability() {
+// env_logger::try_init().ok();
+
+// let db = WorkspaceDb(open_test_db("test_next_id_stability").await);
+
+// db.write(|conn| {
+// conn.migrate(
+// "test_table",
+// &[sql!(
+// CREATE TABLE test_table(
+// text TEXT,
+// workspace_id INTEGER,
+// FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id)
+// ON DELETE CASCADE
+// ) STRICT;
+// )],
+// )
+// .unwrap();
+// })
+// .await;
+
+// let id = db.next_id().await.unwrap();
+// // Assert the empty row got inserted
+// assert_eq!(
+// Some(id),
+// db.select_row_bound::<WorkspaceId, WorkspaceId>(sql!(
+// SELECT workspace_id FROM workspaces WHERE workspace_id = ?
+// ))
+// .unwrap()(id)
+// .unwrap()
+// );
+
+// db.write(move |conn| {
+// conn.exec_bound(sql!(INSERT INTO test_table(text, workspace_id) VALUES (?, ?)))
+// .unwrap()(("test-text-1", id))
+// .unwrap()
+// })
+// .await;
+
+// let test_text_1 = db
+// .select_row_bound::<_, String>(sql!(SELECT text FROM test_table WHERE workspace_id = ?))
+// .unwrap()(1)
+// .unwrap()
+// .unwrap();
+// assert_eq!(test_text_1, "test-text-1");
+// }
+
+// #[gpui::test]
+// async fn test_workspace_id_stability() {
+// env_logger::try_init().ok();
+
+// let db = WorkspaceDb(open_test_db("test_workspace_id_stability").await);
+
+// db.write(|conn| {
+// conn.migrate(
+// "test_table",
+// &[sql!(
+// CREATE TABLE test_table(
+// text TEXT,
+// workspace_id INTEGER,
+// FOREIGN KEY(workspace_id)
+// REFERENCES workspaces(workspace_id)
+// ON DELETE CASCADE
+// ) STRICT;)],
+// )
+// })
+// .await
+// .unwrap();
+
+// let mut workspace_1 = SerializedWorkspace {
+// id: 1,
+// location: (["/tmp", "/tmp2"]).into(),
+// center_group: Default::default(),
+// bounds: Default::default(),
+// display: Default::default(),
+// docks: Default::default(),
+// };
+
+// let workspace_2 = SerializedWorkspace {
+// id: 2,
+// location: (["/tmp"]).into(),
+// center_group: Default::default(),
+// bounds: Default::default(),
+// display: Default::default(),
+// docks: Default::default(),
+// };
+
+// db.save_workspace(workspace_1.clone()).await;
+
+// db.write(|conn| {
+// conn.exec_bound(sql!(INSERT INTO test_table(text, workspace_id) VALUES (?, ?)))
+// .unwrap()(("test-text-1", 1))
+// .unwrap();
+// })
+// .await;
+
+// db.save_workspace(workspace_2.clone()).await;
+
+// db.write(|conn| {
+// conn.exec_bound(sql!(INSERT INTO test_table(text, workspace_id) VALUES (?, ?)))
+// .unwrap()(("test-text-2", 2))
+// .unwrap();
+// })
+// .await;
+
+// workspace_1.location = (["/tmp", "/tmp3"]).into();
+// db.save_workspace(workspace_1.clone()).await;
+// db.save_workspace(workspace_1).await;
+// db.save_workspace(workspace_2).await;
+
+// let test_text_2 = db
+// .select_row_bound::<_, String>(sql!(SELECT text FROM test_table WHERE workspace_id = ?))
+// .unwrap()(2)
+// .unwrap()
+// .unwrap();
+// assert_eq!(test_text_2, "test-text-2");
+
+// let test_text_1 = db
+// .select_row_bound::<_, String>(sql!(SELECT text FROM test_table WHERE workspace_id = ?))
+// .unwrap()(1)
+// .unwrap()
+// .unwrap();
+// assert_eq!(test_text_1, "test-text-1");
+// }
+
+// fn group(axis: gpui::Axis, children: Vec<SerializedPaneGroup>) -> SerializedPaneGroup {
+// SerializedPaneGroup::Group {
+// axis,
+// flexes: None,
+// children,
+// }
+// }
+
+// #[gpui::test]
+// async fn test_full_workspace_serialization() {
+// env_logger::try_init().ok();
+
+// let db = WorkspaceDb(open_test_db("test_full_workspace_serialization").await);
+
+// // -----------------
+// // | 1,2 | 5,6 |
+// // | - - - | |
+// // | 3,4 | |
+// // -----------------
+// let center_group = group(
+// gpui::Axis::Horizontal,
+// vec![
+// group(
+// gpui::Axis::Vertical,
+// vec![
+// SerializedPaneGroup::Pane(SerializedPane::new(
+// vec![
+// SerializedItem::new("Terminal", 5, false),
+// SerializedItem::new("Terminal", 6, true),
+// ],
+// false,
+// )),
+// SerializedPaneGroup::Pane(SerializedPane::new(
+// vec![
+// SerializedItem::new("Terminal", 7, true),
+// SerializedItem::new("Terminal", 8, false),
+// ],
+// false,
+// )),
+// ],
+// ),
+// SerializedPaneGroup::Pane(SerializedPane::new(
+// vec![
+// SerializedItem::new("Terminal", 9, false),
+// SerializedItem::new("Terminal", 10, true),
+// ],
+// false,
+// )),
+// ],
+// );
+
+// let workspace = SerializedWorkspace {
+// id: 5,
+// location: (["/tmp", "/tmp2"]).into(),
+// center_group,
+// bounds: Default::default(),
+// display: Default::default(),
+// docks: Default::default(),
+// };
+
+// db.save_workspace(workspace.clone()).await;
+// let round_trip_workspace = db.workspace_for_roots(&["/tmp2", "/tmp"]);
+
+// assert_eq!(workspace, round_trip_workspace.unwrap());
+
+// // Test guaranteed duplicate IDs
+// db.save_workspace(workspace.clone()).await;
+// db.save_workspace(workspace.clone()).await;
+
+// let round_trip_workspace = db.workspace_for_roots(&["/tmp", "/tmp2"]);
+// assert_eq!(workspace, round_trip_workspace.unwrap());
+// }
+
+// #[gpui::test]
+// async fn test_workspace_assignment() {
+// env_logger::try_init().ok();
+
+// let db = WorkspaceDb(open_test_db("test_basic_functionality").await);
+
+// let workspace_1 = SerializedWorkspace {
+// id: 1,
+// location: (["/tmp", "/tmp2"]).into(),
+// center_group: Default::default(),
+// bounds: Default::default(),
+// display: Default::default(),
+// docks: Default::default(),
+// };
+
+// let mut workspace_2 = SerializedWorkspace {
+// id: 2,
+// location: (["/tmp"]).into(),
+// center_group: Default::default(),
+// bounds: Default::default(),
+// display: Default::default(),
+// docks: Default::default(),
+// };
+
+// db.save_workspace(workspace_1.clone()).await;
+// db.save_workspace(workspace_2.clone()).await;
+
+// // Test that paths are treated as a set
+// assert_eq!(
+// db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
+// workspace_1
+// );
+// assert_eq!(
+// db.workspace_for_roots(&["/tmp2", "/tmp"]).unwrap(),
+// workspace_1
+// );
+
+// // Make sure that other keys work
+// assert_eq!(db.workspace_for_roots(&["/tmp"]).unwrap(), workspace_2);
+// assert_eq!(db.workspace_for_roots(&["/tmp3", "/tmp2", "/tmp4"]), None);
+
+// // Test 'mutate' case of updating a pre-existing id
+// workspace_2.location = (["/tmp", "/tmp2"]).into();
+
+// db.save_workspace(workspace_2.clone()).await;
+// assert_eq!(
+// db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
+// workspace_2
+// );
+
+// // Test other mechanism for mutating
+// let mut workspace_3 = SerializedWorkspace {
+// id: 3,
+// location: (&["/tmp", "/tmp2"]).into(),
+// center_group: Default::default(),
+// bounds: Default::default(),
+// display: Default::default(),
+// docks: Default::default(),
+// };
+
+// db.save_workspace(workspace_3.clone()).await;
+// assert_eq!(
+// db.workspace_for_roots(&["/tmp", "/tmp2"]).unwrap(),
+// workspace_3
+// );
+
+// // Make sure that updating paths differently also works
+// workspace_3.location = (["/tmp3", "/tmp4", "/tmp2"]).into();
+// db.save_workspace(workspace_3.clone()).await;
+// assert_eq!(db.workspace_for_roots(&["/tmp2", "tmp"]), None);
+// assert_eq!(
+// db.workspace_for_roots(&["/tmp2", "/tmp3", "/tmp4"])
+// .unwrap(),
+// workspace_3
+// );
+// }
+
+// use crate::persistence::model::SerializedWorkspace;
+// use crate::persistence::model::{SerializedItem, SerializedPane, SerializedPaneGroup};
+
+// fn default_workspace<P: AsRef<Path>>(
+// workspace_id: &[P],
+// center_group: &SerializedPaneGroup,
+// ) -> SerializedWorkspace {
+// SerializedWorkspace {
+// id: 4,
+// location: workspace_id.into(),
+// center_group: center_group.clone(),
+// bounds: Default::default(),
+// display: Default::default(),
+// docks: Default::default(),
+// }
+// }
+
+// #[gpui::test]
+// async fn test_simple_split() {
+// env_logger::try_init().ok();
+
+// let db = WorkspaceDb(open_test_db("simple_split").await);
+
+// // -----------------
+// // | 1,2 | 5,6 |
+// // | - - - | |
+// // | 3,4 | |
+// // -----------------
+// let center_pane = group(
+// gpui::Axis::Horizontal,
+// vec![
+// group(
+// gpui::Axis::Vertical,
+// vec![
+// SerializedPaneGroup::Pane(SerializedPane::new(
+// vec![
+// SerializedItem::new("Terminal", 1, false),
+// SerializedItem::new("Terminal", 2, true),
+// ],
+// false,
+// )),
+// SerializedPaneGroup::Pane(SerializedPane::new(
+// vec![
+// SerializedItem::new("Terminal", 4, false),
+// SerializedItem::new("Terminal", 3, true),
+// ],
+// true,
+// )),
+// ],
+// ),
+// SerializedPaneGroup::Pane(SerializedPane::new(
+// vec![
+// SerializedItem::new("Terminal", 5, true),
+// SerializedItem::new("Terminal", 6, false),
+// ],
+// false,
+// )),
+// ],
+// );
+
+// let workspace = default_workspace(&["/tmp"], ¢er_pane);
+
+// db.save_workspace(workspace.clone()).await;
+
+// let new_workspace = db.workspace_for_roots(&["/tmp"]).unwrap();
+
+// assert_eq!(workspace.center_group, new_workspace.center_group);
+// }
+
+// #[gpui::test]
+// async fn test_cleanup_panes() {
+// env_logger::try_init().ok();
+
+// let db = WorkspaceDb(open_test_db("test_cleanup_panes").await);
+
+// let center_pane = group(
+// gpui::Axis::Horizontal,
+// vec![
+// group(
+// gpui::Axis::Vertical,
+// vec![
+// SerializedPaneGroup::Pane(SerializedPane::new(
+// vec![
+// SerializedItem::new("Terminal", 1, false),
+// SerializedItem::new("Terminal", 2, true),
+// ],
+// false,
+// )),
+// SerializedPaneGroup::Pane(SerializedPane::new(
+// vec![
+// SerializedItem::new("Terminal", 4, false),
+// SerializedItem::new("Terminal", 3, true),
+// ],
+// true,
+// )),
+// ],
+// ),
+// SerializedPaneGroup::Pane(SerializedPane::new(
+// vec![
+// SerializedItem::new("Terminal", 5, false),
+// SerializedItem::new("Terminal", 6, true),
+// ],
+// false,
+// )),
+// ],
+// );
+
+// let id = &["/tmp"];
+
+// let mut workspace = default_workspace(id, ¢er_pane);
+
+// db.save_workspace(workspace.clone()).await;
+
+// workspace.center_group = group(
+// gpui::Axis::Vertical,
+// vec![
+// SerializedPaneGroup::Pane(SerializedPane::new(
+// vec![
+// SerializedItem::new("Terminal", 1, false),
+// SerializedItem::new("Terminal", 2, true),
+// ],
+// false,
+// )),
+// SerializedPaneGroup::Pane(SerializedPane::new(
+// vec![
+// SerializedItem::new("Terminal", 4, true),
+// SerializedItem::new("Terminal", 3, false),
+// ],
+// true,
+// )),
+// ],
+// );
+
+// db.save_workspace(workspace.clone()).await;
+
+// let new_workspace = db.workspace_for_roots(id).unwrap();
+
+// assert_eq!(workspace.center_group, new_workspace.center_group);
+// }
+// }
@@ -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 async_recursion::async_recursion;
-use db::sqlez::{
+use db2::sqlez::{
bindable::{Bind, Column, StaticColumnCount},
statement::Statement,
};
-use gpui::{
- platform::WindowBounds, AsyncAppContext, Axis, ModelHandle, Task, ViewHandle, WeakViewHandle,
-};
-use project::Project;
+use gpui2::{AsyncAppContext, Handle, Task, View, WeakView, WindowBounds};
+use project2::Project;
use std::{
path::{Path, PathBuf},
sync::Arc,
@@ -151,15 +151,11 @@ impl SerializedPaneGroup {
#[async_recursion(?Send)]
pub(crate) async fn deserialize(
self,
- project: &ModelHandle<Project>,
+ project: &Handle<Project>,
workspace_id: WorkspaceId,
- workspace: &WeakViewHandle<Workspace>,
+ workspace: &WeakView<Workspace>,
cx: &mut AsyncAppContext,
- ) -> Option<(
- Member,
- Option<ViewHandle<Pane>>,
- Vec<Option<Box<dyn ItemHandle>>>,
- )> {
+ ) -> Option<(Member, Option<View<Pane>>, Vec<Option<Box<dyn ItemHandle>>>)> {
match self {
SerializedPaneGroup::Group {
axis,
@@ -208,10 +204,10 @@ impl SerializedPaneGroup {
.read_with(cx, |pane, _| pane.items_len() != 0)
.log_err()?
{
- let pane = pane.upgrade(cx)?;
+ let pane = pane.upgrade()?;
Some((Member::Pane(pane.clone()), active.then(|| pane), new_items))
} else {
- let pane = pane.upgrade(cx)?;
+ let pane = pane.upgrade()?;
workspace
.update(cx, |workspace, cx| workspace.force_remove_pane(&pane, cx))
.log_err()?;
@@ -235,10 +231,10 @@ impl SerializedPane {
pub async fn deserialize_to(
&self,
- project: &ModelHandle<Project>,
- pane: &WeakViewHandle<Pane>,
+ project: &Handle<Project>,
+ pane: &WeakView<Pane>,
workspace_id: WorkspaceId,
- workspace: &WeakViewHandle<Workspace>,
+ workspace: &WeakView<Workspace>,
cx: &mut AsyncAppContext,
) -> Result<Vec<Option<Box<dyn ItemHandle>>>> {
let mut items = Vec::new();
@@ -1,10 +1,7 @@
use crate::ItemHandle;
-use gpui::{
- elements::*, AnyElement, AnyViewHandle, AppContext, Entity, View, ViewContext, ViewHandle,
- WindowContext,
-};
+use gpui2::{AppContext, EventEmitter, View, ViewContext, WindowContext};
-pub trait ToolbarItemView: View {
+pub trait ToolbarItemView: EventEmitter + Sized {
fn set_active_pane_item(
&mut self,
active_pane_item: Option<&dyn crate::ItemHandle>,
@@ -32,7 +29,7 @@ pub trait ToolbarItemView: View {
trait ToolbarItemViewHandle {
fn id(&self) -> usize;
- fn as_any(&self) -> &AnyViewHandle;
+ // fn as_any(&self) -> &AnyViewHandle; todo!()
fn set_active_pane_item(
&self,
active_pane_item: Option<&dyn ItemHandle>,
@@ -57,84 +54,81 @@ pub struct Toolbar {
items: Vec<(Box<dyn ToolbarItemViewHandle>, ToolbarItemLocation)>,
}
-impl Entity for Toolbar {
- type Event = ();
-}
-
-impl View for Toolbar {
- fn ui_name() -> &'static str {
- "Toolbar"
- }
-
- fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
- let theme = &theme::current(cx).workspace.toolbar;
-
- let mut primary_left_items = Vec::new();
- let mut primary_right_items = Vec::new();
- let mut secondary_item = None;
- let spacing = theme.item_spacing;
- let mut primary_items_row_count = 1;
-
- for (item, position) in &self.items {
- match *position {
- ToolbarItemLocation::Hidden => {}
-
- ToolbarItemLocation::PrimaryLeft { flex } => {
- primary_items_row_count = primary_items_row_count.max(item.row_count(cx));
- 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::PrimaryRight { flex } => {
- primary_items_row_count = primary_items_row_count.max(item.row_count(cx));
- let right_item = ChildView::new(item.as_any(), cx).aligned().flex_float();
- if let Some((flex, expanded)) = flex {
- primary_right_items.push(right_item.flex(flex, expanded).into_any());
- } else {
- primary_right_items.push(right_item.into_any());
- }
- }
-
- ToolbarItemLocation::Secondary => {
- secondary_item = Some(
- 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 height = theme.height * primary_items_row_count as f32;
-
- let mut primary_items = Flex::row().with_spacing(spacing);
- primary_items.extend(primary_left_items);
- primary_items.extend(primary_right_items);
-
- let mut toolbar = Flex::column();
- if !primary_items.is_empty() {
- toolbar.add_child(primary_items.constrained().with_height(height));
- }
- if let Some(secondary_item) = secondary_item {
- toolbar.add_child(secondary_item);
- }
-
- if toolbar.is_empty() {
- toolbar.into_any_named("toolbar")
- } else {
- toolbar
- .contained()
- .with_style(container_style)
- .into_any_named("toolbar")
- }
- }
-}
+// todo!()
+// impl View for Toolbar {
+// fn ui_name() -> &'static str {
+// "Toolbar"
+// }
+
+// fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
+// let theme = &theme::current(cx).workspace.toolbar;
+
+// let mut primary_left_items = Vec::new();
+// let mut primary_right_items = Vec::new();
+// let mut secondary_item = None;
+// let spacing = theme.item_spacing;
+// let mut primary_items_row_count = 1;
+
+// for (item, position) in &self.items {
+// match *position {
+// ToolbarItemLocation::Hidden => {}
+
+// ToolbarItemLocation::PrimaryLeft { flex } => {
+// primary_items_row_count = primary_items_row_count.max(item.row_count(cx));
+// 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::PrimaryRight { flex } => {
+// primary_items_row_count = primary_items_row_count.max(item.row_count(cx));
+// let right_item = ChildView::new(item.as_any(), cx).aligned().flex_float();
+// if let Some((flex, expanded)) = flex {
+// primary_right_items.push(right_item.flex(flex, expanded).into_any());
+// } else {
+// primary_right_items.push(right_item.into_any());
+// }
+// }
+
+// ToolbarItemLocation::Secondary => {
+// secondary_item = Some(
+// 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 height = theme.height * primary_items_row_count as f32;
+
+// let mut primary_items = Flex::row().with_spacing(spacing);
+// primary_items.extend(primary_left_items);
+// primary_items.extend(primary_right_items);
+
+// let mut toolbar = Flex::column();
+// if !primary_items.is_empty() {
+// toolbar.add_child(primary_items.constrained().with_height(height));
+// }
+// if let Some(secondary_item) = secondary_item {
+// toolbar.add_child(secondary_item);
+// }
+
+// if toolbar.is_empty() {
+// toolbar.into_any_named("toolbar")
+// } else {
+// toolbar
+// .contained()
+// .with_style(container_style)
+// .into_any_named("toolbar")
+// }
+// }
+// }
// <<<<<<< HEAD
// =======
@@ -206,7 +200,7 @@ impl Toolbar {
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
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
.iter()
.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 {
self.id()
}
- fn as_any(&self) -> &AnyViewHandle {
- self
- }
+ // todo!()
+ // fn as_any(&self) -> &AnyViewHandle {
+ // self
+ // }
fn set_active_pane_item(
&self,
@@ -294,8 +289,9 @@ impl<T: ToolbarItemView> ToolbarItemViewHandle for ViewHandle<T> {
}
}
-impl From<&dyn ToolbarItemViewHandle> for AnyViewHandle {
- fn from(val: &dyn ToolbarItemViewHandle) -> Self {
- val.as_any().clone()
- }
-}
+// todo!()
+// impl From<&dyn ToolbarItemViewHandle> for AnyViewHandle {
+// fn from(val: &dyn ToolbarItemViewHandle) -> Self {
+// val.as_any().clone()
+// }
+// }
@@ -3,12 +3,12 @@ pub mod item;
// pub mod notifications;
pub mod pane;
pub mod pane_group;
-// mod persistence;
+mod persistence;
pub mod searchable;
// pub mod shared_screen;
// mod status_bar;
mod toolbar;
-// mod workspace_settings;
+mod workspace_settings;
use anyhow::{anyhow, Result};
// use call2::ActiveCall;
@@ -36,13 +36,14 @@ use anyhow::{anyhow, Result};
// },
// AnyModelHandle, AnyViewHandle, AnyWeakViewHandle, AnyWindowHandle, AppContext, AsyncAppContext,
// Entity, ModelContext, ModelHandle, SizeConstraint, Subscription, Task, View, ViewContext,
-// ViewHandle, WeakViewHandle, WindowContext, WindowHandle,
+// View, WeakViewHandle, WindowContext, WindowHandle,
// };
// use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem};
// use itertools::Itertools;
// use language2::{LanguageRegistry, Rope};
// use node_runtime::NodeRuntime;// //
+use futures::channel::oneshot;
// use crate::{
// notifications::{simple_message_notification::MessageNotification, NotificationTracker},
// persistence::model::{
@@ -91,7 +92,7 @@ pub use toolbar::{ToolbarItemLocation, ToolbarItemView};
// 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 {
// self
// }
@@ -376,61 +377,61 @@ pub fn register_project_item<I: ProjectItem>(cx: &mut AppContext) {
});
}
-// type FollowableItemBuilder = fn(
-// ViewHandle<Pane>,
-// ViewHandle<Workspace>,
-// ViewId,
-// &mut Option<proto::view::Variant>,
-// &mut AppContext,
-// ) -> Option<Task<Result<Box<dyn FollowableItemHandle>>>>;
-// type FollowableItemBuilders = HashMap<
-// TypeId,
-// (
-// FollowableItemBuilder,
-// fn(&AnyViewHandle) -> Box<dyn FollowableItemHandle>,
-// ),
-// >;
-// pub fn register_followable_item<I: FollowableItem>(cx: &mut AppContext) {
-// cx.update_default_global(|builders: &mut FollowableItemBuilders, _| {
-// builders.insert(
-// TypeId::of::<I>(),
-// (
-// |pane, workspace, id, state, cx| {
-// I::from_state_proto(pane, workspace, id, state, cx).map(|task| {
-// cx.foreground()
-// .spawn(async move { Ok(Box::new(task.await?) as Box<_>) })
-// })
-// },
-// |this| Box::new(this.clone().downcast::<I>().unwrap()),
-// ),
-// );
-// });
-// }
+type FollowableItemBuilder = fn(
+ View<Pane>,
+ View<Workspace>,
+ ViewId,
+ &mut Option<proto::view::Variant>,
+ &mut AppContext,
+) -> Option<Task<Result<Box<dyn FollowableItemHandle>>>>;
+type FollowableItemBuilders = HashMap<
+ TypeId,
+ (
+ FollowableItemBuilder,
+ fn(&AnyView) -> Box<dyn FollowableItemHandle>,
+ ),
+>;
+pub fn register_followable_item<I: FollowableItem>(cx: &mut AppContext) {
+ cx.update_default_global(|builders: &mut FollowableItemBuilders, _| {
+ builders.insert(
+ TypeId::of::<I>(),
+ (
+ |pane, workspace, id, state, cx| {
+ I::from_state_proto(pane, workspace, id, state, cx).map(|task| {
+ cx.foreground()
+ .spawn(async move { Ok(Box::new(task.await?) as Box<_>) })
+ })
+ },
+ |this| Box::new(this.clone().downcast::<I>().unwrap()),
+ ),
+ );
+ });
+}
-// type ItemDeserializers = HashMap<
-// Arc<str>,
-// fn(
-// ModelHandle<Project>,
-// WeakViewHandle<Workspace>,
-// WorkspaceId,
-// ItemId,
-// &mut ViewContext<Pane>,
-// ) -> Task<Result<Box<dyn ItemHandle>>>,
-// >;
-// pub fn register_deserializable_item<I: Item>(cx: &mut AppContext) {
-// cx.update_default_global(|deserializers: &mut ItemDeserializers, _cx| {
-// if let Some(serialized_item_kind) = I::serialized_item_kind() {
-// deserializers.insert(
-// Arc::from(serialized_item_kind),
-// |project, workspace, workspace_id, item_id, cx| {
-// let task = I::deserialize(project, workspace, workspace_id, item_id, cx);
-// cx.foreground()
-// .spawn(async { Ok(Box::new(task.await?) as Box<_>) })
-// },
-// );
-// }
-// });
-// }
+type ItemDeserializers = HashMap<
+ Arc<str>,
+ fn(
+ Handle<Project>,
+ WeakView<Workspace>,
+ WorkspaceId,
+ ItemId,
+ &mut ViewContext<Pane>,
+ ) -> Task<Result<Box<dyn ItemHandle>>>,
+>;
+pub fn register_deserializable_item<I: Item>(cx: &mut AppContext) {
+ cx.update_default_global(|deserializers: &mut ItemDeserializers, _cx| {
+ if let Some(serialized_item_kind) = I::serialized_item_kind() {
+ deserializers.insert(
+ Arc::from(serialized_item_kind),
+ |project, workspace, workspace_id, item_id, cx| {
+ let task = I::deserialize(project, workspace, workspace_id, item_id, cx);
+ cx.foreground()
+ .spawn(async { Ok(Box::new(task.await?) as Box<_>) })
+ },
+ );
+ }
+ });
+}
pub struct AppState {
pub languages: Arc<LanguageRegistry>,
@@ -493,54 +494,54 @@ struct Follower {
// }
// }
-// struct DelayedDebouncedEditAction {
-// task: Option<Task<()>>,
-// cancel_channel: Option<oneshot::Sender<()>>,
-// }
+struct DelayedDebouncedEditAction {
+ task: Option<Task<()>>,
+ cancel_channel: Option<oneshot::Sender<()>>,
+}
-// impl DelayedDebouncedEditAction {
-// fn new() -> DelayedDebouncedEditAction {
-// DelayedDebouncedEditAction {
-// task: None,
-// cancel_channel: None,
-// }
-// }
+impl DelayedDebouncedEditAction {
+ fn new() -> DelayedDebouncedEditAction {
+ DelayedDebouncedEditAction {
+ task: None,
+ cancel_channel: None,
+ }
+ }
-// fn fire_new<F>(&mut self, delay: Duration, cx: &mut ViewContext<Workspace>, func: F)
-// where
-// F: 'static + FnOnce(&mut Workspace, &mut ViewContext<Workspace>) -> Task<Result<()>>,
-// {
-// if let Some(channel) = self.cancel_channel.take() {
-// _ = channel.send(());
-// }
+ fn fire_new<F>(&mut self, delay: Duration, cx: &mut ViewContext<Workspace>, func: F)
+ where
+ F: 'static + FnOnce(&mut Workspace, &mut ViewContext<Workspace>) -> Task<Result<()>>,
+ {
+ if let Some(channel) = self.cancel_channel.take() {
+ _ = channel.send(());
+ }
-// let (sender, mut receiver) = oneshot::channel::<()>();
-// self.cancel_channel = Some(sender);
+ let (sender, mut receiver) = oneshot::channel::<()>();
+ self.cancel_channel = Some(sender);
-// let previous_task = self.task.take();
-// self.task = Some(cx.spawn(|workspace, mut cx| async move {
-// let mut timer = cx.background().timer(delay).fuse();
-// if let Some(previous_task) = previous_task {
-// previous_task.await;
-// }
+ let previous_task = self.task.take();
+ self.task = Some(cx.spawn(|workspace, mut cx| async move {
+ let mut timer = cx.background().timer(delay).fuse();
+ if let Some(previous_task) = previous_task {
+ previous_task.await;
+ }
-// futures::select_biased! {
-// _ = receiver => return,
-// _ = timer => {}
-// }
+ futures::select_biased! {
+ _ = receiver => return,
+ _ = timer => {}
+ }
-// if let Some(result) = workspace
-// .update(&mut cx, |workspace, cx| (func)(workspace, cx))
-// .log_err()
-// {
-// result.await.log_err();
-// }
-// }));
-// }
-// }
+ if let Some(result) = workspace
+ .update(&mut cx, |workspace, cx| (func)(workspace, cx))
+ .log_err()
+ {
+ result.await.log_err();
+ }
+ }));
+ }
+}
// pub enum Event {
-// PaneAdded(ViewHandle<Pane>),
+// PaneAdded(View<Pane>),
// ContactRequestedJoin(u64),
// }
@@ -550,19 +551,19 @@ pub struct Workspace {
// zoomed: Option<AnyWeakViewHandle>,
// zoomed_position: Option<DockPosition>,
// center: PaneGroup,
- // left_dock: ViewHandle<Dock>,
- // bottom_dock: ViewHandle<Dock>,
- // right_dock: ViewHandle<Dock>,
+ // left_dock: View<Dock>,
+ // bottom_dock: View<Dock>,
+ // right_dock: View<Dock>,
panes: Vec<View<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_view_id: Option<proto::ViewId>,
- // status_bar: ViewHandle<StatusBar>,
+ // status_bar: View<StatusBar>,
// titlebar_item: Option<AnyViewHandle>,
// notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>,
project: Handle<Project>,
- // follower_states: HashMap<ViewHandle<Pane>, FollowerState>,
+ // follower_states: HashMap<View<Pane>, FollowerState>,
// last_leaders_by_pane: HashMap<WeakViewHandle<Pane>, PeerId>,
// window_edited: bool,
// active_call: Option<(ModelHandle<ActiveCall>, Vec<Subscription>)>,
@@ -930,19 +931,19 @@ impl Workspace {
// self.weak_self.clone()
// }
- // pub fn left_dock(&self) -> &ViewHandle<Dock> {
+ // pub fn left_dock(&self) -> &View<Dock> {
// &self.left_dock
// }
- // pub fn bottom_dock(&self) -> &ViewHandle<Dock> {
+ // pub fn bottom_dock(&self) -> &View<Dock> {
// &self.bottom_dock
// }
- // pub fn right_dock(&self) -> &ViewHandle<Dock> {
+ // pub fn right_dock(&self) -> &View<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
// T::Event: std::fmt::Debug,
// {
@@ -951,12 +952,12 @@ impl Workspace {
// pub fn add_panel_with_extra_event_handler<T: Panel, F>(
// &mut self,
- // panel: ViewHandle<T>,
+ // panel: View<T>,
// cx: &mut ViewContext<Self>,
// handler: F,
// ) where
// 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) {
// DockPosition::Left => &self.left_dock,
@@ -1033,7 +1034,7 @@ impl Workspace {
// 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
// }
@@ -1617,10 +1618,10 @@ impl Workspace {
// &mut self,
// cx: &mut ViewContext<Self>,
// add_view: F,
- // ) -> Option<ViewHandle<V>>
+ // ) -> Option<View<V>>
// where
// V: 'static + Modal,
- // F: FnOnce(&mut Self, &mut ViewContext<Self>) -> ViewHandle<V>,
+ // F: FnOnce(&mut Self, &mut ViewContext<Self>) -> View<V>,
// {
// cx.notify();
// // 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
// .as_ref()
// .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())
// }
- // 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())
// }
// pub fn items_of_type<'a, T: Item>(
// &'a self,
// cx: &'a AppContext,
- // ) -> impl 'a + Iterator<Item = ViewHandle<T>> {
+ // ) -> impl 'a + Iterator<Item = View<T>> {
// self.panes
// .iter()
// .flat_map(|pane| pane.read(cx).items_of_type())
@@ -1834,7 +1835,7 @@ impl Workspace {
// }
// /// 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)?
// .as_any()
// .clone()
@@ -1888,7 +1889,7 @@ impl Workspace {
// 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] {
// let dock = dock.read(cx);
// if let Some(panel) = dock.panel::<T>() {
@@ -1956,7 +1957,7 @@ impl Workspace {
// 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| {
// Pane::new(
// self.weak_handle(),
@@ -2138,7 +2139,7 @@ impl Workspace {
// &mut self,
// project_item: ModelHandle<T::Item>,
// cx: &mut ViewContext<Self>,
- // ) -> ViewHandle<T>
+ // ) -> View<T>
// where
// T: ProjectItem,
// {
@@ -2162,7 +2163,7 @@ impl Workspace {
// &mut self,
// project_item: ModelHandle<T::Item>,
// cx: &mut ViewContext<Self>,
- // ) -> ViewHandle<T>
+ // ) -> View<T>
// where
// T: ProjectItem,
// {
@@ -2259,7 +2260,7 @@ impl Workspace {
// &mut self,
// direction: SplitDirection,
// cx: &mut ViewContext<Self>,
- // ) -> Option<&ViewHandle<Pane>> {
+ // ) -> Option<&View<Pane>> {
// let Some(bounding_box) = self.center.bounding_box_for_pane(&self.active_pane) else {
// return None;
// };
@@ -2280,7 +2281,7 @@ impl Workspace {
// 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 {
// self.active_pane = pane.clone();
// self.status_bar.update(cx, |status_bar, cx| {
@@ -2304,7 +2305,7 @@ impl Workspace {
// fn handle_pane_event(
// &mut self,
- // pane: ViewHandle<Pane>,
+ // pane: View<Pane>,
// event: &pane::Event,
// cx: &mut ViewContext<Self>,
// ) {
@@ -2363,10 +2364,10 @@ impl Workspace {
// pub fn split_pane(
// &mut self,
- // pane_to_split: ViewHandle<Pane>,
+ // pane_to_split: View<Pane>,
// split_direction: SplitDirection,
// cx: &mut ViewContext<Self>,
- // ) -> ViewHandle<Pane> {
+ // ) -> View<Pane> {
// let new_pane = self.add_pane(cx);
// self.center
// .split(&pane_to_split, &new_pane, split_direction)
@@ -2377,10 +2378,10 @@ impl Workspace {
// pub fn split_and_clone(
// &mut self,
- // pane: ViewHandle<Pane>,
+ // pane: View<Pane>,
// direction: SplitDirection,
// cx: &mut ViewContext<Self>,
- // ) -> Option<ViewHandle<Pane>> {
+ // ) -> Option<View<Pane>> {
// let item = pane.read(cx).active_item()?;
// let maybe_pane_handle = if let Some(clone) = item.clone_on_split(self.database_id(), cx) {
// let new_pane = self.add_pane(cx);
@@ -2440,8 +2441,8 @@ impl Workspace {
// pub fn move_item(
// &mut self,
- // source: ViewHandle<Pane>,
- // destination: ViewHandle<Pane>,
+ // source: View<Pane>,
+ // destination: View<Pane>,
// item_id_to_move: usize,
// destination_index: usize,
// 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() {
// self.force_remove_pane(&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
// }
- // pub fn active_pane(&self) -> &ViewHandle<Pane> {
+ // pub fn active_pane(&self) -> &View<Pane> {
// &self.active_pane
// }
@@ -2651,7 +2652,7 @@ impl Workspace {
// pub fn unfollow(
// &mut self,
- // pane: &ViewHandle<Pane>,
+ // pane: &View<Pane>,
// cx: &mut ViewContext<Self>,
// ) -> Option<PeerId> {
// let state = self.follower_states.remove(pane)?;
@@ -2959,7 +2960,7 @@ impl Workspace {
// async fn add_views_from_leader(
// this: WeakViewHandle<Self>,
// leader_id: PeerId,
- // panes: Vec<ViewHandle<Pane>>,
+ // panes: Vec<View<Pane>>,
// views: Vec<proto::View>,
// cx: &mut AsyncAppContext,
// ) -> 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)
// }
@@ -3133,9 +3134,9 @@ impl Workspace {
// fn shared_screen_for_peer(
// &self,
// peer_id: PeerId,
- // pane: &ViewHandle<Pane>,
+ // pane: &View<Pane>,
// cx: &mut ViewContext<Self>,
- // ) -> Option<ViewHandle<SharedScreen>> {
+ // ) -> Option<View<SharedScreen>> {
// let call = self.active_call()?;
// let room = call.read(cx).room()?.read(cx);
// 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);
// cx.focus(self.panes.last().unwrap());
// if self.last_active_center_pane == Some(pane.downgrade()) {
@@ -3248,7 +3249,7 @@ impl Workspace {
// fn serialize_workspace(&self, cx: &ViewContext<Self>) {
// fn serialize_pane_handle(
- // pane_handle: &ViewHandle<Pane>,
+ // pane_handle: &View<Pane>,
// cx: &AppContext,
// ) -> SerializedPane {
// let (items, active) = {
@@ -4075,7 +4076,7 @@ impl Workspace {
// 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> {
// self.read(cx)
// .worktrees(cx)
@@ -4320,13 +4321,16 @@ pub async fn activate_workspace_for_project(
// None
// }
-use client2::{proto::PeerId, Client, UserStore};
+use client2::{
+ proto::{self, PeerId, ViewId},
+ Client, UserStore,
+};
use collections::{HashMap, HashSet};
use gpui2::{
- AnyHandle, AppContext, AsyncAppContext, DisplayId, Handle, MainThread, Task, View, ViewContext,
- WeakHandle, WeakView, WindowBounds, WindowHandle, WindowOptions,
+ AnyHandle, AnyView, AppContext, AsyncAppContext, DisplayId, Handle, MainThread, Task, View,
+ ViewContext, WeakHandle, WeakView, WindowBounds, WindowHandle, WindowOptions,
};
-use item::{ItemHandle, ProjectItem};
+use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem};
use language2::LanguageRegistry;
use node_runtime::NodeRuntime;
use project2::{Project, ProjectEntryId, ProjectPath, Worktree};
@@ -4334,6 +4338,7 @@ use std::{
any::TypeId,
path::{Path, PathBuf},
sync::Arc,
+ time::Duration,
};
use util::ResultExt;
@@ -1,6 +1,6 @@
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
-use settings::Setting;
+use settings2::Settings;
#[derive(Deserialize)]
pub struct WorkspaceSettings {
@@ -41,7 +41,7 @@ pub enum GitGutterSetting {
Hide,
}
-impl Setting for WorkspaceSettings {
+impl Settings for WorkspaceSettings {
const KEY: Option<&'static str> = None;
type FileContent = WorkspaceSettingsContent;
@@ -49,7 +49,7 @@ impl Setting for WorkspaceSettings {
fn load(
default_value: &Self::FileContent,
user_values: &[&Self::FileContent],
- _: &gpui::AppContext,
+ _: &gpui2::AppContext,
) -> anyhow::Result<Self> {
Self::load_via_json_merge(default_value, user_values)
}