Remove lock from element states

Antonio Scandurra and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

gpui/examples/text.rs                    |   2 
gpui/src/app.rs                          | 156 ++++++++++++++-----------
gpui/src/elements/list.rs                |   2 
gpui/src/elements/mouse_event_handler.rs |  18 +-
gpui/src/presenter.rs                    |  15 ++
server/src/rpc.rs                        |   2 
zed/src/chat_panel.rs                    |   6 
zed/src/editor.rs                        |   2 
zed/src/file_finder.rs                   |   2 
zed/src/project_browser.rs               |   2 
zed/src/theme_selector.rs                |   4 
zed/src/workspace.rs                     |   2 
zed/src/workspace/pane.rs                |  13 +-
zed/src/workspace/sidebar.rs             |  21 ++-
14 files changed, 143 insertions(+), 104 deletions(-)

Detailed changes

gpui/examples/text.rs 🔗

@@ -28,7 +28,7 @@ impl gpui::View for TextView {
         "View"
     }
 
-    fn render(&self, _: &gpui::RenderContext<Self>) -> gpui::ElementBox {
+    fn render(&self, _: &mut gpui::RenderContext<Self>) -> gpui::ElementBox {
         TextElement.boxed()
     }
 }

gpui/src/app.rs 🔗

@@ -5,13 +5,12 @@ use crate::{
     platform::{self, Platform, PromptLevel, WindowOptions},
     presenter::Presenter,
     util::{post_inc, timeout},
-    AssetCache, AssetSource, ClipboardItem, EventContext, FontCache, PathPromptOptions,
-    TextLayoutCache,
+    AssetCache, AssetSource, ClipboardItem, FontCache, PathPromptOptions, TextLayoutCache,
 };
 use anyhow::{anyhow, Result};
 use async_task::Task;
 use keymap::MatchResult;
-use parking_lot::{Mutex, RwLock};
+use parking_lot::Mutex;
 use platform::Event;
 use postage::{mpsc, sink::Sink as _, stream::Stream as _};
 use smol::prelude::*;
