Add View::update which provides a ViewContext

Nathan Sobo created

Change summary

crates/gpui2/src/app.rs                       |   7 
crates/gpui2/src/gpui2.rs                     |  62 ++++++++
crates/gpui2/src/interactive.rs               |   7 
crates/gpui2/src/view.rs                      |  84 ++++++++---
crates/gpui2/src/window.rs                    | 150 +++++++++++++-------
crates/storybook2/src/stories/focus.rs        | 151 ++++++++++----------
crates/storybook2/src/stories/kitchen_sink.rs |  10 
crates/storybook2/src/stories/scroll.rs       |   6 
crates/storybook2/src/stories/text.rs         |   4 
crates/storybook2/src/story_selector.rs       |  82 +++++-----
crates/storybook2/src/storybook2.rs           |   6 
crates/ui2/src/components/buffer_search.rs    |  10 
crates/ui2/src/components/editor_pane.rs      |  15 +
crates/ui2/src/components/title_bar.rs        |  28 ++-
crates/ui2/src/components/workspace.rs        |  20 +
crates/ui2/src/static_data.rs                 |   4 
crates/ui2/src/theme.rs                       |   6 
17 files changed, 404 insertions(+), 248 deletions(-)

Detailed changes

crates/gpui2/src/app.rs 🔗

