From a53c0b94728001a338088d4ac280c1e6dadcc7b0 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 21 Sep 2023 13:39:43 -0600 Subject: [PATCH] WIP --- crates/gpui3/src/app.rs | 7 ++++- crates/gpui3/src/elements.rs | 2 ++ crates/gpui3/src/elements/stateless.rs | 31 +++++++++++++++++++ crates/gpui3/src/window.rs | 10 ++++++ crates/gpui3_macros/src/derive_element.rs | 20 ++++++------ crates/storybook2/src/collab_panel.rs | 37 ++++++++++++----------- crates/storybook2/src/workspace.rs | 24 ++++++--------- 7 files changed, 88 insertions(+), 43 deletions(-) create mode 100644 crates/gpui3/src/elements/stateless.rs diff --git a/crates/gpui3/src/app.rs b/crates/gpui3/src/app.rs index fb0c3f55bd7ce558b811dbd545d64b9a5a188596..b05a34e009997ac09cee7d9f4b9fff90f362f69c 100644 --- a/crates/gpui3/src/app.rs +++ b/crates/gpui3/src/app.rs @@ -29,6 +29,7 @@ impl App { pub struct AppContext { platform: Rc, text_system: Arc, + pub(crate) unit_entity_id: EntityId, pub(crate) entities: SlotMap>>, pub(crate) windows: SlotMap>, // We recycle this memory across layout requests. @@ -38,10 +39,14 @@ pub struct AppContext { impl AppContext { pub fn new(platform: Rc) -> Self { let text_system = Arc::new(TextSystem::new(platform.text_system())); + let mut entities = SlotMap::with_key(); + let unit_entity_id = entities.insert(Some(Box::new(()) as Box)); + AppContext { platform, text_system, - entities: SlotMap::with_key(), + unit_entity_id, + entities, windows: SlotMap::with_key(), layout_id_buffer: Default::default(), } diff --git a/crates/gpui3/src/elements.rs b/crates/gpui3/src/elements.rs index 83c27b8a3b1a88e6dee517c485f5f99ea1df7a93..5bd95ccebb69bdc6ac536d5bb89d990ae66aafb1 100644 --- a/crates/gpui3/src/elements.rs +++ b/crates/gpui3/src/elements.rs @@ -1,9 +1,11 @@ mod div; mod img; +mod stateless; mod svg; mod text; pub use div::*; pub use img::*; +pub use stateless::*; pub use svg::*; pub use text::*; diff --git a/crates/gpui3/src/elements/stateless.rs b/crates/gpui3/src/elements/stateless.rs new file mode 100644 index 0000000000000000000000000000000000000000..3d1110af74648432e16765659bab564f65370938 --- /dev/null +++ b/crates/gpui3/src/elements/stateless.rs @@ -0,0 +1,31 @@ +use std::marker::PhantomData; + +use crate::Element; + +pub struct Stateless, S> { + element: E, + parent_state_type: PhantomData, +} + +impl, S: 'static> Element for Stateless { + type State = S; + type FrameState = E::FrameState; + + fn layout( + &mut self, + _: &mut Self::State, + cx: &mut crate::ViewContext, + ) -> anyhow::Result<(crate::LayoutId, Self::FrameState)> { + cx.erase_state(|cx| self.element.layout(&mut (), cx)) + } + + fn paint( + &mut self, + layout: crate::Layout, + _: &mut Self::State, + frame_state: &mut Self::FrameState, + cx: &mut crate::ViewContext, + ) -> anyhow::Result<()> { + cx.erase_state(|cx| self.element.paint(layout, &mut (), frame_state, cx)) + } +} diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index 133209bbffe1c9d224c0069fe74b5b59e19dedc9..329037cb91b8e54b257af9c2b5dff1bef250a27f 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -220,6 +220,16 @@ impl<'a, 'w, T: 'static> ViewContext<'a, 'w, T> { entity_type: PhantomData, } } + + pub fn erase_state(&mut self, f: impl FnOnce(&mut ViewContext<()>) -> R) -> R { + let unit_entity_id = self.unit_entity_id; + let mut cx = ViewContext::mutable( + &mut *self.window_cx.app, + &mut *self.window_cx.window, + unit_entity_id, + ); + f(&mut cx) + } } impl<'a, 'w, T: 'static> Context for ViewContext<'a, 'w, T> { diff --git a/crates/gpui3_macros/src/derive_element.rs b/crates/gpui3_macros/src/derive_element.rs index 1c996951c509dd89e73070f6d0ca4f48e41ff9d7..a45eca9534b6dd24834e5b139668a1a725bcca46 100644 --- a/crates/gpui3_macros/src/derive_element.rs +++ b/crates/gpui3_macros/src/derive_element.rs @@ -1,32 +1,32 @@ use proc_macro::TokenStream; -use proc_macro2::Ident; use quote::quote; -use syn::{parse_macro_input, parse_quote, DeriveInput, GenericParam}; +use syn::{parse_macro_input, DeriveInput, GenericParam}; pub fn derive_element(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); let type_name = ast.ident; - let mut state_type: Option = None; - for param in ast.generics.params.iter() { + let mut state_type = quote! { () }; + + for param in &ast.generics.params { if let GenericParam::Type(type_param) = param { - state_type = Some(type_param.ident.clone()) + let type_ident = &type_param.ident; + state_type = quote! {#type_ident}; } } - let state_type_name = state_type.unwrap_or_else(|| parse_quote! { () }); let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); let gen = quote! { impl #impl_generics gpui3::Element for #type_name #ty_generics #where_clause { - type State = #state_type_name; - type FrameState = gpui3::AnyElement<#state_type_name>; + type State = #state_type; + type FrameState = gpui3::AnyElement<#state_type>; fn layout( &mut self, - state: &mut #state_type_name, + state: &mut #state_type, cx: &mut gpui3::ViewContext, ) -> anyhow::Result<(gpui3::LayoutId, Self::FrameState)> { let mut rendered_element = self.render(state, cx).into_element().into_any(); @@ -37,7 +37,7 @@ pub fn derive_element(input: TokenStream) -> TokenStream { fn paint( &mut self, layout: &gpui3::Layout, - state: &mut #state_type_name, + state: &mut #state_type, rendered_element: &mut Self::FrameState, cx: &mut gpui3::ViewContext, ) { diff --git a/crates/storybook2/src/collab_panel.rs b/crates/storybook2/src/collab_panel.rs index 560fd20ac9311dc06ae7171faf5dc0cb3e284f1a..af975cc4e45f79e066f83e82e1d7765727cbf36e 100644 --- a/crates/storybook2/src/collab_panel.rs +++ b/crates/storybook2/src/collab_panel.rs @@ -1,26 +1,29 @@ use crate::theme::{theme, Theme}; use gpui3::{ - div, img, svg, ArcCow, Element, IntoAnyElement, ParentElement, ScrollState, StyleHelpers, - ViewContext, + div, img, svg, view, AppContext, ArcCow, Context, Element, IntoAnyElement, ParentElement, + ScrollState, StyleHelpers, View, ViewContext, WindowContext, }; -use std::marker::PhantomData; -pub struct CollabPanelElement { - view_type: PhantomData, +struct CollabPanel { scroll_state: ScrollState, } -// When I improve child view rendering, I'd like to have V implement a trait that -// provides the scroll state, among other things. -pub fn collab_panel(scroll_state: ScrollState) -> CollabPanelElement { - CollabPanelElement { - view_type: PhantomData, - scroll_state, +pub fn collab_panel(cx: &mut WindowContext) -> View { + view(cx.entity(|cx| CollabPanel::new(cx)), |panel, cx| { + panel.render(cx) + }) +} + +impl CollabPanel { + fn new(_: &mut AppContext) -> Self { + CollabPanel { + scroll_state: ScrollState::default(), + } } } -impl CollabPanelElement { - fn render(&mut self, _: &mut V, cx: &mut ViewContext) -> impl Element { +impl CollabPanel { + fn render(&mut self, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); // Panel @@ -115,10 +118,10 @@ impl CollabPanelElement { fn list_section_header( &self, - label: impl IntoAnyElement, + label: impl IntoAnyElement, expanded: bool, theme: &Theme, - ) -> impl Element { + ) -> impl Element { div() .h_7() .px_2() @@ -144,9 +147,9 @@ impl CollabPanelElement { fn list_item( &self, avatar_uri: impl Into>, - label: impl IntoAnyElement, + label: impl IntoAnyElement, theme: &Theme, - ) -> impl Element { + ) -> impl Element { div() .h_7() .px_2() diff --git a/crates/storybook2/src/workspace.rs b/crates/storybook2/src/workspace.rs index 174042719211e3f5e0e5b2c99476c949e420c8ea..b600e77426c670e23e5526396885b6613c5bdfa3 100644 --- a/crates/storybook2/src/workspace.rs +++ b/crates/storybook2/src/workspace.rs @@ -1,7 +1,7 @@ use crate::{collab_panel::collab_panel, theme::theme}; use gpui3::{div, img, svg, Element, ParentElement, ScrollState, StyleHelpers, ViewContext}; -#[derive(Element, Default)] +#[derive(Default)] struct WorkspaceElement { left_scroll_state: ScrollState, right_scroll_state: ScrollState, @@ -271,18 +271,12 @@ impl TitleBar { // ================================================================================ // -struct StatusBar; +mod statusbar { + use gpui3::WindowContext; -pub fn statusbar() -> impl Element { - StatusBar -} + use super::*; -impl StatusBar { - fn render( - &mut self, - _: &mut V, - cx: &mut ViewContext, - ) -> impl Element { + pub fn statusbar(_: &mut V, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); div() .flex() @@ -291,11 +285,11 @@ impl StatusBar { .w_full() .h_8() .fill(theme.lowest.base.default.background) - .child(self.left_group(cx)) - .child(self.right_group(cx)) + .child(left_group(cx)) + .child(right_group(cx)) } - fn left_group(&mut self, cx: &mut ViewContext) -> impl Element { + fn left_group(cx: &mut ViewContext) -> impl Element { let theme = theme(cx); div() .flex() @@ -392,7 +386,7 @@ impl StatusBar { ) } - fn right_group(&mut self, cx: &mut ViewContext) -> impl Element { + fn right_group(cx: &mut ViewContext) -> impl Element { let theme = theme(cx); div() .flex()