WIP

Nathan Sobo created

Change summary

crates/breadcrumbs/src/breadcrumbs.rs                        |  2 
crates/collab_ui/src/face_pile.rs                            | 18 
crates/diagnostics/src/diagnostics.rs                        |  4 
crates/feedback/src/deploy_feedback_button.rs                |  6 
crates/feedback/src/feedback_info_text.rs                    |  4 
crates/feedback/src/submit_feedback_button.rs                |  6 
crates/gpui/src/app.rs                                       | 88 ++++++
crates/gpui/src/elements/mouse_event_handler.rs              |  7 
crates/gpui/src/gpui.rs                                      |  4 
crates/gpui/src/scene/mouse_region.rs                        | 81 -----
crates/gpui/src/views/select.rs                              | 20 
crates/language_selector/src/active_buffer_language.rs       |  8 
crates/language_selector/src/language_selector.rs            |  4 
crates/outline/src/outline.rs                                |  4 
crates/project_panel/src/project_panel.rs                    |  2 
crates/project_symbols/src/project_symbols.rs                |  4 
crates/recent_projects/src/highlighted_workspace_location.rs |  4 
crates/recent_projects/src/recent_projects.rs                |  4 
crates/terminal_view/src/terminal_element.rs                 | 52 +-
crates/terminal_view/src/terminal_view.rs                    |  2 
crates/theme/src/ui.rs                                       |  5 
crates/vim/src/normal.rs                                     |  2 
crates/vim/src/visual.rs                                     |  2 
crates/welcome/src/base_keymap_picker.rs                     |  2 
crates/welcome/src/welcome.rs                                |  6 
crates/workspace/src/pane.rs                                 | 28 
26 files changed, 194 insertions(+), 175 deletions(-)

Detailed changes

crates/breadcrumbs/src/breadcrumbs.rs 🔗

