diff --git a/crates/call2/src/call2.rs b/crates/call2/src/call2.rs index d8678b7ed4..fd09dc3180 100644 --- a/crates/call2/src/call2.rs +++ b/crates/call2/src/call2.rs @@ -67,8 +67,8 @@ impl ActiveCall { incoming_call: watch::channel(), _subscriptions: vec![ - client.add_request_handler(cx.weak_handle(), Self::handle_incoming_call), - client.add_message_handler(cx.weak_handle(), Self::handle_call_canceled), + client.add_request_handler(cx.weak_model(), Self::handle_incoming_call), + client.add_message_handler(cx.weak_model(), Self::handle_call_canceled), ], client, user_store, diff --git a/crates/client2/src/user.rs b/crates/client2/src/user.rs index a8be4b6401..2a8cf34af4 100644 --- a/crates/client2/src/user.rs +++ b/crates/client2/src/user.rs @@ -122,9 +122,9 @@ impl UserStore { let (mut current_user_tx, current_user_rx) = watch::channel(); let (update_contacts_tx, mut update_contacts_rx) = mpsc::unbounded(); let rpc_subscriptions = vec![ - client.add_message_handler(cx.weak_handle(), Self::handle_update_contacts), - client.add_message_handler(cx.weak_handle(), Self::handle_update_invite_info), - client.add_message_handler(cx.weak_handle(), Self::handle_show_contacts), + client.add_message_handler(cx.weak_model(), Self::handle_update_contacts), + client.add_message_handler(cx.weak_model(), Self::handle_update_invite_info), + client.add_message_handler(cx.weak_model(), Self::handle_show_contacts), ]; Self { users: Default::default(), diff --git a/crates/copilot2/src/copilot2.rs b/crates/copilot2/src/copilot2.rs index c3107a2f47..083c491656 100644 --- a/crates/copilot2/src/copilot2.rs +++ b/crates/copilot2/src/copilot2.rs @@ -7,8 +7,8 @@ use async_tar::Archive; use collections::{HashMap, HashSet}; use futures::{channel::oneshot, future::Shared, Future, FutureExt, TryFutureExt}; use gpui2::{ - AppContext, AsyncAppContext, Context, EntityId, EventEmitter, Model, ModelContext, Task, - WeakModel, + AppContext, AsyncAppContext, Context, Entity, EntityId, EventEmitter, Model, ModelContext, + Task, WeakModel, }; use language2::{ language_settings::{all_language_settings, language_settings}, diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 1d2c17d357..8e7a652b4b 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -726,7 +726,7 @@ impl Context for AppContext { /// Update the entity referenced by the given model. The function is passed a mutable reference to the /// entity along with a `ModelContext` for the entity. - fn update_entity( + fn update_model( &mut self, model: &Model, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, diff --git a/crates/gpui2/src/app/async_context.rs b/crates/gpui2/src/app/async_context.rs index 71417f2a5e..042a75848e 100644 --- a/crates/gpui2/src/app/async_context.rs +++ b/crates/gpui2/src/app/async_context.rs @@ -32,7 +32,7 @@ impl Context for AsyncAppContext { Ok(lock.build_model(build_model)) } - fn update_entity( + fn update_model( &mut self, handle: &Model, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, @@ -42,7 +42,7 @@ impl Context for AsyncAppContext { .upgrade() .ok_or_else(|| anyhow!("app was released"))?; let mut lock = app.lock(); // Need this to compile - Ok(lock.update_entity(handle, update)) + Ok(lock.update_model(handle, update)) } } @@ -230,13 +230,13 @@ impl Context for AsyncWindowContext { .update_window(self.window, |cx| cx.build_model(build_model)) } - fn update_entity( + fn update_model( &mut self, handle: &Model, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, ) -> Result { self.app - .update_window(self.window, |cx| cx.update_entity(handle, update)) + .update_window(self.window, |cx| cx.update_model(handle, update)) } } diff --git a/crates/gpui2/src/app/entity_map.rs b/crates/gpui2/src/app/entity_map.rs index 7e0c5626a5..7b1bc0d000 100644 --- a/crates/gpui2/src/app/entity_map.rs +++ b/crates/gpui2/src/app/entity_map.rs @@ -1,4 +1,4 @@ -use crate::{AnyBox, AppContext, Context}; +use crate::{private::Sealed, AnyBox, AppContext, Context, Entity}; use anyhow::{anyhow, Result}; use derive_more::{Deref, DerefMut}; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; @@ -253,6 +253,32 @@ pub struct Model { unsafe impl Send for Model {} unsafe impl Sync for Model {} +impl Sealed for Model {} + +impl Entity for Model { + type Weak = WeakModel; + + fn entity_id(&self) -> EntityId { + self.any_model.entity_id + } + + fn downgrade(&self) -> Self::Weak { + WeakModel { + any_model: self.any_model.downgrade(), + entity_type: self.entity_type, + } + } + + fn upgrade_from(weak: &Self::Weak) -> Option + where + Self: Sized, + { + Some(Model { + any_model: weak.any_model.upgrade()?, + entity_type: weak.entity_type, + }) + } +} impl Model { fn new(id: EntityId, entity_map: Weak>) -> Self @@ -265,11 +291,12 @@ impl Model { } } + /// Downgrade the this to a weak model reference pub fn downgrade(&self) -> WeakModel { - WeakModel { - any_model: self.any_model.downgrade(), - entity_type: self.entity_type, - } + // Delegate to the trait implementation to keep behavior in one place. + // This method was included to improve method resolution in the presence of + // the Model's deref + Entity::downgrade(self) } /// Convert this into a dynamically typed model. @@ -294,7 +321,7 @@ impl Model { where C: Context, { - cx.update_entity(self, update) + cx.update_model(self, update) } } @@ -334,7 +361,7 @@ impl Eq for Model {} impl PartialEq> for Model { fn eq(&self, other: &WeakModel) -> bool { - self.entity_id() == other.entity_id() + self.any_model.entity_id() == other.entity_id() } } @@ -415,11 +442,10 @@ impl Clone for WeakModel { } impl WeakModel { + /// Upgrade this weak model reference into a strong model reference pub fn upgrade(&self) -> Option> { - Some(Model { - any_model: self.any_model.upgrade()?, - entity_type: self.entity_type, - }) + // Delegate to the trait implementation to keep behavior in one place. + Model::upgrade_from(self) } /// Update the entity referenced by this model with the given function if @@ -441,7 +467,7 @@ impl WeakModel { crate::Flatten::flatten( self.upgrade() .ok_or_else(|| anyhow!("entity release")) - .map(|this| cx.update_entity(&this, update)), + .map(|this| cx.update_model(&this, update)), ) } } @@ -462,6 +488,6 @@ impl Eq for WeakModel {} impl PartialEq> for WeakModel { fn eq(&self, other: &Model) -> bool { - self.entity_id() == other.entity_id() + self.entity_id() == other.any_model.entity_id() } } diff --git a/crates/gpui2/src/app/model_context.rs b/crates/gpui2/src/app/model_context.rs index 463652886b..8a4576c052 100644 --- a/crates/gpui2/src/app/model_context.rs +++ b/crates/gpui2/src/app/model_context.rs @@ -1,6 +1,6 @@ use crate::{ - AppContext, AsyncAppContext, Context, Effect, EntityId, EventEmitter, MainThread, Model, - Reference, Subscription, Task, WeakModel, + AppContext, AsyncAppContext, Context, Effect, Entity, EntityId, EventEmitter, MainThread, + Model, Reference, Subscription, Task, WeakModel, }; use derive_more::{Deref, DerefMut}; use futures::FutureExt; @@ -31,29 +31,32 @@ impl<'a, T: 'static> ModelContext<'a, T> { } pub fn handle(&self) -> Model { - self.weak_handle() + self.weak_model() .upgrade() .expect("The entity must be alive if we have a model context") } - pub fn weak_handle(&self) -> WeakModel { + pub fn weak_model(&self) -> WeakModel { self.model_state.clone() } - pub fn observe( + pub fn observe( &mut self, - handle: &Model, - mut on_notify: impl FnMut(&mut T, Model, &mut ModelContext<'_, T>) + Send + 'static, + entity: &E, + mut on_notify: impl FnMut(&mut T, E, &mut ModelContext<'_, T>) + Send + 'static, ) -> Subscription where T: 'static + Send, + T2: 'static, + E: Entity, { - let this = self.weak_handle(); - let handle = handle.downgrade(); + let this = self.weak_model(); + let entity_id = entity.entity_id(); + let handle = entity.downgrade(); self.app.observers.insert( - handle.entity_id, + entity_id, Box::new(move |cx| { - if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) { + if let Some((this, handle)) = this.upgrade().zip(E::upgrade_from(&handle)) { this.update(cx, |this, cx| on_notify(this, handle, cx)); true } else { @@ -63,21 +66,24 @@ impl<'a, T: 'static> ModelContext<'a, T> { ) } - pub fn subscribe( + pub fn subscribe( &mut self, - handle: &Model, - mut on_event: impl FnMut(&mut T, Model, &E::Event, &mut ModelContext<'_, T>) + Send + 'static, + entity: &E, + mut on_event: impl FnMut(&mut T, E, &T2::Event, &mut ModelContext<'_, T>) + Send + 'static, ) -> Subscription where T: 'static + Send, + T2: 'static + EventEmitter, + E: Entity, { - let this = self.weak_handle(); - let handle = handle.downgrade(); + let this = self.weak_model(); + let entity_id = entity.entity_id(); + let entity = entity.downgrade(); self.app.event_listeners.insert( - handle.entity_id, + entity_id, Box::new(move |event, cx| { - let event: &E::Event = event.downcast_ref().expect("invalid event type"); - if let Some((this, handle)) = this.upgrade().zip(handle.upgrade()) { + let event: &T2::Event = event.downcast_ref().expect("invalid event type"); + if let Some((this, handle)) = this.upgrade().zip(E::upgrade_from(&entity)) { this.update(cx, |this, cx| on_event(this, handle, event, cx)); true } else { @@ -103,17 +109,20 @@ impl<'a, T: 'static> ModelContext<'a, T> { ) } - pub fn observe_release( + pub fn observe_release( &mut self, - handle: &Model, - mut on_release: impl FnMut(&mut T, &mut E, &mut ModelContext<'_, T>) + Send + 'static, + entity: &E, + mut on_release: impl FnMut(&mut T, &mut T2, &mut ModelContext<'_, T>) + Send + 'static, ) -> Subscription where T: Any + Send, + T2: 'static, + E: Entity, { - let this = self.weak_handle(); + let entity_id = entity.entity_id(); + let this = self.weak_model(); self.app.release_listeners.insert( - handle.entity_id, + entity_id, Box::new(move |entity, cx| { let entity = entity.downcast_mut().expect("invalid entity type"); if let Some(this) = this.upgrade() { @@ -130,7 +139,7 @@ impl<'a, T: 'static> ModelContext<'a, T> { where T: 'static + Send, { - let handle = self.weak_handle(); + let handle = self.weak_model(); self.global_observers.insert( TypeId::of::(), Box::new(move |cx| handle.update(cx, |view, cx| f(view, cx)).is_ok()), @@ -145,7 +154,7 @@ impl<'a, T: 'static> ModelContext<'a, T> { Fut: 'static + Future + Send, T: 'static + Send, { - let handle = self.weak_handle(); + let handle = self.weak_model(); self.app.quit_observers.insert( (), Box::new(move |cx| { @@ -191,7 +200,7 @@ impl<'a, T: 'static> ModelContext<'a, T> { Fut: Future + Send + 'static, R: Send + 'static, { - let this = self.weak_handle(); + let this = self.weak_model(); self.app.spawn(|cx| f(this, cx)) } @@ -203,7 +212,7 @@ impl<'a, T: 'static> ModelContext<'a, T> { Fut: Future + 'static, R: Send + 'static, { - let this = self.weak_handle(); + let this = self.weak_model(); self.app.spawn_on_main(|cx| f(this, cx)) } } @@ -235,12 +244,12 @@ impl<'a, T> Context for ModelContext<'a, T> { self.app.build_model(build_model) } - fn update_entity( + fn update_model( &mut self, handle: &Model, update: impl FnOnce(&mut U, &mut Self::ModelContext<'_, U>) -> R, ) -> R { - self.app.update_entity(handle, update) + self.app.update_model(handle, update) } } diff --git a/crates/gpui2/src/app/test_context.rs b/crates/gpui2/src/app/test_context.rs index dc5896fe06..2b09a95a34 100644 --- a/crates/gpui2/src/app/test_context.rs +++ b/crates/gpui2/src/app/test_context.rs @@ -26,13 +26,13 @@ impl Context for TestAppContext { lock.build_model(build_model) } - fn update_entity( + fn update_model( &mut self, handle: &Model, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, ) -> Self::Result { let mut lock = self.app.lock(); - lock.update_entity(handle, update) + lock.update_model(handle, update) } } diff --git a/crates/gpui2/src/gpui2.rs b/crates/gpui2/src/gpui2.rs index 85300c1a4a..8625866a44 100644 --- a/crates/gpui2/src/gpui2.rs +++ b/crates/gpui2/src/gpui2.rs @@ -24,6 +24,12 @@ mod util; mod view; mod window; +mod private { + /// A mechanism for restricting implementations of a trait to only those in GPUI. + /// See: https://predr.ag/blog/definitive-guide-to-sealed-traits-in-rust/ + pub trait Sealed {} +} + pub use action::*; pub use anyhow::Result; pub use app::*; @@ -39,6 +45,7 @@ pub use image_cache::*; pub use interactive::*; pub use keymap::*; pub use platform::*; +use private::Sealed; pub use refineable::*; pub use scene::*; pub use serde; @@ -80,7 +87,7 @@ pub trait Context { where T: 'static + Send; - fn update_entity( + fn update_model( &mut self, handle: &Model, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, @@ -104,6 +111,16 @@ pub trait VisualContext: Context { ) -> Self::Result; } +pub trait Entity: Sealed { + type Weak: 'static + Send; + + fn entity_id(&self) -> EntityId; + fn downgrade(&self) -> Self::Weak; + fn upgrade_from(weak: &Self::Weak) -> Option + where + Self: Sized; +} + pub enum GlobalKey { Numeric(usize), View(EntityId), @@ -149,12 +166,12 @@ impl Context for MainThread { }) } - fn update_entity( + fn update_model( &mut self, handle: &Model, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, ) -> Self::Result { - self.0.update_entity(handle, |entity, cx| { + self.0.update_model(handle, |entity, cx| { let cx = unsafe { mem::transmute::< &mut C::ModelContext<'_, T>, diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index eef5819361..08e64261e1 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -1,7 +1,7 @@ use crate::{ - AnyBox, AnyElement, AnyModel, AppContext, AvailableSpace, BorrowWindow, Bounds, Component, - Element, ElementId, EntityId, LayoutId, Model, Pixels, Size, ViewContext, VisualContext, - WeakModel, WindowContext, + private::Sealed, AnyBox, AnyElement, AnyModel, AppContext, AvailableSpace, BorrowWindow, + Bounds, Component, Element, ElementId, Entity, EntityId, LayoutId, Model, Pixels, Size, + ViewContext, VisualContext, WeakModel, WindowContext, }; use anyhow::{Context, Result}; use std::{any::TypeId, marker::PhantomData, sync::Arc}; @@ -16,19 +16,42 @@ pub struct View { pub(crate) model: Model, } +impl Sealed for View {} + impl View { pub fn into_any(self) -> AnyView { AnyView(Arc::new(self)) } } -impl View { - pub fn downgrade(&self) -> WeakView { +impl Entity for View { + type Weak = WeakView; + + fn entity_id(&self) -> EntityId { + self.model.entity_id + } + + fn downgrade(&self) -> Self::Weak { WeakView { model: self.model.downgrade(), } } + fn upgrade_from(weak: &Self::Weak) -> Option + where + Self: Sized, + { + let model = weak.model.upgrade()?; + Some(View { model }) + } +} + +impl View { + /// Convert this strong view reference into a weak view reference. + pub fn downgrade(&self) -> WeakView { + Entity::downgrade(self) + } + pub fn update( &self, cx: &mut C, @@ -111,8 +134,7 @@ pub struct WeakView { impl WeakView { pub fn upgrade(&self) -> Option> { - let model = self.model.upgrade()?; - Some(View { model }) + Entity::upgrade_from(self) } pub fn update( @@ -200,7 +222,7 @@ where } fn entity_id(&self) -> EntityId { - self.model.entity_id + Entity::entity_id(self) } fn model(&self) -> AnyModel { @@ -208,7 +230,7 @@ where } fn initialize(&self, cx: &mut WindowContext) -> AnyBox { - cx.with_element_id(self.entity_id(), |_global_id, cx| { + cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| { self.update(cx, |state, cx| { let mut any_element = Box::new(AnyElement::new(state.render(cx))); any_element.initialize(state, cx); @@ -218,7 +240,7 @@ where } fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId { - cx.with_element_id(self.entity_id(), |_global_id, cx| { + cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| { self.update(cx, |state, cx| { let element = element.downcast_mut::>().unwrap(); element.layout(state, cx) @@ -227,7 +249,7 @@ where } fn paint(&self, _: Bounds, element: &mut AnyBox, cx: &mut WindowContext) { - cx.with_element_id(self.entity_id(), |_global_id, cx| { + cx.with_element_id(ViewObject::entity_id(self), |_global_id, cx| { self.update(cx, |state, cx| { let element = element.downcast_mut::>().unwrap(); element.paint(state, cx); diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index d5e18e1439..7898ac34fc 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -1,8 +1,8 @@ use crate::{ px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect, - EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, GlobalElementId, GlyphId, Hsla, - ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, LayoutId, + Entity, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, GlobalElementId, GlyphId, + Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, LayoutId, MainThread, MainThreadOnly, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams, @@ -1253,7 +1253,7 @@ impl Context for WindowContext<'_, '_> { self.entities.insert(slot, model) } - fn update_entity( + fn update_model( &mut self, model: &Model, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, @@ -1568,23 +1568,25 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { self.window_cx.on_next_frame(move |cx| view.update(cx, f)); } - pub fn observe( + pub fn observe( &mut self, - handle: &Model, - mut on_notify: impl FnMut(&mut V, Model, &mut ViewContext<'_, '_, V>) + Send + 'static, + entity: &E, + mut on_notify: impl FnMut(&mut V, E, &mut ViewContext<'_, '_, V>) + Send + 'static, ) -> Subscription where - E: 'static, + V2: 'static, V: Any + Send, + E: Entity, { let view = self.view(); - let handle = handle.downgrade(); + let entity_id = entity.entity_id(); + let entity = entity.downgrade(); let window_handle = self.window.handle; self.app.observers.insert( - handle.entity_id, + entity_id, Box::new(move |cx| { cx.update_window(window_handle.id, |cx| { - if let Some(handle) = handle.upgrade() { + if let Some(handle) = E::upgrade_from(&entity) { view.update(cx, |this, cx| on_notify(this, handle, cx)) .is_ok() } else { @@ -1596,21 +1598,24 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { ) } - pub fn subscribe( + pub fn subscribe( &mut self, - handle: &Model, - mut on_event: impl FnMut(&mut V, Model, &E::Event, &mut ViewContext<'_, '_, V>) - + Send - + 'static, - ) -> Subscription { + entity: &E, + mut on_event: impl FnMut(&mut V, E, &V2::Event, &mut ViewContext<'_, '_, V>) + Send + 'static, + ) -> Subscription + where + V2: EventEmitter, + E: Entity, + { let view = self.view(); - let handle = handle.downgrade(); + let entity_id = entity.entity_id(); + let handle = entity.downgrade(); let window_handle = self.window.handle; self.app.event_listeners.insert( - handle.entity_id, + entity_id, Box::new(move |event, cx| { cx.update_window(window_handle.id, |cx| { - if let Some(handle) = handle.upgrade() { + 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() @@ -1638,18 +1643,21 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { ) } - pub fn observe_release( + pub fn observe_release( &mut self, - handle: &Model, - mut on_release: impl FnMut(&mut V, &mut T, &mut ViewContext<'_, '_, V>) + Send + 'static, + entity: &E, + mut on_release: impl FnMut(&mut V, &mut V2, &mut ViewContext<'_, '_, V>) + Send + 'static, ) -> Subscription where V: Any + Send, + V2: 'static, + E: Entity, { let view = self.view(); + let entity_id = entity.entity_id(); let window_handle = self.window.handle; self.app.release_listeners.insert( - handle.entity_id, + entity_id, Box::new(move |entity, cx| { let entity = entity.downcast_mut().expect("invalid entity type"); let _ = cx.update_window(window_handle.id, |cx| { @@ -1864,12 +1872,12 @@ impl<'a, 'w, V> Context for ViewContext<'a, 'w, V> { self.window_cx.build_model(build_model) } - fn update_entity( + fn update_model( &mut self, model: &Model, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, ) -> R { - self.window_cx.update_entity(model, update) + self.window_cx.update_model(model, update) } } diff --git a/crates/project2/src/project2.rs b/crates/project2/src/project2.rs index c2ee171866..3f3c5f1308 100644 --- a/crates/project2/src/project2.rs +++ b/crates/project2/src/project2.rs @@ -26,8 +26,8 @@ use futures::{ }; use globset::{Glob, GlobSet, GlobSetBuilder}; use gpui2::{ - AnyModel, AppContext, AsyncAppContext, Context, EventEmitter, Executor, Model, ModelContext, - Task, WeakModel, + AnyModel, AppContext, AsyncAppContext, Context, Entity, EventEmitter, Executor, Model, + ModelContext, Task, WeakModel, }; use itertools::Itertools; use language2::{ @@ -2491,7 +2491,7 @@ impl Project { delay } else { if first_insertion { - let this = cx.weak_handle(); + let this = cx.weak_model(); cx.defer(move |cx| { if let Some(this) = this.upgrade() { this.update(cx, |this, cx| { @@ -8650,7 +8650,7 @@ fn subscribe_for_copilot_events( // Another event wants to re-add the server that was already added and subscribed to, avoid doing it again. if !copilot_server.has_notification_handler::() { let new_server_id = copilot_server.server_id(); - let weak_project = cx.weak_handle(); + let weak_project = cx.weak_model(); let copilot_log_subscription = copilot_server .on_notification::( move |params, mut cx| { diff --git a/crates/project2/src/terminals.rs b/crates/project2/src/terminals.rs index 5cd62d5ae6..ce89914dc6 100644 --- a/crates/project2/src/terminals.rs +++ b/crates/project2/src/terminals.rs @@ -1,5 +1,5 @@ use crate::Project; -use gpui2::{AnyWindowHandle, Context, Model, ModelContext, WeakModel}; +use gpui2::{AnyWindowHandle, Context, Entity, Model, ModelContext, WeakModel}; use settings2::Settings; use std::path::{Path, PathBuf}; use terminal2::{