@@ -129,8 +129,6 @@ pub struct AppContext {
     pub(crate) image_cache: ImageCache,
     pub(crate) text_style_stack: Vec<TextStyleRefinement>,
     pub(crate) globals_by_type: HashMap<TypeId, AnyBox>,
-    pub(crate) unit_entity: Handle<()>,
-    pub(crate) unit_view: View<()>,
     pub(crate) entities: EntityMap,
     pub(crate) windows: SlotMap<WindowId, Option<Window>>,
     pub(crate) keymap: Arc<Mutex<Keymap>>,
@@ -162,8 +160,8 @@ impl AppContext {
         );
 
         let text_system = Arc::new(TextSystem::new(platform.text_system()));
-        let mut entities = EntityMap::new();
-        let unit_entity = entities.insert(entities.reserve(), ());
+        let entities = EntityMap::new();
+
         let app_metadata = AppMetadata {
             os_name: platform.os_name(),
             os_version: platform.os_version().ok(),
@@ -185,7 +183,6 @@ impl AppContext {
                 image_cache: ImageCache::new(http_client),
                 text_style_stack: Vec::new(),
                 globals_by_type: HashMap::default(),
-                unit_entity,
                 entities,
                 windows: SlotMap::with_key(),
                 keymap: Arc::new(Mutex::new(Keymap::default())),

crates/gpui2/src/gpui2.rs 🔗

@@ -87,6 +87,25 @@ pub trait Context {
     ) -> Self::Result<R>;
 }
 
+pub trait VisualContext: Context {
+    type ViewContext<'a, 'w, V>;
+
+    fn build_view<E, V>(
+        &mut self,
+        build_entity: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V,
+        render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
+    ) -> Self::Result<View<V>>
+    where
+        E: Component<V>,
+        V: 'static + Send;
+
+    fn update_view<V: 'static, R>(
+        &mut self,
+        view: &View<V>,
+        update: impl FnOnce(&mut V, &mut Self::ViewContext<'_, '_, V>) -> R,
+    ) -> Self::Result<R>;
+}
+
 pub enum GlobalKey {
     Numeric(usize),
     View(EntityId),
@@ -149,6 +168,49 @@ impl<C: Context> Context for MainThread<C> {
     }
 }
 
+impl<C: VisualContext> VisualContext for MainThread<C> {
+    type ViewContext<'a, 'w, V> = MainThread<C::ViewContext<'a, 'w, V>>;
+
+    fn build_view<E, V>(
+        &mut self,
+        build_entity: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V,
+        render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
+    ) -> Self::Result<View<V>>
+    where
+        E: Component<V>,
+        V: 'static + Send,
+    {
+        self.0.build_view(
+            |cx| {
+                let cx = unsafe {
+                    mem::transmute::<
+                        &mut C::ViewContext<'_, '_, V>,
+                        &mut MainThread<C::ViewContext<'_, '_, V>>,
+                    >(cx)
+                };
+                build_entity(cx)
+            },
+            render,
+        )
+    }
+
+    fn update_view<V: 'static, R>(
+        &mut self,
+        view: &View<V>,
+        update: impl FnOnce(&mut V, &mut Self::ViewContext<'_, '_, V>) -> R,
+    ) -> Self::Result<R> {
+        self.0.update_view(view, |view_state, cx| {
+            let cx = unsafe {
+                mem::transmute::<
+                    &mut C::ViewContext<'_, '_, V>,
+                    &mut MainThread<C::ViewContext<'_, '_, V>>,
+                >(cx)
+            };
+            update(view_state, cx)
+        })
+    }
+}
+
 pub trait BorrowAppContext {
     fn with_text_style<F, R>(&mut self, style: TextStyleRefinement, f: F) -> R
     where

crates/gpui2/src/interactive.rs 🔗

@@ -1,7 +1,8 @@
 use crate::{
-    point, px, view, Action, AnyBox, AnyDrag, AppContext, BorrowWindow, Bounds, Component,
+    point, px, Action, AnyBox, AnyDrag, AppContext, BorrowWindow, Bounds, Component,
     DispatchContext, DispatchPhase, Element, ElementId, FocusHandle, KeyMatch, Keystroke,
-    Modifiers, Overflow, Pixels, Point, SharedString, Size, Style, StyleRefinement, ViewContext,
+    Modifiers, Overflow, Pixels, Point, SharedString, Size, Style, StyleRefinement, View,
+    ViewContext,
 };
 use collections::HashMap;
 use derive_more::{Deref, DerefMut};
@@ -332,7 +333,7 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
             Some(Box::new(move |view_state, cursor_offset, cx| {
                 let drag = listener(view_state, cx);
                 let drag_handle_view = Some(
-                    view(cx.handle().upgrade().unwrap(), move |view_state, cx| {
+                    View::for_handle(cx.handle().upgrade().unwrap(), move |view_state, cx| {
                         (drag.render_drag_handle)(view_state, cx)
                     })
                     .into_any(),

crates/gpui2/src/view.rs 🔗

@@ -1,7 +1,9 @@
 use crate::{
-    AnyBox, AnyElement, BorrowWindow, Bounds, Component, Element, ElementId, EntityId, Handle,
-    LayoutId, Pixels, ViewContext, WeakHandle, WindowContext,
+    AnyBox, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId,
+    EntityId, Handle, LayoutId, Pixels, Size, ViewContext, VisualContext, WeakHandle,
+    WindowContext,
 };
+use anyhow::{Context, Result};
 use parking_lot::Mutex;
 use std::{
     marker::PhantomData,
@@ -13,18 +15,20 @@ pub struct View<V> {
     render: Arc<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>,
 }
 
-pub fn view<V, E>(
-    state: Handle<V>,
-    render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
-) -> View<V>
-where
-    E: Component<V>,
-{
-    View {
-        state,
-        render: Arc::new(Mutex::new(
-            move |state: &mut V, cx: &mut ViewContext<'_, '_, V>| render(state, cx).render(),
-        )),
+impl<V: 'static> View<V> {
+    pub fn for_handle<E>(
+        state: Handle<V>,
+        render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
+    ) -> View<V>
+    where
+        E: Component<V>,
+    {
+        View {
+            state,
+            render: Arc::new(Mutex::new(
+                move |state: &mut V, cx: &mut ViewContext<'_, '_, V>| render(state, cx).render(),
+            )),
+        }
     }
 }
 
@@ -42,17 +46,15 @@ impl<V: 'static> View<V> {
 }
 
 impl<V: 'static> View<V> {
-    pub fn update<R>(
+    pub fn update<C, R>(
         &self,
-        cx: &mut WindowContext,
-        f: impl FnOnce(&mut V, &mut ViewContext<V>) -> R,
-    ) -> R {
-        let this = self.clone();
-        let mut lease = cx.app.entities.lease(&self.state);
-        let mut cx = ViewContext::mutable(&mut *cx.app, &mut *cx.window, this);
-        let result = f(&mut *lease, &mut cx);
-        cx.app.entities.end_lease(lease);
-        result
+        cx: &mut C,
+        f: impl FnOnce(&mut V, &mut C::ViewContext<'_, '_, V>) -> R,
+    ) -> C::Result<R>
+    where
+        C: VisualContext,
+    {
+        cx.update_view(self, f)
     }
 }
 
@@ -115,16 +117,34 @@ impl<V: 'static> Element<()> for View<V> {
 }
 
 pub struct WeakView<V> {
-    state: WeakHandle<V>,
+    pub(crate) state: WeakHandle<V>,
     render: Weak<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>,
 }
 
-impl<V> WeakView<V> {
+impl<V: 'static> WeakView<V> {
     pub fn upgrade(&self) -> Option<View<V>> {
         let state = self.state.upgrade()?;
         let render = self.render.upgrade()?;
         Some(View { state, render })
     }
+
+    pub fn update<R>(
+        &self,
+        cx: &mut WindowContext,
+        f: impl FnOnce(&mut V, &mut ViewContext<V>) -> R,
+    ) -> Result<R> {
+        let view = self.upgrade().context("error upgrading view")?;
+        Ok(view.update(cx, f))
+    }
+}
+
+impl<V> Clone for WeakView<V> {
+    fn clone(&self) -> Self {
+        Self {
+            state: self.state.clone(),
+            render: self.render.clone(),
+        }
+    }
 }
 
 struct EraseViewState<V, ParentV> {
@@ -220,6 +240,18 @@ impl<V: 'static> ViewObject for View<V> {
 #[derive(Clone)]
 pub struct AnyView(Arc<dyn ViewObject>);
 
+impl AnyView {
+    pub(crate) fn draw(&self, available_space: Size<AvailableSpace>, cx: &mut WindowContext) {
+        let mut rendered_element = self.0.initialize(cx);
+        let layout_id = self.0.layout(&mut rendered_element, cx);
+        cx.window
+            .layout_engine
+            .compute_layout(layout_id, available_space);
+        let bounds = cx.window.layout_engine.layout_bounds(layout_id);
+        self.0.paint(bounds, &mut rendered_element, cx);
+    }
+}
+
 impl<ParentV: 'static> Component<ParentV> for AnyView {
     fn render(self) -> AnyElement<ParentV> {
         AnyElement::new(EraseAnyViewState {

crates/gpui2/src/window.rs 🔗

@@ -1,14 +1,14 @@
 use crate::{
     px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
     Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect,
-    Element, EntityId, EventEmitter, ExternalPaths, FileDropEvent, FocusEvent, FontId,
-    GlobalElementId, GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch,
-    KeyMatcher, Keystroke, LayoutId, MainThread, MainThreadOnly, ModelContext, Modifiers,
-    MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels,
-    PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams,
-    RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size,
-    Style, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, WeakHandle,
-    WeakView, WindowOptions, SUBPIXEL_VARIANTS,
+    EntityId, EventEmitter, ExternalPaths, FileDropEvent, FocusEvent, FontId, GlobalElementId,
+    GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher,
+    Keystroke, LayoutId, MainThread, MainThreadOnly, ModelContext, Modifiers, MonochromeSprite,
+    MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas,
+    PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams,
+    RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, Subscription,
+    TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, WeakHandle, WeakView,
+    WindowOptions, SUBPIXEL_VARIANTS,
 };
 use anyhow::Result;
 use collections::HashMap;
@@ -150,7 +150,7 @@ pub struct Window {
     sprite_atlas: Arc<dyn PlatformAtlas>,
     rem_size: Pixels,
     content_size: Size<Pixels>,
-    layout_engine: TaffyLayoutEngine,
+    pub(crate) layout_engine: TaffyLayoutEngine,
     pub(crate) root_view: Option<AnyView>,
     pub(crate) element_id_stack: GlobalElementId,
     prev_frame_element_states: HashMap<GlobalElementId, AnyBox>,
@@ -799,29 +799,23 @@ impl<'a, 'w> WindowContext<'a, 'w> {
     }
 
     pub(crate) fn draw(&mut self) {
-        let unit_entity = self.unit_entity.clone();
-        let mut root_view = self.window.root_view.take().unwrap();
-        let mut root_view_cx = ViewContext::mutable(
-            &mut self.app,
-            &mut self.window,
-            self.unit_entity.downgrade(),
-        );
+        let root_view = self.window.root_view.take().unwrap();
 
-        root_view_cx.start_frame();
+        self.start_frame();
 
-        root_view_cx.stack(0, |cx| {
+        self.stack(0, |cx| {
             let available_space = cx.window.content_size.map(Into::into);
-            draw_any_view(&mut root_view, available_space, cx);
+            root_view.draw(available_space, cx);
         });
 
         if let Some(mut active_drag) = self.app.active_drag.take() {
-            root_view_cx.stack(1, |cx| {
+            self.stack(1, |cx| {
                 let offset = cx.mouse_position() - active_drag.cursor_offset;
                 cx.with_element_offset(Some(offset), |cx| {
                     let available_space =
                         size(AvailableSpace::MinContent, AvailableSpace::MinContent);
                     if let Some(drag_handle_view) = &mut active_drag.drag_handle_view {
-                        draw_any_view(drag_handle_view, available_space, cx);
+                        drag_handle_view.draw(available_space, cx);
                     }
                     cx.active_drag = Some(active_drag);
                 });
@@ -839,23 +833,6 @@ impl<'a, 'w> WindowContext<'a, 'w> {
             cx.window.dirty = false;
         })
         .detach();
-
-        fn draw_any_view(
-            view: &mut AnyView,
-            available_space: Size<AvailableSpace>,
-            cx: &mut ViewContext<()>,
-        ) {
-            cx.with_optional_element_state(view.id(), |element_state, cx| {
-                let mut element_state = view.initialize(&mut (), element_state, cx);
-                let layout_id = view.layout(&mut (), &mut element_state, cx);
-                cx.window
-                    .layout_engine
-                    .compute_layout(layout_id, available_space);
-                let bounds = cx.window.layout_engine.layout_bounds(layout_id);
-                view.paint(bounds, &mut (), &mut element_state, cx);
-                ((), element_state)
-            });
-        }
     }
 
     fn start_frame(&mut self) {
@@ -1202,6 +1179,39 @@ impl Context for WindowContext<'_, '_> {
     }
 }
 
+impl VisualContext for WindowContext<'_, '_> {
+    type ViewContext<'a, 'w, V> = ViewContext<'a, 'w, V>;
+
+    fn build_view<E, V>(
+        &mut self,
+        build_view_state: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V,
+        render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
+    ) -> Self::Result<View<V>>
+    where
+        E: crate::Component<V>,
+        V: 'static + Send,
+    {
+        let slot = self.app.entities.reserve();
+        let view = View::for_handle(slot.clone(), render);
+        let mut cx = ViewContext::mutable(&mut *self.app, &mut *self.window, view.downgrade());
+        let entity = build_view_state(&mut cx);
+        self.entities.insert(slot, entity);
+        view
+    }
+
+    fn update_view<T: 'static, R>(
+        &mut self,
+        view: &View<T>,
+        update: impl FnOnce(&mut T, &mut Self::ViewContext<'_, '_, T>) -> R,
+    ) -> Self::Result<R> {
+        let mut lease = self.app.entities.lease(&view.state);
+        let mut cx = ViewContext::mutable(&mut *self.app, &mut *self.window, view.downgrade());
+        let result = update(&mut *lease, &mut cx);
+        cx.app.entities.end_lease(lease);
+        result
+    }
+}
+
 impl<'a, 'w> std::ops::Deref for WindowContext<'a, 'w> {
     type Target = AppContext;
 
@@ -1388,7 +1398,7 @@ impl<T> BorrowWindow for T where T: BorrowMut<AppContext> + BorrowMut<Window> {}
 
 pub struct ViewContext<'a, 'w, V> {
     window_cx: WindowContext<'a, 'w>,
-    view: View<V>,
+    view: WeakView<V>,
 }
 
 impl<V> Borrow<AppContext> for ViewContext<'_, '_, V> {
@@ -1416,7 +1426,11 @@ impl<V> BorrowMut<Window> for ViewContext<'_, '_, V> {
 }
 
 impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
-    pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window, view: View<V>) -> Self {
+    pub(crate) fn mutable(
+        app: &'a mut AppContext,
+        window: &'w mut Window,
+        view: WeakView<V>,
+    ) -> Self {
         Self {
             window_cx: WindowContext::mutable(app, window),
             view,
@@ -1424,11 +1438,11 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
     }
 
     pub fn view(&self) -> WeakView<V> {
-        self.view.downgrade()
+        self.view.clone()
     }
 
     pub fn handle(&self) -> WeakHandle<V> {
-        self.view.state.downgrade()
+        self.view.state.clone()
     }
 
     pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
@@ -1442,7 +1456,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
     where
         V: Any + Send,
     {
-        let view = self.view();
+        let view = self.view().upgrade().unwrap();
         self.window_cx.on_next_frame(move |cx| view.update(cx, f));
     }
 
@@ -1481,7 +1495,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
             + Send
             + 'static,
     ) -> Subscription {
-        let this = self.view();
+        let view = self.view();
         let handle = handle.downgrade();
         let window_handle = self.window.handle;
         self.app.event_listeners.insert(
@@ -1490,7 +1504,8 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
                 cx.update_window(window_handle.id, |cx| {
                     if let Some(handle) = handle.upgrade() {
                         let event = event.downcast_ref().expect("invalid event type");
-                        this.update(cx, |this, cx| on_event(this, handle, event, cx))
+                        view.update(cx, |this, cx| on_event(this, handle, event, cx))
+                            .is_ok()
                     } else {
                         false
                     }
@@ -1506,7 +1521,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
     ) -> Subscription {
         let window_handle = self.window.handle;
         self.app.release_listeners.insert(
-            self.view.entity_id,
+            self.view.state.entity_id,
             Box::new(move |this, cx| {
                 let this = this.downcast_mut().expect("invalid entity type");
                 // todo!("are we okay with silently swallowing the error?")
@@ -1523,15 +1538,14 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
     where
         V: Any + Send,
     {
-        let this = self.view();
+        let view = self.view();
         let window_handle = self.window.handle;
         self.app.release_listeners.insert(
             handle.entity_id,
             Box::new(move |entity, cx| {
                 let entity = entity.downcast_mut().expect("invalid entity type");
-                // todo!("are we okay with silently swallowing the error?")
                 let _ = cx.update_window(window_handle.id, |cx| {
-                    this.update(cx, |this, cx| on_release(this, entity, cx))
+                    view.update(cx, |this, cx| on_release(this, entity, cx))
                 });
             }),
         )
@@ -1540,7 +1554,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
     pub fn notify(&mut self) {
         self.window_cx.notify();
         self.window_cx.app.push_effect(Effect::Notify {
-            emitter: self.view.entity_id,
+            emitter: self.view.state.entity_id,
         });
     }
 
@@ -1654,22 +1668,22 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
             let cx = unsafe { mem::transmute::<&mut Self, &mut MainThread<Self>>(self) };
             Task::ready(Ok(f(view, cx)))
         } else {
-            let handle = self.view().upgrade().unwrap();
-            self.window_cx.run_on_main(move |cx| handle.update(cx, f))
+            let view = self.view().upgrade().unwrap();
+            self.window_cx.run_on_main(move |cx| view.update(cx, f))
         }
     }
 
     pub fn spawn<Fut, R>(
         &mut self,
-        f: impl FnOnce(WeakHandle<V>, AsyncWindowContext) -> Fut + Send + 'static,
+        f: impl FnOnce(WeakView<V>, AsyncWindowContext) -> Fut + Send + 'static,
     ) -> Task<R>
     where
         R: Send + 'static,
         Fut: Future<Output = R> + Send + 'static,
     {
-        let handle = self.view();
+        let view = self.view();
         self.window_cx.spawn(move |_, cx| {
-            let result = f(handle, cx);
+            let result = f(view, cx);
             async move { result.await }
         })
     }
@@ -1720,7 +1734,7 @@ where
     V::Event: Any + Send,
 {
     pub fn emit(&mut self, event: V::Event) {
-        let emitter = self.view.entity_id;
+        let emitter = self.view.state.entity_id;
         self.app.push_effect(Effect::Emit {
             emitter,
             event: Box::new(event),
@@ -1751,6 +1765,30 @@ impl<'a, 'w, V> Context for ViewContext<'a, 'w, V> {
     }
 }
 
+impl<V: 'static> VisualContext for ViewContext<'_, '_, V> {
+    type ViewContext<'a, 'w, V2> = ViewContext<'a, 'w, V2>;
+
+    fn build_view<E, V2>(
+        &mut self,
+        build_entity: impl FnOnce(&mut Self::ViewContext<'_, '_, V2>) -> V2,
+        render: impl Fn(&mut V2, &mut ViewContext<'_, '_, V2>) -> E + Send + 'static,
+    ) -> Self::Result<View<V2>>
+    where
+        E: crate::Component<V2>,
+        V2: 'static + Send,
+    {
+        self.window_cx.build_view(build_entity, render)
+    }
+
+    fn update_view<V2: 'static, R>(
+        &mut self,
+        view: &View<V2>,
+        update: impl FnOnce(&mut V2, &mut Self::ViewContext<'_, '_, V2>) -> R,
+    ) -> Self::Result<R> {
+        self.window_cx.update_view(view, update)
+    }
+}
+
 impl<'a, 'w, V> std::ops::Deref for ViewContext<'a, 'w, V> {
     type Target = WindowContext<'a, 'w>;
 

crates/storybook2/src/stories/focus.rs 🔗

@@ -1,6 +1,6 @@
 use crate::themes::rose_pine;
 use gpui2::{
-    div, view, Context, Focusable, KeyBinding, ParentElement, StatelessInteractive, Styled, View,
+    div, Focusable, KeyBinding, ParentElement, StatelessInteractive, Styled, View, VisualContext,
     WindowContext,
 };
 use serde::Deserialize;
@@ -35,80 +35,83 @@ impl FocusStory {
         let color_4 = theme.lowest.accent.default.foreground;
         let color_5 = theme.lowest.variant.default.foreground;
         let color_6 = theme.highest.negative.default.foreground;
-
         let child_1 = cx.focus_handle();
         let child_2 = cx.focus_handle();
-        view(cx.entity(|cx| ()), move |_, cx| {
-            div()
-                .id("parent")
-                .focusable()
-                .context("parent")
-                .on_action(|_, action: &ActionA, phase, cx| {
-                    println!("Action A dispatched on parent during {:?}", phase);
-                })
-                .on_action(|_, action: &ActionB, phase, cx| {
-                    println!("Action B dispatched on parent during {:?}", phase);
-                })
-                .on_focus(|_, _, _| println!("Parent focused"))
-                .on_blur(|_, _, _| println!("Parent blurred"))
-                .on_focus_in(|_, _, _| println!("Parent focus_in"))
-                .on_focus_out(|_, _, _| println!("Parent focus_out"))
-                .on_key_down(|_, event, phase, _| {
-                    println!("Key down on parent {:?} {:?}", phase, event)
-                })
-                .on_key_up(|_, event, phase, _| {
-                    println!("Key up on parent {:?} {:?}", phase, event)
-                })
-                .size_full()
-                .bg(color_1)
-                .focus(|style| style.bg(color_2))
-                .focus_in(|style| style.bg(color_3))
-                .child(
-                    div()
-                        .track_focus(&child_1)
-                        .context("child-1")
-                        .on_action(|_, action: &ActionB, phase, cx| {
-                            println!("Action B dispatched on child 1 during {:?}", phase);
-                        })
-                        .w_full()
-                        .h_6()
-                        .bg(color_4)
-                        .focus(|style| style.bg(color_5))
-                        .in_focus(|style| style.bg(color_6))
-                        .on_focus(|_, _, _| println!("Child 1 focused"))
-                        .on_blur(|_, _, _| println!("Child 1 blurred"))
-                        .on_focus_in(|_, _, _| println!("Child 1 focus_in"))
-                        .on_focus_out(|_, _, _| println!("Child 1 focus_out"))
-                        .on_key_down(|_, event, phase, _| {
-                            println!("Key down on child 1 {:?} {:?}", phase, event)
-                        })
-                        .on_key_up(|_, event, phase, _| {
-                            println!("Key up on child 1 {:?} {:?}", phase, event)
-                        })
-                        .child("Child 1"),
-                )
-                .child(
-                    div()
-                        .track_focus(&child_2)
-                        .context("child-2")
-                        .on_action(|_, action: &ActionC, phase, cx| {
-                            println!("Action C dispatched on child 2 during {:?}", phase);
-                        })
-                        .w_full()
-                        .h_6()
-                        .bg(color_4)
-                        .on_focus(|_, _, _| println!("Child 2 focused"))
-                        .on_blur(|_, _, _| println!("Child 2 blurred"))
-                        .on_focus_in(|_, _, _| println!("Child 2 focus_in"))
-                        .on_focus_out(|_, _, _| println!("Child 2 focus_out"))
-                        .on_key_down(|_, event, phase, _| {
-                            println!("Key down on child 2 {:?} {:?}", phase, event)
-                        })
-                        .on_key_up(|_, event, phase, _| {
-                            println!("Key up on child 2 {:?} {:?}", phase, event)
-                        })
-                        .child("Child 2"),
-                )
-        })
+
+        cx.build_view(
+            |_| (),
+            move |_, cx| {
+                div()
+                    .id("parent")
+                    .focusable()
+                    .context("parent")
+                    .on_action(|_, action: &ActionA, phase, cx| {
+                        println!("Action A dispatched on parent during {:?}", phase);
+                    })
+                    .on_action(|_, action: &ActionB, phase, cx| {
+                        println!("Action B dispatched on parent during {:?}", phase);
+                    })
+                    .on_focus(|_, _, _| println!("Parent focused"))
+                    .on_blur(|_, _, _| println!("Parent blurred"))
+                    .on_focus_in(|_, _, _| println!("Parent focus_in"))
+                    .on_focus_out(|_, _, _| println!("Parent focus_out"))
+                    .on_key_down(|_, event, phase, _| {
+                        println!("Key down on parent {:?} {:?}", phase, event)
+                    })
+                    .on_key_up(|_, event, phase, _| {
+                        println!("Key up on parent {:?} {:?}", phase, event)
+                    })
+                    .size_full()
+                    .bg(color_1)
+                    .focus(|style| style.bg(color_2))
+                    .focus_in(|style| style.bg(color_3))
+                    .child(
+                        div()
+                            .track_focus(&child_1)
+                            .context("child-1")
+                            .on_action(|_, action: &ActionB, phase, cx| {
+                                println!("Action B dispatched on child 1 during {:?}", phase);
+                            })
+                            .w_full()
+                            .h_6()
+                            .bg(color_4)
+                            .focus(|style| style.bg(color_5))
+                            .in_focus(|style| style.bg(color_6))
+                            .on_focus(|_, _, _| println!("Child 1 focused"))
+                            .on_blur(|_, _, _| println!("Child 1 blurred"))
+                            .on_focus_in(|_, _, _| println!("Child 1 focus_in"))
+                            .on_focus_out(|_, _, _| println!("Child 1 focus_out"))
+                            .on_key_down(|_, event, phase, _| {
+                                println!("Key down on child 1 {:?} {:?}", phase, event)
+                            })
+                            .on_key_up(|_, event, phase, _| {
+                                println!("Key up on child 1 {:?} {:?}", phase, event)
+                            })
+                            .child("Child 1"),
+                    )
+                    .child(
+                        div()
+                            .track_focus(&child_2)
+                            .context("child-2")
+                            .on_action(|_, action: &ActionC, phase, cx| {
+                                println!("Action C dispatched on child 2 during {:?}", phase);
+                            })
+                            .w_full()
+                            .h_6()
+                            .bg(color_4)
+                            .on_focus(|_, _, _| println!("Child 2 focused"))
+                            .on_blur(|_, _, _| println!("Child 2 blurred"))
+                            .on_focus_in(|_, _, _| println!("Child 2 focus_in"))
+                            .on_focus_out(|_, _, _| println!("Child 2 focus_out"))
+                            .on_key_down(|_, event, phase, _| {
+                                println!("Key down on child 2 {:?} {:?}", phase, event)
+                            })
+                            .on_key_up(|_, event, phase, _| {
+                                println!("Key up on child 2 {:?} {:?}", phase, event)
+                            })
+                            .child("Child 2"),
+                    )
+            },
+        )
     }
 }

crates/storybook2/src/stories/kitchen_sink.rs 🔗

@@ -1,4 +1,4 @@
-use gpui2::{view, Context, View};
+use gpui2::{AppContext, Context, View};
 use strum::IntoEnumIterator;
 use ui::prelude::*;
 
@@ -12,8 +12,12 @@ impl KitchenSinkStory {
         Self {}
     }
 
-    pub fn view(cx: &mut WindowContext) -> View<Self> {
-        view(cx.entity(|cx| Self::new()), Self::render)
+    pub fn view(cx: &mut AppContext) -> View<Self> {
+        {
+            let state = cx.entity(|cx| Self::new());
+            let render = Self::render;
+            View::for_handle(state, render)
+        }
     }
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Component<Self> {

crates/storybook2/src/stories/scroll.rs 🔗

@@ -1,6 +1,6 @@
 use crate::themes::rose_pine;
 use gpui2::{
-    div, px, view, Component, Context, ParentElement, SharedString, Styled, View, WindowContext,
+    div, px, Component, ParentElement, SharedString, Styled, View, VisualContext, WindowContext,
 };
 
 pub struct ScrollStory {
@@ -11,7 +11,9 @@ impl ScrollStory {
     pub fn view(cx: &mut WindowContext) -> View<()> {
         let theme = rose_pine();
 
-        view(cx.entity(|cx| ()), move |_, cx| checkerboard(1))
+        {
+            cx.build_view(|cx| (), move |_, cx| checkerboard(1))
+        }
     }
 }
 

crates/storybook2/src/stories/text.rs 🔗

@@ -1,4 +1,4 @@
-use gpui2::{div, view, white, Context, ParentElement, Styled, View, WindowContext};
+use gpui2::{div, white, ParentElement, Styled, View, VisualContext, WindowContext};
 
 pub struct TextStory {
     text: View<()>,
@@ -6,7 +6,7 @@ pub struct TextStory {
 
 impl TextStory {
     pub fn view(cx: &mut WindowContext) -> View<()> {
-        view(cx.entity(|cx| ()), |_, cx| {
+        cx.build_view(|cx| (), |_, cx| {
             div()
                 .size_full()
                 .bg(white())

crates/storybook2/src/story_selector.rs 🔗

@@ -5,7 +5,7 @@ use crate::stories::*;
 use anyhow::anyhow;
 use clap::builder::PossibleValue;
 use clap::ValueEnum;
-use gpui2::{view, AnyView, Context};
+use gpui2::{AnyView, VisualContext};
 use strum::{EnumIter, EnumString, IntoEnumIterator};
 use ui::prelude::*;
 
@@ -27,16 +27,18 @@ pub enum ElementStory {
 impl ElementStory {
     pub fn story(&self, cx: &mut WindowContext) -> AnyView {
         match self {
-            Self::Avatar => view(cx.entity(|cx| ()), |_, _| ui::AvatarStory.render()).into_any(),
-            Self::Button => view(cx.entity(|cx| ()), |_, _| ui::ButtonStory.render()).into_any(),
-            Self::Details => view(cx.entity(|cx| ()), |_, _| ui::DetailsStory.render()).into_any(),
+            Self::Avatar => { cx.build_view(|cx| (), |_, _| ui::AvatarStory.render()) }.into_any(),
+            Self::Button => { cx.build_view(|cx| (), |_, _| ui::ButtonStory.render()) }.into_any(),
+            Self::Details => {
+                { cx.build_view(|cx| (), |_, _| ui::DetailsStory.render()) }.into_any()
+            }
             Self::Focus => FocusStory::view(cx).into_any(),
-            Self::Icon => view(cx.entity(|cx| ()), |_, _| ui::IconStory.render()).into_any(),
-            Self::Input => view(cx.entity(|cx| ()), |_, _| ui::InputStory.render()).into_any(),
-            Self::Label => view(cx.entity(|cx| ()), |_, _| ui::LabelStory.render()).into_any(),
+            Self::Icon => { cx.build_view(|cx| (), |_, _| ui::IconStory.render()) }.into_any(),
+            Self::Input => { cx.build_view(|cx| (), |_, _| ui::InputStory.render()) }.into_any(),
+            Self::Label => { cx.build_view(|cx| (), |_, _| ui::LabelStory.render()) }.into_any(),
             Self::Scroll => ScrollStory::view(cx).into_any(),
             Self::Text => TextStory::view(cx).into_any(),
-            Self::ZIndex => view(cx.entity(|cx| ()), |_, _| ZIndexStory.render()).into_any(),
+            Self::ZIndex => { cx.build_view(|cx| (), |_, _| ZIndexStory.render()) }.into_any(),
         }
     }
 }
@@ -76,65 +78,67 @@ impl ComponentStory {
     pub fn story(&self, cx: &mut WindowContext) -> AnyView {
         match self {
             Self::AssistantPanel => {
-                view(cx.entity(|cx| ()), |_, _| ui::AssistantPanelStory.render()).into_any()
+                { cx.build_view(|cx| (), |_, _| ui::AssistantPanelStory.render()) }.into_any()
             }
-            Self::Buffer => view(cx.entity(|cx| ()), |_, _| ui::BufferStory.render()).into_any(),
+            Self::Buffer => { cx.build_view(|cx| (), |_, _| ui::BufferStory.render()) }.into_any(),
             Self::Breadcrumb => {
-                view(cx.entity(|cx| ()), |_, _| ui::BreadcrumbStory.render()).into_any()
+                { cx.build_view(|cx| (), |_, _| ui::BreadcrumbStory.render()) }.into_any()
             }
             Self::ChatPanel => {
-                view(cx.entity(|cx| ()), |_, _| ui::ChatPanelStory.render()).into_any()
+                { cx.build_view(|cx| (), |_, _| ui::ChatPanelStory.render()) }.into_any()
             }
             Self::CollabPanel => {
-                view(cx.entity(|cx| ()), |_, _| ui::CollabPanelStory.render()).into_any()
+                { cx.build_view(|cx| (), |_, _| ui::CollabPanelStory.render()) }.into_any()
             }
             Self::CommandPalette => {
-                view(cx.entity(|cx| ()), |_, _| ui::CommandPaletteStory.render()).into_any()
+                { cx.build_view(|cx| (), |_, _| ui::CommandPaletteStory.render()) }.into_any()
             }
             Self::ContextMenu => {
-                view(cx.entity(|cx| ()), |_, _| ui::ContextMenuStory.render()).into_any()
+                { cx.build_view(|cx| (), |_, _| ui::ContextMenuStory.render()) }.into_any()
             }
             Self::Facepile => {
-                view(cx.entity(|cx| ()), |_, _| ui::FacepileStory.render()).into_any()
+                { cx.build_view(|cx| (), |_, _| ui::FacepileStory.render()) }.into_any()
             }
             Self::Keybinding => {
-                view(cx.entity(|cx| ()), |_, _| ui::KeybindingStory.render()).into_any()
+                { cx.build_view(|cx| (), |_, _| ui::KeybindingStory.render()) }.into_any()
+            }
+            Self::LanguageSelector => {
+                { cx.build_view(|cx| (), |_, _| ui::LanguageSelectorStory.render()) }.into_any()
             }
-            Self::LanguageSelector => view(cx.entity(|cx| ()), |_, _| {
-                ui::LanguageSelectorStory.render()
-            })
-            .into_any(),
             Self::MultiBuffer => {
-                view(cx.entity(|cx| ()), |_, _| ui::MultiBufferStory.render()).into_any()
-            }
-            Self::NotificationsPanel => view(cx.entity(|cx| ()), |_, _| {
-                ui::NotificationsPanelStory.render()
-            })
-            .into_any(),
-            Self::Palette => view(cx.entity(|cx| ()), |_, _| ui::PaletteStory.render()).into_any(),
-            Self::Panel => view(cx.entity(|cx| ()), |_, _| ui::PanelStory.render()).into_any(),
+                { cx.build_view(|cx| (), |_, _| ui::MultiBufferStory.render()) }.into_any()
+            }
+            Self::NotificationsPanel => {
+                { cx.build_view(|cx| (), |_, _| ui::NotificationsPanelStory.render()) }.into_any()
+            }
+            Self::Palette => {
+                { cx.build_view(|cx| (), |_, _| ui::PaletteStory.render()) }.into_any()
+            }
+            Self::Panel => { cx.build_view(|cx| (), |_, _| ui::PanelStory.render()) }.into_any(),
             Self::ProjectPanel => {
-                view(cx.entity(|cx| ()), |_, _| ui::ProjectPanelStory.render()).into_any()
+                { cx.build_view(|cx| (), |_, _| ui::ProjectPanelStory.render()) }.into_any()
             }
             Self::RecentProjects => {
-                view(cx.entity(|cx| ()), |_, _| ui::RecentProjectsStory.render()).into_any()
+                { cx.build_view(|cx| (), |_, _| ui::RecentProjectsStory.render()) }.into_any()
             }
-            Self::Tab => view(cx.entity(|cx| ()), |_, _| ui::TabStory.render()).into_any(),
-            Self::TabBar => view(cx.entity(|cx| ()), |_, _| ui::TabBarStory.render()).into_any(),
+            Self::Tab => { cx.build_view(|cx| (), |_, _| ui::TabStory.render()) }.into_any(),
+            Self::TabBar => { cx.build_view(|cx| (), |_, _| ui::TabBarStory.render()) }.into_any(),
             Self::Terminal => {
-                view(cx.entity(|cx| ()), |_, _| ui::TerminalStory.render()).into_any()
+                { cx.build_view(|cx| (), |_, _| ui::TerminalStory.render()) }.into_any()
             }
             Self::ThemeSelector => {
-                view(cx.entity(|cx| ()), |_, _| ui::ThemeSelectorStory.render()).into_any()
+                { cx.build_view(|cx| (), |_, _| ui::ThemeSelectorStory.render()) }.into_any()
             }
             Self::TitleBar => ui::TitleBarStory::view(cx).into_any(),
-            Self::Toast => view(cx.entity(|cx| ()), |_, _| ui::ToastStory.render()).into_any(),
-            Self::Toolbar => view(cx.entity(|cx| ()), |_, _| ui::ToolbarStory.render()).into_any(),
+            Self::Toast => { cx.build_view(|cx| (), |_, _| ui::ToastStory.render()) }.into_any(),
+            Self::Toolbar => {
+                { cx.build_view(|cx| (), |_, _| ui::ToolbarStory.render()) }.into_any()
+            }
             Self::TrafficLights => {
-                view(cx.entity(|cx| ()), |_, _| ui::TrafficLightsStory.render()).into_any()
+                { cx.build_view(|cx| (), |_, _| ui::TrafficLightsStory.render()) }.into_any()
             }
             Self::Copilot => {
-                view(cx.entity(|cx| ()), |_, _| ui::CopilotModalStory.render()).into_any()
+                { cx.build_view(|cx| (), |_, _| ui::CopilotModalStory.render()) }.into_any()
             }
             Self::Workspace => ui::WorkspaceStory::view(cx).into_any(),
         }

crates/storybook2/src/storybook2.rs 🔗

@@ -10,7 +10,7 @@ use std::sync::Arc;
 
 use clap::Parser;
 use gpui2::{
-    div, px, size, view, AnyView, AppContext, Bounds, Context, ViewContext, WindowBounds,
+    div, px, size, AnyView, AppContext, Bounds, ViewContext, VisualContext, WindowBounds,
     WindowOptions,
 };
 use log::LevelFilter;
@@ -85,8 +85,8 @@ fn main() {
                 ..Default::default()
             },
             move |cx| {
-                view(
-                    cx.entity(|cx| StoryWrapper::new(selector.story(cx), theme)),
+                cx.build_view(
+                    |cx| StoryWrapper::new(selector.story(cx), theme),
                     StoryWrapper::render,
                 )
             },

crates/ui2/src/components/buffer_search.rs 🔗

@@ -1,4 +1,4 @@
-use gpui2::{view, Context, View};
+use gpui2::{AppContext, Context, View};
 
 use crate::prelude::*;
 use crate::{h_stack, Icon, IconButton, IconColor, Input};
@@ -21,8 +21,12 @@ impl BufferSearch {
         cx.notify();
     }
 
-    pub fn view(cx: &mut WindowContext) -> View<Self> {
-        view(cx.entity(|cx| Self::new()), Self::render)
+    pub fn view(cx: &mut AppContext) -> View<Self> {
+        {
+            let state = cx.entity(|cx| Self::new());
+            let render = Self::render;
+            View::for_handle(state, render)
+        }
     }
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Component<Self> {

crates/ui2/src/components/editor_pane.rs 🔗

@@ -1,6 +1,6 @@
 use std::path::PathBuf;
 
-use gpui2::{view, Context, View};
+use gpui2::{AppContext, Context, View};
 
 use crate::prelude::*;
 use crate::{
@@ -20,7 +20,7 @@ pub struct EditorPane {
 
 impl EditorPane {
     pub fn new(
-        cx: &mut WindowContext,
+        cx: &mut AppContext,
         tabs: Vec<Tab>,
         path: PathBuf,
         symbols: Vec<Symbol>,
@@ -42,11 +42,12 @@ impl EditorPane {
         cx.notify();
     }
 
-    pub fn view(cx: &mut WindowContext) -> View<Self> {
-        view(
-            cx.entity(|cx| hello_world_rust_editor_with_status_example(cx)),
-            Self::render,
-        )
+    pub fn view(cx: &mut AppContext) -> View<Self> {
+        {
+            let state = cx.entity(|cx| hello_world_rust_editor_with_status_example(cx));
+            let render = Self::render;
+            View::for_handle(state, render)
+        }
     }
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Component<Self> {

crates/ui2/src/components/title_bar.rs 🔗

@@ -1,7 +1,7 @@
 use std::sync::atomic::AtomicBool;
 use std::sync::Arc;
 
-use gpui2::{view, Context, View};
+use gpui2::{AppContext, Context, ModelContext, View};
 
 use crate::prelude::*;
 use crate::settings::user_settings;
@@ -28,7 +28,7 @@ pub struct TitleBar {
 }
 
 impl TitleBar {
-    pub fn new(cx: &mut ViewContext<Self>) -> Self {
+    pub fn new(cx: &mut ModelContext<Self>) -> Self {
         let is_active = Arc::new(AtomicBool::new(true));
         let active = is_active.clone();
 
@@ -80,11 +80,12 @@ impl TitleBar {
         cx.notify();
     }
 
-    pub fn view(cx: &mut WindowContext, livestream: Option<Livestream>) -> View<Self> {
-        view(
-            cx.entity(|cx| Self::new(cx).set_livestream(livestream)),
-            Self::render,
-        )
+    pub fn view(cx: &mut AppContext, livestream: Option<Livestream>) -> View<Self> {
+        {
+            let state = cx.entity(|cx| Self::new(cx).set_livestream(livestream));
+            let render = Self::render;
+            View::for_handle(state, render)
+        }
     }
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Component<Self> {
@@ -195,13 +196,14 @@ mod stories {
     }
 
     impl TitleBarStory {
-        pub fn view(cx: &mut WindowContext) -> View<Self> {
-            view(
-                cx.entity(|cx| Self {
+        pub fn view(cx: &mut AppContext) -> View<Self> {
+            {
+                let state = cx.entity(|cx| Self {
                     title_bar: TitleBar::view(cx, None),
-                }),
-                Self::render,
-            )
+                });
+                let render = Self::render;
+                View::for_handle(state, render)
+            }
         }
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Component<Self> {

crates/ui2/src/components/workspace.rs 🔗

@@ -1,7 +1,7 @@
 use std::sync::Arc;
 
 use chrono::DateTime;
-use gpui2::{px, relative, rems, view, Context, Size, View};
+use gpui2::{px, relative, rems, AppContext, Context, Size, View};
 
 use crate::{
     old_theme, static_livestream, user_settings_mut, v_stack, AssistantPanel, Button, ChatMessage,
@@ -44,7 +44,7 @@ pub struct Workspace {
 }
 
 impl Workspace {
-    pub fn new(cx: &mut ViewContext<Self>) -> Self {
+    pub fn new(cx: &mut AppContext) -> Self {
         Self {
             title_bar: TitleBar::view(cx, None),
             editor_1: EditorPane::view(cx),
@@ -170,8 +170,12 @@ impl Workspace {
         cx.notify();
     }
 
-    pub fn view(cx: &mut WindowContext) -> View<Self> {
-        view(cx.entity(|cx| Self::new(cx)), Self::render)
+    pub fn view(cx: &mut AppContext) -> View<Self> {
+        {
+            let state = cx.entity(|cx| Self::new(cx));
+            let render = Self::render;
+            View::for_handle(state, render)
+        }
     }
 
     pub fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Component<Self> {
@@ -351,6 +355,8 @@ pub use stories::*;
 
 #[cfg(feature = "stories")]
 mod stories {
+    use gpui2::VisualContext;
+
     use super::*;
 
     pub struct WorkspaceStory {
@@ -359,10 +365,10 @@ mod stories {
 
     impl WorkspaceStory {
         pub fn view(cx: &mut WindowContext) -> View<Self> {
-            view(
-                cx.entity(|cx| Self {
+            cx.build_view(
+                |cx| Self {
                     workspace: Workspace::view(cx),
-                }),
+                },
                 |view, cx| view.workspace.clone(),
             )
         }

crates/ui2/src/static_data.rs 🔗

@@ -1,7 +1,7 @@
 use std::path::PathBuf;
 use std::str::FromStr;
 
-use gpui2::WindowContext;
+use gpui2::{AppContext, WindowContext};
 use rand::Rng;
 use theme2::Theme;
 
@@ -781,7 +781,7 @@ pub fn hello_world_rust_buffer_rows(theme: &Theme) -> Vec<BufferRow> {
     ]
 }
 
-pub fn hello_world_rust_editor_with_status_example(cx: &mut WindowContext) -> EditorPane {
+pub fn hello_world_rust_editor_with_status_example(cx: &mut AppContext) -> EditorPane {
     let theme = theme(cx);
 
     EditorPane::new(

crates/ui2/src/theme.rs 🔗

@@ -1,6 +1,6 @@
 use gpui2::{
-    AnyElement, Bounds, Component, Element, Hsla, LayoutId, Pixels, Result, ViewContext,
-    WindowContext,
+    AnyElement, AppContext, Bounds, Component, Element, Hsla, LayoutId, Pixels, Result,
+    ViewContext, WindowContext,
 };
 use serde::{de::Visitor, Deserialize, Deserializer};
 use std::collections::HashMap;
@@ -220,6 +220,6 @@ pub fn old_theme(cx: &WindowContext) -> Arc<Theme> {
     Arc::new(cx.global::<Theme>().clone())
 }
 
-pub fn theme(cx: &WindowContext) -> Arc<theme2::Theme> {
+pub fn theme(cx: &AppContext) -> Arc<theme2::Theme> {
     theme2::active_theme(cx).clone()
 }