@@ -41,7 +41,7 @@ impl View for Breadcrumbs {
         "Breadcrumbs"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         let active_item = match &self.active_item {
             Some(active_item) => active_item,
             None => return Empty::new().boxed(),

crates/collab_ui/src/face_pile.rs 🔗

@@ -7,7 +7,8 @@ use gpui::{
     },
     json::ToJson,
     serde_json::{self, json},
-    Axis, DebugContext, Element, ElementBox, MeasurementContext, PaintContext,
+    Axis, DebugContext, Element, ElementBox, MeasurementContext, PaintContext, SceneBuilder,
+    ViewContext,
 };
 
 pub(crate) struct FacePile {
@@ -24,14 +25,15 @@ impl FacePile {
     }
 }
 
-impl Element for FacePile {
+impl<V: View> Element<V> for FacePile {
     type LayoutState = ();
     type PaintState = ();
 
     fn layout(
         &mut self,
         constraint: gpui::SizeConstraint,
-        cx: &mut gpui::LayoutContext,
+        view: &mut Self,
+        cx: &mut ViewContext<Self>,
     ) -> (Vector2F, Self::LayoutState) {
         debug_assert!(constraint.max_along(Axis::Horizontal) == f32::INFINITY);
 
@@ -46,10 +48,12 @@ impl Element for FacePile {
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _layout: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        view: &mut Self,
+        cx: &mut ViewContext<Self>,
     ) -> Self::PaintState {
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
 
@@ -59,7 +63,7 @@ impl Element for FacePile {
         for face in self.faces.iter_mut().rev() {
             let size = face.size();
             origin_x -= size.x();
-            cx.paint_layer(None, |cx| {
+            scene.paint_layer(None, |scene| {
                 face.paint(scene, vec2f(origin_x, origin_y), visible_bounds, view, cx);
             });
             origin_x += self.overlap;
@@ -94,8 +98,8 @@ impl Element for FacePile {
     }
 }
 
-impl Extend<ElementBox> for FacePile {
-    fn extend<T: IntoIterator<Item = ElementBox>>(&mut self, children: T) {
+impl Extend<ElementBox<Self>> for FacePile {
+    fn extend<T: IntoIterator<Item = ElementBox<Self>>>(&mut self, children: T) {
         self.faces.extend(children);
     }
 }

crates/diagnostics/src/diagnostics.rs 🔗

@@ -1176,9 +1176,7 @@ mod tests {
     }
 
     fn editor_blocks(editor: &ViewHandle<Editor>, cx: &mut AppContext) -> Vec<(u32, String)> {
-        let mut presenter = cx.build_window(editor.id(), 0., Default::default());
-        let mut cx = presenter.build_layout_context(Default::default(), false, cx);
-        cx.render(editor, |editor, cx| {
+        editor.update(cx, |editor, cx| {
             let snapshot = editor.snapshot(cx);
             snapshot
                 .blocks_in_range(0..snapshot.max_point().row())

crates/feedback/src/deploy_feedback_button.rs 🔗

@@ -32,7 +32,7 @@ impl View for DeployFeedbackButton {
         let theme = cx.global::<Settings>().theme.clone();
         Stack::new()
             .with_child(
-                MouseEventHandler::<Self>::new(0, cx, |state, _| {
+                MouseEventHandler::<Self, Self>::new(0, cx, |state, _| {
                     let style = &theme
                         .workspace
                         .status_bar
@@ -53,12 +53,12 @@ impl View for DeployFeedbackButton {
                         .boxed()
                 })
                 .with_cursor_style(CursorStyle::PointingHand)
-                .on_click(MouseButton::Left, move |_, cx| {
+                .on_click(MouseButton::Left, move |_, _, cx| {
                     if !active {
                         cx.dispatch_action(GiveFeedback)
                     }
                 })
-                .with_tooltip::<Self, _>(
+                .with_tooltip::<Self>(
                     0,
                     "Send Feedback".into(),
                     Some(Box::new(GiveFeedback)),

crates/feedback/src/feedback_info_text.rs 🔗

@@ -43,7 +43,7 @@ impl View for FeedbackInfoText {
                 .boxed(),
             )
             .with_child(
-                MouseEventHandler::<OpenZedCommunityRepo>::new(0, cx, |state, _| {
+                MouseEventHandler::<OpenZedCommunityRepo, Self>::new(0, cx, |state, _| {
                     let contained_text = if state.hovered() {
                         &theme.feedback.link_text_hover
                     } else {
@@ -58,7 +58,7 @@ impl View for FeedbackInfoText {
                         .boxed()
                 })
                 .with_cursor_style(CursorStyle::PointingHand)
-                .on_click(MouseButton::Left, |_, cx| {
+                .on_click(MouseButton::Left, |_, _, cx| {
                     cx.dispatch_action(OpenZedCommunityRepo)
                 })
                 .boxed(),

crates/feedback/src/submit_feedback_button.rs 🔗

@@ -32,7 +32,7 @@ impl View for SubmitFeedbackButton {
     fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         let theme = cx.global::<Settings>().theme.clone();
         enum SubmitFeedbackButton {}
-        MouseEventHandler::<SubmitFeedbackButton>::new(0, cx, |state, _| {
+        MouseEventHandler::<SubmitFeedbackButton, Self>::new(0, cx, |state, _| {
             let style = theme.feedback.submit_button.style_for(state, false);
             Label::new("Submit as Markdown", style.text.clone())
                 .contained()
@@ -40,13 +40,13 @@ impl View for SubmitFeedbackButton {
                 .boxed()
         })
         .with_cursor_style(CursorStyle::PointingHand)
-        .on_click(MouseButton::Left, |_, cx| {
+        .on_click(MouseButton::Left, |_, _, cx| {
             cx.dispatch_action(SubmitFeedback)
         })
         .aligned()
         .contained()
         .with_margin_left(theme.feedback.button_margin)
-        .with_tooltip::<Self, _>(
+        .with_tooltip::<Self>(
             0,
             "cmd-s".into(),
             Some(Box::new(SubmitFeedback)),

crates/gpui/src/app.rs 🔗

@@ -3823,6 +3823,94 @@ impl<V: View> UpdateView for ViewContext<'_, '_, '_, V> {
     }
 }
 
+pub struct EventContext<'a, 'b, 'c, 'd, V: View> {
+    view_context: &'d mut ViewContext<'a, 'b, 'c, V>,
+    pub(crate) handled: bool,
+}
+
+impl<'a, 'b, 'c, 'd, V: View> EventContext<'a, 'b, 'c, 'd, V> {
+    pub(crate) fn new(view_context: &'d mut ViewContext<'a, 'b, 'c, V>) -> Self {
+        EventContext {
+            view_context,
+            handled: true,
+        }
+    }
+
+    pub fn propagate_event(&mut self) {
+        self.handled = false;
+    }
+}
+
+impl<'a, 'b, 'c, 'd, V: View> Deref for EventContext<'a, 'b, 'c, 'd, V> {
+    type Target = ViewContext<'a, 'b, 'c, V>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.view_context
+    }
+}
+
+impl<V: View> DerefMut for EventContext<'_, '_, '_, '_, V> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.view_context
+    }
+}
+
+impl<V: View> UpdateModel for EventContext<'_, '_, '_, '_, V> {
+    fn update_model<T: Entity, O>(
+        &mut self,
+        handle: &ModelHandle<T>,
+        update: &mut dyn FnMut(&mut T, &mut ModelContext<T>) -> O,
+    ) -> O {
+        self.view_context.update_model(handle, update)
+    }
+}
+
+impl<V: View> ReadView for EventContext<'_, '_, '_, '_, V> {
+    fn read_view<W: View>(&self, handle: &crate::ViewHandle<W>) -> &W {
+        self.view_context.read_view(handle)
+    }
+}
+
+impl<V: View> UpdateView for EventContext<'_, '_, '_, '_, V> {
+    fn update_view<T, S>(
+        &mut self,
+        handle: &ViewHandle<T>,
+        update: &mut dyn FnMut(&mut T, &mut ViewContext<T>) -> S,
+    ) -> S
+    where
+        T: View,
+    {
+        self.view_context.update_view(handle, update)
+    }
+}
+
+impl<V: View> UpgradeModelHandle for EventContext<'_, '_, '_, '_, V> {
+    fn upgrade_model_handle<T: Entity>(
+        &self,
+        handle: &WeakModelHandle<T>,
+    ) -> Option<ModelHandle<T>> {
+        self.view_context.upgrade_model_handle(handle)
+    }
+
+    fn model_handle_is_upgradable<T: Entity>(&self, handle: &WeakModelHandle<T>) -> bool {
+        self.view_context.model_handle_is_upgradable(handle)
+    }
+
+    fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option<AnyModelHandle> {
+        self.view_context.upgrade_any_model_handle(handle)
+    }
+}
+
+impl<V: View> UpgradeViewHandle for EventContext<'_, '_, '_, '_, V> {
+    fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>> {
+        self.view_context.upgrade_view_handle(handle)
+    }
+
+    fn upgrade_any_view_handle(&self, handle: &AnyWeakViewHandle) -> Option<AnyViewHandle> {
+        self.view_context.upgrade_any_view_handle(handle)
+    }
+}
+
 pub(crate) enum Reference<'a, T> {
     Immutable(&'a T),
     Mutable(&'a mut T),

crates/gpui/src/elements/mouse_event_handler.rs 🔗

@@ -7,10 +7,11 @@ use crate::{
     platform::CursorStyle,
     platform::MouseButton,
     scene::{
-        CursorRegion, EventContext, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag,
-        MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut,
+        CursorRegion, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseHover,
+        MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut,
     },
-    Element, ElementBox, MouseRegion, MouseState, SceneBuilder, SizeConstraint, View, ViewContext,
+    Element, ElementBox, EventContext, MouseRegion, MouseState, SceneBuilder, SizeConstraint, View,
+    ViewContext,
 };
 use serde_json::json;
 use std::{marker::PhantomData, ops::Range};

crates/gpui/src/gpui.rs 🔗

@@ -15,9 +15,7 @@ pub use clipboard::ClipboardItem;
 pub mod fonts;
 pub mod geometry;
 pub mod scene;
-pub use scene::{
-    Border, CursorRegion, EventContext, MouseRegion, MouseRegionId, Quad, Scene, SceneBuilder,
-};
+pub use scene::{Border, CursorRegion, MouseRegion, MouseRegionId, Quad, Scene, SceneBuilder};
 pub mod text_layout;
 pub use text_layout::TextLayoutCache;
 mod util;

crates/gpui/src/scene/mouse_region.rs 🔗

@@ -1,22 +1,14 @@
+use crate::{platform::MouseButton, window::WindowContext, EventContext, View, ViewContext};
+use collections::HashMap;
+use pathfinder_geometry::rect::RectF;
+use smallvec::SmallVec;
 use std::{
     any::{Any, TypeId},
     fmt::Debug,
     mem::Discriminant,
-    ops::{Deref, DerefMut},
     rc::Rc,
 };
 
-use collections::HashMap;
-
-use pathfinder_geometry::rect::RectF;
-use smallvec::SmallVec;
-
-use crate::{
-    platform::MouseButton, window::WindowContext, AnyModelHandle, AnyViewHandle,
-    AnyWeakModelHandle, AnyWeakViewHandle, Entity, ModelHandle, ReadView, UpgradeModelHandle,
-    UpgradeViewHandle, View, ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle,
-};
-
 use super::{
     mouse_event::{
         MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover, MouseMove, MouseUp,
@@ -206,71 +198,6 @@ impl MouseRegionId {
     }
 }
 
-pub struct EventContext<'a, 'b, 'c, 'd, V: View> {
-    view_context: &'d mut ViewContext<'a, 'b, 'c, V>,
-    handled: bool,
-}
-
-impl<'a, 'b, 'c, 'd, V: View> EventContext<'a, 'b, 'c, 'd, V> {
-    fn new(view_context: &'d mut ViewContext<'a, 'b, 'c, V>) -> Self {
-        EventContext {
-            view_context,
-            handled: true,
-        }
-    }
-
-    pub fn propagate_event(&mut self) {
-        self.handled = false;
-    }
-}
-
-impl<'a, 'b, 'c, 'd, V: View> Deref for EventContext<'a, 'b, 'c, 'd, V> {
-    type Target = ViewContext<'a, 'b, 'c, V>;
-
-    fn deref(&self) -> &Self::Target {
-        &self.view_context
-    }
-}
-
-impl<V: View> DerefMut for EventContext<'_, '_, '_, '_, V> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.view_context
-    }
-}
-
-impl<V: View> ReadView for EventContext<'_, '_, '_, '_, V> {
-    fn read_view<W: View>(&self, handle: &crate::ViewHandle<W>) -> &W {
-        self.view_context.read_view(handle)
-    }
-}
-
-impl<V: View> UpgradeModelHandle for EventContext<'_, '_, '_, '_, V> {
-    fn upgrade_model_handle<T: Entity>(
-        &self,
-        handle: &WeakModelHandle<T>,
-    ) -> Option<ModelHandle<T>> {
-        self.view_context.upgrade_model_handle(handle)
-    }
-
-    fn model_handle_is_upgradable<T: Entity>(&self, handle: &WeakModelHandle<T>) -> bool {
-        self.view_context.model_handle_is_upgradable(handle)
-    }
-
-    fn upgrade_any_model_handle(&self, handle: &AnyWeakModelHandle) -> Option<AnyModelHandle> {
-        self.view_context.upgrade_any_model_handle(handle)
-    }
-}
-
-impl<V: View> UpgradeViewHandle for EventContext<'_, '_, '_, '_, V> {
-    fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>> {
-        self.view_context.upgrade_view_handle(handle)
-    }
-
-    fn upgrade_any_view_handle(&self, handle: &AnyWeakViewHandle) -> Option<AnyViewHandle> {
-        self.view_context.upgrade_any_view_handle(handle)
-    }
-}
-
 pub type HandlerCallback = Rc<dyn Fn(MouseEvent, &mut dyn Any, &mut WindowContext, usize) -> bool>;
 
 #[derive(Clone, PartialEq, Eq, Hash)]

crates/gpui/src/views/select.rs 🔗

@@ -1,8 +1,8 @@
 use serde::Deserialize;
 
 use crate::{
-    actions, elements::*, impl_actions, platform::MouseButton, AppContext, Entity, View,
-    ViewContext, WeakViewHandle,
+    actions, elements::*, impl_actions, platform::MouseButton, AppContext, Entity, EventContext,
+    View, ViewContext, WeakViewHandle,
 };
 
 pub struct Select {
@@ -116,9 +116,10 @@ impl View for Select {
                 .with_style(style.header)
                 .boxed()
             })
-            .on_click(MouseButton::Left, move |_, _, cx| {
-                cx.dispatch_action(ToggleSelect)
-            })
+            .on_click(
+                MouseButton::Left,
+                move |_, _, cx: &mut EventContext<Self>| cx.dispatch_action(ToggleSelect),
+            )
             .boxed(),
         );
         if self.is_open {
@@ -150,9 +151,12 @@ impl View for Select {
                                                 )
                                             },
                                         )
-                                        .on_click(MouseButton::Left, move |_, _, cx| {
-                                            cx.dispatch_action(SelectItem(ix))
-                                        })
+                                        .on_click(
+                                            MouseButton::Left,
+                                            move |_, _, cx: &mut EventContext<Self>| {
+                                                cx.dispatch_action(SelectItem(ix))
+                                            },
+                                        )
                                         .boxed()
                                     }))
                                 },

crates/language_selector/src/active_buffer_language.rs 🔗

@@ -50,7 +50,7 @@ impl View for ActiveBufferLanguage {
         "ActiveBufferLanguage"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         if let Some(active_language) = self.active_language.as_ref() {
             let active_language_text = if let Some(active_language_text) = active_language {
                 active_language_text.to_string()
@@ -58,7 +58,7 @@ impl View for ActiveBufferLanguage {
                 "Unknown".to_string()
             };
 
-            MouseEventHandler::<Self>::new(0, cx, |state, cx| {
+            MouseEventHandler::<Self, Self>::new(0, cx, |state, cx| {
                 let theme = &cx.global::<Settings>().theme.workspace.status_bar;
                 let style = theme.active_language.style_for(state, false);
                 Label::new(active_language_text, style.text.clone())
@@ -67,7 +67,9 @@ impl View for ActiveBufferLanguage {
                     .boxed()
             })
             .with_cursor_style(CursorStyle::PointingHand)
-            .on_click(MouseButton::Left, |_, cx| cx.dispatch_action(crate::Toggle))
+            .on_click(MouseButton::Left, |_, _, cx| {
+                cx.dispatch_action(crate::Toggle)
+            })
             .boxed()
         } else {
             Empty::new().boxed()

crates/language_selector/src/language_selector.rs 🔗

@@ -120,7 +120,7 @@ impl View for LanguageSelector {
         "LanguageSelector"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         ChildView::new(&self.picker, cx).boxed()
     }
 
@@ -210,7 +210,7 @@ impl PickerDelegate for LanguageSelector {
         mouse_state: &mut MouseState,
         selected: bool,
         cx: &AppContext,
-    ) -> ElementBox {
+    ) -> ElementBox<Picker<Self>> {
         let settings = cx.global::<Settings>();
         let theme = &settings.theme;
         let mat = &self.matches[ix];

crates/outline/src/outline.rs 🔗

@@ -48,7 +48,7 @@ impl View for OutlineView {
         "OutlineView"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         ChildView::new(&self.picker, cx).boxed()
     }
 
@@ -238,7 +238,7 @@ impl PickerDelegate for OutlineView {
         mouse_state: &mut MouseState,
         selected: bool,
         cx: &AppContext,
-    ) -> ElementBox {
+    ) -> ElementBox<Picker<Self>> {
         let settings = cx.global::<Settings>();
         let string_match = &self.matches[ix];
         let style = settings.theme.picker.item.style_for(mouse_state, selected);

crates/project_panel/src/project_panel.rs 🔗

@@ -1251,7 +1251,7 @@ impl ProjectPanel {
         .as_draggable(entry_id, {
             let row_container_style = theme.dragged_entry.container;
 
-            move |_, _, cx: &mut ViewContext<Workspace>| {
+            move |_, cx: &mut ViewContext<ProjectPanel>| {
                 let theme = cx.global::<Settings>().theme.clone();
                 Self::render_entry_visual_element(
                     &details,

crates/project_symbols/src/project_symbols.rs 🔗

@@ -48,7 +48,7 @@ impl View for ProjectSymbolsView {
         "ProjectSymbolsView"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         ChildView::new(&self.picker, cx).boxed()
     }
 
@@ -238,7 +238,7 @@ impl PickerDelegate for ProjectSymbolsView {
         mouse_state: &mut MouseState,
         selected: bool,
         cx: &AppContext,
-    ) -> ElementBox {
+    ) -> ElementBox<Picker<Self>> {
         let string_match = &self.matches[ix];
         let settings = cx.global::<Settings>();
         let style = &settings.theme.picker.item;

crates/recent_projects/src/highlighted_workspace_location.rs 🔗

@@ -3,7 +3,7 @@ use std::path::Path;
 use fuzzy::StringMatch;
 use gpui::{
     elements::{Label, LabelStyle},
-    Element, ElementBox,
+    Element, ElementBox, View,
 };
 use workspace::WorkspaceLocation;
 
@@ -42,7 +42,7 @@ impl HighlightedText {
         }
     }
 
-    pub fn render(self, style: impl Into<LabelStyle>) -> ElementBox {
+    pub fn render<V: View>(self, style: impl Into<LabelStyle>) -> ElementBox<V> {
         Label::new(self.text, style)
             .with_highlights(self.highlight_positions)
             .boxed()

crates/recent_projects/src/recent_projects.rs 🔗

@@ -101,7 +101,7 @@ impl View for RecentProjectsView {
         "RecentProjectsView"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         ChildView::new(&self.picker, cx).boxed()
     }
 
@@ -183,7 +183,7 @@ impl PickerDelegate for RecentProjectsView {
         mouse_state: &mut gpui::MouseState,
         selected: bool,
         cx: &gpui::AppContext,
-    ) -> ElementBox {
+    ) -> ElementBox<Picker<Self>> {
         let settings = cx.global::<Settings>();
         let string_match = &self.matches[ix];
         let style = settings.theme.picker.item.style_for(mouse_state, selected);

crates/terminal_view/src/terminal_element.rs 🔗

@@ -410,7 +410,7 @@ impl TerminalElement {
                 ),
             )
             // Update drag selections
-            .on_drag(MouseButton::Left, move |event, _, cx| {
+            .on_drag(MouseButton::Left, move |event, _: &mut TerminalView, cx| {
                 if cx.is_parent_view_focused() {
                     if let Some(conn_handle) = connection.upgrade(cx) {
                         conn_handle.update(cx, |terminal, cx| {
@@ -432,7 +432,7 @@ impl TerminalElement {
                 ),
             )
             // Context menu
-            .on_click(MouseButton::Right, move |e, _, cx| {
+            .on_click(MouseButton::Right, move |e, _: &mut TerminalView, cx| {
                 let mouse_mode = if let Some(conn_handle) = connection.upgrade(cx) {
                     conn_handle.update(cx, |terminal, _cx| terminal.mouse_mode(e.shift))
                 } else {
@@ -445,7 +445,7 @@ impl TerminalElement {
                     });
                 }
             })
-            .on_move(move |event, _, cx| {
+            .on_move(move |event, _: &mut TerminalView, cx| {
                 if cx.is_parent_view_focused() {
                     if let Some(conn_handle) = connection.upgrade(cx) {
                         conn_handle.update(cx, |terminal, cx| {
@@ -455,7 +455,7 @@ impl TerminalElement {
                     }
                 }
             })
-            .on_scroll(move |event, _, cx| {
+            .on_scroll(move |event, _: &mut TerminalView, cx| {
                 if let Some(conn_handle) = connection.upgrade(cx) {
                     conn_handle.update(cx, |terminal, cx| {
                         terminal.scroll_wheel(event, origin);
@@ -598,27 +598,25 @@ impl Element<TerminalView> for TerminalElement {
         });
 
         let view_handle = self.view.clone();
-        let hyperlink_tooltip = last_hovered_hyperlink.and_then(|(uri, _, id)| {
-            // last_mouse.and_then(|_last_mouse| {
-            view_handle.upgrade(cx).map(|handle| {
-                let mut tooltip = cx.render(&handle, |_, cx| {
-                    Overlay::new(
-                        Empty::new()
-                            .contained()
-                            .constrained()
-                            .with_width(dimensions.width())
-                            .with_height(dimensions.height())
-                            .with_tooltip::<TerminalElement, _>(id, uri, None, tooltip_style, cx)
-                            .boxed(),
-                    )
-                    .with_position_mode(gpui::elements::OverlayPositionMode::Local)
-                    .boxed()
-                });
+        let hyperlink_tooltip = last_hovered_hyperlink.map(|(uri, _, id)| {
+            let mut tooltip = Overlay::new(
+                Empty::new()
+                    .contained()
+                    .constrained()
+                    .with_width(dimensions.width())
+                    .with_height(dimensions.height())
+                    .with_tooltip::<TerminalElement>(id, uri, None, tooltip_style, cx)
+                    .boxed(),
+            )
+            .with_position_mode(gpui::elements::OverlayPositionMode::Local)
+            .boxed();
 
-                tooltip.layout(SizeConstraint::new(Vector2F::zero(), cx.window_size), cx);
-                tooltip
-            })
-            // })
+            tooltip.layout(
+                SizeConstraint::new(Vector2F::zero(), cx.window_size()),
+                view,
+                cx,
+            );
+            tooltip
         });
 
         let TerminalContent {
@@ -647,7 +645,7 @@ impl Element<TerminalView> for TerminalElement {
             cells,
             &text_style,
             &terminal_theme,
-            cx.text_layout_cache,
+            cx.text_layout_cache(),
             cx.font_cache(),
             last_hovered_hyperlink
                 .as_ref()
@@ -669,7 +667,7 @@ impl Element<TerminalView> for TerminalElement {
                     terminal_theme.foreground
                 };
 
-                cx.text_layout_cache.layout_str(
+                cx.text_layout_cache().layout_str(
                     &str_trxt,
                     text_style.font_size,
                     &[(
@@ -744,11 +742,11 @@ impl Element<TerminalView> for TerminalElement {
 
             // Elements are ephemeral, only at paint time do we know what could be clicked by a mouse
             self.attach_mouse_handlers(
+                scene,
                 origin,
                 self.view.id(),
                 visible_bounds,
                 layout.mode,
-                view,
                 cx,
             );
 

crates/terminal_view/src/terminal_view.rs 🔗

@@ -396,7 +396,7 @@ impl View for TerminalView {
         Stack::new()
             .with_child(
                 TerminalElement::new(
-                    cx.handle(),
+                    cx.handle().downgrade(),
                     terminal_handle,
                     focused,
                     self.should_show_cursor(focused, cx),

crates/theme/src/ui.rs 🔗

@@ -175,7 +175,7 @@ pub fn keystroke_label_for<V: View>(
 
 pub type ButtonStyle = Interactive<ContainedText>;
 
-pub fn cta_button<Tag, L, A, V>(
+pub fn cta_button<L, A, V>(
     label: L,
     action: A,
     max_width: f32,
@@ -183,12 +183,11 @@ pub fn cta_button<Tag, L, A, V>(
     cx: &mut ViewContext<V>,
 ) -> ElementBox<V>
 where
-    Tag: 'static,
     L: Into<Cow<'static, str>>,
     A: 'static + Action + Clone,
     V: View,
 {
-    cta_button_with_click::<Tag, _, _, _>(label, max_width, style, cx, move |_, _, cx| {
+    cta_button_with_click::<A, _, _, _>(label, max_width, style, cx, move |_, _, cx| {
         cx.dispatch_action(action.clone())
     })
     .boxed()

crates/vim/src/normal.rs 🔗

@@ -251,7 +251,7 @@ fn paste(_: &mut Workspace, _: &Paste, cx: &mut ViewContext<Workspace>) {
         vim.update_active_editor(cx, |editor, cx| {
             editor.transact(cx, |editor, cx| {
                 editor.set_clip_at_line_ends(false, cx);
-                if let Some(item) = cx.as_mut().read_from_clipboard() {
+                if let Some(item) = cx.read_from_clipboard() {
                     let mut clipboard_text = Cow::Borrowed(item.text());
                     if let Some(mut clipboard_selections) =
                         item.metadata::<Vec<ClipboardSelection>>()

crates/vim/src/visual.rs 🔗

@@ -209,7 +209,7 @@ pub fn paste(_: &mut Workspace, _: &VisualPaste, cx: &mut ViewContext<Workspace>
     Vim::update(cx, |vim, cx| {
         vim.update_active_editor(cx, |editor, cx| {
             editor.transact(cx, |editor, cx| {
-                if let Some(item) = cx.as_mut().read_from_clipboard() {
+                if let Some(item) = cx.read_from_clipboard() {
                     copy_selections_content(editor, editor.selections.line_mode, cx);
                     let mut clipboard_text = Cow::Borrowed(item.text());
                     if let Some(mut clipboard_selections) =

crates/welcome/src/base_keymap_picker.rs 🔗

@@ -161,7 +161,7 @@ impl PickerDelegate for BaseKeymapSelector {
         mouse_state: &mut gpui::MouseState,
         selected: bool,
         cx: &gpui::AppContext,
-    ) -> gpui::ElementBox {
+    ) -> gpui::ElementBox<Picker<Self>> {
         let theme = &cx.global::<Settings>().theme;
         let keymap_match = &self.matches[ix];
         let style = theme.picker.item.style_for(mouse_state, selected);

crates/welcome/src/welcome.rs 🔗

@@ -10,7 +10,7 @@ use gpui::{
 use settings::{settings_file::SettingsFile, Settings};
 
 use workspace::{
-    item::Item, open_new, sidebar::SidebarSide, AppState, PaneBackdrop, Welcome, Workspace,
+    item::Item, open_new, sidebar::SidebarSide, AppState, Pane, PaneBackdrop, Welcome, Workspace,
     WorkspaceId,
 };
 
@@ -55,7 +55,7 @@ impl View for WelcomePage {
         "WelcomePage"
     }
 
-    fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> ElementBox<Self> {
         let self_handle = cx.handle();
         let settings = cx.global::<Settings>();
         let theme = settings.theme.clone();
@@ -203,7 +203,7 @@ impl Item for WelcomePage {
         _detail: Option<usize>,
         style: &theme::Tab,
         _cx: &gpui::AppContext,
-    ) -> gpui::ElementBox {
+    ) -> ElementBox<Pane> {
         Flex::row()
             .with_child(
                 Label::new("Welcome to Zed!", style.label.clone())

crates/workspace/src/pane.rs 🔗

@@ -1851,13 +1851,13 @@ impl NavHistory {
     }
 }
 
-pub struct PaneBackdrop {
+pub struct PaneBackdrop<V: View> {
     child_view: usize,
-    child: ElementBox<Pane>,
+    child: ElementBox<V>,
 }
 
-impl PaneBackdrop {
-    pub fn new(pane_item_view: usize, child: ElementBox<Pane>) -> Self {
+impl<V: View> PaneBackdrop<V> {
+    pub fn new(pane_item_view: usize, child: ElementBox<V>) -> Self {
         PaneBackdrop {
             child,
             child_view: pane_item_view,
@@ -1865,7 +1865,7 @@ impl PaneBackdrop {
     }
 }
 
-impl Element<Pane> for PaneBackdrop {
+impl<V: View> Element<V> for PaneBackdrop<V> {
     type LayoutState = ();
 
     type PaintState = ();
@@ -1873,8 +1873,8 @@ impl Element<Pane> for PaneBackdrop {
     fn layout(
         &mut self,
         constraint: gpui::SizeConstraint,
-        view: &mut Pane,
-        cx: &mut ViewContext<Pane>,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let size = self.child.layout(constraint, view, cx);
         (size, ())
@@ -1886,8 +1886,8 @@ impl Element<Pane> for PaneBackdrop {
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
-        view: &mut Pane,
-        cx: &mut ViewContext<Pane>,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let background = cx.global::<Settings>().theme.editor.background;
 
@@ -1903,7 +1903,7 @@ impl Element<Pane> for PaneBackdrop {
         scene.push_mouse_region(
             MouseRegion::new::<Self>(child_view_id, 0, visible_bounds).on_down(
                 gpui::platform::MouseButton::Left,
-                move |_, _: &mut Pane, cx| {
+                move |_, _: &mut V, cx| {
                     let window_id = cx.window_id();
                     cx.app_context().focus(window_id, Some(child_view_id))
                 },
@@ -1923,8 +1923,8 @@ impl Element<Pane> for PaneBackdrop {
         _visible_bounds: RectF,
         _layout: &Self::LayoutState,
         _paint: &Self::PaintState,
-        view: &Pane,
-        cx: &gpui::ViewContext<Pane>,
+        view: &V,
+        cx: &gpui::ViewContext<V>,
     ) -> Option<RectF> {
         self.child.rect_for_text_range(range_utf16, view, cx)
     }
@@ -1934,8 +1934,8 @@ impl Element<Pane> for PaneBackdrop {
         _bounds: RectF,
         _layout: &Self::LayoutState,
         _paint: &Self::PaintState,
-        view: &Pane,
-        cx: &gpui::ViewContext<Pane>,
+        view: &V,
+        cx: &gpui::ViewContext<V>,
     ) -> serde_json::Value {
         gpui::json::json!({
             "type": "Pane Back Drop",