diff --git a/crates/workspace2/src/item.rs b/crates/workspace2/src/item.rs index 06592bffac..d359427053 100644 --- a/crates/workspace2/src/item.rs +++ b/crates/workspace2/src/item.rs @@ -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, HighlightStyle)>>, } -pub trait Item: EventEmitter { +pub trait Item: EventEmitter + Sized { // fn deactivated(&mut self, _: &mut ViewContext) {} // fn workspace_deactivated(&mut self, _: &mut ViewContext) {} // fn navigate(&mut self, _: Box, _: &mut ViewContext) -> bool { @@ -138,14 +139,14 @@ pub trait Item: EventEmitter { // } // fn save( // &mut self, - // _project: ModelHandle, + // _project: Handle, // _cx: &mut ViewContext, // ) -> Task> { // unimplemented!("save() must be implemented if can_save() returns true") // } // fn save_as( // &mut self, - // _project: ModelHandle, + // _project: Handle, // _abs_path: PathBuf, // _cx: &mut ViewContext, // ) -> Task> { @@ -153,7 +154,7 @@ pub trait Item: EventEmitter { // } // fn reload( // &mut self, - // _project: ModelHandle, + // _project: Handle, // _cx: &mut ViewContext, // ) -> Task> { // 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_handle: &'a View, // _: &'a AppContext, // ) -> Option<&AnyViewHandle> { // if TypeId::of::() == type_id { @@ -181,7 +182,7 @@ pub trait Item: EventEmitter { // } // } - // fn as_searchable(&self, _: &ViewHandle) -> Option> { + // fn as_searchable(&self, _: &View) -> Option> { // None // } @@ -200,12 +201,12 @@ pub trait Item: EventEmitter { // } // fn deserialize( - // _project: ModelHandle, + // _project: Handle, // _workspace: WeakViewHandle, // _workspace_id: WorkspaceId, // _item_id: ItemId, // _cx: &mut ViewContext, - // ) -> Task>> { + // ) -> Task>> { // 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(&self) -> Option> { +// pub fn downcast(&self) -> Option> { // self.as_any().clone().downcast() // } -// pub fn act_as(&self, cx: &AppContext) -> Option> { +// pub fn act_as(&self, cx: &AppContext) -> Option> { // self.act_as_type(TypeId::of::(), cx) // .and_then(|t| t.clone().downcast()) // } // } -// impl ItemHandle for ViewHandle { -// fn subscribe_to_item_events( -// &self, -// cx: &mut WindowContext, -// handler: Box, -// ) -> gpui2::Subscription { -// cx.subscribe(self, move |_, event, cx| { -// for item_event in T::to_item_events(event) { -// handler(item_event, cx) -// } -// }) -// } +impl ItemHandle for View { + fn subscribe_to_item_events( + &self, + cx: &mut WindowContext, + handler: Box, + ) -> 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> { -// self.read(cx).tab_tooltip_text(cx) -// } + fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option> { + self.read(cx).tab_tooltip_text(cx) + } -// fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option> { -// self.read(cx).tab_description(detail, cx) -// } + fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option> { + self.read(cx).tab_description(detail, cx) + } -// fn tab_content( -// &self, -// detail: Option, -// style: &theme2::Tab, -// cx: &AppContext, -// ) -> AnyElement { -// self.read(cx).tab_content(detail, style, cx) -// } + fn tab_content(&self, detail: Option, cx: &AppContext) -> AnyElement { + self.read(cx).tab_content(detail, cx) + } -// fn dragged_tab_content( -// &self, -// detail: Option, -// style: &theme2::Tab, -// cx: &AppContext, -// ) -> AnyElement { -// self.read(cx).tab_content(detail, style, cx) -// } + fn dragged_tab_content(&self, detail: Option, cx: &AppContext) -> AnyElement { + self.read(cx).tab_content(detail, cx) + } -// fn project_path(&self, cx: &AppContext) -> Option { -// 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 project_path(&self, cx: &AppContext) -> Option { + 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 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 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 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 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 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 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 is_singleton(&self, cx: &AppContext) -> bool { -// self.read(cx).is_singleton(cx) -// } + fn is_singleton(&self, cx: &AppContext) -> bool { + self.read(cx).is_singleton(cx) + } -// fn boxed_clone(&self) -> Box { -// Box::new(self.clone()) -// } + fn boxed_clone(&self) -> Box { + Box::new(self.clone()) + } -// fn clone_on_split( -// &self, -// workspace_id: WorkspaceId, -// cx: &mut WindowContext, -// ) -> Option> { -// self.update(cx, |item, cx| { -// cx.add_option_view(|cx| item.clone_on_split(workspace_id, cx)) -// }) -// .map(|handle| Box::new(handle) as Box) -// } + fn clone_on_split( + &self, + workspace_id: WorkspaceId, + cx: &mut WindowContext, + ) -> Option> { + self.update(cx, |item, cx| { + cx.add_option_view(|cx| item.clone_on_split(workspace_id, cx)) + }) + .map(|handle| Box::new(handle) as Box) + } -// fn added_to_pane( -// &self, -// workspace: &mut Workspace, -// pane: ViewHandle, -// cx: &mut ViewContext, -// ) { -// 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); -// }); + fn added_to_pane( + &self, + workspace: &mut Workspace, + pane: View, + cx: &mut ViewContext, + ) { + 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 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)); + 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; -// }; + 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 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 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, -// ); -// } -// }); -// } -// } + 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; -// } + 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::UpdateTab => { + pane.update(cx, |_, cx| { + cx.emit(pane::Event::ChangeItemTitle); + cx.notify(); + }); + } -// ItemEvent::Edit => { -// let autosave = settings2::get::(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) -// }); -// } -// } + 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 -// && settings2::get::(cx).autosave -// == AutosaveSetting::OnFocusChange -// { -// Pane::autosave_item(&item, workspace.project.clone(), cx) -// .detach_and_log_err(cx); -// } -// }) -// .detach(); + 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(); -// } + 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); -// }); -// } + cx.defer(|workspace, cx| { + workspace.serialize_workspace(cx); + }); + } -// fn deactivated(&self, cx: &mut WindowContext) { -// self.update(cx, |this, cx| this.deactivated(cx)); -// } + fn deactivated(&self, cx: &mut WindowContext) { + self.update(cx, |this, cx| this.deactivated(cx)); + } -// fn workspace_deactivated(&self, cx: &mut WindowContext) { -// self.update(cx, |this, cx| this.workspace_deactivated(cx)); -// } + fn workspace_deactivated(&self, cx: &mut WindowContext) { + self.update(cx, |this, cx| this.workspace_deactivated(cx)); + } -// fn navigate(&self, data: Box, cx: &mut WindowContext) -> bool { -// self.update(cx, |this, cx| this.navigate(data, cx)) -// } + fn navigate(&self, data: Box, cx: &mut WindowContext) -> bool { + self.update(cx, |this, cx| this.navigate(data, cx)) + } -// fn id(&self) -> usize { -// self.id() -// } + fn id(&self) -> usize { + self.id() + } -// fn window(&self) -> AnyWindowHandle { -// AnyViewHandle::window(self) -// } + fn window(&self) -> AnyWindowHandle { + todo!() + // AnyViewHandle::window(self) + } -// fn as_any(&self) -> &AnyViewHandle { -// self -// } + // todo!() + // fn as_any(&self) -> &AnyViewHandle { + // self + // } -// fn is_dirty(&self, cx: &AppContext) -> bool { -// self.read(cx).is_dirty(cx) -// } + fn is_dirty(&self, cx: &AppContext) -> bool { + self.read(cx).is_dirty(cx) + } -// fn has_conflict(&self, cx: &AppContext) -> bool { -// self.read(cx).has_conflict(cx) -// } + fn has_conflict(&self, cx: &AppContext) -> bool { + self.read(cx).has_conflict(cx) + } -// fn can_save(&self, cx: &AppContext) -> bool { -// self.read(cx).can_save(cx) -// } + fn can_save(&self, cx: &AppContext) -> bool { + self.read(cx).can_save(cx) + } -// fn save(&self, project: ModelHandle, cx: &mut WindowContext) -> Task> { -// self.update(cx, |item, cx| item.save(project, cx)) -// } + fn save(&self, project: Handle, cx: &mut WindowContext) -> Task> { + self.update(cx, |item, cx| item.save(project, cx)) + } -// fn save_as( -// &self, -// project: ModelHandle, -// abs_path: PathBuf, -// cx: &mut WindowContext, -// ) -> Task> { -// self.update(cx, |item, cx| item.save_as(project, abs_path, cx)) -// } + fn save_as( + &self, + project: Handle, + abs_path: PathBuf, + cx: &mut WindowContext, + ) -> Task> { + self.update(cx, |item, cx| item.save_as(project, abs_path, cx)) + } -// fn reload(&self, project: ModelHandle, cx: &mut WindowContext) -> Task> { -// self.update(cx, |item, cx| item.reload(project, cx)) -// } + fn reload(&self, project: Handle, cx: &mut WindowContext) -> Task> { + self.update(cx, |item, cx| item.reload(project, cx)) + } -// fn act_as_type<'a>(&'a self, type_id: TypeId, cx: &'a AppContext) -> Option<&'a AnyViewHandle> { -// self.read(cx).act_as_type(type_id, self, cx) -// } + // 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> { -// if cx.has_global::() { -// let builders = cx.global::(); -// let item = self.as_any(); -// Some(builders.get(&item.view_type())?.1(item)) -// } else { -// None -// } -// } + fn to_followable_item_handle(&self, cx: &AppContext) -> Option> { + if cx.has_global::() { + let builders = cx.global::(); + let item = self.as_any(); + Some(builders.get(&item.view_type())?.1(item)) + } else { + None + } + } -// fn on_release( -// &self, -// cx: &mut AppContext, -// callback: Box, -// ) -> gpui2::Subscription { -// cx.observe_release(self, move |_, cx| callback(cx)) -// } + fn on_release( + &self, + cx: &mut AppContext, + callback: Box, + ) -> gpui2::Subscription { + cx.observe_release(self, move |_, cx| callback(cx)) + } -// fn to_searchable_item_handle(&self, cx: &AppContext) -> Option> { -// self.read(cx).as_searchable(self) -// } + fn to_searchable_item_handle(&self, cx: &AppContext) -> Option> { + 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> { -// self.read(cx).breadcrumbs(theme, cx) -// } + fn breadcrumbs(&self, theme: &Theme, cx: &AppContext) -> Option> { + 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 { -// self.read(cx).pixel_position_of_cursor(cx) -// } -// } + fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option> { + self.read(cx).pixel_position_of_cursor(cx) + } +} // impl From> for AnyViewHandle { // fn from(val: Box) -> Self { @@ -747,7 +749,7 @@ pub trait FollowableItemHandle: ItemHandle { fn is_project_item(&self, cx: &AppContext) -> bool; } -// impl FollowableItemHandle for ViewHandle { +// impl FollowableItemHandle for View { // fn remote_id(&self, client: &Arc, cx: &AppContext) -> Option { // 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: &Handle, // message: proto::update_view::Variant, // cx: &mut WindowContext, // ) -> Task> { @@ -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>, +// pub project_items: Vec>, // pub nav_history: Option, // pub tab_descriptions: Option>, // pub tab_detail: Cell>, @@ -872,7 +874,7 @@ pub trait FollowableItemHandle: ItemHandle { // } // impl TestProjectItem { -// pub fn new(id: u64, path: &str, cx: &mut AppContext) -> ModelHandle { +// pub fn new(id: u64, path: &str, cx: &mut AppContext) -> Handle { // 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 { +// pub fn new_untitled(cx: &mut AppContext) -> Handle { // 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]) -> Self { +// pub fn with_project_items(mut self, items: &[Handle]) -> 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, +// _: Handle, // _: &mut ViewContext, // ) -> Task> { // self.save_count += 1; @@ -1058,7 +1060,7 @@ pub trait FollowableItemHandle: ItemHandle { // fn save_as( // &mut self, -// _: ModelHandle, +// _: Handle, // _: std::path::PathBuf, // _: &mut ViewContext, // ) -> Task> { @@ -1069,7 +1071,7 @@ pub trait FollowableItemHandle: ItemHandle { // fn reload( // &mut self, -// _: ModelHandle, +// _: Handle, // _: &mut ViewContext, // ) -> Task> { // self.reload_count += 1; @@ -1086,12 +1088,12 @@ pub trait FollowableItemHandle: ItemHandle { // } // fn deserialize( -// _project: ModelHandle, +// _project: Handle, // _workspace: WeakViewHandle, // workspace_id: WorkspaceId, // _item_id: ItemId, // cx: &mut ViewContext, -// ) -> Task>> { +// ) -> Task>> { // let view = cx.add_view(|_cx| Self::new_deserialized(workspace_id)); // Task::Ready(Some(anyhow::Ok(view))) // } diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index 44420714c7..e0eb1b7ec2 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -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}; diff --git a/crates/workspace2/src/pane_group.rs b/crates/workspace2/src/pane_group.rs index fce913128a..f226f7fc43 100644 --- a/crates/workspace2/src/pane_group.rs +++ b/crates/workspace2/src/pane_group.rs @@ -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, FollowerState>, active_call: Option<&Handle>, active_pane: &View, - zoomed: Option<&AnyViewHandle>, + zoomed: Option<&AnyView>, app_state: &Arc, cx: &mut ViewContext, ) -> AnyElement { @@ -159,136 +159,138 @@ impl Member { follower_states: &HashMap, FollowerState>, active_call: Option<&Handle>, active_pane: &View, - zoomed: Option<&AnyViewHandle>, + zoomed: Option<&AnyView>, app_state: &Arc, cx: &mut ViewContext, ) -> AnyElement { - enum FollowIntoExternalProject {} + todo!() - match self { - Member::Pane(pane) => { - let pane_element = if Some(&**pane) == zoomed { - Empty::new().into_any() - } else { - ChildView::new(pane, cx).into_any() - }; + // enum FollowIntoExternalProject {} - 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) - }); + // match self { + // Member::Pane(pane) => { + // let pane_element = if Some(&**pane) == zoomed { + // Empty::new().into_any() + // } else { + // ChildView::new(pane, cx).into_any() + // }; - 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; + // 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) + // }); - 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::( - 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(), - ), - }; - } + // 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; - 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, - ), - } + // 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::( + // 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>) { @@ -308,7 +310,7 @@ pub(crate) struct PaneAxis { pub axis: Axis, pub members: Vec, pub flexes: Rc>>, - pub bounding_boxes: Rc>>>, + pub bounding_boxes: Rc>>>>, } impl PaneAxis { @@ -428,7 +430,7 @@ impl PaneAxis { } } - fn bounding_box_for_pane(&self, pane: &View) -> Option { + fn bounding_box_for_pane(&self, pane: &View) -> Option> { 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> { + fn pane_at_pixel_position(&self, coordinate: Point) -> Option<&View> { 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, FollowerState>, active_call: Option<&Handle>, active_pane: &View, - zoomed: Option<&AnyViewHandle>, + zoomed: Option<&AnyView>, app_state: &Arc, cx: &mut ViewContext, ) -> AnyElement { 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; + 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(); + // 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); - } + // 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, - ); + // 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; + // 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, - } + // match self.axis { + // Axis::Vertical => border.bottom = true, + // Axis::Horizontal => border.right = true, + // } - member = member.contained().with_border(border).into_any(); - } + // 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() + // 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) -> 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, length: Pixels) -> Bounds { 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}; +// 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 gpui::{ +// // geometry::{ +// // rect::Bounds, +// // vector::{vec2f, Vector2F}, +// // }, +// // json::{self, ToJson}, +// // platform::{CursorStyle, MouseButton}, +// // scene::MouseDrag, +// // AnyElement, Axis, CursorRegion, Element, EventContext, MouseRegion, BoundsExt, +// // SizeConstraint, Vector2FExt, ViewContext, +// // }; - use crate::{ - pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE}, - Workspace, WorkspaceSettings, - }; +// 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, - flexes: Rc>>, - children: Vec>, - bounding_boxes: Rc>>>, - } +// pub struct PaneAxisElement { +// axis: Axis, +// basis: usize, +// active_pane_ix: Option, +// flexes: Rc>>, +// children: Vec>, +// bounding_boxes: Rc>>>>, +// } - impl PaneAxisElement { - pub fn new( - axis: Axis, - basis: usize, - flexes: Rc>>, - bounding_boxes: Rc>>>, - ) -> Self { - Self { - axis, - basis, - flexes, - bounding_boxes, - active_pane_ix: None, - children: Default::default(), - } - } +// impl PaneAxisElement { +// pub fn new( +// axis: Axis, +// basis: usize, +// flexes: Rc>>, +// bounding_boxes: Rc>>>>, +// ) -> 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) { - self.active_pane_ix = active_pane_ix; - } +// pub fn set_active_pane(&mut self, active_pane_ix: Option) { +// 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, - ) { - 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] - }; +// 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, +// ) { +// 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_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)); - } - } +// 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>>, - axis: Axis, - preceding_ix: usize, - child_start: Vector2F, - drag_bounds: RectF, - ) -> impl Fn(MouseDrag, &mut Workspace, &mut EventContext) { - let size = move |ix, flexes: &[f32]| { - drag_bounds.length_along(axis) * (flexes[ix] / flexes.len() as f32) - }; +// fn handle_resize( +// flexes: Rc>>, +// axis: Axis, +// preceding_ix: usize, +// child_start: Vector2F, +// drag_bounds: Bounds, +// ) -> impl Fn(MouseDrag, &mut Workspace, &mut EventContext) { +// 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(); +// 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; - } +// // 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 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 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) - }; +// 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; +// ix_offset += 1; - result - } - }); +// result +// } +// }); - while proposed_current_pixel_change.abs() > 0. { - let Some(current_ix) = successors.next() else { - break; - }; +// 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 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_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_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()); +// 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; +// flexes[current_ix] = current_target_flex; +// flexes[current_ix + 1] = next_target_flex; - proposed_current_pixel_change -= current_pixel_change; - } +// proposed_current_pixel_change -= current_pixel_change; +// } - workspace.schedule_serialize(cx); - cx.notify(); - } - } - } +// workspace.schedule_serialize(cx); +// cx.notify(); +// } +// } +// } - impl Extend> for PaneAxisElement { - fn extend>>(&mut self, children: T) { - self.children.extend(children); - } - } +// impl Extend> for PaneAxisElement { +// fn extend>>(&mut self, children: T) { +// self.children.extend(children); +// } +// } - impl Element for PaneAxisElement { - type LayoutState = f32; - type PaintState = (); +// impl Element for PaneAxisElement { +// type LayoutState = f32; +// type PaintState = (); - fn layout( - &mut self, - constraint: SizeConstraint, - view: &mut Workspace, - cx: &mut ViewContext, - ) -> (Vector2F, Self::LayoutState) { - debug_assert!(self.children.len() == self.flexes.borrow().len()); +// fn layout( +// &mut self, +// constraint: SizeConstraint, +// view: &mut Workspace, +// cx: &mut ViewContext, +// ) -> (Vector2F, Self::LayoutState) { +// debug_assert!(self.children.len() == self.flexes.borrow().len()); - let active_pane_magnification = - settings::get::(cx).active_pane_magnification; +// let active_pane_magnification = +// settings::get::(cx).active_pane_magnification; - let mut remaining_flex = 0.; +// 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; - } - } +// 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); +// 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"); - } +// 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, - ); +// 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), - }; +// 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 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()); - } +// 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) - } +// (size, remaining_space) +// } - fn paint( - &mut self, - bounds: RectF, - visible_bounds: RectF, - remaining_space: &mut Self::LayoutState, - view: &mut Workspace, - cx: &mut ViewContext, - ) -> Self::PaintState { - let can_resize = settings::get::(cx).active_pane_magnification == 1.; - let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); +// fn paint( +// &mut self, +// bounds: Bounds, +// visible_bounds: Bounds, +// remaining_space: &mut Self::LayoutState, +// view: &mut Workspace, +// cx: &mut ViewContext, +// ) -> Self::PaintState { +// let can_resize = settings::get::(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 overflowing = *remaining_space < 0.; +// if overflowing { +// cx.scene().push_layer(Some(visible_bounds)); +// } - let mut child_origin = bounds.origin(); +// let mut child_origin = bounds.origin(); - let mut bounding_boxes = self.bounding_boxes.borrow_mut(); - bounding_boxes.clear(); +// 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); +// 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()))); +// bounding_boxes.push(Some(Bounds::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()), - } +// 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); +// 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_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 handle_bounds = match self.axis { +// Axis::Horizontal => Bounds::new( +// handle_origin, +// vec2f(HANDLE_HITBOX_SIZE, visible_bounds.height()), +// ), +// Axis::Vertical => Bounds::new( +// handle_origin, +// vec2f(visible_bounds.width(), HANDLE_HITBOX_SIZE), +// ), +// }; - let style = match self.axis { - Axis::Horizontal => CursorStyle::ResizeLeftRight, - Axis::Vertical => CursorStyle::ResizeUpDown, - }; +// let style = match self.axis { +// Axis::Horizontal => CursorStyle::ResizeLeftRight, +// Axis::Vertical => CursorStyle::ResizeUpDown, +// }; - cx.scene().push_cursor_region(CursorRegion { - bounds: handle_bounds, - style, - }); +// cx.scene().push_cursor_region(CursorRegion { +// bounds: handle_bounds, +// style, +// }); - enum ResizeHandle {} - let mut mouse_region = MouseRegion::new::( - 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); +// enum ResizeHandle {} +// let mut mouse_region = MouseRegion::new::( +// 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(); - } - } +// cx.scene().pop_stacking_context(); +// } +// } - if overflowing { - cx.scene().pop_layer(); - } - } +// if overflowing { +// cx.scene().pop_layer(); +// } +// } - fn rect_for_text_range( - &self, - range_utf16: Range, - _: RectF, - _: RectF, - _: &Self::LayoutState, - _: &Self::PaintState, - view: &Workspace, - cx: &ViewContext, - ) -> Option { - self.children - .iter() - .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx)) - } +// fn rect_for_text_range( +// &self, +// range_utf16: Range, +// _: Bounds, +// _: Bounds, +// _: &Self::LayoutState, +// _: &Self::PaintState, +// view: &Workspace, +// cx: &ViewContext, +// ) -> Option> { +// 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, - ) -> 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::>() - }) - } - } -} +// fn debug( +// &self, +// bounds: Bounds, +// _: &Self::LayoutState, +// _: &Self::PaintState, +// view: &Workspace, +// cx: &ViewContext, +// ) -> 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::>() +// }) +// } +// } +// } diff --git a/crates/workspace2/src/persistence.rs b/crates/workspace2/src/persistence.rs index 2a4062c079..435518271d 100644 --- a/crates/workspace2/src/persistence.rs +++ b/crates/workspace2/src/persistence.rs @@ -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; +// 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(); +// #[gpui::test] +// async fn test_next_id_stability() { +// env_logger::try_init().ok(); - let db = WorkspaceDb(open_test_db("test_next_id_stability").await); +// let db = WorkspaceDb(open_test_db("test_next_id_stability").await); - db.write(|conn| { - 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; +// 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::(sql!( - SELECT workspace_id FROM workspaces WHERE workspace_id = ? - )) - .unwrap()(id) - .unwrap() - ); +// let id = db.next_id().await.unwrap(); +// // Assert the empty row got inserted +// assert_eq!( +// Some(id), +// db.select_row_bound::(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; +// 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"); - } +// 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(); +// #[gpui::test] +// async fn test_workspace_id_stability() { +// env_logger::try_init().ok(); - let db = WorkspaceDb(open_test_db("test_workspace_id_stability").await); +// let db = WorkspaceDb(open_test_db("test_workspace_id_stability").await); - db.write(|conn| { - 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(); +// 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 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(), - }; +// 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.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.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.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; +// 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; +// 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_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"); - } +// 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::Group { - axis, - flexes: None, - children, - } - } +// fn group(axis: gpui::Axis, children: Vec) -> SerializedPaneGroup { +// SerializedPaneGroup::Group { +// axis, +// flexes: None, +// children, +// } +// } - #[gpui::test] - async fn test_full_workspace_serialization() { - env_logger::try_init().ok(); +// #[gpui::test] +// async fn test_full_workspace_serialization() { +// env_logger::try_init().ok(); - let db = WorkspaceDb(open_test_db("test_full_workspace_serialization").await); +// let db = WorkspaceDb(open_test_db("test_full_workspace_serialization").await); - // ----------------- - // | 1,2 | 5,6 | - // | - - - | | - // | 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, - )), - ], - ); +// // ----------------- +// // | 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(), - }; +// 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"]); +// db.save_workspace(workspace.clone()).await; +// let round_trip_workspace = db.workspace_for_roots(&["/tmp2", "/tmp"]); - assert_eq!(workspace, round_trip_workspace.unwrap()); +// assert_eq!(workspace, round_trip_workspace.unwrap()); - // Test guaranteed duplicate IDs - db.save_workspace(workspace.clone()).await; - db.save_workspace(workspace.clone()).await; +// // 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()); - } +// 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(); +// #[gpui::test] +// async fn test_workspace_assignment() { +// env_logger::try_init().ok(); - let db = WorkspaceDb(open_test_db("test_basic_functionality").await); +// let db = WorkspaceDb(open_test_db("test_basic_functionality").await); - let workspace_1 = SerializedWorkspace { - id: 1, - location: (["/tmp", "/tmp2"]).into(), - center_group: Default::default(), - bounds: Default::default(), - display: Default::default(), - docks: Default::default(), - }; +// 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(), - }; +// 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; +// 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 - ); +// // 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); +// // 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(); +// // 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 - ); +// 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(), - }; +// // 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 - ); +// 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 - ); - } +// // 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}; +// use crate::persistence::model::SerializedWorkspace; +// use crate::persistence::model::{SerializedItem, SerializedPane, SerializedPaneGroup}; - fn default_workspace>( - 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(), - } - } +// fn default_workspace>( +// 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(); +// #[gpui::test] +// async fn test_simple_split() { +// env_logger::try_init().ok(); - let db = WorkspaceDb(open_test_db("simple_split").await); +// let db = WorkspaceDb(open_test_db("simple_split").await); - // ----------------- - // | 1,2 | 5,6 | - // | - - - | | - // | 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, - )), - ], - ); +// // ----------------- +// // | 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); +// let workspace = default_workspace(&["/tmp"], ¢er_pane); - db.save_workspace(workspace.clone()).await; +// db.save_workspace(workspace.clone()).await; - let new_workspace = db.workspace_for_roots(&["/tmp"]).unwrap(); +// let new_workspace = db.workspace_for_roots(&["/tmp"]).unwrap(); - assert_eq!(workspace.center_group, new_workspace.center_group); - } +// assert_eq!(workspace.center_group, new_workspace.center_group); +// } - #[gpui::test] - async fn test_cleanup_panes() { - env_logger::try_init().ok(); +// #[gpui::test] +// async fn test_cleanup_panes() { +// env_logger::try_init().ok(); - let db = WorkspaceDb(open_test_db("test_cleanup_panes").await); +// let db = WorkspaceDb(open_test_db("test_cleanup_panes").await); - let center_pane = group( - 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 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 id = &["/tmp"]; - let mut workspace = default_workspace(id, ¢er_pane); +// let mut workspace = default_workspace(id, ¢er_pane); - db.save_workspace(workspace.clone()).await; +// 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, - )), - ], - ); +// 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; +// db.save_workspace(workspace.clone()).await; - let new_workspace = db.workspace_for_roots(id).unwrap(); +// let new_workspace = db.workspace_for_roots(id).unwrap(); - assert_eq!(workspace.center_group, new_workspace.center_group); - } -} +// assert_eq!(workspace.center_group, new_workspace.center_group); +// } +// } diff --git a/crates/workspace2/src/persistence/model.rs b/crates/workspace2/src/persistence/model.rs index 5f4c29cd5b..2e28dabffb 100644 --- a/crates/workspace2/src/persistence/model.rs +++ b/crates/workspace2/src/persistence/model.rs @@ -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: &Handle, workspace_id: WorkspaceId, - workspace: &WeakViewHandle, + workspace: &WeakView, cx: &mut AsyncAppContext, - ) -> Option<( - Member, - Option>, - Vec>>, - )> { + ) -> Option<(Member, Option>, Vec>>)> { 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, - pane: &WeakViewHandle, + project: &Handle, + pane: &WeakView, workspace_id: WorkspaceId, - workspace: &WeakViewHandle, + workspace: &WeakView, cx: &mut AsyncAppContext, ) -> Result>>> { let mut items = Vec::new(); diff --git a/crates/workspace2/src/toolbar.rs b/crates/workspace2/src/toolbar.rs index c3f4bb9723..4357c6a49d 100644 --- a/crates/workspace2/src/toolbar.rs +++ b/crates/workspace2/src/toolbar.rs @@ -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, ToolbarItemLocation)>, } -impl Entity for Toolbar { - type Event = (); -} +// todo!() +// impl View for Toolbar { +// fn ui_name() -> &'static str { +// "Toolbar" +// } -impl View for Toolbar { - fn ui_name() -> &'static str { - "Toolbar" - } +// fn render(&mut self, cx: &mut ViewContext) -> AnyElement { +// let theme = &theme::current(cx).workspace.toolbar; - fn render(&mut self, cx: &mut ViewContext) -> AnyElement { - 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; - 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 => {} - 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::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::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(), +// ); +// } +// } +// } - 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 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 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); +// } - 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") - } - } -} +// 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(&mut self, item: ViewHandle, cx: &mut ViewContext) + pub fn add_item(&mut self, item: View, cx: &mut ViewContext) where T: 'static + ToolbarItemView, { @@ -252,7 +246,7 @@ impl Toolbar { } } - pub fn item_of_type(&self) -> Option> { + pub fn item_of_type(&self) -> Option> { self.items .iter() .find_map(|(item, _)| item.as_any().clone().downcast()) @@ -263,14 +257,15 @@ impl Toolbar { } } -impl ToolbarItemViewHandle for ViewHandle { +impl ToolbarItemViewHandle for View { 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 ToolbarItemViewHandle for ViewHandle { } } -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() +// } +// } diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index 3436a6805e..3731094b26 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -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 ModalHandle for ViewHandle { +// impl ModalHandle for View { // fn as_any(&self) -> &AnyViewHandle { // self // } @@ -376,61 +377,61 @@ pub fn register_project_item(cx: &mut AppContext) { }); } -// type FollowableItemBuilder = fn( -// ViewHandle, -// ViewHandle, -// ViewId, -// &mut Option, -// &mut AppContext, -// ) -> Option>>>; -// type FollowableItemBuilders = HashMap< -// TypeId, -// ( -// FollowableItemBuilder, -// fn(&AnyViewHandle) -> Box, -// ), -// >; -// pub fn register_followable_item(cx: &mut AppContext) { -// cx.update_default_global(|builders: &mut FollowableItemBuilders, _| { -// builders.insert( -// TypeId::of::(), -// ( -// |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::().unwrap()), -// ), -// ); -// }); -// } +type FollowableItemBuilder = fn( + View, + View, + ViewId, + &mut Option, + &mut AppContext, +) -> Option>>>; +type FollowableItemBuilders = HashMap< + TypeId, + ( + FollowableItemBuilder, + fn(&AnyView) -> Box, + ), +>; +pub fn register_followable_item(cx: &mut AppContext) { + cx.update_default_global(|builders: &mut FollowableItemBuilders, _| { + builders.insert( + TypeId::of::(), + ( + |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::().unwrap()), + ), + ); + }); +} -// type ItemDeserializers = HashMap< -// Arc, -// fn( -// ModelHandle, -// WeakViewHandle, -// WorkspaceId, -// ItemId, -// &mut ViewContext, -// ) -> Task>>, -// >; -// pub fn register_deserializable_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, + fn( + Handle, + WeakView, + WorkspaceId, + ItemId, + &mut ViewContext, + ) -> Task>>, +>; +pub fn register_deserializable_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, @@ -493,54 +494,54 @@ struct Follower { // } // } -// struct DelayedDebouncedEditAction { -// task: Option>, -// cancel_channel: Option>, -// } +struct DelayedDebouncedEditAction { + task: Option>, + cancel_channel: Option>, +} -// 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(&mut self, delay: Duration, cx: &mut ViewContext, func: F) -// where -// F: 'static + FnOnce(&mut Workspace, &mut ViewContext) -> Task>, -// { -// if let Some(channel) = self.cancel_channel.take() { -// _ = channel.send(()); -// } + fn fire_new(&mut self, delay: Duration, cx: &mut ViewContext, func: F) + where + F: 'static + FnOnce(&mut Workspace, &mut ViewContext) -> Task>, + { + 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), +// PaneAdded(View), // ContactRequestedJoin(u64), // } @@ -550,19 +551,19 @@ pub struct Workspace { // zoomed: Option, // zoomed_position: Option, // center: PaneGroup, - // left_dock: ViewHandle, - // bottom_dock: ViewHandle, - // right_dock: ViewHandle, + // left_dock: View, + // bottom_dock: View, + // right_dock: View, panes: Vec>, // panes_by_item: HashMap>, - // active_pane: ViewHandle, + // active_pane: View, last_active_center_pane: Option>, // last_active_view_id: Option, - // status_bar: ViewHandle, + // status_bar: View, // titlebar_item: Option, // notifications: Vec<(TypeId, usize, Box)>, project: Handle, - // follower_states: HashMap, FollowerState>, + // follower_states: HashMap, FollowerState>, // last_leaders_by_pane: HashMap, PeerId>, // window_edited: bool, // active_call: Option<(ModelHandle, Vec)>, @@ -930,19 +931,19 @@ impl Workspace { // self.weak_self.clone() // } - // pub fn left_dock(&self) -> &ViewHandle { + // pub fn left_dock(&self) -> &View { // &self.left_dock // } - // pub fn bottom_dock(&self) -> &ViewHandle { + // pub fn bottom_dock(&self) -> &View { // &self.bottom_dock // } - // pub fn right_dock(&self) -> &ViewHandle { + // pub fn right_dock(&self) -> &View { // &self.right_dock // } - // pub fn add_panel(&mut self, panel: ViewHandle, cx: &mut ViewContext) + // pub fn add_panel(&mut self, panel: View, cx: &mut ViewContext) // where // T::Event: std::fmt::Debug, // { @@ -951,12 +952,12 @@ impl Workspace { // pub fn add_panel_with_extra_event_handler( // &mut self, - // panel: ViewHandle, + // panel: View, // cx: &mut ViewContext, // handler: F, // ) where // T::Event: std::fmt::Debug, - // F: Fn(&mut Self, &ViewHandle, &T::Event, &mut ViewContext) + 'static, + // F: Fn(&mut Self, &View, &T::Event, &mut ViewContext) + '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 { + // pub fn status_bar(&self) -> &View { // &self.status_bar // } @@ -1617,10 +1618,10 @@ impl Workspace { // &mut self, // cx: &mut ViewContext, // add_view: F, - // ) -> Option> + // ) -> Option> // where // V: 'static + Modal, - // F: FnOnce(&mut Self, &mut ViewContext) -> ViewHandle, + // F: FnOnce(&mut Self, &mut ViewContext) -> View, // { // 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(&self) -> Option> { + // pub fn modal(&self) -> Option> { // self.modal // .as_ref() // .and_then(|modal| modal.view.as_any().clone().downcast::()) @@ -1676,14 +1677,14 @@ impl Workspace { // self.panes.iter().flat_map(|pane| pane.read(cx).items()) // } - // pub fn item_of_type(&self, cx: &AppContext) -> Option> { + // pub fn item_of_type(&self, cx: &AppContext) -> Option> { // 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> { + // ) -> impl 'a + Iterator> { // 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(&mut self, cx: &mut ViewContext) -> Option> { + // pub fn focus_panel(&mut self, cx: &mut ViewContext) -> Option> { // self.focus_or_unfocus_panel::(cx, |_, _| true)? // .as_any() // .clone() @@ -1888,7 +1889,7 @@ impl Workspace { // None // } - // pub fn panel(&self, cx: &WindowContext) -> Option> { + // pub fn panel(&self, cx: &WindowContext) -> Option> { // for dock in [&self.left_dock, &self.bottom_dock, &self.right_dock] { // let dock = dock.read(cx); // if let Some(panel) = dock.panel::() { @@ -1956,7 +1957,7 @@ impl Workspace { // cx.notify(); // } - // fn add_pane(&mut self, cx: &mut ViewContext) -> ViewHandle { + // fn add_pane(&mut self, cx: &mut ViewContext) -> View { // let pane = cx.add_view(|cx| { // Pane::new( // self.weak_handle(), @@ -2138,7 +2139,7 @@ impl Workspace { // &mut self, // project_item: ModelHandle, // cx: &mut ViewContext, - // ) -> ViewHandle + // ) -> View // where // T: ProjectItem, // { @@ -2162,7 +2163,7 @@ impl Workspace { // &mut self, // project_item: ModelHandle, // cx: &mut ViewContext, - // ) -> ViewHandle + // ) -> View // where // T: ProjectItem, // { @@ -2259,7 +2260,7 @@ impl Workspace { // &mut self, // direction: SplitDirection, // cx: &mut ViewContext, - // ) -> Option<&ViewHandle> { + // ) -> Option<&View> { // 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, cx: &mut ViewContext) { + // fn handle_pane_focused(&mut self, pane: View, cx: &mut ViewContext) { // 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: View, // event: &pane::Event, // cx: &mut ViewContext, // ) { @@ -2363,10 +2364,10 @@ impl Workspace { // pub fn split_pane( // &mut self, - // pane_to_split: ViewHandle, + // pane_to_split: View, // split_direction: SplitDirection, // cx: &mut ViewContext, - // ) -> ViewHandle { + // ) -> View { // 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: View, // direction: SplitDirection, // cx: &mut ViewContext, - // ) -> Option> { + // ) -> Option> { // 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, - // destination: ViewHandle, + // source: View, + // destination: View, // item_id_to_move: usize, // destination_index: usize, // cx: &mut ViewContext, @@ -2473,7 +2474,7 @@ impl Workspace { // }); // } - // fn remove_pane(&mut self, pane: ViewHandle, cx: &mut ViewContext) { + // fn remove_pane(&mut self, pane: View, cx: &mut ViewContext) { // 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] { + // pub fn panes(&self) -> &[View] { // &self.panes // } - // pub fn active_pane(&self) -> &ViewHandle { + // pub fn active_pane(&self) -> &View { // &self.active_pane // } @@ -2651,7 +2652,7 @@ impl Workspace { // pub fn unfollow( // &mut self, - // pane: &ViewHandle, + // pane: &View, // cx: &mut ViewContext, // ) -> Option { // let state = self.follower_states.remove(pane)?; @@ -2959,7 +2960,7 @@ impl Workspace { // async fn add_views_from_leader( // this: WeakViewHandle, // leader_id: PeerId, - // panes: Vec>, + // panes: Vec>, // views: Vec, // cx: &mut AsyncAppContext, // ) -> Result<()> { @@ -3060,7 +3061,7 @@ impl Workspace { // }) // } - // pub fn leader_for_pane(&self, pane: &ViewHandle) -> Option { + // pub fn leader_for_pane(&self, pane: &View) -> Option { // 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: &View, // cx: &mut ViewContext, - // ) -> Option> { + // ) -> Option> { // 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, cx: &mut ViewContext) { + // fn force_remove_pane(&mut self, pane: &View, cx: &mut ViewContext) { // 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) { // fn serialize_pane_handle( - // pane_handle: &ViewHandle, + // pane_handle: &View, // cx: &AppContext, // ) -> SerializedPane { // let (items, active) = { @@ -4075,7 +4076,7 @@ impl Workspace { // fn file_project_paths(&self, cx: &AppContext) -> Vec; // } -// impl WorkspaceHandle for ViewHandle { +// impl WorkspaceHandle for View { // fn file_project_paths(&self, cx: &AppContext) -> Vec { // 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; diff --git a/crates/workspace2/src/workspace_settings.rs b/crates/workspace2/src/workspace_settings.rs index 6483167018..5d158e5a05 100644 --- a/crates/workspace2/src/workspace_settings.rs +++ b/crates/workspace2/src/workspace_settings.rs @@ -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::load_via_json_merge(default_value, user_values) }