WIP

Nathan Sobo created

Change summary

crates/activity_indicator/src/activity_indicator.rs |   4 
crates/auto_update/src/update_notification.rs       |  12 
crates/copilot_button/src/copilot_button.rs         |   4 
crates/diagnostics/src/diagnostics.rs               |   8 
crates/diagnostics/src/items.rs                     |   6 
crates/editor/src/display_map/block_map.rs          |  22 
crates/editor/src/editor.rs                         |  40 +-
crates/editor/src/element.rs                        | 258 +++++++-------
crates/editor/src/hover_popover.rs                  |  20 
crates/editor/src/items.rs                          |  10 
crates/go_to_line/src/go_to_line.rs                 |   2 
crates/gpui/src/app/window.rs                       |  23 
crates/gpui/src/gpui.rs                             |   2 
crates/gpui/src/scene/mouse_region.rs               |  33 +
crates/picker/src/picker.rs                         |  18 
crates/project_panel/src/project_panel.rs           |  32 
crates/search/src/buffer_search.rs                  |  30 
crates/search/src/project_search.rs                 |  33 
crates/terminal_view/src/terminal_button.rs         |   8 
crates/terminal_view/src/terminal_element.rs        |  75 ++-
crates/terminal_view/src/terminal_view.rs           |   8 
crates/theme_testbench/src/theme_testbench.rs       |  26 
22 files changed, 374 insertions(+), 300 deletions(-)

Detailed changes

crates/activity_indicator/src/activity_indicator.rs 🔗