@@ -38,7 +37,7 @@ pub trait Entity: 'static {
 
 pub trait View: Entity + Sized {
     fn ui_name() -> &'static str;
-    fn render(&self, cx: &RenderContext<'_, Self>) -> ElementBox;
+    fn render(&self, cx: &mut RenderContext<'_, Self>) -> ElementBox;
     fn on_focus(&mut self, _: &mut ViewContext<Self>) {}
     fn on_blur(&mut self, _: &mut ViewContext<Self>) {}
     fn keymap_context(&self, _: &AppContext) -> keymap::Context {
@@ -681,7 +680,7 @@ impl MutableAppContext {
                 models: Default::default(),
                 views: Default::default(),
                 windows: Default::default(),
-                values: Default::default(),
+                element_states: Default::default(),
                 ref_counts: Arc::new(Mutex::new(RefCounts::default())),
                 background,
                 font_cache,
@@ -1308,11 +1307,26 @@ impl MutableAppContext {
         handle
     }
 
+    pub fn element_state<Tag: 'static, T: 'static + Default>(
+        &mut self,
+        id: usize,
+    ) -> ElementStateHandle<T> {
+        let key = (TypeId::of::<Tag>(), id);
+        self.cx
+            .element_states
+            .entry(key)
+            .or_insert_with(|| Box::new(T::default()));
+        ElementStateHandle::new(TypeId::of::<Tag>(), id, &self.cx.ref_counts)
+    }
+
     fn remove_dropped_entities(&mut self) {
         loop {
-            let (dropped_models, dropped_views, dropped_values) =
+            let (dropped_models, dropped_views, dropped_element_states) =
                 self.cx.ref_counts.lock().take_dropped();
-            if dropped_models.is_empty() && dropped_views.is_empty() && dropped_values.is_empty() {
+            if dropped_models.is_empty()
+                && dropped_views.is_empty()
+                && dropped_element_states.is_empty()
+            {
                 break;
             }
 
@@ -1346,9 +1360,8 @@ impl MutableAppContext {
                 }
             }
 
-            let mut values = self.cx.values.write();
-            for key in dropped_values {
-                values.remove(&key);
+            for key in dropped_element_states {
+                self.cx.element_states.remove(&key);
             }
         }
     }
@@ -1667,7 +1680,7 @@ pub struct AppContext {
     models: HashMap<usize, Box<dyn AnyModel>>,
     views: HashMap<(usize, usize), Box<dyn AnyView>>,
     windows: HashMap<usize, Window>,
-    values: RwLock<HashMap<(TypeId, usize), Box<dyn Any>>>,
+    element_states: HashMap<(TypeId, usize), Box<dyn Any>>,
     background: Arc<executor::Background>,
     ref_counts: Arc<Mutex<RefCounts>>,
     font_cache: Arc<FontCache>,
@@ -1698,15 +1711,6 @@ impl AppContext {
     pub fn platform(&self) -> &Arc<dyn Platform> {
         &self.platform
     }
-
-    pub fn value<Tag: 'static, T: 'static + Default>(&self, id: usize) -> ValueHandle<T> {
-        let key = (TypeId::of::<Tag>(), id);
-        self.values
-            .write()
-            .entry(key)
-            .or_insert_with(|| Box::new(T::default()));
-        ValueHandle::new(TypeId::of::<Tag>(), id, &self.ref_counts)
-    }
 }
 
 impl ReadModel for AppContext {
@@ -1875,7 +1879,7 @@ where
     ) -> ElementBox {
         View::render(
             self,
-            &RenderContext {
+            &mut RenderContext {
                 window_id,
                 view_id,
                 app: cx,
@@ -2269,10 +2273,16 @@ impl AsRef<AppContext> for &AppContext {
 }
 
 impl<V: View> Deref for RenderContext<'_, V> {
-    type Target = AppContext;
+    type Target = MutableAppContext;
 
     fn deref(&self) -> &Self::Target {
-        &self.app
+        self.app
+    }
+}
+
+impl<V: View> DerefMut for RenderContext<'_, V> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        self.app
     }
 }
 
@@ -2964,16 +2974,16 @@ impl<T> Clone for WeakViewHandle<T> {
     }
 }
 
-pub struct ValueHandle<T> {
+pub struct ElementStateHandle<T> {
     value_type: PhantomData<T>,
     tag_type_id: TypeId,
     id: usize,
     ref_counts: Weak<Mutex<RefCounts>>,
 }
 
-impl<T: 'static> ValueHandle<T> {
+impl<T: 'static> ElementStateHandle<T> {
     fn new(tag_type_id: TypeId, id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
-        ref_counts.lock().inc_value(tag_type_id, id);
+        ref_counts.lock().inc_element_state(tag_type_id, id);
         Self {
             value_type: PhantomData,
             tag_type_id,
@@ -2982,41 +2992,39 @@ impl<T: 'static> ValueHandle<T> {
         }
     }
 
-    pub fn read<R>(&self, cx: &AppContext, f: impl FnOnce(&T) -> R) -> R {
-        f(cx.values
-            .read()
+    pub fn read<'a>(&self, cx: &'a AppContext) -> &'a T {
+        cx.element_states
             .get(&(self.tag_type_id, self.id))
             .unwrap()
             .downcast_ref()
-            .unwrap())
+            .unwrap()
     }
 
-    pub fn update<R>(
-        &self,
-        cx: &mut EventContext,
-        f: impl FnOnce(&mut T, &mut EventContext) -> R,
-    ) -> R {
-        let mut value = cx
-            .app
+    pub fn update<C, R>(&self, cx: &mut C, f: impl FnOnce(&mut T, &mut C) -> R) -> R
+    where
+        C: DerefMut<Target = MutableAppContext>,
+    {
+        let mut element_state = cx
+            .deref_mut()
             .cx
-            .values
-            .write()
+            .element_states
             .remove(&(self.tag_type_id, self.id))
             .unwrap();
-        let result = f(value.downcast_mut().unwrap(), cx);
-        cx.app
+        let result = f(element_state.downcast_mut().unwrap(), cx);
+        cx.deref_mut()
             .cx
-            .values
-            .write()
-            .insert((self.tag_type_id, self.id), value);
+            .element_states
+            .insert((self.tag_type_id, self.id), element_state);
         result
     }
 }
 
-impl<T> Drop for ValueHandle<T> {
+impl<T> Drop for ElementStateHandle<T> {
     fn drop(&mut self) {
         if let Some(ref_counts) = self.ref_counts.upgrade() {
-            ref_counts.lock().dec_value(self.tag_type_id, self.id);
+            ref_counts
+                .lock()
+                .dec_element_state(self.tag_type_id, self.id);
         }
     }
 }
@@ -3080,10 +3088,10 @@ impl Drop for Subscription {
 #[derive(Default)]
 struct RefCounts {
     entity_counts: HashMap<usize, usize>,
-    value_counts: HashMap<(TypeId, usize), usize>,
+    element_state_counts: HashMap<(TypeId, usize), usize>,
     dropped_models: HashSet<usize>,
     dropped_views: HashSet<(usize, usize)>,
-    dropped_values: HashSet<(TypeId, usize)>,
+    dropped_element_states: HashSet<(TypeId, usize)>,
 }
 
 impl RefCounts {
@@ -3107,8 +3115,11 @@ impl RefCounts {
         }
     }
 
-    fn inc_value(&mut self, tag_type_id: TypeId, id: usize) {
-        *self.value_counts.entry((tag_type_id, id)).or_insert(0) += 1;
+    fn inc_element_state(&mut self, tag_type_id: TypeId, id: usize) {
+        *self
+            .element_state_counts
+            .entry((tag_type_id, id))
+            .or_insert(0) += 1;
     }
 
     fn dec_model(&mut self, model_id: usize) {
@@ -3129,13 +3140,13 @@ impl RefCounts {
         }
     }
 
-    fn dec_value(&mut self, tag_type_id: TypeId, id: usize) {
+    fn dec_element_state(&mut self, tag_type_id: TypeId, id: usize) {
         let key = (tag_type_id, id);
-        let count = self.value_counts.get_mut(&key).unwrap();
+        let count = self.element_state_counts.get_mut(&key).unwrap();
         *count -= 1;
         if *count == 0 {
-            self.value_counts.remove(&key);
-            self.dropped_values.insert(key);
+            self.element_state_counts.remove(&key);
+            self.dropped_element_states.insert(key);
         }
     }
 
@@ -3152,11 +3163,14 @@ impl RefCounts {
     ) {
         let mut dropped_models = HashSet::new();
         let mut dropped_views = HashSet::new();
-        let mut dropped_values = HashSet::new();
+        let mut dropped_element_states = HashSet::new();
         std::mem::swap(&mut self.dropped_models, &mut dropped_models);
         std::mem::swap(&mut self.dropped_views, &mut dropped_views);
-        std::mem::swap(&mut self.dropped_values, &mut dropped_values);
-        (dropped_models, dropped_views, dropped_values)
+        std::mem::swap(
+            &mut self.dropped_element_states,
+            &mut dropped_element_states,
+        );
+        (dropped_models, dropped_views, dropped_element_states)
     }
 }
 
@@ -3314,7 +3328,7 @@ mod tests {
         }
 
         impl super::View for View {
-            fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
+            fn render<'a>(&self, _: &mut RenderContext<Self>) -> ElementBox {
                 Empty::new().boxed()
             }
 
@@ -3378,7 +3392,7 @@ mod tests {
         }
 
         impl super::View for View {
-            fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
+            fn render<'a>(&self, _: &mut RenderContext<Self>) -> ElementBox {
                 let mouse_down_count = self.mouse_down_count.clone();
                 EventHandler::new(Empty::new().boxed())
                     .on_mouse_down(move |_| {
@@ -3440,7 +3454,7 @@ mod tests {
                 "View"
             }
 
-            fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
+            fn render<'a>(&self, _: &mut RenderContext<Self>) -> ElementBox {
                 Empty::new().boxed()
             }
         }
@@ -3480,7 +3494,7 @@ mod tests {
         }
 
         impl super::View for View {
-            fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
+            fn render<'a>(&self, _: &mut RenderContext<Self>) -> ElementBox {
                 Empty::new().boxed()
             }
 
@@ -3536,7 +3550,7 @@ mod tests {
         }
 
         impl super::View for View {
-            fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
+            fn render<'a>(&self, _: &mut RenderContext<Self>) -> ElementBox {
                 Empty::new().boxed()
             }
 
@@ -3586,7 +3600,7 @@ mod tests {
         }
 
         impl super::View for View {
-            fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
+            fn render<'a>(&self, _: &mut RenderContext<Self>) -> ElementBox {
                 Empty::new().boxed()
             }
 
@@ -3630,7 +3644,7 @@ mod tests {
         }
 
         impl super::View for View {
-            fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
+            fn render<'a>(&self, _: &mut RenderContext<Self>) -> ElementBox {
                 Empty::new().boxed()
             }
 
@@ -3677,7 +3691,7 @@ mod tests {
         }
 
         impl super::View for View {
-            fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
+            fn render<'a>(&self, _: &mut RenderContext<Self>) -> ElementBox {
                 Empty::new().boxed()
             }
 
@@ -3735,7 +3749,7 @@ mod tests {
         }
 
         impl View for ViewA {
-            fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
+            fn render<'a>(&self, _: &mut RenderContext<Self>) -> ElementBox {
                 Empty::new().boxed()
             }
 
@@ -3753,7 +3767,7 @@ mod tests {
         }
 
         impl View for ViewB {
-            fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
+            fn render<'a>(&self, _: &mut RenderContext<Self>) -> ElementBox {
                 Empty::new().boxed()
             }
 
@@ -3849,7 +3863,7 @@ mod tests {
         }
 
         impl super::View for View {
-            fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
+            fn render<'a>(&self, _: &mut RenderContext<Self>) -> ElementBox {
                 Empty::new().boxed()
             }
 
@@ -3984,7 +3998,7 @@ mod tests {
                 "test view"
             }
 
-            fn render(&self, _: &RenderContext<Self>) -> ElementBox {
+            fn render(&self, _: &mut RenderContext<Self>) -> ElementBox {
                 Empty::new().boxed()
             }
         }
@@ -4029,7 +4043,7 @@ mod tests {
                 "test view"
             }
 
-            fn render(&self, _: &RenderContext<Self>) -> ElementBox {
+            fn render(&self, _: &mut RenderContext<Self>) -> ElementBox {
                 Empty::new().boxed()
             }
         }
@@ -4052,7 +4066,7 @@ mod tests {
                 "test view"
             }
 
-            fn render(&self, _: &RenderContext<Self>) -> ElementBox {
+            fn render(&self, _: &mut RenderContext<Self>) -> ElementBox {
                 Empty::new().boxed()
             }
         }

gpui/src/elements/list.rs 🔗

@@ -496,7 +496,7 @@ mod tests {
             "TestView"
         }
 
-        fn render(&self, _: &RenderContext<'_, Self>) -> ElementBox {
+        fn render(&self, _: &mut RenderContext<'_, Self>) -> ElementBox {
             unimplemented!()
         }
     }

gpui/src/elements/mouse_event_handler.rs 🔗

@@ -1,12 +1,14 @@
+use std::ops::DerefMut;
+
 use crate::{
     geometry::{rect::RectF, vector::Vector2F},
-    AppContext, DebugContext, Element, ElementBox, Event, EventContext, LayoutContext,
-    PaintContext, SizeConstraint, ValueHandle,
+    DebugContext, Element, ElementBox, ElementStateHandle, Event, EventContext, LayoutContext,
+    MutableAppContext, PaintContext, SizeConstraint,
 };
 use serde_json::json;
 
 pub struct MouseEventHandler {
-    state: ValueHandle<MouseState>,
+    state: ElementStateHandle<MouseState>,
     child: ElementBox,
     click_handler: Option<Box<dyn FnMut(&mut EventContext)>>,
     drag_handler: Option<Box<dyn FnMut(Vector2F, &mut EventContext)>>,
@@ -20,14 +22,14 @@ pub struct MouseState {
 }
 
 impl MouseEventHandler {
-    pub fn new<Tag, F>(id: usize, cx: &AppContext, render_child: F) -> Self
+    pub fn new<Tag, F, C>(id: usize, cx: &mut C, render_child: F) -> Self
     where
         Tag: 'static,
-        F: FnOnce(MouseState) -> ElementBox,
+        F: FnOnce(&MouseState, &mut C) -> ElementBox,
+        C: DerefMut<Target = MutableAppContext>,
     {
-        let state_handle = cx.value::<Tag, _>(id);
-        let state = state_handle.read(cx.as_ref(), |state| *state);
-        let child = render_child(state);
+        let state_handle = cx.element_state::<Tag, _>(id);
+        let child = state_handle.update(cx, |state, cx| render_child(state, cx));
         Self {
             state: state_handle,
             child,

gpui/src/presenter.rs 🔗

@@ -11,6 +11,7 @@ use pathfinder_geometry::vector::{vec2f, Vector2F};
 use serde_json::json;
 use std::{
     collections::{HashMap, HashSet},
+    ops::{Deref, DerefMut},
     sync::Arc,
 };
 
@@ -269,6 +270,20 @@ impl<'a> EventContext<'a> {
     }
 }
 
+impl<'a> Deref for EventContext<'a> {
+    type Target = MutableAppContext;
+
+    fn deref(&self) -> &Self::Target {
+        self.app
+    }
+}
+
+impl<'a> DerefMut for EventContext<'a> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        self.app
+    }
+}
+
 pub struct DebugContext<'a> {
     rendered_views: &'a HashMap<usize, ElementBox>,
     pub font_cache: &'a FontCache,

server/src/rpc.rs 🔗

@@ -1620,7 +1620,7 @@ mod tests {
             "empty view"
         }
 
-        fn render<'a>(&self, _: &gpui::RenderContext<Self>) -> gpui::ElementBox {
+        fn render(&self, _: &mut gpui::RenderContext<Self>) -> gpui::ElementBox {
             gpui::Element::boxed(gpui::elements::Empty)
         }
     }

zed/src/chat_panel.rs 🔗

@@ -99,7 +99,7 @@ impl ChatPanel {
         cx.notify();
     }
 
-    fn render_channel_name(&self, cx: &RenderContext<Self>) -> ElementBox {
+    fn render_channel_name(&self, cx: &mut RenderContext<Self>) -> ElementBox {
         let settings = self.settings.borrow();
         let theme = &settings.theme.chat_panel;
         if let Some((channel, _)) = self.active_channel.as_ref() {
@@ -121,7 +121,7 @@ impl ChatPanel {
         }
     }
 
-    fn render_active_channel_messages(&self, cx: &RenderContext<Self>) -> ElementBox {
+    fn render_active_channel_messages(&self, cx: &mut RenderContext<Self>) -> ElementBox {
         let messages = if let Some((channel, _)) = self.active_channel.as_ref() {
             let channel = channel.read(cx);
             let now = OffsetDateTime::now_utc();
@@ -202,7 +202,7 @@ impl View for ChatPanel {
         "ChatPanel"
     }
 
-    fn render(&self, cx: &RenderContext<Self>) -> ElementBox {
+    fn render(&self, cx: &mut RenderContext<Self>) -> ElementBox {
         let theme = &self.settings.borrow().theme;
         Container::new(
             Flex::column()

zed/src/editor.rs 🔗

@@ -2522,7 +2522,7 @@ impl Entity for Editor {
 }
 
 impl View for Editor {
-    fn render<'a>(&self, _: &RenderContext<Self>) -> ElementBox {
+    fn render<'a>(&self, _: &mut RenderContext<Self>) -> ElementBox {
         EditorElement::new(self.handle.clone()).boxed()
     }
 

zed/src/file_finder.rs 🔗

@@ -79,7 +79,7 @@ impl View for FileFinder {
         "FileFinder"
     }
 
-    fn render(&self, _: &RenderContext<Self>) -> ElementBox {
+    fn render(&self, _: &mut RenderContext<Self>) -> ElementBox {
         let settings = self.settings.borrow();
 
         Align::new(

zed/src/project_browser.rs 🔗

@@ -13,7 +13,7 @@ impl View for ProjectBrowser {
         "ProjectBrowser"
     }
 
-    fn render(&self, _: &gpui::RenderContext<'_, Self>) -> gpui::ElementBox {
+    fn render(&self, _: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox {
         Empty::new().boxed()
     }
 }

zed/src/theme_selector.rs 🔗

@@ -200,7 +200,7 @@ impl ThemeSelector {
         }
     }
 
-    fn render_matches(&self, cx: &RenderContext<Self>) -> ElementBox {
+    fn render_matches(&self, cx: &mut RenderContext<Self>) -> ElementBox {
         if self.matches.is_empty() {
             let settings = self.settings.borrow();
             return Container::new(
@@ -269,7 +269,7 @@ impl View for ThemeSelector {
         "ThemeSelector"
     }
 
-    fn render(&self, cx: &RenderContext<Self>) -> ElementBox {
+    fn render(&self, cx: &mut RenderContext<Self>) -> ElementBox {
         let settings = self.settings.borrow();
 
         Align::new(

zed/src/workspace.rs 🔗

@@ -944,7 +944,7 @@ impl View for Workspace {
         "Workspace"
     }
 
-    fn render(&self, cx: &RenderContext<Self>) -> ElementBox {
+    fn render(&self, cx: &mut RenderContext<Self>) -> ElementBox {
         let settings = self.settings.borrow();
         Container::new(
             Flex::column()

zed/src/workspace/pane.rs 🔗

@@ -6,8 +6,7 @@ use gpui::{
     elements::*,
     geometry::{rect::RectF, vector::vec2f},
     keymap::Binding,
-    AppContext, Border, Entity, MutableAppContext, Quad, RenderContext, View, ViewContext,
-    ViewHandle,
+    Border, Entity, MutableAppContext, Quad, RenderContext, View, ViewContext, ViewHandle,
 };
 use postage::watch;
 use std::{cmp, path::Path, sync::Arc};
@@ -175,7 +174,7 @@ impl Pane {
         cx.emit(Event::Split(direction));
     }
 
-    fn render_tabs(&self, cx: &AppContext) -> ElementBox {
+    fn render_tabs(&self, cx: &mut RenderContext<Self>) -> ElementBox {
         let settings = self.settings.borrow();
         let theme = &settings.theme;
         let line_height = cx.font_cache().line_height(
@@ -194,7 +193,7 @@ impl Pane {
             row.add_child(
                 Expanded::new(
                     1.0,
-                    MouseEventHandler::new::<Tab, _>(item.id(), cx, |mouse_state| {
+                    MouseEventHandler::new::<Tab, _, _>(item.id(), cx, |mouse_state, cx| {
                         let title = item.title(cx);
 
                         let mut border = border.clone();
@@ -299,7 +298,7 @@ impl Pane {
         is_dirty: bool,
         has_conflict: bool,
         theme: &theme::Theme,
-        cx: &AppContext,
+        cx: &mut RenderContext<Self>,
     ) -> ElementBox {
         enum TabCloseButton {}
 
@@ -318,7 +317,7 @@ impl Pane {
             let close_color = current_color.unwrap_or(theme.workspace.tab.icon_close);
             let icon = Svg::new("icons/x.svg").with_color(close_color);
 
-            MouseEventHandler::new::<TabCloseButton, _>(item_id, cx, |mouse_state| {
+            MouseEventHandler::new::<TabCloseButton, _, _>(item_id, cx, |mouse_state, _| {
                 if mouse_state.hovered {
                     Container::new(icon.with_color(Color::white()).boxed())
                         .with_background_color(if mouse_state.clicked {
@@ -370,7 +369,7 @@ impl View for Pane {
         "Pane"
     }
 
-    fn render<'a>(&self, cx: &RenderContext<Self>) -> ElementBox {
+    fn render(&self, cx: &mut RenderContext<Self>) -> ElementBox {
         if let Some(active_item) = self.active_item() {
             Flex::column()
                 .with_child(self.render_tabs(cx))

zed/src/workspace/sidebar.rs 🔗

@@ -1,5 +1,6 @@
+use super::Workspace;
 use crate::Settings;
-use gpui::{action, elements::*, AnyViewHandle, AppContext};
+use gpui::{action, elements::*, AnyViewHandle, MutableAppContext, RenderContext};
 use std::{cell::RefCell, rc::Rc};
 
 pub struct Sidebar {
@@ -56,7 +57,7 @@ impl Sidebar {
             .map(|item| &item.view)
     }
 
-    pub fn render(&self, settings: &Settings, cx: &AppContext) -> ElementBox {
+    pub fn render(&self, settings: &Settings, cx: &mut RenderContext<Workspace>) -> ElementBox {
         let side = self.side;
         let theme = &settings.theme;
         let line_height = cx.font_cache().line_height(
@@ -73,7 +74,7 @@ impl Sidebar {
                         &settings.theme.workspace.sidebar_icon
                     };
                     enum SidebarButton {}
-                    MouseEventHandler::new::<SidebarButton, _>(item.view.id(), cx, |_| {
+                    MouseEventHandler::new::<SidebarButton, _, _>(item.view.id(), cx, |_, _| {
                         ConstrainedBox::new(
                             Align::new(
                                 ConstrainedBox::new(
@@ -98,7 +99,11 @@ impl Sidebar {
         .boxed()
     }
 
-    pub fn render_active_item(&self, settings: &Settings, cx: &AppContext) -> Option<ElementBox> {
+    pub fn render_active_item(
+        &self,
+        settings: &Settings,
+        cx: &mut MutableAppContext,
+    ) -> Option<ElementBox> {
         if let Some(active_item) = self.active_item() {
             let mut container = Flex::row();
             if matches!(self.side, Side::Right) {
@@ -118,10 +123,14 @@ impl Sidebar {
         }
     }
 
-    fn render_resize_handle(&self, settings: &Settings, cx: &AppContext) -> ElementBox {
+    fn render_resize_handle(
+        &self,
+        settings: &Settings,
+        mut cx: &mut MutableAppContext,
+    ) -> ElementBox {
         let width = self.width.clone();
         let side = self.side;
-        MouseEventHandler::new::<Self, _>(self.side.id(), cx, |_| {
+        MouseEventHandler::new::<Self, _, _>(self.side.id(), &mut cx, |_, _| {
             Container::new(Empty::new().boxed())
                 .with_style(&settings.theme.workspace.sidebar.resize_handle)
                 .boxed()