diff --git a/crates/gpui3/src/app.rs b/crates/gpui3/src/app.rs index dbe53603cd..ad8e861b69 100644 --- a/crates/gpui3/src/app.rs +++ b/crates/gpui3/src/app.rs @@ -1,6 +1,10 @@ +mod model_context; + +pub use model_context::*; + use crate::{ - current_platform, AnyWindowHandle, Context, LayoutId, MainThreadOnly, Platform, Reference, - RootView, TextSystem, Window, WindowContext, WindowHandle, WindowId, + current_platform, AnyWindowHandle, Context, LayoutId, MainThreadOnly, Platform, RootView, + TextSystem, Window, WindowContext, WindowHandle, WindowId, }; use anyhow::{anyhow, Result}; use collections::{HashMap, VecDeque}; @@ -274,94 +278,6 @@ impl AsyncContext { } } -pub struct ModelContext<'a, T> { - app: Reference<'a, AppContext>, - entity_type: PhantomData, - entity_id: EntityId, -} - -impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> { - pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self { - Self { - app: Reference::Mutable(app), - entity_type: PhantomData, - entity_id, - } - } - - // todo! - // fn update(&mut self, update: impl FnOnce(&mut T, &mut Self) -> R) -> R { - // let mut entity = self - // .app - // .entities - // .get_mut(self.entity_id) - // .unwrap() - // .take() - // .unwrap(); - // let result = update(entity.downcast_mut::().unwrap(), self); - // self.app - // .entities - // .get_mut(self.entity_id) - // .unwrap() - // .replace(entity); - // result - // } - - pub fn handle(&self) -> WeakHandle { - WeakHandle { - id: self.entity_id, - entity_type: PhantomData, - } - } - - pub fn observe( - &mut self, - handle: &Handle, - on_notify: impl Fn(&mut T, Handle, &mut ModelContext<'_, T>) + Send + Sync + 'static, - ) { - let this = self.handle(); - let handle = handle.downgrade(); - self.app - .observers - .entry(handle.id) - .or_default() - .push(Arc::new(move |cx| { - if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) { - this.update(cx, |this, cx| on_notify(this, handle, cx)); - true - } else { - false - } - })); - } - - pub fn notify(&mut self) { - self.app - .pending_effects - .push_back(Effect::Notify(self.entity_id)); - } -} - -impl<'a, T: 'static> Context for ModelContext<'a, T> { - type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>; - type Result = U; - - fn entity( - &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U, - ) -> Handle { - self.app.entity(build_entity) - } - - fn update_entity( - &mut self, - handle: &Handle, - update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R, - ) -> R { - self.app.update_entity(handle, update) - } -} - slotmap::new_key_type! { pub struct EntityId; } pub struct Handle { diff --git a/crates/gpui3/src/app/model_context.rs b/crates/gpui3/src/app/model_context.rs new file mode 100644 index 0000000000..6ad5a06a56 --- /dev/null +++ b/crates/gpui3/src/app/model_context.rs @@ -0,0 +1,90 @@ +use crate::{AppContext, Context, Effect, EntityId, Handle, Reference, WeakHandle}; +use std::{marker::PhantomData, sync::Arc}; + +pub struct ModelContext<'a, T> { + app: Reference<'a, AppContext>, + entity_type: PhantomData, + entity_id: EntityId, +} + +impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> { + pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self { + Self { + app: Reference::Mutable(app), + entity_type: PhantomData, + entity_id, + } + } + + // todo! + // fn update(&mut self, update: impl FnOnce(&mut T, &mut Self) -> R) -> R { + // let mut entity = self + // .app + // .entities + // .get_mut(self.entity_id) + // .unwrap() + // .take() + // .unwrap(); + // let result = update(entity.downcast_mut::().unwrap(), self); + // self.app + // .entities + // .get_mut(self.entity_id) + // .unwrap() + // .replace(entity); + // result + // } + + pub fn handle(&self) -> WeakHandle { + WeakHandle { + id: self.entity_id, + entity_type: PhantomData, + } + } + + pub fn observe( + &mut self, + handle: &Handle, + on_notify: impl Fn(&mut T, Handle, &mut ModelContext<'_, T>) + Send + Sync + 'static, + ) { + let this = self.handle(); + let handle = handle.downgrade(); + self.app + .observers + .entry(handle.id) + .or_default() + .push(Arc::new(move |cx| { + if let Some((this, handle)) = this.upgrade(cx).zip(handle.upgrade(cx)) { + this.update(cx, |this, cx| on_notify(this, handle, cx)); + true + } else { + false + } + })); + } + + pub fn notify(&mut self) { + self.app + .pending_effects + .push_back(Effect::Notify(self.entity_id)); + } +} + +impl<'a, T: 'static> Context for ModelContext<'a, T> { + type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>; + type Result = U; + + fn entity( + &mut self, + build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U, + ) -> Handle { + self.app.entity(build_entity) + } + + fn update_entity( + &mut self, + handle: &Handle, + update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R, + ) -> R { + self.app.update_entity(handle, update) + } +} diff --git a/crates/gpui3/src/platform/test.rs b/crates/gpui3/src/platform/test.rs index 8c418eb9c1..3b709f503f 100644 --- a/crates/gpui3/src/platform/test.rs +++ b/crates/gpui3/src/platform/test.rs @@ -9,53 +9,54 @@ impl TestPlatform { } } +// todo!("implement out what our tests needed in GPUI 1") impl Platform for TestPlatform { fn dispatcher(&self) -> std::sync::Arc { - todo!() + unimplemented!() } fn text_system(&self) -> std::sync::Arc { - todo!() + unimplemented!() } fn run(&self, _on_finish_launching: Box) { - todo!() + unimplemented!() } fn quit(&self) { - todo!() + unimplemented!() } fn restart(&self) { - todo!() + unimplemented!() } fn activate(&self, _ignoring_other_apps: bool) { - todo!() + unimplemented!() } fn hide(&self) { - todo!() + unimplemented!() } fn hide_other_apps(&self) { - todo!() + unimplemented!() } fn unhide_other_apps(&self) { - todo!() + unimplemented!() } fn screens(&self) -> Vec> { - todo!() + unimplemented!() } fn screen_by_id(&self, _id: ScreenId) -> Option> { - todo!() + unimplemented!() } fn main_window(&self) -> Option { - todo!() + unimplemented!() } fn open_window( @@ -63,93 +64,93 @@ impl Platform for TestPlatform { _handle: crate::AnyWindowHandle, _options: crate::WindowOptions, ) -> Box { - todo!() + unimplemented!() } fn open_url(&self, _url: &str) { - todo!() + unimplemented!() } fn on_open_urls(&self, _callback: Box)>) { - todo!() + unimplemented!() } fn prompt_for_paths( &self, _options: crate::PathPromptOptions, ) -> futures::channel::oneshot::Receiver>> { - todo!() + unimplemented!() } fn prompt_for_new_path( &self, _directory: &std::path::Path, ) -> futures::channel::oneshot::Receiver> { - todo!() + unimplemented!() } fn reveal_path(&self, _path: &std::path::Path) { - todo!() + unimplemented!() } fn on_become_active(&self, _callback: Box) { - todo!() + unimplemented!() } fn on_resign_active(&self, _callback: Box) { - todo!() + unimplemented!() } fn on_quit(&self, _callback: Box) { - todo!() + unimplemented!() } fn on_reopen(&self, _callback: Box) { - todo!() + unimplemented!() } fn on_event(&self, _callback: Box bool>) { - todo!() + unimplemented!() } fn os_name(&self) -> &'static str { - todo!() + unimplemented!() } fn os_version(&self) -> anyhow::Result { - todo!() + unimplemented!() } fn app_version(&self) -> anyhow::Result { - todo!() + unimplemented!() } fn app_path(&self) -> anyhow::Result { - todo!() + unimplemented!() } fn local_timezone(&self) -> time::UtcOffset { - todo!() + unimplemented!() } fn path_for_auxiliary_executable(&self, _name: &str) -> anyhow::Result { - todo!() + unimplemented!() } fn set_cursor_style(&self, _style: crate::CursorStyle) { - todo!() + unimplemented!() } fn should_auto_hide_scrollbars(&self) -> bool { - todo!() + unimplemented!() } fn write_to_clipboard(&self, _item: crate::ClipboardItem) { - todo!() + unimplemented!() } fn read_from_clipboard(&self) -> Option { - todo!() + unimplemented!() } fn write_credentials( @@ -158,14 +159,14 @@ impl Platform for TestPlatform { _username: &str, _password: &[u8], ) -> anyhow::Result<()> { - todo!() + unimplemented!() } fn read_credentials(&self, _url: &str) -> anyhow::Result)>> { - todo!() + unimplemented!() } fn delete_credentials(&self, _url: &str) -> anyhow::Result<()> { - todo!() + unimplemented!() } }