@@ -314,14 +314,14 @@ impl View for ActivityIndicator {
         "ActivityIndicator"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         let Content {
             icon,
             message,
             action,
         } = self.content_to_render(cx);
 
-        let mut element = MouseEventHandler::<Self>::new(0, cx, |state, cx| {
+        let mut element = MouseEventHandler::<Self, _>::new(0, cx, |state, cx| {
             let theme = &cx
                 .global::<Settings>()
                 .theme

crates/auto_update/src/update_notification.rs 🔗

@@ -26,13 +26,13 @@ impl View for UpdateNotification {
         "UpdateNotification"
     }
 
-    fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> gpui::ElementBox {
+    fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> gpui::ElementBox<Self> {
         let theme = cx.global::<Settings>().theme.clone();
         let theme = &theme.update_notification;
 
         let app_name = cx.global::<ReleaseChannel>().display_name();
 
-        MouseEventHandler::<ViewReleaseNotes>::new(0, cx, |state, cx| {
+        MouseEventHandler::<ViewReleaseNotes, _>::new(0, cx, |state, cx| {
             Flex::column()
                 .with_child(
                     Flex::row()
@@ -50,7 +50,7 @@ impl View for UpdateNotification {
                             .boxed(),
                         )
                         .with_child(
-                            MouseEventHandler::<Cancel>::new(0, cx, |state, _| {
+                            MouseEventHandler::<Cancel, _>::new(0, cx, |state, _| {
                                 let style = theme.dismiss_button.style_for(state, false);
                                 Svg::new("icons/x_mark_8.svg")
                                     .with_color(style.color)
@@ -65,7 +65,9 @@ impl View for UpdateNotification {
                                     .boxed()
                             })
                             .with_padding(Padding::uniform(5.))
-                            .on_click(MouseButton::Left, move |_, cx| cx.dispatch_action(Cancel))
+                            .on_click(MouseButton::Left, move |_, _, cx| {
+                                cx.dispatch_action(Cancel)
+                            })
                             .aligned()
                             .constrained()
                             .with_height(cx.font_cache().line_height(theme.message.text.font_size))
@@ -87,7 +89,7 @@ impl View for UpdateNotification {
                 .boxed()
         })
         .with_cursor_style(CursorStyle::PointingHand)
-        .on_click(MouseButton::Left, |_, cx| {
+        .on_click(MouseButton::Left, |_, _, cx| {
             cx.dispatch_action(ViewReleaseNotes)
         })
         .boxed()

crates/copilot_button/src/copilot_button.rs 🔗

@@ -91,7 +91,7 @@ impl View for CopilotButton {
         "CopilotButton"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         let settings = cx.global::<Settings>();
 
         if !settings.enable_copilot_integration {
@@ -111,7 +111,7 @@ impl View for CopilotButton {
 
         Stack::new()
             .with_child(
-                MouseEventHandler::<Self>::new(0, cx, {
+                MouseEventHandler::<Self, _>::new(0, cx, {
                     let theme = theme.clone();
                     let status = status.clone();
                     move |state, _cx| {

crates/diagnostics/src/diagnostics.rs 🔗

@@ -86,7 +86,7 @@ impl View for ProjectDiagnosticsEditor {
         "ProjectDiagnosticsEditor"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         if self.path_states.is_empty() {
             let theme = &cx.global::<Settings>().theme.project_diagnostics;
             Label::new("No problems in workspace", theme.empty_message.clone())
@@ -509,7 +509,7 @@ impl Item for ProjectDiagnosticsEditor {
         _detail: Option<usize>,
         style: &theme::Tab,
         cx: &AppContext,
-    ) -> ElementBox {
+    ) -> ElementBox<Pane> {
         render_summary(
             &self.summary,
             &style.label.text,
@@ -691,7 +691,7 @@ pub(crate) fn render_summary(
     summary: &DiagnosticSummary,
     text_style: &TextStyle,
     theme: &theme::ProjectDiagnostics,
-) -> ElementBox {
+) -> ElementBox<Pane> {
     if summary.error_count == 0 && summary.warning_count == 0 {
         Label::new("No problems", text_style.clone()).boxed()
     } else {
@@ -1186,7 +1186,7 @@ mod tests {
                     let name = match block {
                         TransformBlock::Custom(block) => block
                             .render(&mut BlockContext {
-                                cx,
+                                view_context: cx,
                                 anchor_x: 0.,
                                 scroll_x: 0.,
                                 gutter_padding: 0.,

crates/diagnostics/src/items.rs 🔗

@@ -84,14 +84,14 @@ impl View for DiagnosticIndicator {
         "DiagnosticIndicator"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         enum Summary {}
         enum Message {}
 
         let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
         let in_progress = !self.in_progress_checks.is_empty();
         let mut element = Flex::row().with_child(
-            MouseEventHandler::<Summary>::new(0, cx, |state, cx| {
+            MouseEventHandler::<Summary, _>::new(0, cx, |state, cx| {
                 let style = cx
                     .global::<Settings>()
                     .theme
@@ -189,7 +189,7 @@ impl View for DiagnosticIndicator {
         } else if let Some(diagnostic) = &self.current_diagnostic {
             let message_style = style.diagnostic_message.clone();
             element.add_child(
-                MouseEventHandler::<Message>::new(1, cx, |state, _| {
+                MouseEventHandler::<Message, _>::new(1, cx, |state, _| {
                     Label::new(
                         diagnostic.message.split('\n').next().unwrap().to_string(),
                         message_style.style_for(state, false).text.clone(),

crates/editor/src/display_map/block_map.rs 🔗

@@ -2,7 +2,7 @@ use super::{
     wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot},
     TextHighlights,
 };
-use crate::{Anchor, ExcerptId, ExcerptRange, ToPoint as _};
+use crate::{Anchor, Editor, ExcerptId, ExcerptRange, ToPoint as _};
 use collections::{Bound, HashMap, HashSet};
 use gpui::{fonts::HighlightStyle, ElementBox, ViewContext};
 use language::{BufferSnapshot, Chunk, Patch, Point};
@@ -50,7 +50,7 @@ struct BlockRow(u32);
 #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
 struct WrapRow(u32);
 
-pub type RenderBlock = Arc<dyn Fn(&mut BlockContext) -> ElementBox>;
+pub type RenderBlock = Arc<dyn Fn(&mut BlockContext) -> ElementBox<Editor>>;
 
 pub struct Block {
     id: BlockId,
@@ -69,7 +69,7 @@ where
     pub position: P,
     pub height: u8,
     pub style: BlockStyle,
-    pub render: Arc<dyn Fn(&mut BlockContext) -> ElementBox>,
+    pub render: Arc<dyn Fn(&mut BlockContext) -> ElementBox<Editor>>,
     pub disposition: BlockDisposition,
 }
 
@@ -80,8 +80,8 @@ pub enum BlockStyle {
     Sticky,
 }
 
-pub struct BlockContext<'a, 'b> {
-    pub cx: &'b mut ViewContext<'a, crate::Editor>,
+pub struct BlockContext<'a, 'b, 'c, 'd> {
+    pub view_context: &'d mut ViewContext<'a, 'b, 'c, Editor>,
     pub anchor_x: f32,
     pub scroll_x: f32,
     pub gutter_width: f32,
@@ -932,22 +932,22 @@ impl BlockDisposition {
     }
 }
 
-impl<'a, 'b> Deref for BlockContext<'a, 'b> {
-    type Target = ViewContext<'a, crate::Editor>;
+impl<'a, 'b, 'c, 'd> Deref for BlockContext<'a, 'b, 'c, 'd> {
+    type Target = ViewContext<'a, 'b, 'c, Editor>;
 
     fn deref(&self) -> &Self::Target {
-        self.cx
+        self.view_context
     }
 }
 
-impl<'a, 'b> DerefMut for BlockContext<'a, 'b> {
+impl DerefMut for BlockContext<'_, '_, '_, '_> {
     fn deref_mut(&mut self) -> &mut Self::Target {
-        self.cx
+        self.view_context
     }
 }
 
 impl Block {
-    pub fn render(&self, cx: &mut BlockContext) -> ElementBox {
+    pub fn render(&self, cx: &mut BlockContext) -> ElementBox<Editor> {
         self.render.lock()(cx)
     }
 

crates/editor/src/editor.rs 🔗

@@ -722,7 +722,7 @@ impl ContextMenu {
         cursor_position: DisplayPoint,
         style: EditorStyle,
         cx: &mut ViewContext<Editor>,
-    ) -> (DisplayPoint, ElementBox) {
+    ) -> (DisplayPoint, ElementBox<Editor>) {
         match self {
             ContextMenu::Completions(menu) => (cursor_position, menu.render(style, cx)),
             ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, cx),
@@ -774,7 +774,7 @@ impl CompletionsMenu {
         !self.matches.is_empty()
     }
 
-    fn render(&self, style: EditorStyle, cx: &mut ViewContext<Editor>) -> ElementBox {
+    fn render(&self, style: EditorStyle, cx: &mut ViewContext<Editor>) -> ElementBox<Editor> {
         enum CompletionTag {}
 
         let completions = self.completions.clone();
@@ -791,7 +791,7 @@ impl CompletionsMenu {
                     let completion = &completions[mat.candidate_id];
                     let item_ix = start_ix + ix;
                     items.push(
-                        MouseEventHandler::<CompletionTag>::new(
+                        MouseEventHandler::<CompletionTag, _>::new(
                             mat.candidate_id,
                             cx,
                             |state, _| {
@@ -820,7 +820,7 @@ impl CompletionsMenu {
                             },
                         )
                         .with_cursor_style(CursorStyle::PointingHand)
-                        .on_down(MouseButton::Left, move |_, cx| {
+                        .on_down(MouseButton::Left, move |_, _, cx| {
                             cx.dispatch_action(ConfirmCompletion {
                                 item_ix: Some(item_ix),
                             });
@@ -951,7 +951,7 @@ impl CodeActionsMenu {
         mut cursor_position: DisplayPoint,
         style: EditorStyle,
         cx: &mut ViewContext<Editor>,
-    ) -> (DisplayPoint, ElementBox) {
+    ) -> (DisplayPoint, ElementBox<Editor>) {
         enum ActionTag {}
 
         let container_style = style.autocomplete.container;
@@ -966,7 +966,7 @@ impl CodeActionsMenu {
                 for (ix, action) in actions[range].iter().enumerate() {
                     let item_ix = start_ix + ix;
                     items.push(
-                        MouseEventHandler::<ActionTag>::new(item_ix, cx, |state, _| {
+                        MouseEventHandler::<ActionTag, _>::new(item_ix, cx, |state, _| {
                             let item_style = if item_ix == selected_item {
                                 style.autocomplete.selected_item
                             } else if state.hovered() {
@@ -982,7 +982,7 @@ impl CodeActionsMenu {
                                 .boxed()
                         })
                         .with_cursor_style(CursorStyle::PointingHand)
-                        .on_down(MouseButton::Left, move |_, cx| {
+                        .on_down(MouseButton::Left, move |_, _, cx| {
                             cx.dispatch_action(ConfirmCodeAction {
                                 item_ix: Some(item_ix),
                             });
@@ -2929,18 +2929,18 @@ impl Editor {
         style: &EditorStyle,
         active: bool,
         cx: &mut ViewContext<Self>,
-    ) -> Option<ElementBox> {
+    ) -> Option<ElementBox<Self>> {
         if self.available_code_actions.is_some() {
             enum CodeActions {}
             Some(
-                MouseEventHandler::<CodeActions>::new(0, cx, |state, _| {
+                MouseEventHandler::<CodeActions, _>::new(0, cx, |state, _| {
                     Svg::new("icons/bolt_8.svg")
                         .with_color(style.code_actions.indicator.style_for(state, active).color)
                         .boxed()
                 })
                 .with_cursor_style(CursorStyle::PointingHand)
                 .with_padding(Padding::uniform(3.))
-                .on_down(MouseButton::Left, |_, cx| {
+                .on_down(MouseButton::Left, |_, _, cx| {
                     cx.dispatch_action(ToggleCodeActions {
                         deployed_from_indicator: true,
                     });
@@ -2960,7 +2960,7 @@ impl Editor {
         line_height: f32,
         gutter_margin: f32,
         cx: &mut ViewContext<Self>,
-    ) -> Vec<Option<ElementBox>> {
+    ) -> Vec<Option<ElementBox<Self>>> {
         enum FoldIndicators {}
 
         let style = style.folds.clone();
@@ -2972,10 +2972,10 @@ impl Editor {
                 fold_data
                     .map(|(fold_status, buffer_row, active)| {
                         (active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| {
-                            MouseEventHandler::<FoldIndicators>::new(
+                            MouseEventHandler::<FoldIndicators, _>::new(
                                 ix as usize,
                                 cx,
-                                |mouse_state, _| -> ElementBox {
+                                |mouse_state, _| -> ElementBox<Editor> {
                                     Svg::new(match fold_status {
                                         FoldStatus::Folded => style.folded_icon.clone(),
                                         FoldStatus::Foldable => style.foldable_icon.clone(),
@@ -3002,7 +3002,7 @@ impl Editor {
                             .with_cursor_style(CursorStyle::PointingHand)
                             .with_padding(Padding::uniform(3.))
                             .on_click(MouseButton::Left, {
-                                move |_, cx| {
+                                move |_, _, cx| {
                                     cx.dispatch_any_action(match fold_status {
                                         FoldStatus::Folded => Box::new(UnfoldAt { buffer_row }),
                                         FoldStatus::Foldable => Box::new(FoldAt { buffer_row }),
@@ -3028,7 +3028,7 @@ impl Editor {
         cursor_position: DisplayPoint,
         style: EditorStyle,
         cx: &mut ViewContext<Editor>,
-    ) -> Option<(DisplayPoint, ElementBox)> {
+    ) -> Option<(DisplayPoint, ElementBox<Editor>)> {
         self.context_menu
             .as_ref()
             .map(|menu| menu.render(cursor_position, style, cx))
@@ -3911,7 +3911,7 @@ impl Editor {
 
     pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
         self.transact(cx, |this, 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>>() {
                     let old_selections = this.selections.all::<usize>(cx);
@@ -5793,7 +5793,7 @@ impl Editor {
         self.pending_rename.as_ref()
     }
 
-    fn format(&mut self, _: &Format, cx: &mut ViewContext<'_, Self>) -> Option<Task<Result<()>>> {
+    fn format(&mut self, _: &Format, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
         let project = match &self.project {
             Some(project) => project.clone(),
             None => return None,
@@ -5806,7 +5806,7 @@ impl Editor {
         &mut self,
         project: ModelHandle<Project>,
         trigger: FormatTrigger,
-        cx: &mut ViewContext<'_, Self>,
+        cx: &mut ViewContext<Self>,
     ) -> Task<Result<()>> {
         let buffer = self.buffer().clone();
         let buffers = buffer.read(cx).all_buffers();
@@ -6795,7 +6795,7 @@ impl Entity for Editor {
 }
 
 impl View for Editor {
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         let style = self.style(cx);
         let font_changed = self.display_map.update(cx, |map, cx| {
             map.set_fold_ellipses_color(style.folds.ellipses.text_color);
@@ -6804,7 +6804,7 @@ impl View for Editor {
 
         if font_changed {
             let handle = self.handle.clone();
-            cx.defer(move |cx: &mut ViewContext<Editor>| {
+            cx.defer(move |_, cx: &mut ViewContext<Editor>| {
                 if let Some(editor) = handle.upgrade(cx) {
                     editor.update(cx, |editor, cx| {
                         hide_hover(editor, &HideHover, cx);

crates/editor/src/element.rs 🔗

@@ -31,8 +31,8 @@ use gpui::{
     json::{self, ToJson},
     platform::{CursorStyle, Modifiers, MouseButton, MouseButtonEvent, MouseMovedEvent},
     text_layout::{self, Line, RunStyle, TextLayoutCache},
-    AppContext, Axis, Border, CursorRegion, Element, ElementBox, MouseRegion, Quad, SceneBuilder,
-    SizeConstraint, ViewContext, WeakViewHandle,
+    AppContext, Axis, Border, CursorRegion, Element, ElementBox, EventContext, MouseRegion, Quad,
+    SceneBuilder, SizeConstraint, ViewContext, WeakViewHandle, WindowContext,
 };
 use itertools::Itertools;
 use json::json;
@@ -98,10 +98,6 @@ impl EditorElement {
         }
     }
 
-    fn view<'a>(&self, cx: &'a AppContext) -> &'a Editor {
-        self.view.upgrade(cx).unwrap().read(cx)
-    }
-
     fn update_view<F, T>(&self, cx: &mut AppContext, f: F) -> T
     where
         F: FnOnce(&mut Editor, &mut ViewContext<Editor>) -> T,
@@ -114,6 +110,7 @@ impl EditorElement {
     }
 
     fn attach_mouse_handlers(
+        scene: &mut SceneBuilder,
         view: &WeakViewHandle<Editor>,
         position_map: &Arc<PositionMap>,
         has_popovers: bool,
@@ -121,14 +118,14 @@ impl EditorElement {
         text_bounds: RectF,
         gutter_bounds: RectF,
         bounds: RectF,
-        cx: &mut PaintContext,
+        cx: &mut ViewContext<Editor>,
     ) {
         enum EditorElementMouseHandlers {}
         scene.push_mouse_region(
             MouseRegion::new::<EditorElementMouseHandlers>(view.id(), view.id(), visible_bounds)
                 .on_down(MouseButton::Left, {
                     let position_map = position_map.clone();
-                    move |e, cx| {
+                    move |e, _, cx| {
                         if !Self::mouse_down(
                             e.platform_event,
                             position_map.as_ref(),
@@ -142,7 +139,7 @@ impl EditorElement {
                 })
                 .on_down(MouseButton::Right, {
                     let position_map = position_map.clone();
-                    move |e, cx| {
+                    move |e, _, cx| {
                         if !Self::mouse_right_down(
                             e.position,
                             position_map.as_ref(),
@@ -156,7 +153,7 @@ impl EditorElement {
                 .on_up(MouseButton::Left, {
                     let view = view.clone();
                     let position_map = position_map.clone();
-                    move |e, cx| {
+                    move |e, _, cx| {
                         if !Self::mouse_up(
                             view.clone(),
                             e.position,
@@ -173,7 +170,7 @@ impl EditorElement {
                 .on_drag(MouseButton::Left, {
                     let view = view.clone();
                     let position_map = position_map.clone();
-                    move |e, cx| {
+                    move |e, _, cx| {
                         if !Self::mouse_dragged(
                             view.clone(),
                             e.platform_event,
@@ -187,20 +184,20 @@ impl EditorElement {
                 })
                 .on_move({
                     let position_map = position_map.clone();
-                    move |e, cx| {
+                    move |e, _, cx| {
                         if !Self::mouse_moved(e.platform_event, &position_map, text_bounds, cx) {
                             cx.propagate_event()
                         }
                     }
                 })
-                .on_move_out(move |_, cx| {
+                .on_move_out(move |_, _: &mut Editor, cx| {
                     if has_popovers {
                         cx.dispatch_action(HideHover);
                     }
                 })
                 .on_scroll({
                     let position_map = position_map.clone();
-                    move |e, cx| {
+                    move |e, _, cx| {
                         if !Self::scroll(
                             e.position,
                             *e.delta.raw(),
@@ -218,7 +215,7 @@ impl EditorElement {
         enum GutterHandlers {}
         scene.push_mouse_region(
             MouseRegion::new::<GutterHandlers>(view.id(), view.id() + 1, gutter_bounds).on_hover(
-                |hover, cx| {
+                |hover, _: &mut Editor, cx| {
                     cx.dispatch_action(GutterHover {
                         hovered: hover.started,
                     })
@@ -244,7 +241,7 @@ impl EditorElement {
         position_map: &PositionMap,
         text_bounds: RectF,
         gutter_bounds: RectF,
-        cx: &mut EventContext,
+        cx: &mut EventContext<Editor>,
     ) -> bool {
         if gutter_bounds.contains_point(position) {
             click_count = 3; // Simulate triple-click when clicking the gutter to select lines
@@ -279,7 +276,7 @@ impl EditorElement {
         position: Vector2F,
         position_map: &PositionMap,
         text_bounds: RectF,
-        cx: &mut EventContext,
+        cx: &mut EventContext<Editor>,
     ) -> bool {
         if !text_bounds.contains_point(position) {
             return false;
@@ -298,9 +295,9 @@ impl EditorElement {
         shift: bool,
         position_map: &PositionMap,
         text_bounds: RectF,
-        cx: &mut EventContext,
+        cx: &mut EventContext<Editor>,
     ) -> bool {
-        let view = view.upgrade(cx.app).unwrap().read(cx.app);
+        let view = view.upgrade(cx).unwrap().read(cx);
         let end_selection = view.has_pending_selection();
         let pending_nonempty_selections = view.has_pending_nonempty_selection();
 
@@ -334,7 +331,7 @@ impl EditorElement {
         }: MouseMovedEvent,
         position_map: &PositionMap,
         text_bounds: RectF,
-        cx: &mut EventContext,
+        cx: &mut EventContext<Editor>,
     ) -> bool {
         // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed
         // Don't trigger hover popover if mouse is hovering over context menu
@@ -355,7 +352,7 @@ impl EditorElement {
             shift_held: shift,
         });
 
-        let view = view.upgrade(cx.app).unwrap().read(cx.app);
+        let view = view.upgrade(cx).unwrap().read(cx);
         if view.has_pending_selection() {
             let mut scroll_delta = Vector2F::zero();
 
@@ -480,7 +477,7 @@ impl EditorElement {
             border: Border::new(0., Color::transparent_black()),
             corner_radius: 0.,
         });
-        c.push_quad(Quad {
+        scene.push_quad(Quad {
             bounds: text_bounds,
             background: Some(self.style.background),
             border: Border::new(0., Color::transparent_black()),
@@ -545,7 +542,7 @@ impl EditorElement {
         visible_bounds: RectF,
         layout: &mut LayoutState,
         editor: &mut Editor,
-        cx: &mut PaintContext,
+        cx: &mut ViewContext<Editor>,
     ) {
         let line_height = layout.position_map.line_height;
 
@@ -561,7 +558,7 @@ impl EditorElement {
         );
 
         if show_gutter {
-            Self::paint_diff_hunks(bounds, layout, cx);
+            Self::paint_diff_hunks(scene, bounds, layout, cx);
         }
 
         for (ix, line) in layout.line_number_layouts.iter().enumerate() {
@@ -608,7 +605,12 @@ impl EditorElement {
         }
     }
 
-    fn paint_diff_hunks(bounds: RectF, layout: &mut LayoutState, cx: &mut PaintContext) {
+    fn paint_diff_hunks(
+        scene: &mut SceneBuilder,
+        bounds: RectF,
+        layout: &mut LayoutState,
+        cx: &mut ViewContext<Editor>,
+    ) {
         let diff_style = &cx.global::<Settings>().theme.editor.diff.clone();
         let line_height = layout.position_map.line_height;
 
@@ -698,11 +700,10 @@ impl EditorElement {
         visible_bounds: RectF,
         layout: &mut LayoutState,
         editor: &mut Editor,
-        cx: &mut PaintContext,
+        cx: &mut ViewContext<Editor>,
     ) {
-        let view = self.view(cx.app);
         let style = &self.style;
-        let local_replica_id = view.replica_id(cx);
+        let local_replica_id = editor.replica_id(cx);
         let scroll_position = layout.position_map.snapshot.scroll_position();
         let start_row = layout.visible_display_row_range.start;
         let scroll_top = scroll_position.y() * layout.position_map.line_height;
@@ -715,7 +716,7 @@ impl EditorElement {
 
         scene.push_cursor_region(CursorRegion {
             bounds,
-            style: if !view.link_go_to_definition_state.definitions.is_empty() {
+            style: if !editor.link_go_to_definition_state.definitions.is_empty() {
                 CursorStyle::PointingHand
             } else {
                 CursorStyle::IBeam
@@ -761,7 +762,7 @@ impl EditorElement {
 
                 scene.push_mouse_region(
                     MouseRegion::new::<FoldMarkers>(self.view.id(), *id as usize, bound)
-                        .on_click(MouseButton::Left, move |_, cx| {
+                        .on_click(MouseButton::Left, move |_, _: &mut Editor, cx| {
                             cx.dispatch_action(UnfoldAt { buffer_row })
                         })
                         .with_notify_on_hover(true)
@@ -807,7 +808,7 @@ impl EditorElement {
                     cx,
                 );
 
-                if view.show_local_cursors(cx) || *replica_id != local_replica_id {
+                if editor.show_local_cursors(cx) || *replica_id != local_replica_id {
                     let cursor_position = selection.head;
                     if layout
                         .visible_display_row_range
@@ -834,7 +835,7 @@ impl EditorElement {
                                         cursor_row_layout.font_for_index(cursor_column)?;
                                     let text = character.to_string();
 
-                                    Some(cx.text_layout_cache.layout_str(
+                                    Some(cx.text_layout_cache().layout_str(
                                         &text,
                                         cursor_row_layout.font_size(),
                                         &[(
@@ -905,8 +906,8 @@ impl EditorElement {
 
             // Snap the right edge of the list to the right edge of the window if
             // its horizontal bounds overflow.
-            if list_origin.x() + list_width > cx.window_size.x() {
-                list_origin.set_x((cx.window_size.x() - list_width).max(0.));
+            if list_origin.x() + list_width > cx.window_size().x() {
+                list_origin.set_x((cx.window_size().x() - list_width).max(0.));
             }
 
             if list_origin.y() + list_height > bounds.max_y() {
@@ -1059,7 +1060,7 @@ impl EditorElement {
             MouseRegion::new::<ScrollbarMouseHandlers>(view.id(), view.id(), track_bounds)
                 .on_move({
                     let view = view.clone();
-                    move |_, cx| {
+                    move |_, _: &mut Editor, cx| {
                         if let Some(view) = view.upgrade(cx.deref_mut()) {
                             view.update(cx.deref_mut(), |view, cx| {
                                 view.scroll_manager.show_scrollbar(cx);
@@ -1070,7 +1071,7 @@ impl EditorElement {
                 .on_down(MouseButton::Left, {
                     let view = view.clone();
                     let row_range = row_range.clone();
-                    move |e, cx| {
+                    move |e, _: &mut Editor, cx| {
                         let y = e.position.y();
                         if let Some(view) = view.upgrade(cx.deref_mut()) {
                             view.update(cx.deref_mut(), |view, cx| {
@@ -1092,7 +1093,7 @@ impl EditorElement {
                 })
                 .on_drag(MouseButton::Left, {
                     let view = view.clone();
-                    move |e, cx| {
+                    move |e, _: &mut Editor, cx| {
                         let y = e.prev_mouse_position.y();
                         let new_y = e.position.y();
                         if thumb_top < y && y < thumb_bottom {
@@ -1127,7 +1128,7 @@ impl EditorElement {
         scroll_top: f32,
         scroll_left: f32,
         bounds: RectF,
-        cx: &mut ViewContext<Self>,
+        cx: &mut ViewContext<Editor>,
     ) {
         let start_row = layout.visible_display_row_range.start;
         let end_row = layout.visible_display_row_range.end;
@@ -1182,7 +1183,7 @@ impl EditorElement {
         visible_bounds: RectF,
         layout: &mut LayoutState,
         editor: &mut Editor,
-        cx: &mut PaintContext,
+        cx: &mut ViewContext<Editor>,
     ) {
         let scroll_position = layout.position_map.snapshot.scroll_position();
         let scroll_left = scroll_position.x() * layout.position_map.em_width;
@@ -1203,11 +1204,11 @@ impl EditorElement {
         }
     }
 
-    fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &LayoutContext) -> f32 {
+    fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &ViewContext<Editor>) -> f32 {
         let digit_count = (snapshot.max_buffer_row() as f32).log10().floor() as usize + 1;
         let style = &self.style;
 
-        cx.text_layout_cache
+        cx.text_layout_cache()
             .layout_str(
                 "1".repeat(digit_count).as_str(),
                 style.text.font_size,
@@ -1252,7 +1253,7 @@ impl EditorElement {
         active_rows: &BTreeMap<u32, bool>,
         is_singleton: bool,
         snapshot: &EditorSnapshot,
-        cx: &LayoutContext,
+        cx: &ViewContext<Editor>,
     ) -> (
         Vec<Option<text_layout::Line>>,
         Vec<Option<(FoldStatus, BufferRow, bool)>>,
@@ -1277,7 +1278,7 @@ impl EditorElement {
                 if include_line_numbers {
                     line_number.clear();
                     write!(&mut line_number, "{}", buffer_row + 1).unwrap();
-                    line_number_layouts.push(Some(cx.text_layout_cache.layout_str(
+                    line_number_layouts.push(Some(cx.text_layout_cache().layout_str(
                         &line_number,
                         style.text.font_size,
                         &[(
@@ -1312,7 +1313,7 @@ impl EditorElement {
         &mut self,
         rows: Range<u32>,
         snapshot: &EditorSnapshot,
-        cx: &LayoutContext,
+        cx: &ViewContext<Editor>,
     ) -> Vec<text_layout::Line> {
         if rows.start >= rows.end {
             return Vec::new();
@@ -1335,7 +1336,7 @@ impl EditorElement {
                 .take(rows.len());
             placeholder_lines
                 .map(|line| {
-                    cx.text_layout_cache.layout_str(
+                    cx.text_layout_cache().layout_str(
                         line,
                         placeholder_style.font_size,
                         &[(
@@ -1395,8 +1396,8 @@ impl EditorElement {
             layout_highlighted_chunks(
                 chunks,
                 &style.text,
-                cx.text_layout_cache,
-                cx.font_cache,
+                cx.text_layout_cache(),
+                cx.font_cache(),
                 MAX_LINE_LEN,
                 rows.len() as usize,
             )
@@ -1419,7 +1420,7 @@ impl EditorElement {
         line_layouts: &[text_layout::Line],
         include_root: bool,
         editor: &mut Editor,
-        cx: &mut LayoutContext,
+        cx: &mut ViewContext<Editor>,
     ) -> (f32, Vec<BlockLayout>) {
         let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
         let scroll_x = snapshot.scroll_anchor.offset.x();
@@ -1441,20 +1442,18 @@ impl EditorElement {
                             line_layouts[(align_to.row() - rows.start) as usize]
                                 .x_for_index(align_to.column() as usize)
                         } else {
-                            layout_line(align_to.row(), snapshot, style, cx.text_layout_cache)
+                            layout_line(align_to.row(), snapshot, style, cx.text_layout_cache())
                                 .x_for_index(align_to.column() as usize)
                         };
 
-                    cx.render(&editor, |_, cx| {
-                        block.render(&mut BlockContext {
-                            cx,
-                            anchor_x,
-                            gutter_padding,
-                            line_height,
-                            scroll_x,
-                            gutter_width,
-                            em_width,
-                        })
+                    block.render(&mut BlockContext {
+                        view_context: cx,
+                        anchor_x,
+                        gutter_padding,
+                        line_height,
+                        scroll_x,
+                        gutter_width,
+                        em_width,
                     })
                 }
                 TransformBlock::ExcerptHeader {
@@ -1480,36 +1479,34 @@ impl EditorElement {
                         };
 
                         enum JumpIcon {}
-                        cx.render(&editor, |_, cx| {
-                            MouseEventHandler::<JumpIcon>::new(id.into(), cx, |state, _| {
-                                let style = style.jump_icon.style_for(state, false);
-                                Svg::new("icons/arrow_up_right_8.svg")
-                                    .with_color(style.color)
-                                    .constrained()
-                                    .with_width(style.icon_width)
-                                    .aligned()
-                                    .contained()
-                                    .with_style(style.container)
-                                    .constrained()
-                                    .with_width(style.button_width)
-                                    .with_height(style.button_width)
-                                    .boxed()
-                            })
-                            .with_cursor_style(CursorStyle::PointingHand)
-                            .on_click(MouseButton::Left, move |_, cx| {
-                                cx.dispatch_action(jump_action.clone())
-                            })
-                            .with_tooltip::<JumpIcon, _>(
-                                id.into(),
-                                "Jump to Buffer".to_string(),
-                                Some(Box::new(crate::OpenExcerpts)),
-                                tooltip_style.clone(),
-                                cx,
-                            )
-                            .aligned()
-                            .flex_float()
-                            .boxed()
+                        MouseEventHandler::<JumpIcon, _>::new(id.into(), cx, |state, _| {
+                            let style = style.jump_icon.style_for(state, false);
+                            Svg::new("icons/arrow_up_right_8.svg")
+                                .with_color(style.color)
+                                .constrained()
+                                .with_width(style.icon_width)
+                                .aligned()
+                                .contained()
+                                .with_style(style.container)
+                                .constrained()
+                                .with_width(style.button_width)
+                                .with_height(style.button_width)
+                                .boxed()
                         })
+                        .with_cursor_style(CursorStyle::PointingHand)
+                        .on_click(MouseButton::Left, move |_, _, cx| {
+                            cx.dispatch_action(jump_action.clone())
+                        })
+                        .with_tooltip::<JumpIcon>(
+                            id.into(),
+                            "Jump to Buffer".to_string(),
+                            Some(Box::new(crate::OpenExcerpts)),
+                            tooltip_style.clone(),
+                            cx,
+                        )
+                        .aligned()
+                        .flex_float()
+                        .boxed()
                     });
 
                     if *starts_new_buffer {
@@ -1614,31 +1611,32 @@ impl EditorElement {
     }
 }
 
-impl Element for EditorElement {
+impl Element<Editor> for EditorElement {
     type LayoutState = LayoutState;
     type PaintState = ();
 
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        editor: &mut Editor,
+        cx: &mut ViewContext<Editor>,
     ) -> (Vector2F, Self::LayoutState) {
         let mut size = constraint.max;
         if size.x().is_infinite() {
             unimplemented!("we don't yet handle an infinite width constraint on buffer elements");
         }
 
-        let snapshot = self.snapshot(cx.app);
+        let snapshot = self.snapshot(cx);
         let style = self.style.clone();
-        let line_height = style.text.line_height(cx.font_cache);
+        let line_height = style.text.line_height(cx.font_cache());
 
         let gutter_padding;
         let gutter_width;
         let gutter_margin;
         if snapshot.mode == EditorMode::Full {
-            gutter_padding = style.text.em_width(cx.font_cache) * style.gutter_padding_factor;
+            gutter_padding = style.text.em_width(cx.font_cache()) * style.gutter_padding_factor;
             gutter_width = self.max_line_number_width(&snapshot, cx) + gutter_padding * 2.0;
-            gutter_margin = -style.text.descent(cx.font_cache);
+            gutter_margin = -style.text.descent(cx.font_cache());
         } else {
             gutter_padding = 0.0;
             gutter_width = 0.0;
@@ -1646,10 +1644,10 @@ impl Element for EditorElement {
         };
 
         let text_width = size.x() - gutter_width;
-        let em_width = style.text.em_width(cx.font_cache);
-        let em_advance = style.text.em_advance(cx.font_cache);
+        let em_width = style.text.em_width(cx.font_cache());
+        let em_advance = style.text.em_advance(cx.font_cache());
         let overscroll = vec2f(em_width, 0.);
-        let snapshot = self.update_view(cx.app, |view, cx| {
+        let snapshot = self.update_view(cx, |view, cx| {
             view.set_visible_line_count(size.y() / line_height);
 
             let editor_width = text_width - gutter_margin - overscroll.x() - em_width;
@@ -1686,7 +1684,7 @@ impl Element for EditorElement {
         let gutter_size = vec2f(gutter_width, size.y());
         let text_size = vec2f(text_width, size.y());
 
-        let (autoscroll_horizontally, mut snapshot) = self.update_view(cx.app, |view, cx| {
+        let (autoscroll_horizontally, mut snapshot) = self.update_view(cx, |view, cx| {
             let autoscroll_horizontally = view.autoscroll_vertically(size.y(), line_height, cx);
             let snapshot = view.snapshot(cx);
             (autoscroll_horizontally, snapshot)
@@ -1728,7 +1726,7 @@ impl Element for EditorElement {
         let mut show_scrollbars = false;
         let mut include_root = false;
         let mut is_singleton = false;
-        self.update_view(cx.app, |view, cx| {
+        self.update_view(cx, |view, cx| {
             is_singleton = view.is_singleton(cx);
 
             let display_map = view.display_map.update(cx, |map, cx| map.snapshot(cx));
@@ -1859,11 +1857,11 @@ impl Element for EditorElement {
             snapshot.longest_row(),
             &snapshot,
             &style,
-            cx.text_layout_cache,
+            cx.text_layout_cache(),
         )
         .width();
         let scroll_width = longest_line_width.max(max_visible_line_width) + overscroll.x();
-        let em_width = style.text.em_width(cx.font_cache);
+        let em_width = style.text.em_width(cx.font_cache());
         let (scroll_width, blocks) = self.layout_blocks(
             start_row..end_row,
             &snapshot,
@@ -1886,7 +1884,7 @@ impl Element for EditorElement {
             max_row as f32,
         );
 
-        self.update_view(cx.app, |view, cx| {
+        self.update_view(cx, |view, cx| {
             let clamped = view.scroll_manager.clamp_scroll_left(scroll_max.x());
 
             let autoscrolled = if autoscroll_horizontally {
@@ -1911,47 +1909,52 @@ impl Element for EditorElement {
         let mut code_actions_indicator = None;
         let mut hover = None;
         let mut mode = EditorMode::Full;
-        let mut fold_indicators = cx.render(&self.view.upgrade(cx).unwrap(), |view, cx| {
-            let newest_selection_head = view
+        let mut fold_indicators = {
+            let newest_selection_head = editor
                 .selections
                 .newest::<usize>(cx)
                 .head()
                 .to_display_point(&snapshot);
 
-            let style = view.style(cx);
+            let style = editor.style(cx);
             if (start_row..end_row).contains(&newest_selection_head.row()) {
-                if view.context_menu_visible() {
+                if editor.context_menu_visible() {
                     context_menu =
-                        view.render_context_menu(newest_selection_head, style.clone(), cx);
+                        editor.render_context_menu(newest_selection_head, style.clone(), cx);
                 }
 
-                let active = matches!(view.context_menu, Some(crate::ContextMenu::CodeActions(_)));
+                let active = matches!(
+                    editor.context_menu,
+                    Some(crate::ContextMenu::CodeActions(_))
+                );
 
-                code_actions_indicator = view
+                code_actions_indicator = editor
                     .render_code_actions_indicator(&style, active, cx)
                     .map(|indicator| (newest_selection_head.row(), indicator));
             }
 
             let visible_rows = start_row..start_row + line_layouts.len() as u32;
-            hover = view.hover_state.render(&snapshot, &style, visible_rows, cx);
-            mode = view.mode;
+            hover = editor
+                .hover_state
+                .render(&snapshot, &style, visible_rows, cx);
+            mode = editor.mode;
 
-            view.render_fold_indicators(
+            editor.render_fold_indicators(
                 fold_statuses,
                 &style,
-                view.gutter_hovered,
+                editor.gutter_hovered,
                 line_height,
                 gutter_margin,
                 cx,
             )
-        });
+        };
 
         if let Some((_, context_menu)) = context_menu.as_mut() {
             context_menu.layout(
                 SizeConstraint {
                     min: Vector2F::zero(),
                     max: vec2f(
-                        cx.window_size.x() * 0.7,
+                        cx.window_size().x() * 0.7,
                         (12. * line_height).min((size.y() - line_height) / 2.),
                     ),
                 },
@@ -1978,6 +1981,7 @@ impl Element for EditorElement {
                         Axis::Vertical,
                         line_height * style.code_actions.vertical_scale,
                     ),
+                    editor,
                     cx,
                 );
             }
@@ -1997,6 +2001,7 @@ impl Element for EditorElement {
                                 .max(MIN_POPOVER_LINE_HEIGHT * line_height), // Apply minimum height of 4 lines
                         ),
                     },
+                    editor,
                     cx,
                 );
             }
@@ -2041,10 +2046,12 @@ impl Element for EditorElement {
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         layout: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        editor: &mut Editor,
+        cx: &mut ViewContext<Editor>,
     ) -> Self::PaintState {
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
         scene.push_layer(Some(visible_bounds));
@@ -2056,6 +2063,7 @@ impl Element for EditorElement {
         );
 
         Self::attach_mouse_handlers(
+            scene,
             &self.view,
             &layout.position_map,
             layout.hover_popovers.is_some(),
@@ -2089,7 +2097,8 @@ impl Element for EditorElement {
         _: RectF,
         layout: &Self::LayoutState,
         _: &Self::PaintState,
-        _: &gpui::MeasurementContext,
+        _: &Editor,
+        _: &ViewContext<Editor>,
     ) -> Option<RectF> {
         let text_bounds = RectF::new(
             bounds.origin() + vec2f(layout.gutter_size.x(), 0.0),
@@ -2132,7 +2141,8 @@ impl Element for EditorElement {
         bounds: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        _: &gpui::DebugContext,
+        _: &Editor,
+        _: &ViewContext<Editor>,
     ) -> json::Value {
         json!({
             "type": "BufferElement",
@@ -2162,10 +2172,10 @@ pub struct LayoutState {
     scrollbar_row_range: Range<f32>,
     show_scrollbars: bool,
     max_row: u32,
-    context_menu: Option<(DisplayPoint, ElementBox)>,
-    code_actions_indicator: Option<(u32, ElementBox)>,
-    hover_popovers: Option<(DisplayPoint, Vec<ElementBox>)>,
-    fold_indicators: Vec<Option<ElementBox>>,
+    context_menu: Option<(DisplayPoint, ElementBox<Editor>)>,
+    code_actions_indicator: Option<(u32, ElementBox<Editor>)>,
+    hover_popovers: Option<(DisplayPoint, Vec<ElementBox<Editor>>)>,
+    fold_indicators: Vec<Option<ElementBox<Editor>>>,
 }
 
 pub struct PositionMap {
@@ -2216,7 +2226,7 @@ impl PositionMap {
 
 struct BlockLayout {
     row: u32,
-    element: ElementBox,
+    element: ElementBox<Editor>,
     style: BlockStyle,
 }
 
@@ -2287,7 +2297,7 @@ impl Cursor {
         )
     }
 
-    pub fn paint(&self, scene: &mut SceneBuilder, origin: Vector2F, cx: &mut AppContext) {
+    pub fn paint(&self, scene: &mut SceneBuilder, origin: Vector2F, cx: &mut WindowContext) {
         let bounds = match self.shape {
             CursorShape::Bar => RectF::new(self.origin + origin, vec2f(2.0, self.line_height)),
             CursorShape::Block | CursorShape::Hollow => RectF::new(

crates/editor/src/hover_popover.rs 🔗

@@ -283,7 +283,7 @@ impl HoverState {
         style: &EditorStyle,
         visible_rows: Range<u32>,
         cx: &mut ViewContext<Editor>,
-    ) -> Option<(DisplayPoint, Vec<ElementBox>)> {
+    ) -> Option<(DisplayPoint, Vec<ElementBox<Editor>>)> {
         // If there is a diagnostic, position the popovers based on that.
         // Otherwise use the start of the hover range
         let anchor = self
@@ -323,9 +323,9 @@ pub struct InfoPopover {
 }
 
 impl InfoPopover {
-    pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext<Editor>) -> ElementBox {
-        MouseEventHandler::<InfoPopover>::new(0, cx, |_, cx| {
-            let mut flex = Flex::new(Axis::Vertical).scrollable::<HoverBlock, _>(1, None, cx);
+    pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext<Editor>) -> ElementBox<Editor> {
+        MouseEventHandler::<InfoPopover, _>::new(0, cx, |_, cx| {
+            let mut flex = Flex::new(Axis::Vertical).scrollable::<HoverBlock>(1, None, cx);
             flex.extend(self.contents.iter().map(|content| {
                 let languages = self.project.read(cx).languages();
                 if let Some(language) = content.language.clone().and_then(|language| {
@@ -360,7 +360,7 @@ impl InfoPopover {
                 .with_style(style.hover_popover.container)
                 .boxed()
         })
-        .on_move(|_, _| {}) // Consume move events so they don't reach regions underneath.
+        .on_move(|_, _, _| {}) // Consume move events so they don't reach regions underneath.
         .with_cursor_style(CursorStyle::Arrow)
         .with_padding(Padding {
             bottom: HOVER_POPOVER_GAP,
@@ -378,7 +378,7 @@ pub struct DiagnosticPopover {
 }
 
 impl DiagnosticPopover {
-    pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext<Editor>) -> ElementBox {
+    pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext<Editor>) -> ElementBox<Editor> {
         enum PrimaryDiagnostic {}
 
         let mut text_style = style.hover_popover.prose.clone();
@@ -394,7 +394,7 @@ impl DiagnosticPopover {
 
         let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
 
-        MouseEventHandler::<DiagnosticPopover>::new(0, cx, |_, _| {
+        MouseEventHandler::<DiagnosticPopover, _>::new(0, cx, |_, _| {
             Text::new(self.local_diagnostic.diagnostic.message.clone(), text_style)
                 .with_soft_wrap(true)
                 .contained()
@@ -406,12 +406,12 @@ impl DiagnosticPopover {
             bottom: HOVER_POPOVER_GAP,
             ..Default::default()
         })
-        .on_move(|_, _| {}) // Consume move events so they don't reach regions underneath.
-        .on_click(MouseButton::Left, |_, cx| {
+        .on_move(|_, _, _| {}) // Consume move events so they don't reach regions underneath.
+        .on_click(MouseButton::Left, |_, _, cx| {
             cx.dispatch_action(GoToDiagnostic)
         })
         .with_cursor_style(CursorStyle::PointingHand)
-        .with_tooltip::<PrimaryDiagnostic, _>(
+        .with_tooltip::<PrimaryDiagnostic>(
             0,
             "Go To Diagnostic".to_string(),
             Some(Box::new(crate::GoToDiagnostic)),

crates/editor/src/items.rs 🔗

@@ -8,7 +8,7 @@ use collections::HashSet;
 use futures::future::try_join_all;
 use gpui::{
     elements::*, geometry::vector::vec2f, AppContext, Entity, ModelHandle, Subscription, Task,
-    View, ViewContext, ViewContext, ViewHandle, WeakViewHandle,
+    View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use language::{
     proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, OffsetRangeExt, Point,
@@ -526,7 +526,7 @@ impl Item for Editor {
         detail: Option<usize>,
         style: &theme::Tab,
         cx: &AppContext,
-    ) -> ElementBox {
+    ) -> ElementBox<Pane> {
         Flex::row()
             .with_child(
                 Label::new(self.title(cx).to_string(), style.label.clone())
@@ -606,7 +606,7 @@ impl Item for Editor {
         self.report_event("save editor", cx);
         let format = self.perform_format(project.clone(), FormatTrigger::Save, cx);
         let buffers = self.buffer().clone().read(cx).all_buffers();
-        cx.as_mut().spawn(|mut cx| async move {
+        cx.spawn(|_, mut cx| async move {
             format.await?;
 
             if buffers.len() == 1 {
@@ -727,7 +727,7 @@ impl Item for Editor {
         ToolbarItemLocation::PrimaryLeft { flex: None }
     }
 
-    fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option<Vec<ElementBox>> {
+    fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option<Vec<ElementBox<Pane>>> {
         let cursor = self.selections.newest_anchor().head();
         let multibuffer = &self.buffer().read(cx);
         let (buffer_id, symbols) =
@@ -1078,7 +1078,7 @@ impl View for CursorPosition {
         "CursorPosition"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         if let Some(position) = self.position {
             let theme = &cx.global::<Settings>().theme.workspace.status_bar;
             let mut text = format!("{},{}", position.row + 1, position.column + 1);

crates/go_to_line/src/go_to_line.rs 🔗

@@ -156,7 +156,7 @@ impl View for GoToLine {
         "GoToLine"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         let theme = &cx.global::<Settings>().theme.picker;
 
         let label = format!(

crates/gpui/src/app/window.rs 🔗

@@ -12,9 +12,10 @@ use crate::{
     },
     text_layout::TextLayoutCache,
     util::post_inc,
-    AnyView, AnyViewHandle, AppContext, Element, ElementBox, Entity, ModelContext, ModelHandle,
-    MouseRegion, MouseRegionId, ParentId, ReadView, RenderParams, SceneBuilder, UpdateModel, View,
-    ViewContext, ViewHandle, WindowInvalidation,
+    AnyView, AnyViewHandle, AnyWeakViewHandle, AppContext, Element, ElementBox, Entity,
+    ModelContext, ModelHandle, MouseRegion, MouseRegionId, ParentId, ReadView, RenderParams,
+    SceneBuilder, UpdateModel, UpgradeViewHandle, View, ViewContext, ViewHandle, WeakViewHandle,
+    WindowInvalidation,
 };
 use anyhow::bail;
 use collections::{HashMap, HashSet};
@@ -121,10 +122,10 @@ impl DerefMut for WindowContext<'_, '_> {
 }
 
 impl UpdateModel for WindowContext<'_, '_> {
-    fn update_model<M: Entity, R>(
+    fn update_model<T: Entity, R>(
         &mut self,
-        handle: &ModelHandle<M>,
-        update: &mut dyn FnMut(&mut M, &mut ModelContext<M>) -> R,
+        handle: &ModelHandle<T>,
+        update: &mut dyn FnMut(&mut T, &mut ModelContext<T>) -> R,
     ) -> R {
         self.app_context.update_model(handle, update)
     }
@@ -136,6 +137,16 @@ impl ReadView for WindowContext<'_, '_> {
     }
 }
 
+impl UpgradeViewHandle for WindowContext<'_, '_> {
+    fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>> {
+        self.app_context.upgrade_view_handle(handle)
+    }
+
+    fn upgrade_any_view_handle(&self, handle: &AnyWeakViewHandle) -> Option<AnyViewHandle> {
+        self.app_context.upgrade_any_view_handle(handle)
+    }
+}
+
 impl<'a: 'b, 'b> WindowContext<'a, 'b> {
     pub fn new(app_context: &'a mut AppContext, window: &'b mut Window, window_id: usize) -> Self {
         Self {

crates/gpui/src/gpui.rs 🔗

@@ -29,7 +29,7 @@ pub mod json;
 pub mod keymap_matcher;
 pub mod platform;
 pub use gpui_macros::test;
-pub use window::{Axis, SizeConstraint, Vector2FExt};
+pub use window::{Axis, SizeConstraint, Vector2FExt, WindowContext};
 
 pub use anyhow;
 pub use serde_json;

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

@@ -11,7 +11,11 @@ use collections::HashMap;
 use pathfinder_geometry::rect::RectF;
 use smallvec::SmallVec;
 
-use crate::{platform::MouseButton, window::WindowContext, ReadView, View, ViewContext};
+use crate::{
+    platform::MouseButton, window::WindowContext, AnyModelHandle, AnyViewHandle,
+    AnyWeakModelHandle, AnyWeakViewHandle, Entity, ModelHandle, ReadView, UpgradeModelHandle,
+    UpgradeViewHandle, View, ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle,
+};
 
 use super::{
     mouse_event::{
@@ -240,6 +244,33 @@ impl<V: View> ReadView for EventContext<'_, '_, '_, '_, V> {
     }
 }
 
+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/picker/src/picker.rs 🔗

@@ -4,8 +4,8 @@ use gpui::{
     geometry::vector::{vec2f, Vector2F},
     keymap_matcher::KeymapContext,
     platform::{CursorStyle, MouseButton},
-    AnyViewHandle, AppContext, Axis, Entity, MouseState, Task, View, ViewContext, ViewHandle,
-    WeakViewHandle,
+    AnyViewHandle, AppContext, Axis, ElementBox, Entity, MouseState, Task, View, ViewContext,
+    ViewHandle, WeakViewHandle,
 };
 use menu::{Cancel, Confirm, SelectFirst, SelectIndex, SelectLast, SelectNext, SelectPrev};
 use parking_lot::Mutex;
@@ -33,7 +33,7 @@ pub trait PickerDelegate: View {
         state: &mut MouseState,
         selected: bool,
         cx: &AppContext,
-    ) -> ElementBox;
+    ) -> ElementBox<Self>;
     fn center_selection_after_match_updates(&self) -> bool {
         false
     }
@@ -48,11 +48,11 @@ impl<D: PickerDelegate> View for Picker<D> {
         "Picker"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> gpui::ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         let theme = (self.theme.lock())(&cx.global::<settings::Settings>().theme);
         let query = self.query(cx);
         let delegate = self.delegate.clone();
-        let match_count = if let Some(delegate) = delegate.upgrade(cx.app) {
+        let match_count = if let Some(delegate) = delegate.upgrade(cx) {
             delegate.read(cx).match_count()
         } else {
             0
@@ -97,15 +97,15 @@ impl<D: PickerDelegate> View for Picker<D> {
                             let selected_ix = delegate.read(cx).selected_index();
                             range.end = cmp::min(range.end, delegate.read(cx).match_count());
                             items.extend(range.map(move |ix| {
-                                MouseEventHandler::<D>::new(ix, cx, |state, cx| {
+                                MouseEventHandler::<D, _>::new(ix, cx, |state, cx| {
                                     delegate
                                         .read(cx)
                                         .render_match(ix, state, ix == selected_ix, cx)
                                 })
                                 // Capture mouse events
-                                .on_down(MouseButton::Left, |_, _| {})
-                                .on_up(MouseButton::Left, |_, _| {})
-                                .on_click(MouseButton::Left, move |_, cx| {
+                                .on_down(MouseButton::Left, |_, _, _| {})
+                                .on_up(MouseButton::Left, |_, _, _| {})
+                                .on_click(MouseButton::Left, move |_, _, cx| {
                                     cx.dispatch_action(SelectIndex(ix))
                                 })
                                 .with_cursor_style(CursorStyle::PointingHand)

crates/project_panel/src/project_panel.rs 🔗

@@ -1098,7 +1098,7 @@ impl ProjectPanel {
         row_container_style: ContainerStyle,
         style: &ProjectPanelEntry,
         cx: &mut ViewContext<V>,
-    ) -> ElementBox {
+    ) -> ElementBox<V> {
         let kind = details.kind;
         let show_editor = details.is_editing && !details.is_processing;
 
@@ -1155,8 +1155,8 @@ impl ProjectPanel {
         dragged_entry_destination: &mut Option<Arc<Path>>,
         theme: &theme::ProjectPanel,
         cx: &mut ViewContext<Self>,
-    ) -> ElementBox {
-        let this = cx.handle();
+    ) -> ElementBox<Self> {
+        let this = cx.handle().downgrade();
         let kind = details.kind;
         let path = details.path.clone();
         let padding = theme.container.padding.left + details.depth as f32 * theme.indent_width;
@@ -1171,7 +1171,7 @@ impl ProjectPanel {
 
         let show_editor = details.is_editing && !details.is_processing;
 
-        MouseEventHandler::<Self>::new(entry_id.to_usize(), cx, |state, cx| {
+        MouseEventHandler::<Self, _>::new(entry_id.to_usize(), cx, |state, cx| {
             let mut style = entry_style.style_for(state, details.is_selected).clone();
 
             if cx
@@ -1201,7 +1201,7 @@ impl ProjectPanel {
                 cx,
             )
         })
-        .on_click(MouseButton::Left, move |e, cx| {
+        .on_click(MouseButton::Left, move |e, _, cx| {
             if !show_editor {
                 if kind == EntryKind::Dir {
                     cx.dispatch_action(ToggleExpanded(entry_id))
@@ -1213,13 +1213,13 @@ impl ProjectPanel {
                 }
             }
         })
-        .on_down(MouseButton::Right, move |e, cx| {
+        .on_down(MouseButton::Right, move |e, _, cx| {
             cx.dispatch_action(DeployContextMenu {
                 entry_id,
                 position: e.position,
             })
         })
-        .on_up(MouseButton::Left, move |_, cx| {
+        .on_up(MouseButton::Left, move |_, _, cx| {
             if let Some((_, dragged_entry)) = cx
                 .global::<DragAndDrop<Workspace>>()
                 .currently_dragged::<ProjectEntryId>(cx.window_id())
@@ -1231,14 +1231,14 @@ impl ProjectPanel {
                 });
             }
         })
-        .on_move(move |_, cx| {
+        .on_move(move |_, _, cx| {
             if cx
                 .global::<DragAndDrop<Workspace>>()
                 .currently_dragged::<ProjectEntryId>(cx.window_id())
                 .is_some()
             {
-                if let Some(this) = this.upgrade(cx.app) {
-                    this.update(cx.app, |this, _| {
+                if let Some(this) = this.upgrade(cx) {
+                    this.update(cx, |this, _, _| {
                         this.dragged_entry_destination = if matches!(kind, EntryKind::File(_)) {
                             path.parent().map(|parent| Arc::from(parent))
                         } else {
@@ -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<Workspace>| {
                 let theme = cx.global::<Settings>().theme.clone();
                 Self::render_entry_visual_element(
                     &details,
@@ -1273,7 +1273,7 @@ impl View for ProjectPanel {
         "ProjectPanel"
     }
 
-    fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox {
+    fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> gpui::ElementBox<Self> {
         enum ProjectPanel {}
         let theme = &cx.global::<Settings>().theme.project_panel;
         let mut container_style = theme.container;
@@ -1285,7 +1285,7 @@ impl View for ProjectPanel {
         if has_worktree {
             Stack::new()
                 .with_child(
-                    MouseEventHandler::<ProjectPanel>::new(0, cx, |_, cx| {
+                    MouseEventHandler::<ProjectPanel, _>::new(0, cx, |_, cx| {
                         UniformList::new(
                             self.list.clone(),
                             self.visible_entries
@@ -1317,7 +1317,7 @@ impl View for ProjectPanel {
                         .expanded()
                         .boxed()
                     })
-                    .on_down(MouseButton::Right, move |e, cx| {
+                    .on_down(MouseButton::Right, move |e, _, cx| {
                         // When deploying the context menu anywhere below the last project entry,
                         // act as if the user clicked the root of the last worktree.
                         if let Some(entry_id) = last_worktree_root_id {
@@ -1334,7 +1334,7 @@ impl View for ProjectPanel {
         } else {
             Flex::column()
                 .with_child(
-                    MouseEventHandler::<Self>::new(2, cx, {
+                    MouseEventHandler::<Self, _>::new(2, cx, {
                         let button_style = theme.open_project_button.clone();
                         let context_menu_item_style =
                             cx.global::<Settings>().theme.context_menu.item.clone();
@@ -1353,7 +1353,7 @@ impl View for ProjectPanel {
                             .boxed()
                         }
                     })
-                    .on_click(MouseButton::Left, move |_, cx| {
+                    .on_click(MouseButton::Left, move |_, _, cx| {
                         cx.dispatch_action(workspace::Open)
                     })
                     .with_cursor_style(CursorStyle::PointingHand)

crates/search/src/buffer_search.rs 🔗

@@ -91,7 +91,7 @@ impl View for BufferSearchBar {
         }
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         let theme = cx.global::<Settings>().theme.clone();
         let editor_container = if self.query_contains_error {
             theme.search.invalid_editor
@@ -324,7 +324,7 @@ impl BufferSearchBar {
         icon: &'static str,
         option: SearchOption,
         cx: &mut ViewContext<Self>,
-    ) -> Option<ElementBox> {
+    ) -> Option<ElementBox<Self>> {
         if !option_supported {
             return None;
         }
@@ -332,7 +332,7 @@ impl BufferSearchBar {
         let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
         let is_active = self.is_search_option_enabled(option);
         Some(
-            MouseEventHandler::<Self>::new(option as usize, cx, |state, cx| {
+            MouseEventHandler::<Self, _>::new(option as usize, cx, |state, cx| {
                 let style = cx
                     .global::<Settings>()
                     .theme
@@ -344,11 +344,11 @@ impl BufferSearchBar {
                     .with_style(style.container)
                     .boxed()
             })
-            .on_click(MouseButton::Left, move |_, cx| {
+            .on_click(MouseButton::Left, move |_, _, cx| {
                 cx.dispatch_any_action(option.to_toggle_action())
             })
             .with_cursor_style(CursorStyle::PointingHand)
-            .with_tooltip::<Self, _>(
+            .with_tooltip::<Self, _, _>(
                 option as usize,
                 format!("Toggle {}", option.label()),
                 Some(option.to_toggle_action()),
@@ -364,7 +364,7 @@ impl BufferSearchBar {
         icon: &'static str,
         direction: Direction,
         cx: &mut ViewContext<Self>,
-    ) -> ElementBox {
+    ) -> ElementBox<Self> {
         let action: Box<dyn Action>;
         let tooltip;
         match direction {
@@ -380,7 +380,7 @@ impl BufferSearchBar {
         let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
 
         enum NavButton {}
-        MouseEventHandler::<NavButton>::new(direction as usize, cx, |state, cx| {
+        MouseEventHandler::<NavButton, _>::new(direction as usize, cx, |state, cx| {
             let style = cx
                 .global::<Settings>()
                 .theme
@@ -394,10 +394,10 @@ impl BufferSearchBar {
         })
         .on_click(MouseButton::Left, {
             let action = action.boxed_clone();
-            move |_, cx| cx.dispatch_any_action(action.boxed_clone())
+            mov_, _, cx| cx.dispatch_any_action(action.boxed_clone())
         })
         .with_cursor_style(CursorStyle::PointingHand)
-        .with_tooltip::<NavButton, _>(
+        .with_tooltip::<NavButton,_ _,,  _>(
             direction as usize,
             tooltip.to_string(),
             Some(action),
@@ -407,13 +407,17 @@ impl BufferSearchBar {
         .boxed()
     }
 
-    fn render_close_button(&self, theme: &theme::Search, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render_close_button(
+        &self,
+        theme: &theme::Search,
+        cx: &mut ViewContext<Self>,
+    ) -> ElementBox<Self> {
         let action = Box::new(Dismiss);
         let tooltip = "Dismiss Buffer Search";
         let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
 
         enum CloseButton {}
-        MouseEventHandler::<CloseButton>::new(0, cx, |state, _| {
+        MouseEventHandler::<CloseButton, _>::new(0, cx, |state, _| {
             let style = theme.dismiss_button.style_for(state, false);
             Svg::new("icons/x_mark_8.svg")
                 .with_color(style.color)
@@ -428,10 +432,10 @@ impl BufferSearchBar {
         })
         .on_click(MouseButton::Left, {
             let action = action.boxed_clone();
-            move |_, cx| cx.dispatch_any_action(action.boxed_clone())
+            move |_, _, _, cx| cx.dispatch_any_action(action.boxed_clone())
         })
         .with_cursor_style(CursorStyle::PointingHand)
-        .with_tooltip::<CloseButton, _>(0, tooltip.to_string(), Some(action), tooltip_style, cx)
+        .with_tooltip::<CloseButton>(0, tooltip.to_string(), Some(action), tooltip_style, cx)
         .boxed()
     }
 

crates/search/src/project_search.rs 🔗

@@ -177,7 +177,7 @@ impl View for ProjectSearchView {
         "ProjectSearchView"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         let model = &self.model.read(cx);
         if model.match_ranges.is_empty() {
             enum Status {}
@@ -190,7 +190,7 @@ impl View for ProjectSearchView {
             } else {
                 "No results"
             };
-            MouseEventHandler::<Status>::new(0, cx, |_, _| {
+            MouseEventHandler::<Status, _>::new(0, cx, |_, _| {
                 Label::new(text, theme.search.results_status.clone())
                     .aligned()
                     .contained()
@@ -198,7 +198,7 @@ impl View for ProjectSearchView {
                     .flex(1., true)
                     .boxed()
             })
-            .on_down(MouseButton::Left, |_, cx| {
+            .on_down(MouseButton::Left, |_, _, _, cx| {
                 cx.focus_parent_view();
             })
             .boxed()
@@ -249,7 +249,7 @@ impl Item for ProjectSearchView {
         _detail: Option<usize>,
         tab_theme: &theme::Tab,
         cx: &AppContext,
-    ) -> ElementBox {
+    ) -> ElementBox<Pane> {
         Flex::row()
             .with_child(
                 Svg::new("icons/magnifying_glass_12.svg")
@@ -364,7 +364,7 @@ impl Item for ProjectSearchView {
         }
     }
 
-    fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option<Vec<ElementBox>> {
+    fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option<Vec<ElementBox<Pane>>> {
         self.results_editor.breadcrumbs(theme, cx)
     }
 
@@ -747,7 +747,7 @@ impl ProjectSearchBar {
         icon: &'static str,
         direction: Direction,
         cx: &mut ViewContext<Self>,
-    ) -> ElementBox {
+    ) -> ElementBox<Self> {
         let action: Box<dyn Action>;
         let tooltip;
         match direction {
@@ -763,7 +763,7 @@ impl ProjectSearchBar {
         let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
 
         enum NavButton {}
-        MouseEventHandler::<NavButton>::new(direction as usize, cx, |state, cx| {
+        MouseEventHandler::<NavButton, _>::new(direction as usize, cx, |state, cx| {
             let style = &cx
                 .global::<Settings>()
                 .theme
@@ -775,13 +775,12 @@ impl ProjectSearchBar {
                 .with_style(style.container)
                 .boxed()
         })
-        .on_click(MouseButton::Left, {
+        .on_click(MouseButton::Le {
             let action = action.boxed_clone();
-            move |_, cx| cx.dispatch_any_action(action.boxed_clone())
-        })
+            move |_, _, cx| cx.dispatch_any_action(action.boxed_clone())
+    _,    })
         .with_cursor_style(CursorStyle::PointingHand)
-        .with_tooltip::<NavButton, _>(
-            direction as usize,
+        .with_tooltip::<NavButton, _            direction as usize,
             tooltip.to_string(),
             Some(action),
             tooltip_style,
@@ -795,10 +794,10 @@ impl ProjectSearchBar {
         icon: &'static str,
         option: SearchOption,
         cx: &mut ViewContext<Self>,
-    ) -> ElementBox {
+    ) -> ElementBox<Self> {
         let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
         let is_active = self.is_option_enabled(option, cx);
-        MouseEventHandler::<Self>::new(option as usize, cx, |state, cx| {
+        MouseEventHandler::<Self, _>::new(option as usize, cx, |state, cx| {
             let style = &cx
                 .global::<Settings>()
                 .theme
@@ -810,11 +809,11 @@ impl ProjectSearchBar {
                 .with_style(style.container)
                 .boxed()
         })
-        .on_click(MouseButton::Left, move |_, cx| {
+        .on_click(MouseButton::Left, move |_, _, cx| {
             cx.dispatch_any_action(option.to_toggle_action())
         })
         .with_cursor_style(CursorStyle::PointingHand)
-        .with_tooltip::<Self, _>(
+        .with_tooltip::<Self>(
             option as usize,
             format!("Toggle {}", option.label()),
             Some(option.to_toggle_action()),
@@ -847,7 +846,7 @@ impl View for ProjectSearchBar {
         "ProjectSearchBar"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         if let Some(search) = self.active_project_search.as_ref() {
             let search = search.read(cx);
             let theme = cx.global::<Settings>().theme.clone();

crates/terminal_view/src/terminal_button.rs 🔗

@@ -42,7 +42,7 @@ impl View for TerminalButton {
         "TerminalButton"
     }
 
-    fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         let workspace = self.workspace.upgrade(cx);
         let project = match workspace {
             Some(workspace) => workspace.read(cx).project().read(cx),
@@ -62,7 +62,7 @@ impl View for TerminalButton {
 
         Stack::new()
             .with_child(
-                MouseEventHandler::<Self>::new(0, cx, {
+                MouseEventHandler::<Self, _>::new(0, cx, {
                     let theme = theme.clone();
                     move |state, _cx| {
                         let style = theme
@@ -96,7 +96,7 @@ impl View for TerminalButton {
                     }
                 })
                 .with_cursor_style(CursorStyle::PointingHand)
-                .on_click(MouseButton::Left, move |_, cx| {
+                .on_click(MouseButton::Left, move |_, _, cx| {
                     if has_terminals {
                         cx.dispatch_action(DeployTerminalMenu);
                     } else {
@@ -105,7 +105,7 @@ impl View for TerminalButton {
                         }
                     };
                 })
-                .with_tooltip::<Self, _>(
+                .with_tooltip::<Self>(
                     0,
                     "Show Terminal".into(),
                     Some(Box::new(FocusDock)),

crates/terminal_view/src/terminal_element.rs 🔗

@@ -100,7 +100,7 @@ impl LayoutCell {
         };
 
         self.text
-            .paint(pos, visible_bounds, layout.size.line_height, view, cx);
+            .paint(scene, pos, visible_bounds, layout.size.line_height, cx);
     }
 }
 
@@ -128,7 +128,14 @@ impl LayoutRect {
         }
     }
 
-    fn paint(&self, origin: Vector2F, layout: &LayoutState, cx: &mut PaintContext) {
+    fn paint(
+        &self,
+        scene: &mut SceneBuilder,
+        origin: Vector2F,
+        layout: &LayoutState,
+        view: &mut TerminalView,
+        cx: &mut ViewContext<TerminalView>,
+    ) {
         let position = {
             let point = self.point;
             vec2f(
@@ -363,11 +370,11 @@ impl TerminalElement {
         connection: WeakModelHandle<Terminal>,
         origin: Vector2F,
         f: impl Fn(&mut Terminal, Vector2F, E, &mut ModelContext<Terminal>),
-    ) -> impl Fn(E, &mut EventContext) {
-        move |event, cx| {
+    ) -> impl Fn(E, &mut TerminalView, &mut EventContext<TerminalView>) {
+        move |event, _: &mut TerminalView, cx| {
             cx.focus_parent_view();
-            if let Some(conn_handle) = connection.upgrade(cx.app) {
-                conn_handle.update(cx.app, |terminal, cx| {
+            if let Some(conn_handle) = connection.upgrade(cx) {
+                conn_handle.update(cx, |terminal, cx| {
                     f(terminal, origin, event, cx);
 
                     cx.notify();
@@ -378,6 +385,7 @@ impl TerminalElement {
 
     fn attach_mouse_handlers(
         &self,
+        scene: &mut SceneBuilder,
         origin: Vector2F,
         view_id: usize,
         visible_bounds: RectF,
@@ -402,10 +410,10 @@ impl TerminalElement {
                 ),
             )
             // Update drag selections
-            .on_drag(MouseButton::Left, move |event, cx| {
+            .on_drag(MouseButton::Left, move |event, _, cx| {
                 if cx.is_parent_view_focused() {
-                    if let Some(conn_handle) = connection.upgrade(cx.app) {
-                        conn_handle.update(cx.app, |terminal, cx| {
+                    if let Some(conn_handle) = connection.upgrade(cx) {
+                        conn_handle.update(cx, |terminal, cx| {
                             terminal.mouse_drag(event, origin);
                             cx.notify();
                         })
@@ -424,9 +432,9 @@ impl TerminalElement {
                 ),
             )
             // Context menu
-            .on_click(MouseButton::Right, move |e, cx| {
-                let mouse_mode = if let Some(conn_handle) = connection.upgrade(cx.app) {
-                    conn_handle.update(cx.app, |terminal, _cx| terminal.mouse_mode(e.shift))
+            .on_click(MouseButton::Right, move |e, _, cx| {
+                let mouse_mode = if let Some(conn_handle) = connection.upgrade(cx) {
+                    conn_handle.update(cx, |terminal, _cx| terminal.mouse_mode(e.shift))
                 } else {
                     // If we can't get the model handle, probably can't deploy the context menu
                     true
@@ -437,20 +445,19 @@ impl TerminalElement {
                     });
                 }
             })
-            .on_move(move |event, cx| {
+            .on_move(move |event, _, cx| {
                 if cx.is_parent_view_focused() {
-                    if let Some(conn_handle) = connection.upgrade(cx.app) {
-                        conn_handle.update(cx.app, |terminal, cx| {
+                    if let Some(conn_handle) = connection.upgrade(cx) {
+                        conn_handle.update(cx, |terminal, cx| {
                             terminal.mouse_move(&event, origin);
                             cx.notify();
                         })
                     }
                 }
             })
-            .on_scroll(move |event, cx| {
-                // cx.focus_parent_view();
-                if let Some(conn_handle) = connection.upgrade(cx.app) {
-                    conn_handle.update(cx.app, |terminal, cx| {
+            .on_scroll(move |event, _, cx| {
+                if let Some(conn_handle) = connection.upgrade(cx) {
+                    conn_handle.update(cx, |terminal, cx| {
                         terminal.scroll_wheel(event, origin);
                         cx.notify();
                     })
@@ -548,7 +555,7 @@ impl TerminalElement {
     }
 }
 
-impl Element for TerminalElement {
+impl Element<TerminalView> for TerminalElement {
     type LayoutState = LayoutState;
     type PaintState = ();
 
@@ -584,7 +591,7 @@ impl Element for TerminalElement {
         let background_color = terminal_theme.background;
         let terminal_handle = self.terminal.upgrade(cx).unwrap();
 
-        let last_hovered_hyperlink = terminal_handle.update(cx.app, |terminal, cx| {
+        let last_hovered_hyperlink = terminal_handle.update(cx, |terminal, cx| {
             terminal.set_size(dimensions);
             terminal.try_sync(cx);
             terminal.last_content.last_hovered_hyperlink.clone()
@@ -724,6 +731,7 @@ impl Element for TerminalElement {
         bounds: RectF,
         visible_bounds: RectF,
         layout: &mut Self::LayoutState,
+        view: &mut TerminalView,
         cx: &mut ViewContext<TerminalView>,
     ) -> Self::PaintState {
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
@@ -735,7 +743,14 @@ impl Element for TerminalElement {
             let origin = bounds.origin() + vec2f(layout.size.cell_width, 0.);
 
             // Elements are ephemeral, only at paint time do we know what could be clicked by a mouse
-            self.attach_mouse_handlers(origin, self.view.id(), visible_bounds, layout.mode, cx);
+            self.attach_mouse_handlers(
+                origin,
+                self.view.id(),
+                visible_bounds,
+                layout.mode,
+                view,
+                cx,
+            );
 
             scene.push_cursor_region(gpui::CursorRegion {
                 bounds,
@@ -756,7 +771,7 @@ impl Element for TerminalElement {
                 });
 
                 for rect in &layout.rects {
-                    rect.paint(origin, layout, cx)
+                    rect.paint(scene, origin, layout, view, cx)
                 }
             });
 
@@ -797,7 +812,7 @@ impl Element for TerminalElement {
             }
 
             if let Some(element) = &mut layout.hyperlink_tooltip {
-                Element<TerminalView>::paint(element, scene, origin, visible_bounds, view, cx)
+                Element::paint(element, scene, origin, visible_bounds, view, view, cx)
             }
         });
     }
@@ -808,10 +823,11 @@ impl Element for TerminalElement {
 
     fn debug(
         &self,
-        _bounds: RectF,
-        _layout: &Self::LayoutState,
-        _paint: &Self::PaintState,
-        _cx: &gpui::DebugContext,
+        _: RectF,
+        _: &Self::LayoutState,
+        _: &Self::PaintState,
+        _: &TerminalView,
+        _: &gpui::ViewContext<TerminalView>,
     ) -> gpui::serde_json::Value {
         json!({
             "type": "TerminalElement",
@@ -825,7 +841,8 @@ impl Element for TerminalElement {
         _: RectF,
         layout: &Self::LayoutState,
         _: &Self::PaintState,
-        _: &gpui::MeasurementContext,
+        _: &TerminalView,
+        _: &gpui::ViewContext<TerminalView>,
     ) -> Option<RectF> {
         // Use the same origin that's passed to `Cursor::paint` in the paint
         // method bove.

crates/terminal_view/src/terminal_view.rs 🔗

@@ -236,7 +236,7 @@ impl TerminalView {
         cx.notify();
     }
 
-    pub fn should_show_cursor(&self, focused: bool, cx: &mut gpui::ViewContext<'_, Self>) -> bool {
+    pub fn should_show_cursor(&self, focused: bool, cx: &mut gpui::ViewContext<Self>) -> bool {
         //Don't blink the cursor when not focused, blinking is disabled, or paused
         if !focused
             || !self.blinking_on
@@ -384,7 +384,7 @@ impl View for TerminalView {
         "Terminal"
     }
 
-    fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> ElementBox<Self> {
         let terminal_handle = self.terminal.clone().downgrade();
 
         let self_id = cx.view_id();
@@ -544,7 +544,7 @@ impl Item for TerminalView {
         _detail: Option<usize>,
         tab_theme: &theme::Tab,
         cx: &gpui::AppContext,
-    ) -> ElementBox {
+    ) -> ElementBox<Pane> {
         let title = self.terminal().read(cx).title();
 
         Flex::row()
@@ -606,7 +606,7 @@ impl Item for TerminalView {
         ToolbarItemLocation::PrimaryLeft { flex: None }
     }
 
-    fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option<Vec<ElementBox>> {
+    fn breadcrumbs(&self, theme: &theme::Theme, cx: &AppContext) -> Option<Vec<ElementBox<Pane>>> {
         Some(vec![Text::new(
             self.terminal().read(cx).breadcrumb_text.clone(),
             theme.workspace.breadcrumbs.default.text.clone(),

crates/theme_testbench/src/theme_testbench.rs 🔗

@@ -34,11 +34,11 @@ impl ThemeTestbench {
         workspace.add_item(Box::new(view), cx);
     }
 
-    fn render_ramps(color_scheme: &ColorScheme) -> Flex {
-        fn display_ramp(ramp: &Vec<Color>) -> ElementBox {
+    fn render_ramps(color_scheme: &ColorScheme) -> Flex<Self> {
+        fn display_ramp(ramp: &Vec<Color>) -> ElementBox<ThemeTestbench> {
             Flex::row()
                 .with_children(ramp.iter().cloned().map(|color| {
-                    Canvas::new(move |bounds, _, cx| {
+                    Canvas::new(move |scene, bounds, _, _, _| {
                         scene.push_quad(Quad {
                             bounds,
                             background: Some(color),
@@ -67,8 +67,8 @@ impl ThemeTestbench {
     fn render_layer(
         layer_index: usize,
         layer: &Layer,
-        cx: &mut ViewContext<'_, Self>,
-    ) -> Container {
+        cx: &mut ViewContext<Self>,
+    ) -> Container<Self> {
         Flex::column()
             .with_child(
                 Self::render_button_set(0, layer_index, "base", &layer.base, cx)
@@ -123,8 +123,8 @@ impl ThemeTestbench {
         layer_index: usize,
         set_name: &'static str,
         style_set: &StyleSet,
-        cx: &mut ViewContext<'_, Self>,
-    ) -> Flex {
+        cx: &mut ViewContext<Self>,
+    ) -> Flex<Self> {
         Flex::row()
             .with_child(Self::render_button(
                 set_index * 6,
@@ -182,10 +182,10 @@ impl ThemeTestbench {
         text: &'static str,
         style_set: &StyleSet,
         style_override: Option<fn(&StyleSet) -> &Style>,
-        cx: &mut ViewContext<'_, Self>,
-    ) -> ElementBox {
+        cx: &mut ViewContext<Self>,
+    ) -> ElementBox<Self> {
         enum TestBenchButton {}
-        MouseEventHandler::<TestBenchButton>::new(layer_index + button_index, cx, |state, cx| {
+        MouseEventHandler::<TestBenchButton, _>::new(layer_index + button_index, cx, |state, cx| {
             let style = if let Some(style_override) = style_override {
                 style_override(&style_set)
             } else if state.clicked().is_some() {
@@ -230,7 +230,7 @@ impl ThemeTestbench {
         .boxed()
     }
 
-    fn render_label(text: String, style: &Style, cx: &mut ViewContext<'_, Self>) -> Label {
+    fn render_label(text: String, style: &Style, cx: &mut ViewContext<Self>) -> Label {
         let settings = cx.global::<Settings>();
         let font_cache = cx.font_cache();
         let family_id = settings.buffer_font_family;
@@ -262,7 +262,7 @@ impl View for ThemeTestbench {
         "ThemeTestbench"
     }
 
-    fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox {
+    fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> ElementBox<Self> {
         let color_scheme = &cx.global::<Settings>().theme.clone().color_scheme;
 
         Flex::row()
@@ -303,7 +303,7 @@ impl Item for ThemeTestbench {
         _: Option<usize>,
         style: &theme::Tab,
         _: &AppContext,
-    ) -> gpui::ElementBox {
+    ) -> ElementBox<Pane> {
         Label::new("Theme Testbench", style.label.clone())
             .aligned()
             .contained()