Unified · Split
| @@ -1,4 +1,4 @@ | |||
| 1 | use crate::{AnyBox, AppContext, Context}; | 1 | use crate::{AnyBox, AppContext, Context, EntityHandle}; |
| 2 | use anyhow::{anyhow, Result}; | 2 | use anyhow::{anyhow, Result}; |
| 3 | use derive_more::{Deref, DerefMut}; | 3 | use derive_more::{Deref, DerefMut}; |
| 4 | use parking_lot::{RwLock, RwLockUpgradableReadGuard}; | 4 | use parking_lot::{RwLock, RwLockUpgradableReadGuard}; |
| @@ -329,7 +329,26 @@ impl<T> Eq for Handle<T> {} · 324 unmodified lines | |||
| 329 | 329 | ||
| 330 | impl<T> PartialEq<WeakHandle<T>> for Handle<T> { | 330 | impl<T> PartialEq<WeakHandle<T>> for Handle<T> { |
| 331 | fn eq(&self, other: &WeakHandle<T>) -> bool { | 331 | fn eq(&self, other: &WeakHandle<T>) -> bool { |
| 332 | self.entity_id() == other.entity_id() | 332 | self.entity_id == other.entity_id |
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | impl<T: 'static> EntityHandle<T> for Handle<T> { | ||
| 337 | type Weak = WeakHandle<T>; | ||
| 338 | |||
| 339 | fn entity_id(&self) -> EntityId { | ||
| 340 | self.entity_id | ||
| 341 | } | ||
| 342 | |||
| 343 | fn downgrade(&self) -> Self::Weak { | ||
| 344 | self.downgrade() | ||
| 345 | } | ||
| 346 | |||
| 347 | fn upgrade_from(weak: &Self::Weak) -> Option<Self> | ||
| 348 | where | ||
| 349 | Self: Sized, | ||
| 350 | { | ||
| 351 | weak.upgrade() | ||
| 333 | } | 352 | } |
| 334 | } | 353 | } |
| 335 | 354 | ||
| @@ -457,6 +476,6 @@ impl<T> Eq for WeakHandle<T> {} · 121 unmodified lines | |||
| 457 | 476 | ||
| 458 | impl<T> PartialEq<Handle<T>> for WeakHandle<T> { | 477 | impl<T> PartialEq<Handle<T>> for WeakHandle<T> { |
| 459 | fn eq(&self, other: &Handle<T>) -> bool { | 478 | fn eq(&self, other: &Handle<T>) -> bool { |
| 460 | self.entity_id() == other.entity_id() | 479 | self.entity_id == other.entity_id |
| 461 | } | 480 | } |
| 462 | } | 481 | } |
| @@ -106,6 +106,16 @@ pub trait VisualContext: Context { · 105 unmodified lines | |||
| 106 | ) -> Self::Result<R>; | 106 | ) -> Self::Result<R>; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | pub trait EntityHandle<T> { | ||
| 110 | type Weak: 'static + Send; | ||
| 111 | |||
| 112 | fn entity_id(&self) -> EntityId; | ||
| 113 | fn downgrade(&self) -> Self::Weak; | ||
| 114 | fn upgrade_from(weak: &Self::Weak) -> Option<Self> | ||
| 115 | where | ||
| 116 | Self: Sized; | ||
| 117 | } | ||
| 118 | |||
| 109 | pub enum GlobalKey { | 119 | pub enum GlobalKey { |
| 110 | Numeric(usize), | 120 | Numeric(usize), |
| 111 | View(EntityId), | 121 | View(EntityId), |
| @@ -1,7 +1,7 @@ | |||
| 1 | use crate::{ | 1 | use crate::{ |
| 2 | AnyBox, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId, | 2 | AnyBox, AnyElement, AppContext, AvailableSpace, BorrowWindow, Bounds, Component, Element, |
| 3 | EntityId, Flatten, Handle, LayoutId, Pixels, Size, ViewContext, VisualContext, WeakHandle, | 3 | ElementId, EntityHandle, EntityId, Flatten, Handle, LayoutId, Pixels, Size, ViewContext, |
| 4 | WindowContext, | 4 | VisualContext, WeakHandle, WindowContext, |
| 5 | }; | 5 | }; |
| 6 | use anyhow::{Context, Result}; | 6 | use anyhow::{Context, Result}; |
| 7 | use parking_lot::Mutex; | 7 | use parking_lot::Mutex; |
| @@ -31,9 +31,7 @@ impl<V: 'static> View<V> { · 23 unmodified lines | |||
| 31 | )), | 31 | )), |
| 32 | } | 32 | } |
| 33 | } | 33 | } |
| 34 | } | ||
| 35 | 34 | ||
| 36 | impl<V: 'static> View<V> { | ||
| 37 | pub fn into_any(self) -> AnyView { | 35 | pub fn into_any(self) -> AnyView { |
| 38 | AnyView(Arc::new(self)) | 36 | AnyView(Arc::new(self)) |
| 39 | } | 37 | } |
| @@ -44,9 +42,7 @@ impl<V: 'static> View<V> { · 4 unmodified lines | |||
| 44 | render: Arc::downgrade(&self.render), | 42 | render: Arc::downgrade(&self.render), |
| 45 | } | 43 | } |
| 46 | } | 44 | } |
| 47 | } | ||
| 48 | 45 | ||
| 49 | impl<V: 'static> View<V> { | ||
| 50 | pub fn update<C, R>( | 46 | pub fn update<C, R>( |
| 51 | &self, | 47 | &self, |
| 52 | cx: &mut C, | 48 | cx: &mut C, |
| @@ -58,11 +54,8 @@ impl<V: 'static> View<V> { · 5 unmodified lines | |||
| 58 | cx.update_view(self, f) | 54 | cx.update_view(self, f) |
| 59 | } | 55 | } |
| 60 | 56 | ||
| 61 | pub fn read<C>(&self, cx: &mut C) -> &V | 57 | pub fn read<'a>(&self, cx: &'a AppContext) -> &'a V { |
| 62 | where | 58 | cx.entities.read(&self.state) |
| 63 | C: VisualContext, | ||
| 64 | { | ||
| 65 | todo!() | ||
| 66 | } | 59 | } |
| 67 | } | 60 | } |
| 68 | 61 | ||
| @@ -124,6 +117,25 @@ impl<V: 'static> Element<()> for View<V> { · 55 unmodified lines | |||
| 124 | } | 117 | } |
| 125 | } | 118 | } |
| 126 | 119 | ||
| 120 | impl<T: 'static> EntityHandle<T> for View<T> { | ||
| 121 | type Weak = WeakView<T>; | ||
| 122 | |||
| 123 | fn entity_id(&self) -> EntityId { | ||
| 124 | self.state.entity_id | ||
| 125 | } | ||
| 126 | |||
| 127 | fn downgrade(&self) -> Self::Weak { | ||
| 128 | self.downgrade() | ||
| 129 | } | ||
| 130 | |||
| 131 | fn upgrade_from(weak: &Self::Weak) -> Option<Self> | ||
| 132 | where | ||
| 133 | Self: Sized, | ||
| 134 | { | ||
| 135 | weak.upgrade() | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 127 | pub struct WeakView<V> { | 139 | pub struct WeakView<V> { |
| 128 | pub(crate) state: WeakHandle<V>, | 140 | pub(crate) state: WeakHandle<V>, |
| 129 | render: Weak<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>, | 141 | render: Weak<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>, |
| @@ -1,14 +1,14 @@ | |||
| 1 | use crate::{ | 1 | use crate::{ |
| 2 | px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace, | 2 | px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace, |
| 3 | Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect, | 3 | Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect, |
| 4 | EntityId, EventEmitter, ExternalPaths, FileDropEvent, FocusEvent, FontId, GlobalElementId, | 4 | EntityHandle, EntityId, EventEmitter, ExternalPaths, FileDropEvent, FocusEvent, FontId, |
| 5 | GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, | 5 | GlobalElementId, GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, |
| 6 | Keystroke, LayoutId, MainThread, MainThreadOnly, ModelContext, Modifiers, MonochromeSprite, | 6 | KeyMatcher, Keystroke, LayoutId, MainThread, MainThreadOnly, ModelContext, Modifiers, |
| 7 | MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, | 7 | MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, |
| 8 | PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams, | 8 | PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, |
| 9 | RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, Subscription, | 9 | RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, |
| 10 | TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, WeakHandle, WeakView, | 10 | Style, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, |
| 11 | WindowOptions, SUBPIXEL_VARIANTS, | 11 | WeakHandle, WeakView, WindowOptions, SUBPIXEL_VARIANTS, |
| 12 | }; | 12 | }; |
| 13 | use anyhow::Result; | 13 | use anyhow::Result; |
| 14 | use collections::HashMap; | 14 | use collections::HashMap; |
| @@ -376,6 +376,35 @@ impl<'a, 'w> WindowContext<'a, 'w> { · 361 unmodified lines | |||
| 376 | self.notify(); | 376 | self.notify(); |
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | pub fn subscribe<E, H>( | ||
| 380 | &mut self, | ||
| 381 | handle: &H, | ||
| 382 | mut on_event: impl FnMut(H, &E::Event, &mut WindowContext<'_, '_>) + Send + 'static, | ||
| 383 | ) -> Subscription | ||
| 384 | where | ||
| 385 | E: EventEmitter, | ||
| 386 | H: EntityHandle<E>, | ||
| 387 | { | ||
| 388 | let entity_id = handle.entity_id(); | ||
| 389 | let handle = handle.downgrade(); | ||
| 390 | let window_handle = self.window.handle; | ||
| 391 | self.app.event_listeners.insert( | ||
| 392 | entity_id, | ||
| 393 | Box::new(move |event, cx| { | ||
| 394 | cx.update_window(window_handle, |cx| { | ||
| 395 | if let Some(handle) = H::upgrade_from(&handle) { | ||
| 396 | let event = event.downcast_ref().expect("invalid event type"); | ||
| 397 | on_event(handle, event, cx); | ||
| 398 | true | ||
| 399 | } else { | ||
| 400 | false | ||
| 401 | } | ||
| 402 | }) | ||
| 403 | .unwrap_or(false) | ||
| 404 | }), | ||
| 405 | ) | ||
| 406 | } | ||
| 407 | |||
| 379 | /// Schedule the given closure to be run on the main thread. It will be invoked with | 408 | /// Schedule the given closure to be run on the main thread. It will be invoked with |
| 380 | /// a `MainThread<WindowContext>`, which provides access to platform-specific functionality | 409 | /// a `MainThread<WindowContext>`, which provides access to platform-specific functionality |
| 381 | /// of the window. | 410 | /// of the window. |
| @@ -1600,21 +1629,24 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { · 1218 unmodified lines | |||
| 1600 | ) | 1629 | ) |
| 1601 | } | 1630 | } |
| 1602 | 1631 | ||
| 1603 | pub fn subscribe<E: EventEmitter>( | 1632 | pub fn subscribe<E, H>( |
| 1604 | &mut self, | 1633 | &mut self, |
| 1605 | handle: &Handle<E>, | 1634 | handle: &H, |
| 1606 | mut on_event: impl FnMut(&mut V, Handle<E>, &E::Event, &mut ViewContext<'_, '_, V>) | 1635 | mut on_event: impl FnMut(&mut V, H, &E::Event, &mut ViewContext<'_, '_, V>) + Send + 'static, |
| 1607 | + Send | 1636 | ) -> Subscription |
| 1608 | + 'static, | 1637 | where |
| 1609 | ) -> Subscription { | 1638 | E: EventEmitter, |
| 1639 | H: EntityHandle<E>, | ||
| 1640 | { | ||
| 1610 | let view = self.view(); | 1641 | let view = self.view(); |
| 1642 | let entity_id = handle.entity_id(); | ||
| 1611 | let handle = handle.downgrade(); | 1643 | let handle = handle.downgrade(); |
| 1612 | let window_handle = self.window.handle; | 1644 | let window_handle = self.window.handle; |
| 1613 | self.app.event_listeners.insert( | 1645 | self.app.event_listeners.insert( |
| 1614 | handle.entity_id, | 1646 | entity_id, |
| 1615 | Box::new(move |event, cx| { | 1647 | Box::new(move |event, cx| { |
| 1616 | cx.update_window(window_handle, |cx| { | 1648 | cx.update_window(window_handle, |cx| { |
| 1617 | if let Some(handle) = handle.upgrade() { | 1649 | if let Some(handle) = H::upgrade_from(&handle) { |
| 1618 | let event = event.downcast_ref().expect("invalid event type"); | 1650 | let event = event.downcast_ref().expect("invalid event type"); |
| 1619 | view.update(cx, |this, cx| on_event(this, handle, event, cx)) | 1651 | view.update(cx, |this, cx| on_event(this, handle, event, cx)) |
| 1620 | .is_ok() | 1652 | .is_ok() |
| @@ -104,30 +104,26 @@ pub trait Item: EventEmitter + Sized { · 103 unmodified lines | |||
| 104 | // fn navigate(&mut self, _: Box<dyn Any>, _: &mut ViewContext<Self>) -> bool { | 104 | // fn navigate(&mut self, _: Box<dyn Any>, _: &mut ViewContext<Self>) -> bool { |
| 105 | // false | 105 | // false |
| 106 | // } | 106 | // } |
| 107 | // fn tab_tooltip_text(&self, _: &AppContext) -> Option<Cow<str>> { | 107 | fn tab_tooltip_text(&self, _: &AppContext) -> Option<SharedString> { |
| 108 | // None | 108 | None |
| 109 | // } | 109 | } |
| 110 | // fn tab_description<'a>(&'a self, _: usize, _: &'a AppContext) -> Option<Cow<str>> { | 110 | fn tab_description(&self, _: usize, _: &AppContext) -> Option<SharedString> { |
| 111 | // None | 111 | None |
| 112 | // } | 112 | } |
| 113 | // fn tab_content<V: 'static>( | 113 | fn tab_content<V: 'static>(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<V>; |
| 114 | // &self, | 114 | |
| 115 | // detail: Option<usize>, | 115 | fn for_each_project_item(&self, _: &AppContext, _: &mut dyn FnMut(usize, &dyn project2::Item)) { |
| 116 | // style: &theme2::Tab, | 116 | } // (model id, Item) |
| 117 | // cx: &AppContext, | ||
| 118 | // ) -> AnyElement<V>; | ||
| 119 | // fn for_each_project_item(&self, _: &AppContext, _: &mut dyn FnMut(usize, &dyn project2::Item)) { | ||
| 120 | // } // (model id, Item) | ||
| 121 | fn is_singleton(&self, _cx: &AppContext) -> bool { | 117 | fn is_singleton(&self, _cx: &AppContext) -> bool { |
| 122 | false | 118 | false |
| 123 | } | 119 | } |
| 124 | // fn set_nav_history(&mut self, _: ItemNavHistory, _: &mut ViewContext<Self>) {} | 120 | // fn set_nav_history(&mut self, _: ItemNavHistory, _: &mut ViewContext<Self>) {} |
| 125 | // fn clone_on_split(&self, _workspace_id: WorkspaceId, _: &mut ViewContext<Self>) -> Option<Self> | 121 | fn clone_on_split(&self, _workspace_id: WorkspaceId, _: &mut ViewContext<Self>) -> Option<Self> |
| 126 | // where | 122 | where |
| 127 | // Self: Sized, | 123 | Self: Sized, |
| 128 | // { | 124 | { |
| 129 | // None | 125 | None |
| 130 | // } | 126 | } |
| 131 | // fn is_dirty(&self, _: &AppContext) -> bool { | 127 | // fn is_dirty(&self, _: &AppContext) -> bool { |
| 132 | // false | 128 | // false |
| 133 | // } | 129 | // } |
| @@ -221,7 +217,6 @@ pub trait Item: EventEmitter + Sized { · 87 unmodified lines | |||
| 221 | 217 | ||
| 222 | use std::{ | 218 | use std::{ |
| 223 | any::Any, | 219 | any::Any, |
| 224 | borrow::Cow, | ||
| 225 | cell::RefCell, | 220 | cell::RefCell, |
| 226 | ops::Range, | 221 | ops::Range, |
| 227 | path::PathBuf, | 222 | path::PathBuf, |
| @@ -235,7 +230,7 @@ use std::{ · 7 unmodified lines | |||
| 235 | 230 | ||
| 236 | use gpui2::{ | 231 | use gpui2::{ |
| 237 | AnyElement, AnyWindowHandle, AppContext, EventEmitter, Handle, HighlightStyle, Pixels, Point, | 232 | AnyElement, AnyWindowHandle, AppContext, EventEmitter, Handle, HighlightStyle, Pixels, Point, |
| 238 | Task, View, ViewContext, WindowContext, | 233 | SharedString, Task, View, ViewContext, VisualContext, WindowContext, |
| 239 | }; | 234 | }; |
| 240 | use project2::{Project, ProjectEntryId, ProjectPath}; | 235 | use project2::{Project, ProjectEntryId, ProjectPath}; |
| 241 | use smallvec::SmallVec; | 236 | use smallvec::SmallVec; |
| @@ -252,10 +247,10 @@ pub trait ItemHandle: 'static + Send { · 10 unmodified lines | |||
| 252 | fn subscribe_to_item_events( | 247 | fn subscribe_to_item_events( |
| 253 | &self, | 248 | &self, |
| 254 | cx: &mut WindowContext, | 249 | cx: &mut WindowContext, |
| 255 | handler: Box<dyn Fn(ItemEvent, &mut WindowContext)>, | 250 | handler: Box<dyn Fn(ItemEvent, &mut WindowContext) + Send>, |
| 256 | ) -> gpui2::Subscription; | 251 | ) -> gpui2::Subscription; |
| 257 | fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option<Cow<'a, str>>; | 252 | fn tab_tooltip_text(&self, cx: &AppContext) -> Option<SharedString>; |
| 258 | fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option<Cow<'a, str>>; | 253 | fn tab_description(&self, detail: usize, cx: &AppContext) -> Option<SharedString>; |
| 259 | fn tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Pane>; | 254 | fn tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Pane>; |
| 260 | fn dragged_tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Workspace>; | 255 | fn dragged_tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Workspace>; |
| 261 | fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>; | 256 | fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>; |
| @@ -329,7 +324,7 @@ impl<T: Item> ItemHandle for View<T> { · 67 unmodified lines | |||
| 329 | fn subscribe_to_item_events( | 324 | fn subscribe_to_item_events( |
| 330 | &self, | 325 | &self, |
| 331 | cx: &mut WindowContext, | 326 | cx: &mut WindowContext, |
| 332 | handler: Box<dyn Fn(ItemEvent, &mut WindowContext)>, | 327 | handler: Box<dyn Fn(ItemEvent, &mut WindowContext) + Send>, |
| 333 | ) -> gpui2::Subscription { | 328 | ) -> gpui2::Subscription { |
| 334 | cx.subscribe(self, move |_, event, cx| { | 329 | cx.subscribe(self, move |_, event, cx| { |
| 335 | for item_event in T::to_item_events(event) { | 330 | for item_event in T::to_item_events(event) { |
| @@ -338,11 +333,11 @@ impl<T: Item> ItemHandle for View<T> { · 2 unmodified lines | |||
| 338 | }) | 333 | }) |
| 339 | } | 334 | } |
| 340 | 335 | ||
| 341 | fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option<Cow<'a, str>> { | 336 | fn tab_tooltip_text(&self, cx: &AppContext) -> Option<SharedString> { |
| 342 | self.read(cx).tab_tooltip_text(cx) | 337 | self.read(cx).tab_tooltip_text(cx) |
| 343 | } | 338 | } |
| 344 | 339 | ||
| 345 | fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option<Cow<'a, str>> { | 340 | fn tab_description(&self, detail: usize, cx: &AppContext) -> Option<SharedString> { |
| 346 | self.read(cx).tab_description(detail, cx) | 341 | self.read(cx).tab_description(detail, cx) |
| 347 | } | 342 | } |
| 348 | 343 | ||