diff --git a/Cargo.lock b/Cargo.lock index 849a9663396c83eafc523031e98e00ef4d2811d4..c1223f74e1bd3cc3e3f85b7583ff6fd0830d99a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6109,7 +6109,6 @@ dependencies = [ "settings2", "theme2", "util", - "workspace2", ] [[package]] diff --git a/crates/call2/src/call2.rs b/crates/call2/src/call2.rs index b19720bcdcb80c35cb54f5238131aebc46b5fafb..2fab3d40ce600c0b9c26cbc31b95398cc1ab9a96 100644 --- a/crates/call2/src/call2.rs +++ b/crates/call2/src/call2.rs @@ -17,6 +17,7 @@ use gpui::{ }; use postage::watch; use project::Project; +use room::Event; use settings::Settings; use std::sync::Arc; @@ -85,9 +86,7 @@ pub struct ActiveCall { _subscriptions: Vec, } -impl EventEmitter for ActiveCall { - type Event = room::Event; -} +impl EventEmitter for ActiveCall {} impl ActiveCall { fn new(client: Arc, user_store: Model, cx: &mut ModelContext) -> Self { diff --git a/crates/call2/src/room.rs b/crates/call2/src/room.rs index 27bc51a277af7f6a66f49b1ec516d3fce919715c..87118764fdc717620521b32e5b77aa7e1c4aca9f 100644 --- a/crates/call2/src/room.rs +++ b/crates/call2/src/room.rs @@ -79,9 +79,7 @@ pub struct Room { maintain_connection: Option>>, } -impl EventEmitter for Room { - type Event = Event; -} +impl EventEmitter for Room {} impl Room { pub fn channel_id(&self) -> Option { diff --git a/crates/channel2/src/channel_buffer.rs b/crates/channel2/src/channel_buffer.rs index 4c321a8fbcde454d4a4b21c1104e1af8d85b5d7d..764f5f7661702b1d33bac9dd1b1f8b97cdd93a71 100644 --- a/crates/channel2/src/channel_buffer.rs +++ b/crates/channel2/src/channel_buffer.rs @@ -38,9 +38,7 @@ pub enum ChannelBufferEvent { ChannelChanged, } -impl EventEmitter for ChannelBuffer { - type Event = ChannelBufferEvent; -} +impl EventEmitter for ChannelBuffer {} impl ChannelBuffer { pub(crate) async fn new( diff --git a/crates/channel2/src/channel_chat.rs b/crates/channel2/src/channel_chat.rs index a5b5249853a4d4bf7a9ffb46bb379f065e9e07f2..eb92eb18e4f83ad9af7daf1ee17a95bdf33fc354 100644 --- a/crates/channel2/src/channel_chat.rs +++ b/crates/channel2/src/channel_chat.rs @@ -76,9 +76,7 @@ pub enum ChannelChatEvent { }, } -impl EventEmitter for ChannelChat { - type Event = ChannelChatEvent; -} +impl EventEmitter for ChannelChat {} pub fn init(client: &Arc) { client.add_model_message_handler(ChannelChat::handle_message_sent); client.add_model_message_handler(ChannelChat::handle_message_removed); diff --git a/crates/channel2/src/channel_store.rs b/crates/channel2/src/channel_store.rs index 3c9abd59e279e2c35fc580634faff753296d220e..5fcc2b95668f423eac3d1874cb15c444e63bb0dd 100644 --- a/crates/channel2/src/channel_store.rs +++ b/crates/channel2/src/channel_store.rs @@ -114,9 +114,7 @@ pub enum ChannelEvent { ChannelRenamed(ChannelId), } -impl EventEmitter for ChannelStore { - type Event = ChannelEvent; -} +impl EventEmitter for ChannelStore {} enum OpenedModelHandle { Open(WeakModel), diff --git a/crates/client2/src/user.rs b/crates/client2/src/user.rs index 8ff134e6b7f83ea56eab218754b22ba91c9c028c..a5dba03d2da59e8277ed5f36a71d92fe51c63162 100644 --- a/crates/client2/src/user.rs +++ b/crates/client2/src/user.rs @@ -103,9 +103,7 @@ pub enum ContactEventKind { Cancelled, } -impl EventEmitter for UserStore { - type Event = Event; -} +impl EventEmitter for UserStore {} enum UpdateContacts { Update(proto::UpdateContacts), diff --git a/crates/copilot2/src/copilot2.rs b/crates/copilot2/src/copilot2.rs index 9e82823b9bcaee3ebeee7edf9c03a3d0a9486fb5..2daf2fec12434f23071135741c6a07a5dd5f847c 100644 --- a/crates/copilot2/src/copilot2.rs +++ b/crates/copilot2/src/copilot2.rs @@ -284,9 +284,7 @@ pub enum Event { CopilotLanguageServerStarted, } -impl EventEmitter for Copilot { - type Event = Event; -} +impl EventEmitter for Copilot {} impl Copilot { pub fn global(cx: &AppContext) -> Option> { diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 2fe35bb1f68e325ca9be8e40272b9bede754c4b0..a9ae59fec69f26184e6d1e463cb721436bb86727 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -96,7 +96,9 @@ use theme::{ ActiveTheme, DiagnosticStyle, PlayerColor, SyntaxTheme, Theme, ThemeColors, ThemeSettings, }; use util::{post_inc, RangeExt, ResultExt, TryFutureExt}; -use workspace::{ItemNavHistory, SplitDirection, ViewId, Workspace}; +use workspace::{ + item::ItemEvent, searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, +}; const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500); const MAX_LINE_LEN: usize = 1024; @@ -1904,7 +1906,8 @@ impl Editor { if let Some(project) = project.as_ref() { if buffer.read(cx).is_singleton() { project_subscriptions.push(cx.observe(project, |_, _, cx| { - cx.emit(Event::TitleChanged); + cx.emit(ItemEvent::UpdateTab); + cx.emit(ItemEvent::UpdateBreadcrumbs); })); } project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| { @@ -2363,6 +2366,15 @@ impl Editor { self.blink_manager.update(cx, BlinkManager::pause_blinking); cx.emit(Event::SelectionsChanged { local }); + + if self.selections.disjoint_anchors().len() == 1 { + cx.emit(SearchEvent::ActiveMatchChanged) + } + + if local { + cx.emit(ItemEvent::UpdateBreadcrumbs); + } + cx.notify(); } @@ -8762,6 +8774,9 @@ impl Editor { self.update_visible_copilot_suggestion(cx); } cx.emit(Event::BufferEdited); + cx.emit(ItemEvent::Edit); + cx.emit(ItemEvent::UpdateBreadcrumbs); + cx.emit(SearchEvent::MatchesInvalidated); if *sigleton_buffer_edited { if let Some(project) = &self.project { @@ -8808,13 +8823,20 @@ impl Editor { self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx); cx.emit(Event::ExcerptsRemoved { ids: ids.clone() }) } - multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed), - multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged), - multi_buffer::Event::Saved => cx.emit(Event::Saved), - multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged), - multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged), + multi_buffer::Event::Reparsed => { + cx.emit(ItemEvent::UpdateBreadcrumbs); + } + multi_buffer::Event::DirtyChanged => { + cx.emit(ItemEvent::UpdateTab); + } + multi_buffer::Event::Saved + | multi_buffer::Event::FileHandleChanged + | multi_buffer::Event::Reloaded => { + cx.emit(ItemEvent::UpdateTab); + cx.emit(ItemEvent::UpdateBreadcrumbs); + } multi_buffer::Event::DiffBaseChanged => cx.emit(Event::DiffBaseChanged), - multi_buffer::Event::Closed => cx.emit(Event::Closed), + multi_buffer::Event::Closed => cx.emit(ItemEvent::CloseItem), multi_buffer::Event::DiagnosticsUpdated => { self.refresh_active_diagnostics(cx); } @@ -9380,12 +9402,8 @@ pub enum Event { }, BufferEdited, Edited, - Reparsed, Focused, Blurred, - DirtyChanged, - Saved, - TitleChanged, DiffBaseChanged, SelectionsChanged { local: bool, @@ -9394,7 +9412,6 @@ pub enum Event { local: bool, autoscroll: bool, }, - Closed, } pub struct EditorFocused(pub View); @@ -9409,9 +9426,7 @@ pub struct EditorReleased(pub WeakView); // } // } // -impl EventEmitter for Editor { - type Event = Event; -} +impl EventEmitter for Editor {} impl Render for Editor { type Element = EditorElement; diff --git a/crates/editor2/src/items.rs b/crates/editor2/src/items.rs index 9c49e5f14317579eb1ca6e103c5058de97e76d40..1081a329c6145ab6e6cea620aeaff1ec006cf017 100644 --- a/crates/editor2/src/items.rs +++ b/crates/editor2/src/items.rs @@ -7,9 +7,9 @@ use anyhow::{anyhow, Context, Result}; use collections::HashSet; use futures::future::try_join_all; use gpui::{ - div, point, AnyElement, AppContext, AsyncAppContext, Entity, EntityId, FocusHandle, Model, - ParentElement, Pixels, SharedString, Styled, Subscription, Task, View, ViewContext, - VisualContext, WeakView, + div, point, AnyElement, AppContext, AsyncAppContext, Entity, EntityId, EventEmitter, + FocusHandle, Model, ParentElement, Pixels, SharedString, Styled, Subscription, Task, View, + ViewContext, VisualContext, WeakView, }; use language::{ proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, OffsetRangeExt, Point, @@ -29,7 +29,7 @@ use std::{ use text::Selection; use theme::{ActiveTheme, Theme}; use util::{paths::PathExt, ResultExt, TryFutureExt}; -use workspace::item::{BreadcrumbText, FollowableItemHandle}; +use workspace::item::{BreadcrumbText, FollowEvent, FollowableEvents, FollowableItemHandle}; use workspace::{ item::{FollowableItem, Item, ItemEvent, ItemHandle, ProjectItem}, searchable::{Direction, SearchEvent, SearchableItem, SearchableItemHandle}, @@ -38,7 +38,26 @@ use workspace::{ pub const MAX_TAB_TITLE_LEN: usize = 24; +impl FollowableEvents for Event { + fn to_follow_event(&self) -> Option { + match self { + Event::Edited => Some(FollowEvent::Unfollow), + Event::SelectionsChanged { local } | Event::ScrollPositionChanged { local, .. } => { + if *local { + Some(FollowEvent::Unfollow) + } else { + None + } + } + _ => None, + } + } +} + +impl EventEmitter for Editor {} + impl FollowableItem for Editor { + type FollowableEvent = Event; fn remote_id(&self) -> Option { self.remote_id } @@ -217,7 +236,7 @@ impl FollowableItem for Editor { fn add_event_to_update_proto( &self, - event: &Self::Event, + event: &Self::FollowableEvent, update: &mut Option, cx: &AppContext, ) -> bool { @@ -292,15 +311,6 @@ impl FollowableItem for Editor { }) } - fn should_unfollow_on_event(event: &Self::Event, _: &AppContext) -> bool { - match event { - Event::Edited => true, - Event::SelectionsChanged { local } => *local, - Event::ScrollPositionChanged { local, .. } => *local, - _ => false, - } - } - fn is_project_item(&self, _cx: &AppContext) -> bool { true } @@ -739,32 +749,6 @@ impl Item for Editor { }) } - fn to_item_events(event: &Self::Event) -> SmallVec<[ItemEvent; 2]> { - let mut result = SmallVec::new(); - match event { - Event::Closed => result.push(ItemEvent::CloseItem), - Event::Saved | Event::TitleChanged => { - result.push(ItemEvent::UpdateTab); - result.push(ItemEvent::UpdateBreadcrumbs); - } - Event::Reparsed => { - result.push(ItemEvent::UpdateBreadcrumbs); - } - Event::SelectionsChanged { local } if *local => { - result.push(ItemEvent::UpdateBreadcrumbs); - } - Event::DirtyChanged => { - result.push(ItemEvent::UpdateTab); - } - Event::BufferEdited => { - result.push(ItemEvent::Edit); - result.push(ItemEvent::UpdateBreadcrumbs); - } - _ => {} - } - result - } - fn as_searchable(&self, handle: &View) -> Option> { Some(Box::new(handle.clone())) } @@ -913,28 +897,12 @@ impl ProjectItem for Editor { } } +impl EventEmitter for Editor {} + pub(crate) enum BufferSearchHighlights {} impl SearchableItem for Editor { type Match = Range; - fn to_search_event( - &mut self, - event: &Self::Event, - _: &mut ViewContext, - ) -> Option { - match event { - Event::BufferEdited => Some(SearchEvent::MatchesInvalidated), - Event::SelectionsChanged { .. } => { - if self.selections.disjoint_anchors().len() == 1 { - Some(SearchEvent::ActiveMatchChanged) - } else { - None - } - } - _ => None, - } - } - fn clear_matches(&mut self, cx: &mut ViewContext) { todo!() // self.clear_background_highlights::(cx); diff --git a/crates/go_to_line2/src/go_to_line.rs b/crates/go_to_line2/src/go_to_line.rs index af69d42d41db6f171ec13adadf288723e181a6af..c65373e6acc0c1af750173caa8a648eb9881be7b 100644 --- a/crates/go_to_line2/src/go_to_line.rs +++ b/crates/go_to_line2/src/go_to_line.rs @@ -8,7 +8,7 @@ use text::{Bias, Point}; use theme::ActiveTheme; use ui::{h_stack, modal, v_stack, Label, LabelColor}; use util::paths::FILE_ROW_COLUMN_DELIMITER; -use workspace::{Modal, ModalEvent, Workspace}; +use workspace::{ModalEvent, Workspace}; actions!(Toggle); @@ -41,9 +41,9 @@ pub enum Event { Dismissed, } -impl EventEmitter for GoToLine { - type Event = Event; -} +impl EventEmitter for GoToLine {} + +impl EventEmitter for GoToLine {} impl GoToLine { pub fn new(active_editor: View, cx: &mut ViewContext) -> Self { @@ -149,14 +149,6 @@ impl GoToLine { } } -impl Modal for GoToLine { - fn to_modal_event(&self, e: &Self::Event) -> Option { - match e { - Event::Dismissed => Some(ModalEvent::Dismissed), - } - } -} - impl Render for GoToLine { type Element = Div>; diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 33eaf070be9452ce3ce7e32394403d3a0b298d8a..356cf1b76bf5bcf40e15cb7ae9f10e3511db73d1 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -203,7 +203,8 @@ pub struct AppContext { pub(crate) pending_notifications: HashSet, pub(crate) pending_global_notifications: HashSet, pub(crate) observers: SubscriberSet, - pub(crate) event_listeners: SubscriberSet, + // TypeId is the type of the event that the listener callback expects + pub(crate) event_listeners: SubscriberSet, pub(crate) release_listeners: SubscriberSet, pub(crate) global_observers: SubscriberSet, pub(crate) quit_observers: SubscriberSet<(), QuitHandler>, @@ -354,14 +355,15 @@ impl AppContext { ) } - pub fn subscribe( + pub fn subscribe( &mut self, entity: &E, - mut on_event: impl FnMut(E, &T::Event, &mut AppContext) + 'static, + mut on_event: impl FnMut(E, &Evt, &mut AppContext) + 'static, ) -> Subscription where - T: 'static + EventEmitter, + T: 'static + EventEmitter, E: Entity, + Evt: 'static, { self.subscribe_internal(entity, move |entity, event, cx| { on_event(entity, event, cx); @@ -369,27 +371,32 @@ impl AppContext { }) } - pub(crate) fn subscribe_internal( + pub(crate) fn subscribe_internal( &mut self, entity: &E, - mut on_event: impl FnMut(E, &T::Event, &mut AppContext) -> bool + 'static, + mut on_event: impl FnMut(E, &Evt, &mut AppContext) -> bool + 'static, ) -> Subscription where - T: 'static + EventEmitter, + T: 'static + EventEmitter, E: Entity, + Evt: 'static, { let entity_id = entity.entity_id(); let entity = entity.downgrade(); + self.event_listeners.insert( entity_id, - Box::new(move |event, cx| { - let event: &T::Event = event.downcast_ref().expect("invalid event type"); - if let Some(handle) = E::upgrade_from(&entity) { - on_event(handle, event, cx) - } else { - false - } - }), + ( + TypeId::of::(), + Box::new(move |event, cx| { + let event: &Evt = event.downcast_ref().expect("invalid event type"); + if let Some(handle) = E::upgrade_from(&entity) { + on_event(handle, event, cx) + } else { + false + } + }), + ), ) } @@ -512,7 +519,11 @@ impl AppContext { Effect::Notify { emitter } => { self.apply_notify_effect(emitter); } - Effect::Emit { emitter, event } => self.apply_emit_effect(emitter, event), + Effect::Emit { + emitter, + event_type, + event, + } => self.apply_emit_effect(emitter, event_type, event), Effect::FocusChanged { window_handle, focused, @@ -608,10 +619,16 @@ impl AppContext { .retain(&emitter, |handler| handler(self)); } - fn apply_emit_effect(&mut self, emitter: EntityId, event: Box) { + fn apply_emit_effect(&mut self, emitter: EntityId, event_type: TypeId, event: Box) { self.event_listeners .clone() - .retain(&emitter, |handler| handler(event.as_ref(), self)); + .retain(&emitter, |(stored_type, handler)| { + if *stored_type == event_type { + handler(event.as_ref(), self) + } else { + true + } + }); } fn apply_focus_changed_effect( @@ -999,6 +1016,7 @@ pub(crate) enum Effect { }, Emit { emitter: EntityId, + event_type: TypeId, event: Box, }, FocusChanged { diff --git a/crates/gpui2/src/app/model_context.rs b/crates/gpui2/src/app/model_context.rs index 35d41ab362989d27ed00d99e13bb557702d43862..44a3337f0321d926d21934864e18377214287b37 100644 --- a/crates/gpui2/src/app/model_context.rs +++ b/crates/gpui2/src/app/model_context.rs @@ -59,15 +59,16 @@ impl<'a, T: 'static> ModelContext<'a, T> { }) } - pub fn subscribe( + pub fn subscribe( &mut self, entity: &E, - mut on_event: impl FnMut(&mut T, E, &T2::Event, &mut ModelContext<'_, T>) + 'static, + mut on_event: impl FnMut(&mut T, E, &Evt, &mut ModelContext<'_, T>) + 'static, ) -> Subscription where T: 'static, - T2: 'static + EventEmitter, + T2: 'static + EventEmitter, E: Entity, + Evt: 'static, { let this = self.weak_model(); self.app.subscribe_internal(entity, move |e, event, cx| { @@ -189,13 +190,15 @@ impl<'a, T: 'static> ModelContext<'a, T> { } } -impl<'a, T> ModelContext<'a, T> -where - T: EventEmitter, -{ - pub fn emit(&mut self, event: T::Event) { +impl<'a, T> ModelContext<'a, T> { + pub fn emit(&mut self, event: Evt) + where + T: EventEmitter, + Evt: 'static, + { self.app.pending_effects.push_back(Effect::Emit { emitter: self.model_state.entity_id, + event_type: TypeId::of::(), event: Box::new(event), }); } diff --git a/crates/gpui2/src/app/test_context.rs b/crates/gpui2/src/app/test_context.rs index eb5ce283a570123d059d5fa52249abc6e5037097..7b5ab5f7d76dc728556d66925dc67ca086c37893 100644 --- a/crates/gpui2/src/app/test_context.rs +++ b/crates/gpui2/src/app/test_context.rs @@ -197,12 +197,12 @@ impl TestAppContext { rx } - pub fn events( + pub fn events>( &mut self, entity: &Model, - ) -> futures::channel::mpsc::UnboundedReceiver + ) -> futures::channel::mpsc::UnboundedReceiver where - T::Event: 'static + Clone, + Evt: 'static + Clone, { let (tx, rx) = futures::channel::mpsc::unbounded(); entity @@ -240,10 +240,11 @@ impl TestAppContext { } } -impl Model { - pub fn next_event(&self, cx: &mut TestAppContext) -> T::Event +impl Model { + pub fn next_event(&self, cx: &mut TestAppContext) -> Evt where - T::Event: Send + Clone, + Evt: Send + Clone + 'static, + T: EventEmitter, { let (tx, mut rx) = futures::channel::mpsc::unbounded(); let _subscription = self.update(cx, |_, cx| { diff --git a/crates/gpui2/src/gpui2.rs b/crates/gpui2/src/gpui2.rs index 91e41417351293cf69866a85e61cd9f57a43a488..d54027c13aef08f9e08c4622b566284b5845ff86 100644 --- a/crates/gpui2/src/gpui2.rs +++ b/crates/gpui2/src/gpui2.rs @@ -138,6 +138,8 @@ pub trait Entity: Sealed { Self: Sized; } +pub trait EventEmitter: 'static {} + pub enum GlobalKey { Numeric(usize), View(EntityId), @@ -171,10 +173,6 @@ where } } -pub trait EventEmitter: 'static { - type Event: Any; -} - pub trait Flatten { fn flatten(self) -> Result; } diff --git a/crates/gpui2/src/subscription.rs b/crates/gpui2/src/subscription.rs index 2f4ec0d2f13212440fe7d23585781bac7b2be069..7cb023a9074094b27d16b6effa27c68b967f30c8 100644 --- a/crates/gpui2/src/subscription.rs +++ b/crates/gpui2/src/subscription.rs @@ -75,6 +75,8 @@ where .flatten() } + /// Call the given callback for each subscriber to the given emitter. + /// If the callback returns false, the subscriber is removed. pub fn retain(&self, emitter: &EmitterKey, mut f: F) where F: FnMut(&mut Callback) -> bool, diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 1daebf184c1f67e8af712ed8326e355ba65db22a..ce50b8e7f1161775a415819c5df72a54b05e92e4 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -438,33 +438,37 @@ impl<'a> WindowContext<'a> { }); } - pub fn subscribe( + pub fn subscribe( &mut self, entity: &E, - mut on_event: impl FnMut(E, &Emitter::Event, &mut WindowContext<'_>) + 'static, + mut on_event: impl FnMut(E, &Evt, &mut WindowContext<'_>) + 'static, ) -> Subscription where - Emitter: EventEmitter, + Emitter: EventEmitter, E: Entity, + Evt: 'static, { let entity_id = entity.entity_id(); let entity = entity.downgrade(); let window_handle = self.window.handle; self.app.event_listeners.insert( entity_id, - Box::new(move |event, cx| { - window_handle - .update(cx, |_, cx| { - if let Some(handle) = E::upgrade_from(&entity) { - let event = event.downcast_ref().expect("invalid event type"); - on_event(handle, event, cx); - true - } else { - false - } - }) - .unwrap_or(false) - }), + ( + TypeId::of::(), + Box::new(move |event, cx| { + window_handle + .update(cx, |_, cx| { + if let Some(handle) = E::upgrade_from(&entity) { + let event = event.downcast_ref().expect("invalid event type"); + on_event(handle, event, cx); + true + } else { + false + } + }) + .unwrap_or(false) + }), + ), ) } @@ -1817,14 +1821,15 @@ impl<'a, V: 'static> ViewContext<'a, V> { ) } - pub fn subscribe( + pub fn subscribe( &mut self, entity: &E, - mut on_event: impl FnMut(&mut V, E, &V2::Event, &mut ViewContext<'_, V>) + 'static, + mut on_event: impl FnMut(&mut V, E, &Evt, &mut ViewContext<'_, V>) + 'static, ) -> Subscription where - V2: EventEmitter, + V2: EventEmitter, E: Entity, + Evt: 'static, { let view = self.view().downgrade(); let entity_id = entity.entity_id(); @@ -1832,19 +1837,22 @@ impl<'a, V: 'static> ViewContext<'a, V> { let window_handle = self.window.handle; self.app.event_listeners.insert( entity_id, - Box::new(move |event, cx| { - window_handle - .update(cx, |_, cx| { - if let Some(handle) = E::upgrade_from(&handle) { - let event = event.downcast_ref().expect("invalid event type"); - view.update(cx, |this, cx| on_event(this, handle, event, cx)) - .is_ok() - } else { - false - } - }) - .unwrap_or(false) - }), + ( + TypeId::of::(), + Box::new(move |event, cx| { + window_handle + .update(cx, |_, cx| { + if let Some(handle) = E::upgrade_from(&handle) { + let event = event.downcast_ref().expect("invalid event type"); + view.update(cx, |this, cx| on_event(this, handle, event, cx)) + .is_ok() + } else { + false + } + }) + .unwrap_or(false) + }), + ), ) } @@ -2176,15 +2184,16 @@ impl<'a, V: 'static> ViewContext<'a, V> { } } -impl ViewContext<'_, V> -where - V: EventEmitter, - V::Event: 'static, -{ - pub fn emit(&mut self, event: V::Event) { +impl ViewContext<'_, V> { + pub fn emit(&mut self, event: Evt) + where + Evt: 'static, + V: EventEmitter, + { let emitter = self.view.model.entity_id; self.app.push_effect(Effect::Emit { emitter, + event_type: TypeId::of::(), event: Box::new(event), }); } diff --git a/crates/language2/src/buffer.rs b/crates/language2/src/buffer.rs index b19cf973546e847f60e4e66eef751cdba49c4d42..2c8c55d5776d1970e4597f86372aef9d65627c16 100644 --- a/crates/language2/src/buffer.rs +++ b/crates/language2/src/buffer.rs @@ -1815,9 +1815,7 @@ impl Buffer { } } -impl EventEmitter for Buffer { - type Event = Event; -} +impl EventEmitter for Buffer {} impl Deref for Buffer { type Target = TextBuffer; diff --git a/crates/multi_buffer2/src/multi_buffer2.rs b/crates/multi_buffer2/src/multi_buffer2.rs index df33f98b4b67be4e13dfd6df025fec5a8c52574b..a38d36f02f415cda7a815ef80703f88d54c53076 100644 --- a/crates/multi_buffer2/src/multi_buffer2.rs +++ b/crates/multi_buffer2/src/multi_buffer2.rs @@ -1872,9 +1872,7 @@ impl MultiBuffer { } } -impl EventEmitter for MultiBuffer { - type Event = Event; -} +impl EventEmitter for MultiBuffer {} impl MultiBufferSnapshot { pub fn text(&self) -> String { diff --git a/crates/picker2/Cargo.toml b/crates/picker2/Cargo.toml index 8d88c25366fa52bcaa20018503608d3dd86ebbf2..90e1ae931c916f7f04ab60915026902342894a20 100644 --- a/crates/picker2/Cargo.toml +++ b/crates/picker2/Cargo.toml @@ -15,7 +15,6 @@ menu = { package = "menu2", path = "../menu2" } settings = { package = "settings2", path = "../settings2" } util = { path = "../util" } theme = { package = "theme2", path = "../theme2" } -workspace = { package = "workspace2", path = "../workspace2" } parking_lot.workspace = true @@ -23,6 +22,5 @@ parking_lot.workspace = true editor = { package = "editor2", path = "../editor2", features = ["test-support"] } gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] } serde_json.workspace = true -workspace = { package = "workspace2", path = "../workspace2", features = ["test-support"] } ctor.workspace = true env_logger.workspace = true diff --git a/crates/project2/src/project2.rs b/crates/project2/src/project2.rs index 5d7c976e774bb7df501e701b8031b92cf566f743..95f04dfc8225d80daa0b54527d44bedcaf780a99 100644 --- a/crates/project2/src/project2.rs +++ b/crates/project2/src/project2.rs @@ -9062,9 +9062,7 @@ impl<'a> Iterator for PathMatchCandidateSetIter<'a> { } } -impl EventEmitter for Project { - type Event = Event; -} +impl EventEmitter for Project {} impl> From<(WorktreeId, P)> for ProjectPath { fn from((worktree_id, path): (WorktreeId, P)) -> Self { diff --git a/crates/project2/src/worktree.rs b/crates/project2/src/worktree.rs index 937a549a312ca644b0aa53099c9c0e675cf841d1..65959d3f310598de3a6e6c4d5b59e215d262d351 100644 --- a/crates/project2/src/worktree.rs +++ b/crates/project2/src/worktree.rs @@ -281,9 +281,7 @@ pub enum Event { UpdatedGitRepositories(UpdatedGitRepositoriesSet), } -impl EventEmitter for Worktree { - type Event = Event; -} +impl EventEmitter for Worktree {} impl Worktree { pub async fn local( diff --git a/crates/terminal2/src/terminal2.rs b/crates/terminal2/src/terminal2.rs index 3d06b488123016c19102e8d911d6b24568124ab1..9f94339504b7c7b1705161bf9ea876021ec49028 100644 --- a/crates/terminal2/src/terminal2.rs +++ b/crates/terminal2/src/terminal2.rs @@ -1351,9 +1351,7 @@ impl Drop for Terminal { } } -impl EventEmitter for Terminal { - type Event = Event; -} +impl EventEmitter for Terminal {} /// Based on alacritty/src/display/hint.rs > regex_match_at /// Retrieve the match, if the specified point is inside the content matching the regex. diff --git a/crates/workspace2/src/dock.rs b/crates/workspace2/src/dock.rs index 635b48051a441e81833faadb7b785281462c909e..f21eb84ae21eb59873f63110f2ffeb9696614d13 100644 --- a/crates/workspace2/src/dock.rs +++ b/crates/workspace2/src/dock.rs @@ -7,7 +7,16 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::sync::Arc; -pub trait Panel: Render + EventEmitter { +pub enum PanelEvent { + ChangePosition, + ZoomIn, + ZoomOut, + Activate, + Close, + Focus, +} + +pub trait Panel: Render + EventEmitter { fn persistent_name(&self) -> &'static str; fn position(&self, cx: &WindowContext) -> DockPosition; fn position_is_valid(&self, position: DockPosition) -> bool; @@ -19,26 +28,12 @@ pub trait Panel: Render + EventEmitter { fn icon_label(&self, _: &WindowContext) -> Option { None } - fn should_change_position_on_event(_: &Self::Event) -> bool; - fn should_zoom_in_on_event(_: &Self::Event) -> bool { - false - } - fn should_zoom_out_on_event(_: &Self::Event) -> bool { - false - } fn is_zoomed(&self, _cx: &WindowContext) -> bool { false } fn set_zoomed(&mut self, _zoomed: bool, _cx: &mut ViewContext) {} fn set_active(&mut self, _active: bool, _cx: &mut ViewContext) {} - fn should_activate_on_event(_: &Self::Event) -> bool { - false - } - fn should_close_on_event(_: &Self::Event) -> bool { - false - } fn has_focus(&self, cx: &WindowContext) -> bool; - fn is_focus_event(_: &Self::Event) -> bool; } pub trait PanelHandle: Send + Sync { @@ -268,21 +263,37 @@ impl Dock { let subscriptions = [ cx.observe(&panel, |_, _, cx| cx.notify()), cx.subscribe(&panel, |this, panel, event, cx| { - if T::should_activate_on_event(event) { - if let Some(ix) = this - .panel_entries - .iter() - .position(|entry| entry.panel.id() == panel.id()) - { - this.set_open(true, cx); - this.activate_panel(ix, cx); + match event { + PanelEvent::ChangePosition => { + //todo!() + // see: Workspace::add_panel_with_extra_event_handler + } + PanelEvent::ZoomIn => { + //todo!() + // see: Workspace::add_panel_with_extra_event_handler + } + PanelEvent::ZoomOut => { // todo!() - // cx.focus(&panel); + // // see: Workspace::add_panel_with_extra_event_handler } - } else if T::should_close_on_event(event) - && this.visible_panel().map_or(false, |p| p.id() == panel.id()) - { - this.set_open(false, cx); + PanelEvent::Activate => { + if let Some(ix) = this + .panel_entries + .iter() + .position(|entry| entry.panel.id() == panel.id()) + { + this.set_open(true, cx); + this.activate_panel(ix, cx); + //` todo!() + // cx.focus(&panel); + } + } + PanelEvent::Close => { + if this.visible_panel().map_or(false, |p| p.id() == panel.id()) { + this.set_open(false, cx); + } + } + PanelEvent::Focus => todo!(), } }), ]; @@ -460,10 +471,6 @@ impl PanelButtons { } } -impl EventEmitter for PanelButtons { - type Event = (); -} - // impl Render for PanelButtons { // type Element = (); @@ -633,7 +640,7 @@ impl StatusItemView for PanelButtons { _active_pane_item: Option<&dyn crate::ItemHandle>, _cx: &mut ViewContext, ) { - // todo!(This is empty in the old `workspace::dock`) + // Nothing to do, panel buttons don't depend on the active center item } } @@ -642,16 +649,6 @@ pub mod test { use super::*; use gpui::{div, Div, ViewContext, WindowContext}; - #[derive(Debug)] - pub enum TestPanelEvent { - PositionChanged, - Activated, - Closed, - ZoomIn, - ZoomOut, - Focus, - } - pub struct TestPanel { pub position: DockPosition, pub zoomed: bool, @@ -660,9 +657,7 @@ pub mod test { pub size: f32, } - impl EventEmitter for TestPanel { - type Event = TestPanelEvent; - } + impl EventEmitter for TestPanel {} impl TestPanel { pub fn new(position: DockPosition) -> Self { @@ -699,7 +694,7 @@ pub mod test { fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext) { self.position = position; - cx.emit(TestPanelEvent::PositionChanged); + cx.emit(PanelEvent::ChangePosition); } fn size(&self, _: &WindowContext) -> f32 { @@ -718,18 +713,6 @@ pub mod test { ("Test Panel".into(), None) } - fn should_change_position_on_event(event: &Self::Event) -> bool { - matches!(event, TestPanelEvent::PositionChanged) - } - - fn should_zoom_in_on_event(event: &Self::Event) -> bool { - matches!(event, TestPanelEvent::ZoomIn) - } - - fn should_zoom_out_on_event(event: &Self::Event) -> bool { - matches!(event, TestPanelEvent::ZoomOut) - } - fn is_zoomed(&self, _: &WindowContext) -> bool { self.zoomed } @@ -742,20 +725,8 @@ pub mod test { self.active = active; } - fn should_activate_on_event(event: &Self::Event) -> bool { - matches!(event, TestPanelEvent::Activated) - } - - fn should_close_on_event(event: &Self::Event) -> bool { - matches!(event, TestPanelEvent::Closed) - } - fn has_focus(&self, _cx: &WindowContext) -> bool { self.has_focus } - - fn is_focus_event(event: &Self::Event) -> bool { - matches!(event, TestPanelEvent::Focus) - } } } diff --git a/crates/workspace2/src/item.rs b/crates/workspace2/src/item.rs index 1a7f30646d7ca3bc49520c65e284eaafbe6a92ef..2b750a98619ebd9c8acf50df868e8d3b330efcb2 100644 --- a/crates/workspace2/src/item.rs +++ b/crates/workspace2/src/item.rs @@ -91,7 +91,7 @@ pub struct BreadcrumbText { pub highlights: Option, HighlightStyle)>>, } -pub trait Item: Render + EventEmitter { +pub trait Item: Render + EventEmitter { fn focus_handle(&self) -> FocusHandle; fn deactivated(&mut self, _: &mut ViewContext) {} fn workspace_deactivated(&mut self, _: &mut ViewContext) {} @@ -106,12 +106,13 @@ pub trait Item: Render + EventEmitter { } fn tab_content(&self, detail: Option, cx: &AppContext) -> AnyElement; + /// (model id, Item) fn for_each_project_item( &self, _: &AppContext, _: &mut dyn FnMut(EntityId, &dyn project2::Item), ) { - } // (model id, Item) + } fn is_singleton(&self, _cx: &AppContext) -> bool { false } @@ -153,15 +154,6 @@ pub trait Item: Render + EventEmitter { ) -> Task> { unimplemented!("reload() must be implemented if can_save() returns true") } - fn to_item_events(_event: &Self::Event) -> SmallVec<[ItemEvent; 2]> { - SmallVec::new() - } - fn should_close_item_on_event(_: &Self::Event) -> bool { - false - } - fn should_update_tab_on_event(_: &Self::Event) -> bool { - false - } fn act_as_type<'a>( &'a self, @@ -218,7 +210,7 @@ pub trait ItemHandle: 'static + Send { fn subscribe_to_item_events( &self, cx: &mut WindowContext, - handler: Box, + handler: Box, ) -> gpui::Subscription; fn tab_tooltip_text(&self, cx: &AppContext) -> Option; fn tab_description(&self, detail: usize, cx: &AppContext) -> Option; @@ -300,12 +292,10 @@ impl ItemHandle for View { fn subscribe_to_item_events( &self, cx: &mut WindowContext, - handler: Box, + handler: Box, ) -> gpui::Subscription { cx.subscribe(self, move |_, event, cx| { - for item_event in T::to_item_events(event) { - handler(item_event, cx) - } + handler(event, cx); }) } @@ -433,7 +423,10 @@ impl ItemHandle for View { 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) { + let follow_event = item.to_follow_event(event); + if leader_id.is_some() + && matches!(follow_event, Some(FollowEvent::Unfollow)) + { workspace.unfollow(&pane, cx); } @@ -467,36 +460,34 @@ impl ItemHandle for View { } } - 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; - } + match 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 = 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) - }); - } + 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) + }); } - - _ => {} } + + _ => {} } })); @@ -660,7 +651,16 @@ pub trait ProjectItem: Item { Self: Sized; } +pub enum FollowEvent { + Unfollow, +} + +pub trait FollowableEvents { + fn to_follow_event(&self) -> Option; +} + pub trait FollowableItem: Item { + type FollowableEvent: FollowableEvents; fn remote_id(&self) -> Option; fn to_state_proto(&self, cx: &AppContext) -> Option; fn from_state_proto( @@ -672,7 +672,7 @@ pub trait FollowableItem: Item { ) -> Option>>>; fn add_event_to_update_proto( &self, - event: &Self::Event, + event: &Self::FollowableEvent, update: &mut Option, cx: &AppContext, ) -> bool; @@ -685,7 +685,6 @@ pub trait FollowableItem: Item { fn is_project_item(&self, cx: &AppContext) -> bool; fn set_leader_peer_id(&mut self, leader_peer_id: Option, cx: &mut ViewContext); - fn should_unfollow_on_event(event: &Self::Event, cx: &AppContext) -> bool; } pub trait FollowableItemHandle: ItemHandle { @@ -698,13 +697,13 @@ pub trait FollowableItemHandle: ItemHandle { update: &mut Option, cx: &AppContext, ) -> bool; + fn to_follow_event(&self, event: &dyn Any) -> Option; fn apply_update_proto( &self, project: &Model, message: proto::update_view::Variant, cx: &mut WindowContext, ) -> Task>; - fn should_unfollow_on_event(&self, event: &dyn Any, cx: &AppContext) -> bool; fn is_project_item(&self, cx: &AppContext) -> bool; } @@ -739,6 +738,13 @@ impl FollowableItemHandle for View { } } + fn to_follow_event(&self, event: &dyn Any) -> Option { + event + .downcast_ref() + .map(T::FollowableEvent::to_follow_event) + .flatten() + } + fn apply_update_proto( &self, project: &Model, @@ -748,14 +754,6 @@ impl FollowableItemHandle for View { self.update(cx, |this, cx| this.apply_update_proto(project, message, cx)) } - fn should_unfollow_on_event(&self, event: &dyn Any, cx: &AppContext) -> bool { - if let Some(event) = event.downcast_ref() { - T::should_unfollow_on_event(event, cx) - } else { - false - } - } - fn is_project_item(&self, cx: &AppContext) -> bool { self.read(cx).is_project_item(cx) } diff --git a/crates/workspace2/src/modal_layer.rs b/crates/workspace2/src/modal_layer.rs index 564db0f98291fbfcc92475996cc1ddb56ae43264..a5760380f5efa6f138f237a0eb3ae3a0e34216de 100644 --- a/crates/workspace2/src/modal_layer.rs +++ b/crates/workspace2/src/modal_layer.rs @@ -16,10 +16,6 @@ pub enum ModalEvent { Dismissed, } -pub trait Modal: EventEmitter + Render { - fn to_modal_event(&self, _: &Self::Event) -> Option; -} - impl ModalLayer { pub fn new() -> Self { Self { @@ -31,7 +27,7 @@ impl ModalLayer { pub fn register_modal(&mut self, action: A, build_view: B) where - V: Modal, + V: EventEmitter + Render, B: Fn(&mut Workspace, &mut ViewContext) -> Option> + 'static, { let build_view = Arc::new(build_view); @@ -51,12 +47,12 @@ impl ModalLayer { )); } - pub fn show_modal(&mut self, new_modal: View, cx: &mut ViewContext) { - self.subscription = Some(cx.subscribe(&new_modal, |this, modal, e, cx| { - match modal.read(cx).to_modal_event(e) { - Some(ModalEvent::Dismissed) => this.modal_layer().hide_modal(cx), - None => {} - } + pub fn show_modal(&mut self, new_modal: View, cx: &mut ViewContext) + where + V: EventEmitter + Render, + { + self.subscription = Some(cx.subscribe(&new_modal, |this, modal, e, cx| match e { + ModalEvent::Dismissed => this.modal_layer().hide_modal(cx), })); self.open_modal = Some(new_modal.into()); cx.notify(); diff --git a/crates/workspace2/src/notifications.rs b/crates/workspace2/src/notifications.rs index 5dd5b2c7ae8c24ebe4a3bc091feff61536e8101a..7277cc6fc47b33bb93ada4d37c0a2a5c68550f57 100644 --- a/crates/workspace2/src/notifications.rs +++ b/crates/workspace2/src/notifications.rs @@ -9,10 +9,12 @@ pub fn init(cx: &mut AppContext) { // simple_message_notification::init(cx); } -pub trait Notification: EventEmitter + Render { - fn should_dismiss_notification_on_event(&self, event: &Self::Event) -> bool; +pub enum NotificationEvent { + Dismiss, } +pub trait Notification: EventEmitter + Render {} + pub trait NotificationHandle: Send { fn id(&self) -> EntityId; fn to_any(&self) -> AnyView; @@ -101,11 +103,14 @@ impl Workspace { }) { let notification = build_notification(cx); - cx.subscribe(¬ification, move |this, handle, event, cx| { - if handle.read(cx).should_dismiss_notification_on_event(event) { - this.dismiss_notification_internal(type_id, id, cx); - } - }) + cx.subscribe( + ¬ification, + move |this, handle, event: &NotificationEvent, cx| match event { + NotificationEvent::Dismiss => { + this.dismiss_notification_internal(type_id, id, cx); + } + }, + ) .detach(); self.notifications .push((type_id, id, Box::new(notification))); @@ -159,7 +164,7 @@ impl Workspace { } pub mod simple_message_notification { - use super::Notification; + use super::{Notification, NotificationEvent}; use gpui::{AnyElement, AppContext, Div, EventEmitter, Render, TextStyle, ViewContext}; use serde::Deserialize; use std::{borrow::Cow, sync::Arc}; @@ -200,13 +205,7 @@ pub mod simple_message_notification { click_message: Option>, } - pub enum MessageNotificationEvent { - Dismiss, - } - - impl EventEmitter for MessageNotification { - type Event = MessageNotificationEvent; - } + impl EventEmitter for MessageNotification {} impl MessageNotification { pub fn new(message: S) -> MessageNotification @@ -359,13 +358,8 @@ pub mod simple_message_notification { // } // } - impl Notification for MessageNotification { - fn should_dismiss_notification_on_event(&self, event: &Self::Event) -> bool { - match event { - MessageNotificationEvent::Dismiss => true, - } - } - } + impl EventEmitter for MessageNotification {} + impl Notification for MessageNotification {} } pub trait NotifyResultExt { diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index 5af5514da4386a444aea737f6307b8c13f97b834..2bba684d12c67c2477299ed5915b80a65e7de2d4 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -9,8 +9,9 @@ use crate::{ use anyhow::Result; use collections::{HashMap, HashSet, VecDeque}; use gpui::{ - AppContext, AsyncWindowContext, Component, Div, EntityId, EventEmitter, FocusHandle, Model, - PromptLevel, Render, Task, View, ViewContext, VisualContext, WeakView, WindowContext, + actions, register_action, AppContext, AsyncWindowContext, Component, Div, EntityId, + EventEmitter, FocusHandle, Model, PromptLevel, Render, Task, View, ViewContext, VisualContext, + WeakView, WindowContext, }; use parking_lot::Mutex; use project2::{Project, ProjectEntryId, ProjectPath}; @@ -48,8 +49,10 @@ pub enum SaveIntent { Skip, } -// #[derive(Clone, Deserialize, PartialEq)] -// pub struct ActivateItem(pub usize); +//todo!("Do we need the default bound on actions? Decide soon") +// #[register_action] +#[derive(Clone, Deserialize, PartialEq, Debug)] +pub struct ActivateItem(pub usize); // #[derive(Clone, PartialEq)] // pub struct CloseItemById { @@ -69,40 +72,37 @@ pub enum SaveIntent { // pub pane: WeakView, // } -// #[derive(Clone, PartialEq, Debug, Deserialize, Default)] -// #[serde(rename_all = "camelCase")] -// pub struct CloseActiveItem { -// pub save_intent: Option, -// } +#[register_action] +#[derive(Clone, PartialEq, Debug, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct CloseActiveItem { + pub save_intent: Option, +} -// #[derive(Clone, PartialEq, Debug, Deserialize)] -// #[serde(rename_all = "camelCase")] -// pub struct CloseAllItems { -// pub save_intent: Option, -// } +#[register_action] +#[derive(Clone, PartialEq, Debug, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct CloseAllItems { + pub save_intent: Option, +} -// todo!() -// actions!( -// pane, -// [ -// ActivatePrevItem, -// ActivateNextItem, -// ActivateLastItem, -// CloseInactiveItems, -// CloseCleanItems, -// CloseItemsToTheLeft, -// CloseItemsToTheRight, -// GoBack, -// GoForward, -// ReopenClosedItem, -// SplitLeft, -// SplitUp, -// SplitRight, -// SplitDown, -// ] -// ); - -// impl_actions!(pane, [ActivateItem, CloseActiveItem, CloseAllItems]); +// todo!(These used to be under pane::{Action}. Are they now workspace::pane::{Action}?) +actions!( + ActivatePrevItem, + ActivateNextItem, + ActivateLastItem, + CloseInactiveItems, + CloseCleanItems, + CloseItemsToTheLeft, + CloseItemsToTheRight, + GoBack, + GoForward, + ReopenClosedItem, + SplitLeft, + SplitUp, + SplitRight, + SplitDown, +); const MAX_NAVIGATION_HISTORY_LEN: usize = 1024; @@ -310,9 +310,7 @@ pub struct NavigationEntry { // .into_any_named("nav button") // } -impl EventEmitter for Pane { - type Event = Event; -} +impl EventEmitter for Pane {} impl Pane { pub fn new( diff --git a/crates/workspace2/src/searchable.rs b/crates/workspace2/src/searchable.rs index 2b870c29441221ff3210c96c6a99390ee10a5d58..2a393a9f6de5e8c4d8295eb606b705273b8afe0d 100644 --- a/crates/workspace2/src/searchable.rs +++ b/crates/workspace2/src/searchable.rs @@ -1,6 +1,8 @@ use std::{any::Any, sync::Arc}; -use gpui::{AnyView, AppContext, Subscription, Task, View, ViewContext, WindowContext}; +use gpui::{ + AnyView, AppContext, EventEmitter, Subscription, Task, View, ViewContext, WindowContext, +}; use project2::search::SearchQuery; use crate::{ @@ -29,7 +31,7 @@ pub struct SearchOptions { pub replacement: bool, } -pub trait SearchableItem: Item { +pub trait SearchableItem: Item + EventEmitter { type Match: Any + Sync + Send + Clone; fn supported_options() -> SearchOptions { @@ -40,11 +42,7 @@ pub trait SearchableItem: Item { replacement: true, } } - fn to_search_event( - &mut self, - event: &Self::Event, - cx: &mut ViewContext, - ) -> Option; + fn clear_matches(&mut self, cx: &mut ViewContext); fn update_matches(&mut self, matches: Vec, cx: &mut ViewContext); fn query_suggestion(&mut self, cx: &mut ViewContext) -> String; @@ -95,7 +93,7 @@ pub trait SearchableItemHandle: ItemHandle { fn subscribe_to_search_events( &self, cx: &mut WindowContext, - handler: Box, + handler: Box, ) -> Subscription; fn clear_matches(&self, cx: &mut WindowContext); fn update_matches(&self, matches: &Vec>, cx: &mut WindowContext); @@ -146,14 +144,9 @@ impl SearchableItemHandle for View { fn subscribe_to_search_events( &self, cx: &mut WindowContext, - handler: Box, + handler: Box, ) -> Subscription { - cx.subscribe(self, move |handle, event, cx| { - let search_event = handle.update(cx, |handle, cx| handle.to_search_event(event, cx)); - if let Some(search_event) = search_event { - handler(search_event, cx) - } - }) + cx.subscribe(self, move |_, event: &SearchEvent, cx| handler(event, cx)) } fn clear_matches(&self, cx: &mut WindowContext) { diff --git a/crates/workspace2/src/toolbar.rs b/crates/workspace2/src/toolbar.rs index 25054571da9c15fd059aa0dfeae0313ef5deb524..1d67da06b223155d076c39e53492ce370391aa06 100644 --- a/crates/workspace2/src/toolbar.rs +++ b/crates/workspace2/src/toolbar.rs @@ -1,25 +1,19 @@ use crate::ItemHandle; use gpui::{ - AnyView, AppContext, Div, Entity, EntityId, EventEmitter, Render, View, ViewContext, - WindowContext, + AnyView, Div, Entity, EntityId, EventEmitter, Render, View, ViewContext, WindowContext, }; -pub trait ToolbarItemView: Render + EventEmitter { +pub enum ToolbarItemEvent { + ChangeLocation(ToolbarItemLocation), +} + +pub trait ToolbarItemView: Render + EventEmitter { fn set_active_pane_item( &mut self, active_pane_item: Option<&dyn crate::ItemHandle>, cx: &mut ViewContext, ) -> ToolbarItemLocation; - fn location_for_event( - &self, - _event: &Self::Event, - current_location: ToolbarItemLocation, - _cx: &AppContext, - ) -> ToolbarItemLocation { - current_location - } - fn pane_focus_update(&mut self, _pane_focused: bool, _cx: &mut ViewContext) {} /// Number of times toolbar's height will be repeated to get the effective height. @@ -141,61 +135,6 @@ impl Render for Toolbar { // } // } -// <<<<<<< HEAD -// ======= -// #[allow(clippy::too_many_arguments)] -// fn nav_button)>( -// svg_path: &'static str, -// style: theme::Interactive, -// nav_button_height: f32, -// tooltip_style: TooltipStyle, -// enabled: bool, -// spacing: f32, -// on_click: F, -// tooltip_action: A, -// action_name: &'static str, -// cx: &mut ViewContext, -// ) -> AnyElement { -// MouseEventHandler::new::(0, cx, |state, _| { -// let style = if enabled { -// style.style_for(state) -// } else { -// style.disabled_style() -// }; -// Svg::new(svg_path) -// .with_color(style.color) -// .constrained() -// .with_width(style.icon_width) -// .aligned() -// .contained() -// .with_style(style.container) -// .constrained() -// .with_width(style.button_width) -// .with_height(nav_button_height) -// .aligned() -// .top() -// }) -// .with_cursor_style(if enabled { -// CursorStyle::PointingHand -// } else { -// CursorStyle::default() -// }) -// .on_click(MouseButton::Left, move |_, toolbar, cx| { -// on_click(toolbar, cx) -// }) -// .with_tooltip::( -// 0, -// action_name, -// Some(Box::new(tooltip_action)), -// tooltip_style, -// cx, -// ) -// .contained() -// .with_margin_right(spacing) -// .into_any_named("nav button") -// } - -// >>>>>>> 139cbbfd3aebd0863a7d51b0c12d748764cf0b2e impl Toolbar { pub fn new() -> Self { Self { @@ -220,12 +159,13 @@ impl Toolbar { if let Some((_, current_location)) = this.items.iter_mut().find(|(i, _)| i.id() == item.id()) { - let new_location = item - .read(cx) - .location_for_event(event, *current_location, cx); - if new_location != *current_location { - *current_location = new_location; - cx.notify(); + match event { + ToolbarItemEvent::ChangeLocation(new_location) => { + if new_location != current_location { + *current_location = *new_location; + cx.notify(); + } + } } } }) diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index 99e93b1375a654f109981193b5787816dad34258..24ec810ac5be090cb4522d8f2d699c89b3928d1b 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -36,7 +36,7 @@ use futures::{ Future, FutureExt, StreamExt, }; use gpui::{ - div, point, rems, size, AnyModel, AnyView, AnyWeakView, AppContext, AsyncAppContext, + actions, div, point, rems, size, AnyModel, AnyView, AnyWeakView, AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Component, Div, Entity, EntityId, EventEmitter, FocusHandle, GlobalPixels, Model, ModelContext, ParentElement, Point, Render, Size, StatefulInteractive, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds, @@ -87,35 +87,32 @@ lazy_static! { // #[derive(Clone, PartialEq)] // pub struct RemoveWorktreeFromProject(pub WorktreeId); -// actions!( -// workspace, -// [ -// Open, -// NewFile, -// NewWindow, -// CloseWindow, -// CloseInactiveTabsAndPanes, -// AddFolderToProject, -// Unfollow, -// SaveAs, -// ReloadActiveItem, -// ActivatePreviousPane, -// ActivateNextPane, -// FollowNextCollaborator, -// NewTerminal, -// NewCenterTerminal, -// ToggleTerminalFocus, -// NewSearch, -// Feedback, -// Restart, -// Welcome, -// ToggleZoom, -// ToggleLeftDock, -// ToggleRightDock, -// ToggleBottomDock, -// CloseAllDocks, -// ] -// ); +actions!( + Open, + NewFile, + NewWindow, + CloseWindow, + CloseInactiveTabsAndPanes, + AddFolderToProject, + Unfollow, + SaveAs, + ReloadActiveItem, + ActivatePreviousPane, + ActivateNextPane, + FollowNextCollaborator, + NewTerminal, + NewCenterTerminal, + ToggleTerminalFocus, + NewSearch, + Feedback, + Restart, + Welcome, + ToggleZoom, + ToggleLeftDock, + ToggleRightDock, + ToggleBottomDock, + CloseAllDocks, +); // #[derive(Clone, PartialEq)] // pub struct OpenPaths { @@ -967,6 +964,9 @@ impl Workspace { // let mut prev_position = panel.position(cx); // move |this, panel, event, cx| { // if T::should_change_position_on_event(event) { + // THIS HAS BEEN MOVED TO NORMAL EVENT EMISSION + // See: Dock::add_panel + // // let new_position = panel.read(cx).position(cx); // let mut was_visible = false; // dock.update(cx, |dock, cx| { @@ -997,6 +997,9 @@ impl Workspace { // } // }); // } else if T::should_zoom_in_on_event(event) { + // THIS HAS BEEN MOVED TO NORMAL EVENT EMISSION + // See: Dock::add_panel + // // dock.update(cx, |dock, cx| dock.set_panel_zoomed(&panel, true, cx)); // if !panel.has_focus(cx) { // cx.focus(&panel); @@ -1004,6 +1007,9 @@ impl Workspace { // this.zoomed = Some(panel.downgrade().into_any()); // this.zoomed_position = Some(panel.read(cx).position(cx)); // } else if T::should_zoom_out_on_event(event) { + // THIS HAS BEEN MOVED TO NORMAL EVENT EMISSION + // See: Dock::add_panel + // // dock.update(cx, |dock, cx| dock.set_panel_zoomed(&panel, false, cx)); // if this.zoomed_position == Some(prev_position) { // this.zoomed = None; @@ -1011,6 +1017,9 @@ impl Workspace { // } // cx.notify(); // } else if T::is_focus_event(event) { + // THIS HAS BEEN MOVED TO NORMAL EVENT EMISSION + // See: Dock::add_panel + // // let position = panel.read(cx).position(cx); // this.dismiss_zoomed_items_to_reveal(Some(position), cx); // if panel.is_zoomed(cx) { @@ -3694,9 +3703,7 @@ fn notify_if_database_failed(workspace: WindowHandle, cx: &mut AsyncA .log_err(); } -impl EventEmitter for Workspace { - type Event = Event; -} +impl EventEmitter for Workspace {} impl Render for Workspace { type Element = Div; @@ -4138,10 +4145,6 @@ impl WorkspaceStore { } } -impl EventEmitter for WorkspaceStore { - type Event = (); -} - impl ViewId { pub(crate) fn from_proto(message: proto::ViewId) -> Result { Ok(Self {