WIP: Remove V parameter on elements (#3366)

Mikayla Maki created

This is an exploration of what it would take to remove the `V` generic
from the element type. Answer: less than I expected.

I added a new struct to GPUI2: `CallbackHandle<Event>`, and reworked the
interactivity related APIs to take this type. I also added a
`.callback()` function to `ViewContext` that can construct a
`CallbackHandle` to wrap our current `|&mut View, &Evt, &mut
ViewContext| {...}` based APIs. With these two changes, we can now
capture the context of the callsite of a click handler, allowing us to
capture all relevant types and data _before_ sending them into GPUI.
This lets us achieve a similar programing style to the existing system,
while also letting us remove all of the generics from the entire element
system. For an example of what this looks like in practice, here's a
side by side diff of the test in `interactive.rs` (which compiles and
passes):

<img width="1310" alt="Screenshot 2023-11-19 at 7 32 08 PM"
src="https://github.com/zed-industries/zed/assets/2280405/596f2a9a-9c8e-4158-bf6d-0003cf973015">

Note how the new arrangement of types is more amenable to rust's type
inference, allowing the code to be just as terse as before despite the
extra function call in the middle.

This approach also allows components to provide well typed APIs to
views, without ever knowing that view's type. This PR includes an
example rewrite of the button component in `ui2`, here's what it's
struct could look like now:

<img width="1105" alt="Screenshot 2023-11-19 at 7 24 28 PM"
src="https://github.com/zed-industries/zed/assets/2280405/fc98d3c2-6831-4c0f-a324-ab0fae33b0bc">

However, I have not yet ported the derive macro for Component to this
new structure, as I know @nathansobo is currently reworking that code.

Once that macro has been rewritten, it should be relatively easy to
rewrite the rest of Zed2 with this approach, the only major difference
that I can foresee is that the editor element would need to wrap it's
operations in an update callback. Though I can think of a few ways to
fix this with a new `ViewElement` trait, that does the wrapping for you.

Change summary

Cargo.lock                                       |   63 -
Cargo.toml                                       |    4 
crates/auto_update2/src/update_notification.rs   |    4 
crates/collab_ui2/src/collab_panel.rs            |    4 
crates/collab_ui2/src/collab_titlebar_item.rs    |   12 
crates/command_palette2/src/command_palette.rs   |    6 
crates/diagnostics2/src/diagnostics.rs           |   15 
crates/diagnostics2/src/items.rs                 |   12 
crates/diagnostics2/src/toolbar_controls.rs      |   10 
crates/editor2/src/display_map/block_map.rs      |    6 
crates/editor2/src/editor.rs                     |   69 
crates/editor2/src/element.rs                    |  526 ++++---
crates/editor2/src/hover_popover.rs              |    4 
crates/editor2/src/items.rs                      |    4 
crates/file_finder2/src/file_finder.rs           |    6 
crates/go_to_line2/src/go_to_line.rs             |    8 
crates/gpui2/src/app.rs                          |    2 
crates/gpui2/src/app/async_context.rs            |    6 
crates/gpui2/src/app/test_context.rs             |   14 
crates/gpui2/src/element.rs                      |  275 +--
crates/gpui2/src/elements/div.rs                 |  480 +++----
crates/gpui2/src/elements/img.rs                 |   33 
crates/gpui2/src/elements/overlay.rs             |   28 
crates/gpui2/src/elements/svg.rs                 |   32 
crates/gpui2/src/elements/text.rs                |  169 --
crates/gpui2/src/elements/uniform_list.rs        |   91 
crates/gpui2/src/gpui2.rs                        |    4 
crates/gpui2/src/input.rs                        |    8 
crates/gpui2/src/interactive.rs                  |   38 
crates/gpui2/src/style.rs                        |    4 
crates/gpui2/src/view.rs                         |  182 -
crates/gpui2/src/window.rs                       |  160 +-
crates/gpui2_macros/src/derive_render_once.rs    |   45 
crates/picker2/src/picker2.rs                    |   78 
crates/project_panel2/src/project_panel.rs       |   84 
crates/rich_text2/src/rich_text.rs               |    4 
crates/storybook2/src/stories/colors.rs          |    4 
crates/storybook2/src/stories/focus.rs           |   60 
crates/storybook2/src/stories/kitchen_sink.rs    |    4 
crates/storybook2/src/stories/text.rs            |    4 
crates/terminal_view2/src/terminal_panel.rs      |    4 
crates/terminal_view2/src/terminal_view.rs       |   59 
crates/theme2/src/story.rs                       |   13 
crates/theme2/src/styles/players.rs              |    6 
crates/theme2/src/theme2.rs                      |    6 
crates/ui2/src/components/avatar.rs              |   12 
crates/ui2/src/components/button.rs              |  132 -
crates/ui2/src/components/checkbox.rs            |   40 
crates/ui2/src/components/context_menu.rs        |  129 -
crates/ui2/src/components/details.rs             |   20 
crates/ui2/src/components/divider.rs             |    8 
crates/ui2/src/components/elevated_surface.rs    |    4 
crates/ui2/src/components/facepile.rs            |   37 
crates/ui2/src/components/icon.rs                |   14 
crates/ui2/src/components/icon_button.rs         |   51 
crates/ui2/src/components/indicator.rs           |    8 
crates/ui2/src/components/input.rs               |   12 
crates/ui2/src/components/keybinding.rs          |   19 
crates/ui2/src/components/label.rs               |   18 
crates/ui2/src/components/list.rs                |   66 
crates/ui2/src/components/modal.rs               |   27 
crates/ui2/src/components/notification_toast.rs  |    2 
crates/ui2/src/components/palette.rs             |   19 
crates/ui2/src/components/panel.rs               |   30 
crates/ui2/src/components/player.rs              |    6 
crates/ui2/src/components/player_stack.rs        |    6 
crates/ui2/src/components/stack.rs               |    4 
crates/ui2/src/components/tab.rs                 |  500 ++++----
crates/ui2/src/components/toast.rs               |   24 
crates/ui2/src/components/toggle.rs              |    2 
crates/ui2/src/components/tool_divider.rs        |    8 
crates/ui2/src/components/tooltip.rs             |    4 
crates/ui2/src/lib.rs                            |   21 
crates/ui2/src/settings.rs                       |   74 -
crates/ui2/src/static_data.rs                    | 1123 ------------------
crates/ui2/src/story.rs                          |   14 
crates/ui2/src/styled_ext.rs                     |   10 
crates/ui2/src/to_extract.rs                     |   47 
crates/ui2/src/to_extract/assistant_panel.rs     |   97 -
crates/ui2/src/to_extract/breadcrumb.rs          |  118 -
crates/ui2/src/to_extract/buffer.rs              |  281 ----
crates/ui2/src/to_extract/buffer_search.rs       |   45 
crates/ui2/src/to_extract/chat_panel.rs          |  158 --
crates/ui2/src/to_extract/collab_panel.rs        |  118 -
crates/ui2/src/to_extract/command_palette.rs     |   53 
crates/ui2/src/to_extract/copilot.rs             |   49 
crates/ui2/src/to_extract/editor_pane.rs         |   77 -
crates/ui2/src/to_extract/language_selector.rs   |   83 -
crates/ui2/src/to_extract/multi_buffer.rs        |   68 -
crates/ui2/src/to_extract/notifications_panel.rs |  379 ------
crates/ui2/src/to_extract/panes.rs               |  139 --
crates/ui2/src/to_extract/project_panel.rs       |  117 -
crates/ui2/src/to_extract/recent_projects.rs     |   58 
crates/ui2/src/to_extract/status_bar.rs          |  201 ---
crates/ui2/src/to_extract/tab_bar.rs             |  156 --
crates/ui2/src/to_extract/terminal.rs            |  166 --
crates/ui2/src/to_extract/theme_selector.rs      |   66 -
crates/ui2/src/to_extract/title_bar.rs           |  218 ---
crates/ui2/src/to_extract/toolbar.rs             |  130 --
crates/ui2/src/to_extract/traffic_lights.rs      |  109 -
crates/ui2/src/to_extract/workspace.rs           |  398 ------
crates/workspace2/src/dock.rs                    |   23 
crates/workspace2/src/item.rs                    |   10 
crates/workspace2/src/modal_layer.rs             |   12 
crates/workspace2/src/notifications.rs           |   12 
crates/workspace2/src/pane.rs                    |   58 
crates/workspace2/src/pane_group.rs              |    6 
crates/workspace2/src/status_bar.rs              |   10 
crates/workspace2/src/toolbar.rs                 |    6 
crates/workspace2/src/workspace2.rs              |  100 
110 files changed, 1,863 insertions(+), 6,799 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -841,17 +841,6 @@ dependencies = [
  "rustc-demangle",
 ]
 
-[[package]]
-name = "backtrace-on-stack-overflow"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fd2d70527f3737a1ad17355e260706c1badebabd1fa06a7a053407380df841b"
-dependencies = [
- "backtrace",
- "libc",
- "nix 0.23.2",
-]
-
 [[package]]
 name = "base64"
 version = "0.13.1"
@@ -5570,19 +5559,6 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
-[[package]]
-name = "nix"
-version = "0.23.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c"
-dependencies = [
- "bitflags 1.3.2",
- "cc",
- "cfg-if 1.0.0",
- "libc",
- "memoffset 0.6.5",
-]
-
 [[package]]
 name = "nix"
 version = "0.24.3"
@@ -8854,45 +8830,6 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
 
-[[package]]
-name = "storybook2"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "backtrace-on-stack-overflow",
- "chrono",
- "clap 4.4.4",
- "editor2",
- "fuzzy2",
- "gpui2",
- "itertools 0.11.0",
- "language2",
- "log",
- "menu2",
- "picker2",
- "rust-embed",
- "serde",
- "settings2",
- "simplelog",
- "smallvec",
- "strum",
- "theme",
- "theme2",
- "ui2",
- "util",
-]
-
-[[package]]
-name = "storybook3"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "gpui2",
- "settings2",
- "theme2",
- "ui2",
-]
-
 [[package]]
 name = "stringprep"
 version = "0.1.4"

Cargo.toml 🔗

@@ -96,8 +96,8 @@ members = [
     "crates/sqlez",
     "crates/sqlez_macros",
     "crates/rich_text",
-    "crates/storybook2",
-    "crates/storybook3",
+    # "crates/storybook2",
+    # "crates/storybook3",
     "crates/sum_tree",
     "crates/terminal",
     "crates/terminal2",

crates/auto_update2/src/update_notification.rs 🔗

@@ -8,8 +8,8 @@ pub struct UpdateNotification {
 
 impl EventEmitter<NotificationEvent> for UpdateNotification {}
 
-impl Render<Self> for UpdateNotification {
-    type Element = Div<Self>;
+impl Render for UpdateNotification {
+    type Element = Div;
 
     fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> Self::Element {
         div().child("Updated zed!")

crates/collab_ui2/src/collab_panel.rs 🔗

@@ -3294,8 +3294,8 @@ impl CollabPanel {
 //     .with_width(size.x())
 // }
 
-impl Render<Self> for CollabPanel {
-    type Element = Focusable<Self, Div<Self>>;
+impl Render for CollabPanel {
+    type Element = Focusable<Div>;
 
     fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
         div()

crates/collab_ui2/src/collab_titlebar_item.rs 🔗

@@ -81,8 +81,8 @@ pub struct CollabTitlebarItem {
     _subscriptions: Vec<Subscription>,
 }
 
-impl Render<Self> for CollabTitlebarItem {
-    type Element = Stateful<Self, Div<Self>>;
+impl Render for CollabTitlebarItem {
+    type Element = Stateful<Div>;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         h_stack()
@@ -100,7 +100,7 @@ impl Render<Self> for CollabTitlebarItem {
                 |s| s.pl(px(68.)),
             )
             .bg(cx.theme().colors().title_bar_background)
-            .on_click(|_, event, cx| {
+            .on_click(|event, cx| {
                 if event.up.click_count == 2 {
                     cx.zoom_window();
                 }
@@ -117,14 +117,14 @@ impl Render<Self> for CollabTitlebarItem {
                                     .variant(ButtonVariant::Ghost)
                                     .color(Some(TextColor::Player(0))),
                             )
-                            .tooltip(move |_, cx| Tooltip::text("Toggle following", cx)),
+                            .tooltip(move |cx| Tooltip::text("Toggle following", cx)),
                     )
                     // TODO - Add project menu
                     .child(
                         div()
                             .id("titlebar_project_menu_button")
                             .child(Button::new("project_name").variant(ButtonVariant::Ghost))
-                            .tooltip(move |_, cx| Tooltip::text("Recent Projects", cx)),
+                            .tooltip(move |cx| Tooltip::text("Recent Projects", cx)),
                     )
                     // TODO - Add git menu
                     .child(
@@ -135,7 +135,7 @@ impl Render<Self> for CollabTitlebarItem {
                                     .variant(ButtonVariant::Ghost)
                                     .color(Some(TextColor::Muted)),
                             )
-                            .tooltip(move |_, cx| {
+                            .tooltip(move |cx| {
                                 cx.build_view(|_| {
                                     Tooltip::new("Recent Branches")
                                         .key_binding(KeyBinding::new(gpui::KeyBinding::new(

crates/command_palette2/src/command_palette.rs 🔗

@@ -76,8 +76,8 @@ impl FocusableView for CommandPalette {
     }
 }
 
-impl Render<Self> for CommandPalette {
-    type Element = Div<Self>;
+impl Render for CommandPalette {
+    type Element = Div;
 
     fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
         v_stack().w_96().child(self.picker.clone())
@@ -140,7 +140,7 @@ impl CommandPaletteDelegate {
 }
 
 impl PickerDelegate for CommandPaletteDelegate {
-    type ListItem = Div<Picker<Self>>;
+    type ListItem = Div;
 
     fn placeholder_text(&self) -> Arc<str> {
         "Execute a command...".into()

crates/diagnostics2/src/diagnostics.rs 🔗

@@ -16,7 +16,7 @@ use gpui::{
     actions, div, AnyElement, AnyView, AppContext, Context, Div, EventEmitter, FocusEvent,
     FocusHandle, Focusable, FocusableElement, FocusableView, InteractiveElement, Model,
     ParentElement, Render, RenderOnce, SharedString, Styled, Subscription, Task, View, ViewContext,
-    VisualContext, WeakView,
+    VisualContext, WeakView, WindowContext,
 };
 use language::{
     Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection,
@@ -90,8 +90,8 @@ struct DiagnosticGroupState {
 
 impl EventEmitter<ItemEvent> for ProjectDiagnosticsEditor {}
 
-impl Render<Self> for ProjectDiagnosticsEditor {
-    type Element = Focusable<Self, Div<Self>>;
+impl Render for ProjectDiagnosticsEditor {
+    type Element = Focusable<Div>;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         let child = if self.path_states.is_empty() {
@@ -109,8 +109,8 @@ impl Render<Self> for ProjectDiagnosticsEditor {
         div()
             .track_focus(&self.focus_handle)
             .size_full()
-            .on_focus_in(Self::focus_in)
-            .on_action(Self::toggle_warnings)
+            .on_focus_in(cx.listener(Self::focus_in))
+            .on_action(cx.listener(Self::toggle_warnings))
             .child(child)
     }
 }
@@ -662,7 +662,7 @@ impl Item for ProjectDiagnosticsEditor {
         Some("Project Diagnostics".into())
     }
 
-    fn tab_content<T: 'static>(&self, _detail: Option<usize>, _: &AppContext) -> AnyElement<T> {
+    fn tab_content(&self, _detail: Option<usize>, _: &WindowContext) -> AnyElement {
         render_summary(&self.summary)
     }
 
@@ -796,11 +796,10 @@ fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock {
     })
 }
 
-pub(crate) fn render_summary<T: 'static>(summary: &DiagnosticSummary) -> AnyElement<T> {
+pub(crate) fn render_summary(summary: &DiagnosticSummary) -> AnyElement {
     if summary.error_count == 0 && summary.warning_count == 0 {
         let label = Label::new("No problems");
         label.render_into_any()
-        //.render()
     } else {
         h_stack()
             .bg(gpui::red())

crates/diagnostics2/src/items.rs 🔗

@@ -21,8 +21,8 @@ pub struct DiagnosticIndicator {
     _observe_active_editor: Option<Subscription>,
 }
 
-impl Render<Self> for DiagnosticIndicator {
-    type Element = Stateful<Self, Div<Self>>;
+impl Render for DiagnosticIndicator {
+    type Element = Stateful<Div>;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         let diagnostic_indicator = match (self.summary.error_count, self.summary.warning_count) {
@@ -45,7 +45,7 @@ impl Render<Self> for DiagnosticIndicator {
 
         h_stack()
             .id(cx.entity_id())
-            .on_action(Self::go_to_next_diagnostic)
+            .on_action(cx.listener(Self::go_to_next_diagnostic))
             .rounded_md()
             .flex_none()
             .h(rems(1.375))
@@ -54,14 +54,14 @@ impl Render<Self> for DiagnosticIndicator {
             .bg(cx.theme().colors().ghost_element_background)
             .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
             .active(|style| style.bg(cx.theme().colors().ghost_element_active))
-            .tooltip(|_, cx| Tooltip::text("Project Diagnostics", cx))
-            .on_click(|this, _, cx| {
+            .tooltip(|cx| Tooltip::text("Project Diagnostics", cx))
+            .on_click(cx.listener(|this, _, cx| {
                 if let Some(workspace) = this.workspace.upgrade() {
                     workspace.update(cx, |workspace, cx| {
                         ProjectDiagnosticsEditor::deploy(workspace, &Default::default(), cx)
                     })
                 }
-            })
+            }))
             .child(diagnostic_indicator)
     }
 }

crates/diagnostics2/src/toolbar_controls.rs 🔗

@@ -7,8 +7,8 @@ pub struct ToolbarControls {
     editor: Option<WeakView<ProjectDiagnosticsEditor>>,
 }
 
-impl Render<Self> for ToolbarControls {
-    type Element = Div<Self>;
+impl Render for ToolbarControls {
+    type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         let include_warnings = self
@@ -26,14 +26,14 @@ impl Render<Self> for ToolbarControls {
 
         div().child(
             IconButton::new("toggle-warnings", Icon::ExclamationTriangle)
-                .tooltip(move |_, cx| Tooltip::text(tooltip, cx))
-                .on_click(|this: &mut Self, cx| {
+                .tooltip(move |cx| Tooltip::text(tooltip, cx))
+                .on_click(cx.listener(|this, _, cx| {
                     if let Some(editor) = this.editor.as_ref().and_then(|editor| editor.upgrade()) {
                         editor.update(cx, |editor, cx| {
                             editor.toggle_warnings(&Default::default(), cx);
                         });
                     }
-                }),
+                })),
         )
     }
 }

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

@@ -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) -> AnyElement<Editor>>;
+pub type RenderBlock = Arc<dyn Fn(&mut BlockContext) -> AnyElement>;
 
 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) -> AnyElement<Editor>>,
+    pub render: Arc<dyn Fn(&mut BlockContext) -> AnyElement>,
     pub disposition: BlockDisposition,
 }
 
@@ -947,7 +947,7 @@ impl DerefMut for BlockContext<'_, '_> {
 }
 
 impl Block {
-    pub fn render(&self, cx: &mut BlockContext) -> AnyElement<Editor> {
+    pub fn render(&self, cx: &mut BlockContext) -> AnyElement {
         self.render.lock()(cx)
     }
 

crates/editor2/src/editor.rs 🔗

@@ -907,7 +907,7 @@ impl ContextMenu {
         style: &EditorStyle,
         workspace: Option<WeakView<Workspace>>,
         cx: &mut ViewContext<Editor>,
-    ) -> (DisplayPoint, AnyElement<Editor>) {
+    ) -> (DisplayPoint, AnyElement) {
         match self {
             ContextMenu::Completions(menu) => (cursor_position, menu.render(style, workspace, cx)),
             ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, cx),
@@ -1223,7 +1223,7 @@ impl CompletionsMenu {
         style: &EditorStyle,
         workspace: Option<WeakView<Workspace>>,
         cx: &mut ViewContext<Editor>,
-    ) -> AnyElement<Editor> {
+    ) -> AnyElement {
         todo!("old implementation below")
     }
 
@@ -1541,13 +1541,15 @@ impl CodeActionsMenu {
         mut cursor_position: DisplayPoint,
         style: &EditorStyle,
         cx: &mut ViewContext<Editor>,
-    ) -> (DisplayPoint, AnyElement<Editor>) {
+    ) -> (DisplayPoint, AnyElement) {
         let actions = self.actions.clone();
         let selected_item = self.selected_item;
+
         let element = uniform_list(
+            cx.view().clone(),
             "code_actions_menu",
             self.actions.len(),
-            move |editor, range, cx| {
+            move |this, range, cx| {
                 actions[range.clone()]
                     .iter()
                     .enumerate()
@@ -1569,17 +1571,20 @@ impl CodeActionsMenu {
                                     .bg(colors.element_hover)
                                     .text_color(colors.text_accent)
                             })
-                            .on_mouse_down(MouseButton::Left, move |editor: &mut Editor, _, cx| {
-                                cx.stop_propagation();
-                                editor
-                                    .confirm_code_action(
-                                        &ConfirmCodeAction {
-                                            item_ix: Some(item_ix),
-                                        },
-                                        cx,
-                                    )
-                                    .map(|task| task.detach_and_log_err(cx));
-                            })
+                            .on_mouse_down(
+                                MouseButton::Left,
+                                cx.listener(move |editor, _, cx| {
+                                    cx.stop_propagation();
+                                    editor
+                                        .confirm_code_action(
+                                            &ConfirmCodeAction {
+                                                item_ix: Some(item_ix),
+                                            },
+                                            cx,
+                                        )
+                                        .map(|task| task.detach_and_log_err(cx));
+                                }),
+                            )
                             // TASK: It would be good to make lsp_action.title a SharedString to avoid allocating here.
                             .child(SharedString::from(action.lsp_action.title.clone()))
                     })
@@ -4354,11 +4359,11 @@ impl Editor {
         style: &EditorStyle,
         is_active: bool,
         cx: &mut ViewContext<Self>,
-    ) -> Option<IconButton<Self>> {
+    ) -> Option<IconButton> {
         if self.available_code_actions.is_some() {
             Some(
-                IconButton::new("code_actions_indicator", ui::Icon::Bolt).on_click(
-                    |editor: &mut Editor, cx| {
+                IconButton::new("code_actions_indicator", ui::Icon::Bolt).on_click(cx.listener(
+                    |editor, e, cx| {
                         editor.toggle_code_actions(
                             &ToggleCodeActions {
                                 deployed_from_indicator: true,
@@ -4366,7 +4371,7 @@ impl Editor {
                             cx,
                         );
                     },
-                ),
+                )),
             )
         } else {
             None
@@ -4381,7 +4386,7 @@ impl Editor {
         line_height: Pixels,
         gutter_margin: Pixels,
         cx: &mut ViewContext<Self>,
-    ) -> Vec<Option<IconButton<Self>>> {
+    ) -> Vec<Option<IconButton>> {
         fold_data
             .iter()
             .enumerate()
@@ -4394,14 +4399,14 @@ impl Editor {
                                 FoldStatus::Foldable => ui::Icon::ChevronDown,
                             };
                             IconButton::new(ix as usize, icon)
-                                .on_click(move |editor: &mut Editor, cx| match fold_status {
+                                .on_click(cx.listener(move |editor, e, cx| match fold_status {
                                     FoldStatus::Folded => {
                                         editor.unfold_at(&UnfoldAt { buffer_row }, cx);
                                     }
                                     FoldStatus::Foldable => {
                                         editor.fold_at(&FoldAt { buffer_row }, cx);
                                     }
-                                })
+                                }))
                                 .color(ui::TextColor::Muted)
                         })
                     })
@@ -4422,7 +4427,7 @@ impl Editor {
         cursor_position: DisplayPoint,
         style: &EditorStyle,
         cx: &mut ViewContext<Editor>,
-    ) -> Option<(DisplayPoint, AnyElement<Editor>)> {
+    ) -> Option<(DisplayPoint, AnyElement)> {
         self.context_menu.read().as_ref().map(|menu| {
             menu.render(
                 cursor_position,
@@ -7781,7 +7786,7 @@ impl Editor {
                                     }
                                     div()
                                         .pl(cx.anchor_x)
-                                        .child(rename_editor.render_with(EditorElement::new(
+                                        .child(EditorElement::new(
                                             &rename_editor,
                                             EditorStyle {
                                                 background: cx.theme().system().transparent,
@@ -7789,10 +7794,12 @@ impl Editor {
                                                 text: text_style,
                                                 scrollbar_width: cx.editor_style.scrollbar_width,
                                                 syntax: cx.editor_style.syntax.clone(),
-                                                diagnostic_style:
-                                                    cx.editor_style.diagnostic_style.clone(),
+                                                diagnostic_style: cx
+                                                    .editor_style
+                                                    .diagnostic_style
+                                                    .clone(),
                                             },
-                                        )))
+                                        ))
                                         .render_into_any()
                                 }
                             }),
@@ -9382,7 +9389,7 @@ impl FocusableView for Editor {
     }
 }
 
-impl Render<Self> for Editor {
+impl Render for Editor {
     type Element = EditorElement;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
@@ -9996,10 +10003,10 @@ pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> Rend
                     .ml(cx.anchor_x)
             }))
             .cursor_pointer()
-            .on_click(move |_, _, cx| {
+            .on_click(cx.listener(move |_, _, cx| {
                 cx.write_to_clipboard(ClipboardItem::new(message.clone()));
-            })
-            .tooltip(|_, cx| Tooltip::text("Copy diagnostic message", cx))
+            }))
+            .tooltip(|cx| Tooltip::text("Copy diagnostic message", cx))
             .render_into_any()
     })
 }

crates/editor2/src/element.rs 🔗

@@ -23,7 +23,7 @@ use gpui::{
     ElementId, ElementInputHandler, Entity, EntityId, Hsla, InteractiveElement, LineLayout,
     MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, RenderOnce,
     ScrollWheelEvent, ShapedLine, SharedString, Size, StatefulInteractiveElement, Style, Styled,
-    TextRun, TextStyle, View, ViewContext, WindowContext, WrappedLine,
+    TextRun, TextStyle, View, ViewContext, WeakView, WindowContext, WrappedLine,
 };
 use itertools::Itertools;
 use language::language_settings::ShowWhitespaceSetting;
@@ -112,14 +112,14 @@ impl SelectionLayout {
 }
 
 pub struct EditorElement {
-    editor_id: EntityId,
+    editor: View<Editor>,
     style: EditorStyle,
 }
 
 impl EditorElement {
     pub fn new(editor: &View<Editor>, style: EditorStyle) -> Self {
         Self {
-            editor_id: editor.entity_id(),
+            editor: editor.clone(),
             style,
         }
     }
@@ -349,7 +349,7 @@ impl EditorElement {
         gutter_bounds: Bounds<Pixels>,
         text_bounds: Bounds<Pixels>,
         layout: &LayoutState,
-        cx: &mut ViewContext<Editor>,
+        cx: &mut WindowContext,
     ) {
         let bounds = gutter_bounds.union(&text_bounds);
         let scroll_top =
@@ -460,7 +460,7 @@ impl EditorElement {
         bounds: Bounds<Pixels>,
         layout: &mut LayoutState,
         editor: &mut Editor,
-        cx: &mut ViewContext<Editor>,
+        cx: &mut WindowContext,
     ) {
         let line_height = layout.position_map.line_height;
 
@@ -495,7 +495,7 @@ impl EditorElement {
                     AvailableSpace::MinContent,
                     AvailableSpace::Definite(line_height * 0.55),
                 );
-                let fold_indicator_size = fold_indicator.measure(available_space, editor, cx);
+                let fold_indicator_size = fold_indicator.measure(available_space, cx);
 
                 let position = point(
                     bounds.size.width - layout.gutter_padding,
@@ -506,7 +506,7 @@ impl EditorElement {
                     (line_height - fold_indicator_size.height) / 2.,
                 );
                 let origin = bounds.origin + position + centering_offset;
-                fold_indicator.draw(origin, available_space, editor, cx);
+                fold_indicator.draw(origin, available_space, cx);
             }
         }
 
@@ -516,7 +516,7 @@ impl EditorElement {
                 AvailableSpace::MinContent,
                 AvailableSpace::Definite(line_height),
             );
-            let indicator_size = button.measure(available_space, editor, cx);
+            let indicator_size = button.measure(available_space, cx);
 
             let mut x = Pixels::ZERO;
             let mut y = indicator.row as f32 * line_height - scroll_top;
@@ -524,15 +524,11 @@ impl EditorElement {
             x += ((layout.gutter_padding + layout.gutter_margin) - indicator_size.width) / 2.;
             y += (line_height - indicator_size.height) / 2.;
 
-            button.draw(bounds.origin + point(x, y), available_space, editor, cx);
+            button.draw(bounds.origin + point(x, y), available_space, cx);
         }
     }
 
-    fn paint_diff_hunks(
-        bounds: Bounds<Pixels>,
-        layout: &LayoutState,
-        cx: &mut ViewContext<Editor>,
-    ) {
+    fn paint_diff_hunks(bounds: Bounds<Pixels>, layout: &LayoutState, cx: &mut WindowContext) {
         // todo!()
         // let diff_style = &theme::current(cx).editor.diff.clone();
         // let line_height = layout.position_map.line_height;
@@ -621,7 +617,7 @@ impl EditorElement {
         text_bounds: Bounds<Pixels>,
         layout: &mut LayoutState,
         editor: &mut Editor,
-        cx: &mut ViewContext<Editor>,
+        cx: &mut WindowContext,
     ) {
         let scroll_position = layout.position_map.snapshot.scroll_position();
         let start_row = layout.visible_display_row_range.start;
@@ -676,20 +672,22 @@ impl EditorElement {
                             div()
                                 .id(fold.id)
                                 .size_full()
-                                .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
-                                .on_click(move |editor: &mut Editor, _, cx| {
-                                    editor.unfold_ranges(
-                                        [fold_range.start..fold_range.end],
-                                        true,
-                                        false,
-                                        cx,
-                                    );
-                                    cx.stop_propagation();
-                                })
+                                .on_mouse_down(MouseButton::Left, |_, cx| cx.stop_propagation())
+                                .on_click(cx.listener_for(
+                                    &self.editor,
+                                    move |editor: &mut Editor, _, cx| {
+                                        editor.unfold_ranges(
+                                            [fold_range.start..fold_range.end],
+                                            true,
+                                            false,
+                                            cx,
+                                        );
+                                        cx.stop_propagation();
+                                    },
+                                ))
                                 .draw(
                                     fold_bounds.origin,
                                     fold_bounds.size,
-                                    editor,
                                     cx,
                                     |fold_element_state, cx| {
                                         if fold_element_state.is_active() {
@@ -852,7 +850,7 @@ impl EditorElement {
                                     .min((text_bounds.size.height - line_height) / 2.),
                             ),
                         );
-                        let context_menu_size = context_menu.measure(available_space, editor, cx);
+                        let context_menu_size = context_menu.measure(available_space, cx);
 
                         let cursor_row_layout = &layout.position_map.line_layouts
                             [(position.row() - start_row) as usize]
@@ -876,7 +874,7 @@ impl EditorElement {
                             list_origin.y -= layout.position_map.line_height - list_height;
                         }
 
-                        context_menu.draw(list_origin, available_space, editor, cx);
+                        context_menu.draw(list_origin, available_space, cx);
                     })
                 }
 
@@ -1167,7 +1165,7 @@ impl EditorElement {
         layout: &LayoutState,
         content_origin: gpui::Point<Pixels>,
         bounds: Bounds<Pixels>,
-        cx: &mut ViewContext<Editor>,
+        cx: &mut WindowContext,
     ) {
         let start_row = layout.visible_display_row_range.start;
         let end_row = layout.visible_display_row_range.end;
@@ -1220,7 +1218,7 @@ impl EditorElement {
         bounds: Bounds<Pixels>,
         layout: &mut LayoutState,
         editor: &mut Editor,
-        cx: &mut ViewContext<Editor>,
+        cx: &mut WindowContext,
     ) {
         let scroll_position = layout.position_map.snapshot.scroll_position();
         let scroll_left = scroll_position.x * layout.position_map.em_width;
@@ -1235,9 +1233,7 @@ impl EditorElement {
             if !matches!(block.style, BlockStyle::Sticky) {
                 origin += point(-scroll_left, Pixels::ZERO);
             }
-            block
-                .element
-                .draw(origin, block.available_space, editor, cx);
+            block.element.draw(origin, block.available_space, cx);
         }
     }
 
@@ -2030,12 +2026,10 @@ impl EditorElement {
                         let jump_position = language::ToPoint::to_point(&jump_anchor, buffer);
 
                         IconButton::new(block_id, ui::Icon::ArrowUpRight)
-                            .on_click(move |editor: &mut Editor, cx| {
+                            .on_click(cx.listener_for(&self.editor, move |editor, e, cx| {
                                 editor.jump(jump_path.clone(), jump_position, jump_anchor, cx);
-                            })
-                            .tooltip(move |_, cx| {
-                                Tooltip::for_action("Jump to Buffer", &OpenExcerpts, cx)
-                            })
+                            }))
+                            .tooltip(|cx| Tooltip::for_action("Jump to Buffer", &OpenExcerpts, cx))
                     });
 
                     let element = if *starts_new_buffer {
@@ -2074,7 +2068,7 @@ impl EditorElement {
                 }
             };
 
-            let size = element.measure(available_space, editor, cx);
+            let size = element.measure(available_space, cx);
             (element, size)
         };
 
@@ -2133,47 +2127,61 @@ impl EditorElement {
         gutter_bounds: Bounds<Pixels>,
         text_bounds: Bounds<Pixels>,
         layout: &LayoutState,
-        cx: &mut ViewContext<Editor>,
+        cx: &mut WindowContext,
     ) {
         let content_origin = text_bounds.origin + point(layout.gutter_margin, Pixels::ZERO);
 
         cx.on_mouse_event({
             let position_map = layout.position_map.clone();
-            move |editor, event: &ScrollWheelEvent, phase, cx| {
+            let editor = self.editor.clone();
+
+            move |event: &ScrollWheelEvent, phase, cx| {
                 if phase != DispatchPhase::Bubble {
                     return;
                 }
 
-                if Self::scroll(editor, event, &position_map, bounds, cx) {
+                let should_cancel = editor.update(cx, |editor, cx| {
+                    Self::scroll(editor, event, &position_map, bounds, cx)
+                });
+                if should_cancel {
                     cx.stop_propagation();
                 }
             }
         });
+
         cx.on_mouse_event({
             let position_map = layout.position_map.clone();
-            move |editor, event: &MouseDownEvent, phase, cx| {
+            let editor = self.editor.clone();
+
+            move |event: &MouseDownEvent, phase, cx| {
                 if phase != DispatchPhase::Bubble {
                     return;
                 }
 
-                if Self::mouse_down(editor, event, &position_map, text_bounds, gutter_bounds, cx) {
+                let should_cancel = editor.update(cx, |editor, cx| {
+                    Self::mouse_down(editor, event, &position_map, text_bounds, gutter_bounds, cx)
+                });
+
+                if should_cancel {
                     cx.stop_propagation()
                 }
             }
         });
+
         cx.on_mouse_event({
             let position_map = layout.position_map.clone();
-            move |editor, event: &MouseUpEvent, phase, cx| {
-                if phase != DispatchPhase::Bubble {
-                    return;
-                }
+            let editor = self.editor.clone();
+            move |event: &MouseUpEvent, phase, cx| {
+                let should_cancel = editor.update(cx, |editor, cx| {
+                    Self::mouse_up(editor, event, &position_map, text_bounds, cx)
+                });
 
-                if Self::mouse_up(editor, event, &position_map, text_bounds, cx) {
+                if should_cancel {
                     cx.stop_propagation()
                 }
             }
         });
-        // todo!()
+        //todo!()
         // on_down(MouseButton::Right, {
         //     let position_map = layout.position_map.clone();
         //     move |event, editor, cx| {
@@ -2190,12 +2198,17 @@ impl EditorElement {
         // });
         cx.on_mouse_event({
             let position_map = layout.position_map.clone();
-            move |editor, event: &MouseMoveEvent, phase, cx| {
+            let editor = self.editor.clone();
+            move |event: &MouseMoveEvent, phase, cx| {
                 if phase != DispatchPhase::Bubble {
                     return;
                 }
 
-                if Self::mouse_moved(editor, event, &position_map, text_bounds, gutter_bounds, cx) {
+                let stop_propogating = editor.update(cx, |editor, cx| {
+                    Self::mouse_moved(editor, event, &position_map, text_bounds, gutter_bounds, cx)
+                });
+
+                if stop_propogating {
                     cx.stop_propagation()
                 }
             }
@@ -2324,7 +2337,7 @@ impl LineWithInvisibles {
         content_origin: gpui::Point<Pixels>,
         whitespace_setting: ShowWhitespaceSetting,
         selection_ranges: &[Range<DisplayPoint>],
-        cx: &mut ViewContext<Editor>,
+        cx: &mut WindowContext,
     ) {
         let line_height = layout.position_map.line_height;
         let line_y = line_height * row as f32 - layout.position_map.scroll_position.y;
@@ -2356,7 +2369,7 @@ impl LineWithInvisibles {
         row: u32,
         line_height: Pixels,
         whitespace_setting: ShowWhitespaceSetting,
-        cx: &mut ViewContext<Editor>,
+        cx: &mut WindowContext,
     ) {
         let allowed_invisibles_regions = match whitespace_setting {
             ShowWhitespaceSetting::None => return,
@@ -2399,85 +2412,98 @@ enum Invisible {
     Whitespace { line_offset: usize },
 }
 
-impl Element<Editor> for EditorElement {
+impl Element for EditorElement {
     type State = ();
 
     fn layout(
         &mut self,
-        editor: &mut Editor,
         element_state: Option<Self::State>,
-        cx: &mut gpui::ViewContext<Editor>,
+        cx: &mut gpui::WindowContext,
     ) -> (gpui::LayoutId, Self::State) {
-        editor.style = Some(self.style.clone()); // Long-term, we'd like to eliminate this.
-
-        let rem_size = cx.rem_size();
-        let mut style = Style::default();
-        style.size.width = relative(1.).into();
-        style.size.height = match editor.mode {
-            EditorMode::SingleLine => self.style.text.line_height_in_pixels(cx.rem_size()).into(),
-            EditorMode::AutoHeight { .. } => todo!(),
-            EditorMode::Full => relative(1.).into(),
-        };
-        let layout_id = cx.request_layout(&style, None);
-        (layout_id, ())
+        self.editor.update(cx, |editor, cx| {
+            editor.style = Some(self.style.clone()); // Long-term, we'd like to eliminate this.
+
+            let rem_size = cx.rem_size();
+            let mut style = Style::default();
+            style.size.width = relative(1.).into();
+            style.size.height = match editor.mode {
+                EditorMode::SingleLine => {
+                    self.style.text.line_height_in_pixels(cx.rem_size()).into()
+                }
+                EditorMode::AutoHeight { .. } => todo!(),
+                EditorMode::Full => relative(1.).into(),
+            };
+            let layout_id = cx.request_layout(&style, None);
+
+            (layout_id, ())
+        })
     }
 
     fn paint(
         mut self,
         bounds: Bounds<gpui::Pixels>,
-        editor: &mut Editor,
         element_state: &mut Self::State,
-        cx: &mut gpui::ViewContext<Editor>,
+        cx: &mut gpui::WindowContext,
     ) {
-        let mut layout = self.compute_layout(editor, cx, bounds);
-        let gutter_bounds = Bounds {
-            origin: bounds.origin,
-            size: layout.gutter_size,
-        };
-        let text_bounds = Bounds {
-            origin: gutter_bounds.upper_right(),
-            size: layout.text_size,
-        };
-
-        let dispatch_context = editor.dispatch_context(cx);
-        cx.with_key_dispatch(
-            dispatch_context,
-            Some(editor.focus_handle.clone()),
-            |_, cx| {
-                register_actions(cx);
+        let editor = self.editor.clone();
+        editor.update(cx, |editor, cx| {
+            let mut layout = self.compute_layout(editor, cx, bounds);
+            let gutter_bounds = Bounds {
+                origin: bounds.origin,
+                size: layout.gutter_size,
+            };
+            let text_bounds = Bounds {
+                origin: gutter_bounds.upper_right(),
+                size: layout.text_size,
+            };
 
-                // We call with_z_index to establish a new stacking context.
-                cx.with_z_index(0, |cx| {
-                    cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
-                        // Paint mouse listeners first, so any elements we paint on top of the editor
-                        // take precedence.
-                        self.paint_mouse_listeners(bounds, gutter_bounds, text_bounds, &layout, cx);
-                        let input_handler = ElementInputHandler::new(bounds, cx);
-                        cx.handle_input(&editor.focus_handle, input_handler);
-
-                        self.paint_background(gutter_bounds, text_bounds, &layout, cx);
-                        if layout.gutter_size.width > Pixels::ZERO {
-                            self.paint_gutter(gutter_bounds, &mut layout, editor, cx);
-                        }
-                        self.paint_text(text_bounds, &mut layout, editor, cx);
+            let dispatch_context = editor.dispatch_context(cx);
+            let editor_handle = cx.view().clone();
+            cx.with_key_dispatch(
+                dispatch_context,
+                Some(editor.focus_handle.clone()),
+                |_, cx| {
+                    register_actions(&editor_handle, cx);
+
+                    // We call with_z_index to establish a new stacking context.
+                    cx.with_z_index(0, |cx| {
+                        cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
+                            // Paint mouse listeners first, so any elements we paint on top of the editor
+                            // take precedence.
+                            self.paint_mouse_listeners(
+                                bounds,
+                                gutter_bounds,
+                                text_bounds,
+                                &layout,
+                                cx,
+                            );
+                            let input_handler = ElementInputHandler::new(bounds, editor_handle, cx);
+                            cx.handle_input(&editor.focus_handle, input_handler);
+
+                            self.paint_background(gutter_bounds, text_bounds, &layout, cx);
+                            if layout.gutter_size.width > Pixels::ZERO {
+                                self.paint_gutter(gutter_bounds, &mut layout, editor, cx);
+                            }
+                            self.paint_text(text_bounds, &mut layout, editor, cx);
 
-                        if !layout.blocks.is_empty() {
-                            cx.with_element_id(Some("editor_blocks"), |cx| {
-                                self.paint_blocks(bounds, &mut layout, editor, cx);
-                            })
-                        }
+                            if !layout.blocks.is_empty() {
+                                cx.with_element_id(Some("editor_blocks"), |cx| {
+                                    self.paint_blocks(bounds, &mut layout, editor, cx);
+                                })
+                            }
+                        });
                     });
-                });
-            },
-        )
+                },
+            )
+        })
     }
 }
 
-impl RenderOnce<Editor> for EditorElement {
+impl RenderOnce for EditorElement {
     type Element = Self;
 
     fn element_id(&self) -> Option<gpui::ElementId> {
-        Some(self.editor_id.into())
+        self.editor.element_id()
     }
 
     fn render_once(self) -> Self::Element {
@@ -3106,17 +3132,17 @@ pub struct LayoutState {
     show_scrollbars: bool,
     is_singleton: bool,
     max_row: u32,
-    context_menu: Option<(DisplayPoint, AnyElement<Editor>)>,
+    context_menu: Option<(DisplayPoint, AnyElement)>,
     code_actions_indicator: Option<CodeActionsIndicator>,
-    // hover_popovers: Option<(DisplayPoint, Vec<AnyElement<Editor>>)>,
-    fold_indicators: Vec<Option<IconButton<Editor>>>,
+    // hover_popovers: Option<(DisplayPoint, Vec<AnyElement>)>,
+    fold_indicators: Vec<Option<IconButton>>,
     tab_invisible: ShapedLine,
     space_invisible: ShapedLine,
 }
 
 struct CodeActionsIndicator {
     row: u32,
-    button: IconButton<Editor>,
+    button: IconButton,
 }
 
 struct PositionMap {
@@ -3201,7 +3227,7 @@ impl PositionMap {
 
 struct BlockLayout {
     row: u32,
-    element: AnyElement<Editor>,
+    element: AnyElement,
     available_space: Size<AvailableSpace>,
     style: BlockStyle,
 }
@@ -3906,187 +3932,191 @@ fn scale_horizontal_mouse_autoscroll_delta(delta: Pixels) -> f32 {
 //     }
 // }
 
-fn register_actions(cx: &mut ViewContext<Editor>) {
-    register_action(cx, Editor::move_left);
-    register_action(cx, Editor::move_right);
-    register_action(cx, Editor::move_down);
-    register_action(cx, Editor::move_up);
+fn register_actions(view: &View<Editor>, cx: &mut WindowContext) {
+    register_action(view, cx, Editor::move_left);
+    register_action(view, cx, Editor::move_right);
+    register_action(view, cx, Editor::move_down);
+    register_action(view, cx, Editor::move_up);
     // on_action(cx, Editor::new_file); todo!()
     // on_action(cx, Editor::new_file_in_direction); todo!()
-    register_action(cx, Editor::cancel);
-    register_action(cx, Editor::newline);
-    register_action(cx, Editor::newline_above);
-    register_action(cx, Editor::newline_below);
-    register_action(cx, Editor::backspace);
-    register_action(cx, Editor::delete);
-    register_action(cx, Editor::tab);
-    register_action(cx, Editor::tab_prev);
-    register_action(cx, Editor::indent);
-    register_action(cx, Editor::outdent);
-    register_action(cx, Editor::delete_line);
-    register_action(cx, Editor::join_lines);
-    register_action(cx, Editor::sort_lines_case_sensitive);
-    register_action(cx, Editor::sort_lines_case_insensitive);
-    register_action(cx, Editor::reverse_lines);
-    register_action(cx, Editor::shuffle_lines);
-    register_action(cx, Editor::convert_to_upper_case);
-    register_action(cx, Editor::convert_to_lower_case);
-    register_action(cx, Editor::convert_to_title_case);
-    register_action(cx, Editor::convert_to_snake_case);
-    register_action(cx, Editor::convert_to_kebab_case);
-    register_action(cx, Editor::convert_to_upper_camel_case);
-    register_action(cx, Editor::convert_to_lower_camel_case);
-    register_action(cx, Editor::delete_to_previous_word_start);
-    register_action(cx, Editor::delete_to_previous_subword_start);
-    register_action(cx, Editor::delete_to_next_word_end);
-    register_action(cx, Editor::delete_to_next_subword_end);
-    register_action(cx, Editor::delete_to_beginning_of_line);
-    register_action(cx, Editor::delete_to_end_of_line);
-    register_action(cx, Editor::cut_to_end_of_line);
-    register_action(cx, Editor::duplicate_line);
-    register_action(cx, Editor::move_line_up);
-    register_action(cx, Editor::move_line_down);
-    register_action(cx, Editor::transpose);
-    register_action(cx, Editor::cut);
-    register_action(cx, Editor::copy);
-    register_action(cx, Editor::paste);
-    register_action(cx, Editor::undo);
-    register_action(cx, Editor::redo);
-    register_action(cx, Editor::move_page_up);
-    register_action(cx, Editor::move_page_down);
-    register_action(cx, Editor::next_screen);
-    register_action(cx, Editor::scroll_cursor_top);
-    register_action(cx, Editor::scroll_cursor_center);
-    register_action(cx, Editor::scroll_cursor_bottom);
-    register_action(cx, |editor, _: &LineDown, cx| {
+    register_action(view, cx, Editor::cancel);
+    register_action(view, cx, Editor::newline);
+    register_action(view, cx, Editor::newline_above);
+    register_action(view, cx, Editor::newline_below);
+    register_action(view, cx, Editor::backspace);
+    register_action(view, cx, Editor::delete);
+    register_action(view, cx, Editor::tab);
+    register_action(view, cx, Editor::tab_prev);
+    register_action(view, cx, Editor::indent);
+    register_action(view, cx, Editor::outdent);
+    register_action(view, cx, Editor::delete_line);
+    register_action(view, cx, Editor::join_lines);
+    register_action(view, cx, Editor::sort_lines_case_sensitive);
+    register_action(view, cx, Editor::sort_lines_case_insensitive);
+    register_action(view, cx, Editor::reverse_lines);
+    register_action(view, cx, Editor::shuffle_lines);
+    register_action(view, cx, Editor::convert_to_upper_case);
+    register_action(view, cx, Editor::convert_to_lower_case);
+    register_action(view, cx, Editor::convert_to_title_case);
+    register_action(view, cx, Editor::convert_to_snake_case);
+    register_action(view, cx, Editor::convert_to_kebab_case);
+    register_action(view, cx, Editor::convert_to_upper_camel_case);
+    register_action(view, cx, Editor::convert_to_lower_camel_case);
+    register_action(view, cx, Editor::delete_to_previous_word_start);
+    register_action(view, cx, Editor::delete_to_previous_subword_start);
+    register_action(view, cx, Editor::delete_to_next_word_end);
+    register_action(view, cx, Editor::delete_to_next_subword_end);
+    register_action(view, cx, Editor::delete_to_beginning_of_line);
+    register_action(view, cx, Editor::delete_to_end_of_line);
+    register_action(view, cx, Editor::cut_to_end_of_line);
+    register_action(view, cx, Editor::duplicate_line);
+    register_action(view, cx, Editor::move_line_up);
+    register_action(view, cx, Editor::move_line_down);
+    register_action(view, cx, Editor::transpose);
+    register_action(view, cx, Editor::cut);
+    register_action(view, cx, Editor::copy);
+    register_action(view, cx, Editor::paste);
+    register_action(view, cx, Editor::undo);
+    register_action(view, cx, Editor::redo);
+    register_action(view, cx, Editor::move_page_up);
+    register_action(view, cx, Editor::move_page_down);
+    register_action(view, cx, Editor::next_screen);
+    register_action(view, cx, Editor::scroll_cursor_top);
+    register_action(view, cx, Editor::scroll_cursor_center);
+    register_action(view, cx, Editor::scroll_cursor_bottom);
+    register_action(view, cx, |editor, _: &LineDown, cx| {
         editor.scroll_screen(&ScrollAmount::Line(1.), cx)
     });
-    register_action(cx, |editor, _: &LineUp, cx| {
+    register_action(view, cx, |editor, _: &LineUp, cx| {
         editor.scroll_screen(&ScrollAmount::Line(-1.), cx)
     });
-    register_action(cx, |editor, _: &HalfPageDown, cx| {
+    register_action(view, cx, |editor, _: &HalfPageDown, cx| {
         editor.scroll_screen(&ScrollAmount::Page(0.5), cx)
     });
-    register_action(cx, |editor, _: &HalfPageUp, cx| {
+    register_action(view, cx, |editor, _: &HalfPageUp, cx| {
         editor.scroll_screen(&ScrollAmount::Page(-0.5), cx)
     });
-    register_action(cx, |editor, _: &PageDown, cx| {
+    register_action(view, cx, |editor, _: &PageDown, cx| {
         editor.scroll_screen(&ScrollAmount::Page(1.), cx)
     });
-    register_action(cx, |editor, _: &PageUp, cx| {
+    register_action(view, cx, |editor, _: &PageUp, cx| {
         editor.scroll_screen(&ScrollAmount::Page(-1.), cx)
     });
-    register_action(cx, Editor::move_to_previous_word_start);
-    register_action(cx, Editor::move_to_previous_subword_start);
-    register_action(cx, Editor::move_to_next_word_end);
-    register_action(cx, Editor::move_to_next_subword_end);
-    register_action(cx, Editor::move_to_beginning_of_line);
-    register_action(cx, Editor::move_to_end_of_line);
-    register_action(cx, Editor::move_to_start_of_paragraph);
-    register_action(cx, Editor::move_to_end_of_paragraph);
-    register_action(cx, Editor::move_to_beginning);
-    register_action(cx, Editor::move_to_end);
-    register_action(cx, Editor::select_up);
-    register_action(cx, Editor::select_down);
-    register_action(cx, Editor::select_left);
-    register_action(cx, Editor::select_right);
-    register_action(cx, Editor::select_to_previous_word_start);
-    register_action(cx, Editor::select_to_previous_subword_start);
-    register_action(cx, Editor::select_to_next_word_end);
-    register_action(cx, Editor::select_to_next_subword_end);
-    register_action(cx, Editor::select_to_beginning_of_line);
-    register_action(cx, Editor::select_to_end_of_line);
-    register_action(cx, Editor::select_to_start_of_paragraph);
-    register_action(cx, Editor::select_to_end_of_paragraph);
-    register_action(cx, Editor::select_to_beginning);
-    register_action(cx, Editor::select_to_end);
-    register_action(cx, Editor::select_all);
-    register_action(cx, |editor, action, cx| {
+    register_action(view, cx, Editor::move_to_previous_word_start);
+    register_action(view, cx, Editor::move_to_previous_subword_start);
+    register_action(view, cx, Editor::move_to_next_word_end);
+    register_action(view, cx, Editor::move_to_next_subword_end);
+    register_action(view, cx, Editor::move_to_beginning_of_line);
+    register_action(view, cx, Editor::move_to_end_of_line);
+    register_action(view, cx, Editor::move_to_start_of_paragraph);
+    register_action(view, cx, Editor::move_to_end_of_paragraph);
+    register_action(view, cx, Editor::move_to_beginning);
+    register_action(view, cx, Editor::move_to_end);
+    register_action(view, cx, Editor::select_up);
+    register_action(view, cx, Editor::select_down);
+    register_action(view, cx, Editor::select_left);
+    register_action(view, cx, Editor::select_right);
+    register_action(view, cx, Editor::select_to_previous_word_start);
+    register_action(view, cx, Editor::select_to_previous_subword_start);
+    register_action(view, cx, Editor::select_to_next_word_end);
+    register_action(view, cx, Editor::select_to_next_subword_end);
+    register_action(view, cx, Editor::select_to_beginning_of_line);
+    register_action(view, cx, Editor::select_to_end_of_line);
+    register_action(view, cx, Editor::select_to_start_of_paragraph);
+    register_action(view, cx, Editor::select_to_end_of_paragraph);
+    register_action(view, cx, Editor::select_to_beginning);
+    register_action(view, cx, Editor::select_to_end);
+    register_action(view, cx, Editor::select_all);
+    register_action(view, cx, |editor, action, cx| {
         editor.select_all_matches(action, cx).log_err();
     });
-    register_action(cx, Editor::select_line);
-    register_action(cx, Editor::split_selection_into_lines);
-    register_action(cx, Editor::add_selection_above);
-    register_action(cx, Editor::add_selection_below);
-    register_action(cx, |editor, action, cx| {
+    register_action(view, cx, Editor::select_line);
+    register_action(view, cx, Editor::split_selection_into_lines);
+    register_action(view, cx, Editor::add_selection_above);
+    register_action(view, cx, Editor::add_selection_below);
+    register_action(view, cx, |editor, action, cx| {
         editor.select_next(action, cx).log_err();
     });
-    register_action(cx, |editor, action, cx| {
+    register_action(view, cx, |editor, action, cx| {
         editor.select_previous(action, cx).log_err();
     });
-    register_action(cx, Editor::toggle_comments);
-    register_action(cx, Editor::select_larger_syntax_node);
-    register_action(cx, Editor::select_smaller_syntax_node);
-    register_action(cx, Editor::move_to_enclosing_bracket);
-    register_action(cx, Editor::undo_selection);
-    register_action(cx, Editor::redo_selection);
-    register_action(cx, Editor::go_to_diagnostic);
-    register_action(cx, Editor::go_to_prev_diagnostic);
-    register_action(cx, Editor::go_to_hunk);
-    register_action(cx, Editor::go_to_prev_hunk);
-    register_action(cx, Editor::go_to_definition);
-    register_action(cx, Editor::go_to_definition_split);
-    register_action(cx, Editor::go_to_type_definition);
-    register_action(cx, Editor::go_to_type_definition_split);
-    register_action(cx, Editor::fold);
-    register_action(cx, Editor::fold_at);
-    register_action(cx, Editor::unfold_lines);
-    register_action(cx, Editor::unfold_at);
-    register_action(cx, Editor::fold_selected_ranges);
-    register_action(cx, Editor::show_completions);
-    register_action(cx, Editor::toggle_code_actions);
+    register_action(view, cx, Editor::toggle_comments);
+    register_action(view, cx, Editor::select_larger_syntax_node);
+    register_action(view, cx, Editor::select_smaller_syntax_node);
+    register_action(view, cx, Editor::move_to_enclosing_bracket);
+    register_action(view, cx, Editor::undo_selection);
+    register_action(view, cx, Editor::redo_selection);
+    register_action(view, cx, Editor::go_to_diagnostic);
+    register_action(view, cx, Editor::go_to_prev_diagnostic);
+    register_action(view, cx, Editor::go_to_hunk);
+    register_action(view, cx, Editor::go_to_prev_hunk);
+    register_action(view, cx, Editor::go_to_definition);
+    register_action(view, cx, Editor::go_to_definition_split);
+    register_action(view, cx, Editor::go_to_type_definition);
+    register_action(view, cx, Editor::go_to_type_definition_split);
+    register_action(view, cx, Editor::fold);
+    register_action(view, cx, Editor::fold_at);
+    register_action(view, cx, Editor::unfold_lines);
+    register_action(view, cx, Editor::unfold_at);
+    register_action(view, cx, Editor::fold_selected_ranges);
+    register_action(view, cx, Editor::show_completions);
+    register_action(view, cx, Editor::toggle_code_actions);
     // on_action(cx, Editor::open_excerpts); todo!()
-    register_action(cx, Editor::toggle_soft_wrap);
-    register_action(cx, Editor::toggle_inlay_hints);
-    register_action(cx, Editor::reveal_in_finder);
-    register_action(cx, Editor::copy_path);
-    register_action(cx, Editor::copy_relative_path);
-    register_action(cx, Editor::copy_highlight_json);
-    register_action(cx, |editor, action, cx| {
+    register_action(view, cx, Editor::toggle_soft_wrap);
+    register_action(view, cx, Editor::toggle_inlay_hints);
+    register_action(view, cx, Editor::reveal_in_finder);
+    register_action(view, cx, Editor::copy_path);
+    register_action(view, cx, Editor::copy_relative_path);
+    register_action(view, cx, Editor::copy_highlight_json);
+    register_action(view, cx, |editor, action, cx| {
         editor
             .format(action, cx)
             .map(|task| task.detach_and_log_err(cx));
     });
-    register_action(cx, Editor::restart_language_server);
-    register_action(cx, Editor::show_character_palette);
+    register_action(view, cx, Editor::restart_language_server);
+    register_action(view, cx, Editor::show_character_palette);
     // on_action(cx, Editor::confirm_completion); todo!()
-    register_action(cx, |editor, action, cx| {
+    register_action(view, cx, |editor, action, cx| {
         editor
             .confirm_code_action(action, cx)
             .map(|task| task.detach_and_log_err(cx));
     });
-    register_action(cx, |editor, action, cx| {
+    register_action(view, cx, |editor, action, cx| {
         editor
             .rename(action, cx)
             .map(|task| task.detach_and_log_err(cx));
     });
-    register_action(cx, |editor, action, cx| {
+    register_action(view, cx, |editor, action, cx| {
         editor
             .confirm_rename(action, cx)
             .map(|task| task.detach_and_log_err(cx));
     });
-    register_action(cx, |editor, action, cx| {
+    register_action(view, cx, |editor, action, cx| {
         editor
             .find_all_references(action, cx)
             .map(|task| task.detach_and_log_err(cx));
     });
-    register_action(cx, Editor::next_copilot_suggestion);
-    register_action(cx, Editor::previous_copilot_suggestion);
-    register_action(cx, Editor::copilot_suggest);
-    register_action(cx, Editor::context_menu_first);
-    register_action(cx, Editor::context_menu_prev);
-    register_action(cx, Editor::context_menu_next);
-    register_action(cx, Editor::context_menu_last);
+    register_action(view, cx, Editor::next_copilot_suggestion);
+    register_action(view, cx, Editor::previous_copilot_suggestion);
+    register_action(view, cx, Editor::copilot_suggest);
+    register_action(view, cx, Editor::context_menu_first);
+    register_action(view, cx, Editor::context_menu_prev);
+    register_action(view, cx, Editor::context_menu_next);
+    register_action(view, cx, Editor::context_menu_last);
 }
 
 fn register_action<T: Action>(
-    cx: &mut ViewContext<Editor>,
+    view: &View<Editor>,
+    cx: &mut WindowContext,
     listener: impl Fn(&mut Editor, &T, &mut ViewContext<Editor>) + 'static,
 ) {
-    cx.on_action(TypeId::of::<T>(), move |editor, action, phase, cx| {
+    let view = view.clone();
+    cx.on_action(TypeId::of::<T>(), move |action, phase, cx| {
         let action = action.downcast_ref().unwrap();
         if phase == DispatchPhase::Bubble {
-            listener(editor, action, cx);
+            view.update(cx, |editor, cx| {
+                listener(editor, action, cx);
+            })
         }
     })
 }

crates/editor2/src/hover_popover.rs 🔗

@@ -422,7 +422,7 @@ impl HoverState {
         visible_rows: Range<u32>,
         workspace: Option<WeakView<Workspace>>,
         cx: &mut ViewContext<Editor>,
-    ) -> Option<(DisplayPoint, Vec<AnyElement<Editor>>)> {
+    ) -> Option<(DisplayPoint, Vec<AnyElement>)> {
         todo!("old version below")
     }
     //     // If there is a diagnostic, position the popovers based on that.
@@ -504,7 +504,7 @@ pub struct DiagnosticPopover {
 }
 
 impl DiagnosticPopover {
-    pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext<Editor>) -> AnyElement<Editor> {
+    pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext<Editor>) -> AnyElement {
         todo!()
         // enum PrimaryDiagnostic {}
 

crates/editor2/src/items.rs 🔗

@@ -10,7 +10,7 @@ use futures::future::try_join_all;
 use gpui::{
     div, point, AnyElement, AppContext, AsyncAppContext, Entity, EntityId, EventEmitter,
     FocusHandle, Model, ParentElement, Pixels, SharedString, Styled, Subscription, Task, View,
-    ViewContext, VisualContext, WeakView,
+    ViewContext, VisualContext, WeakView, WindowContext,
 };
 use language::{
     proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, OffsetRangeExt,
@@ -584,7 +584,7 @@ impl Item for Editor {
         Some(path.to_string_lossy().to_string().into())
     }
 
-    fn tab_content<T: 'static>(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<T> {
+    fn tab_content(&self, detail: Option<usize>, cx: &WindowContext) -> AnyElement {
         let theme = cx.theme();
 
         AnyElement::new(

crates/file_finder2/src/file_finder.rs 🔗

@@ -117,8 +117,8 @@ impl FocusableView for FileFinder {
         self.picker.focus_handle(cx)
     }
 }
-impl Render<Self> for FileFinder {
-    type Element = Div<Self>;
+impl Render for FileFinder {
+    type Element = Div;
 
     fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
         v_stack().w_96().child(self.picker.clone())
@@ -530,7 +530,7 @@ impl FileFinderDelegate {
 }
 
 impl PickerDelegate for FileFinderDelegate {
-    type ListItem = Div<Picker<Self>>;
+    type ListItem = Div;
 
     fn placeholder_text(&self) -> Arc<str> {
         "Search project files...".into()

crates/go_to_line2/src/go_to_line.rs 🔗

@@ -144,15 +144,15 @@ impl GoToLine {
     }
 }
 
-impl Render<Self> for GoToLine {
-    type Element = Div<Self>;
+impl Render for GoToLine {
+    type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         div()
             .elevation_2(cx)
             .key_context("GoToLine")
-            .on_action(Self::cancel)
-            .on_action(Self::confirm)
+            .on_action(cx.listener(Self::cancel))
+            .on_action(cx.listener(Self::confirm))
             .w_96()
             .child(
                 v_stack()

crates/gpui2/src/app.rs 🔗

@@ -424,7 +424,7 @@ impl AppContext {
     /// Opens a new window with the given option and the root view returned by the given function.
     /// The function is invoked with a `WindowContext`, which can be used to interact with window-specific
     /// functionality.
-    pub fn open_window<V: 'static + Render<V>>(
+    pub fn open_window<V: 'static + Render>(
         &mut self,
         options: crate::WindowOptions,
         build_root_view: impl FnOnce(&mut WindowContext) -> View<V>,

crates/gpui2/src/app/async_context.rs 🔗

@@ -115,7 +115,7 @@ impl AsyncAppContext {
         build_root_view: impl FnOnce(&mut WindowContext) -> View<V>,
     ) -> Result<WindowHandle<V>>
     where
-        V: 'static + Render<V>,
+        V: 'static + Render,
     {
         let app = self
             .app
@@ -286,7 +286,7 @@ impl VisualContext for AsyncWindowContext {
         build_view_state: impl FnOnce(&mut ViewContext<'_, V>) -> V,
     ) -> Self::Result<View<V>>
     where
-        V: 'static + Render<V>,
+        V: 'static + Render,
     {
         self.window
             .update(self, |_, cx| cx.build_view(build_view_state))
@@ -306,7 +306,7 @@ impl VisualContext for AsyncWindowContext {
         build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
     ) -> Self::Result<View<V>>
     where
-        V: 'static + Render<V>,
+        V: 'static + Render,
     {
         self.window
             .update(self, |_, cx| cx.replace_root_view(build_view))

crates/gpui2/src/app/test_context.rs 🔗

@@ -126,7 +126,7 @@ impl TestAppContext {
     pub fn add_window<F, V>(&mut self, build_window: F) -> WindowHandle<V>
     where
         F: FnOnce(&mut ViewContext<V>) -> V,
-        V: 'static + Render<V>,
+        V: 'static + Render,
     {
         let mut cx = self.app.borrow_mut();
         cx.open_window(WindowOptions::default(), |cx| cx.build_view(build_window))
@@ -143,7 +143,7 @@ impl TestAppContext {
     pub fn add_window_view<F, V>(&mut self, build_window: F) -> (View<V>, &mut VisualTestContext)
     where
         F: FnOnce(&mut ViewContext<V>) -> V,
-        V: 'static + Render<V>,
+        V: 'static + Render,
     {
         let mut cx = self.app.borrow_mut();
         let window = cx.open_window(WindowOptions::default(), |cx| cx.build_view(build_window));
@@ -569,7 +569,7 @@ impl<'a> VisualContext for VisualTestContext<'a> {
         build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
     ) -> Self::Result<View<V>>
     where
-        V: 'static + Render<V>,
+        V: 'static + Render,
     {
         self.window
             .update(self.cx, |_, cx| cx.build_view(build_view))
@@ -591,7 +591,7 @@ impl<'a> VisualContext for VisualTestContext<'a> {
         build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
     ) -> Self::Result<View<V>>
     where
-        V: 'static + Render<V>,
+        V: 'static + Render,
     {
         self.window
             .update(self.cx, |_, cx| cx.replace_root_view(build_view))
@@ -619,7 +619,7 @@ impl<'a> VisualContext for VisualTestContext<'a> {
 }
 
 impl AnyWindowHandle {
-    pub fn build_view<V: Render<V> + 'static>(
+    pub fn build_view<V: Render + 'static>(
         &self,
         cx: &mut TestAppContext,
         build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
@@ -630,8 +630,8 @@ impl AnyWindowHandle {
 
 pub struct EmptyView {}
 
-impl Render<Self> for EmptyView {
-    type Element = Div<Self>;
+impl Render for EmptyView {
+    type Element = Div;
 
     fn render(&mut self, _cx: &mut crate::ViewContext<Self>) -> Self::Element {
         div()

crates/gpui2/src/element.rs 🔗

@@ -1,24 +1,25 @@
 use crate::{
     AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size, ViewContext,
+    WindowContext,
 };
 use derive_more::{Deref, DerefMut};
 pub(crate) use smallvec::SmallVec;
-use std::{any::Any, fmt::Debug, marker::PhantomData};
+use std::{any::Any, fmt::Debug};
 
-pub trait Render<V: 'static>: 'static + Sized {
-    type Element: Element<V> + 'static;
+pub trait Render: 'static + Sized {
+    type Element: Element + 'static;
 
-    fn render(&mut self, cx: &mut ViewContext<V>) -> Self::Element;
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element;
 }
 
-pub trait RenderOnce<V: 'static>: Sized {
-    type Element: Element<V> + 'static;
+pub trait RenderOnce: Sized {
+    type Element: Element + 'static;
 
     fn element_id(&self) -> Option<ElementId>;
 
     fn render_once(self) -> Self::Element;
 
-    fn render_into_any(self) -> AnyElement<V> {
+    fn render_into_any(self) -> AnyElement {
         self.render_once().into_any()
     }
 
@@ -26,9 +27,8 @@ pub trait RenderOnce<V: 'static>: Sized {
         self,
         origin: Point<Pixels>,
         available_space: Size<T>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
-        f: impl FnOnce(&mut <Self::Element as Element<V>>::State, &mut ViewContext<V>) -> R,
+        cx: &mut WindowContext,
+        f: impl FnOnce(&mut <Self::Element as Element>::State, &mut WindowContext) -> R,
     ) -> R
     where
         T: Clone + Default + Debug + Into<AvailableSpace>,
@@ -39,13 +39,9 @@ pub trait RenderOnce<V: 'static>: Sized {
             element: Some(element),
             phase: ElementDrawPhase::Start,
         };
-        let frame_state = DrawableElement::draw(
-            element,
-            origin,
-            available_space.map(Into::into),
-            view_state,
-            cx,
-        );
+
+        let frame_state =
+            DrawableElement::draw(element, origin, available_space.map(Into::into), cx);
 
         if let Some(mut frame_state) = frame_state {
             f(&mut frame_state, cx)
@@ -61,7 +57,7 @@ pub trait RenderOnce<V: 'static>: Sized {
     fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
     where
         Self: Sized,
-        U: RenderOnce<V>,
+        U: RenderOnce,
     {
         f(self)
     }
@@ -87,70 +83,55 @@ pub trait RenderOnce<V: 'static>: Sized {
     }
 }
 
-pub trait Element<V: 'static>: 'static + RenderOnce<V> {
+pub trait Element: 'static + RenderOnce {
     type State: 'static;
 
     fn layout(
         &mut self,
-        view_state: &mut V,
-        element_state: Option<Self::State>,
-        cx: &mut ViewContext<V>,
+        state: Option<Self::State>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::State);
 
-    fn paint(
-        self,
-        bounds: Bounds<Pixels>,
-        view_state: &mut V,
-        element_state: &mut Self::State,
-        cx: &mut ViewContext<V>,
-    );
+    fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext);
 
-    fn into_any(self) -> AnyElement<V> {
+    fn into_any(self) -> AnyElement {
         AnyElement::new(self)
     }
 }
 
-pub trait Component<V: 'static>: 'static {
-    type Rendered: RenderOnce<V>;
+pub trait Component: 'static {
+    type Rendered: RenderOnce;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered;
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered;
 }
 
-pub struct CompositeElement<V, C> {
+pub struct CompositeElement<C> {
     component: Option<C>,
-    view_type: PhantomData<V>,
 }
 
-pub struct CompositeElementState<V: 'static, C: Component<V>> {
-    rendered_element: Option<<C::Rendered as RenderOnce<V>>::Element>,
-    rendered_element_state: <<C::Rendered as RenderOnce<V>>::Element as Element<V>>::State,
+pub struct CompositeElementState<C: Component> {
+    rendered_element: Option<<C::Rendered as RenderOnce>::Element>,
+    rendered_element_state: <<C::Rendered as RenderOnce>::Element as Element>::State,
 }
 
-impl<V, C> CompositeElement<V, C> {
+impl<C> CompositeElement<C> {
     pub fn new(component: C) -> Self {
         CompositeElement {
             component: Some(component),
-            view_type: PhantomData,
         }
     }
 }
 
-impl<V: 'static, C: Component<V>> Element<V> for CompositeElement<V, C> {
-    type State = CompositeElementState<V, C>;
+impl<C: Component> Element for CompositeElement<C> {
+    type State = CompositeElementState<C>;
 
     fn layout(
         &mut self,
-        view: &mut V,
         state: Option<Self::State>,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
-        let mut element = self
-            .component
-            .take()
-            .unwrap()
-            .render(view, cx)
-            .render_once();
-        let (layout_id, state) = element.layout(view, state.map(|s| s.rendered_element_state), cx);
+        let mut element = self.component.take().unwrap().render(cx).render_once();
+        let (layout_id, state) = element.layout(state.map(|s| s.rendered_element_state), cx);
         let state = CompositeElementState {
             rendered_element: Some(element),
             rendered_element_state: state,
@@ -158,23 +139,16 @@ impl<V: 'static, C: Component<V>> Element<V> for CompositeElement<V, C> {
         (layout_id, state)
     }
 
-    fn paint(
-        self,
-        bounds: Bounds<Pixels>,
-        view: &mut V,
-        state: &mut Self::State,
-        cx: &mut ViewContext<V>,
-    ) {
-        state.rendered_element.take().unwrap().paint(
-            bounds,
-            view,
-            &mut state.rendered_element_state,
-            cx,
-        );
+    fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
+        state
+            .rendered_element
+            .take()
+            .unwrap()
+            .paint(bounds, &mut state.rendered_element_state, cx);
     }
 }
 
-impl<V: 'static, C: Component<V>> RenderOnce<V> for CompositeElement<V, C> {
+impl<C: Component> RenderOnce for CompositeElement<C> {
     type Element = Self;
 
     fn element_id(&self) -> Option<ElementId> {
@@ -189,10 +163,10 @@ impl<V: 'static, C: Component<V>> RenderOnce<V> for CompositeElement<V, C> {
 #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
 pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
 
-pub trait ParentElement<V: 'static> {
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
+pub trait ParentElement {
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>;
 
-    fn child(mut self, child: impl RenderOnce<V>) -> Self
+    fn child(mut self, child: impl RenderOnce) -> Self
     where
         Self: Sized,
     {
@@ -200,7 +174,7 @@ pub trait ParentElement<V: 'static> {
         self
     }
 
-    fn children(mut self, children: impl IntoIterator<Item = impl RenderOnce<V>>) -> Self
+    fn children(mut self, children: impl IntoIterator<Item = impl RenderOnce>) -> Self
     where
         Self: Sized,
     {
@@ -213,26 +187,28 @@ pub trait ParentElement<V: 'static> {
     }
 }
 
-trait ElementObject<V> {
+trait ElementObject {
     fn element_id(&self) -> Option<ElementId>;
-    fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
-    fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
+
+    fn layout(&mut self, cx: &mut WindowContext) -> LayoutId;
+
+    fn paint(&mut self, cx: &mut WindowContext);
+
     fn measure(
         &mut self,
         available_space: Size<AvailableSpace>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> Size<Pixels>;
+
     fn draw(
         &mut self,
         origin: Point<Pixels>,
         available_space: Size<AvailableSpace>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     );
 }
 
-pub struct DrawableElement<V: 'static, E: Element<V>> {
+pub struct DrawableElement<E: Element> {
     element: Option<E>,
     phase: ElementDrawPhase<E::State>,
 }
@@ -253,7 +229,7 @@ enum ElementDrawPhase<S> {
 }
 
 /// A wrapper around an implementer of [Element] that allows it to be drawn in a window.
-impl<V, E: Element<V>> DrawableElement<V, E> {
+impl<E: Element> DrawableElement<E> {
     fn new(element: E) -> Self {
         DrawableElement {
             element: Some(element),
@@ -265,18 +241,15 @@ impl<V, E: Element<V>> DrawableElement<V, E> {
         self.element.as_ref()?.element_id()
     }
 
-    fn layout(&mut self, state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
+    fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
         let (layout_id, frame_state) = if let Some(id) = self.element.as_ref().unwrap().element_id()
         {
             let layout_id = cx.with_element_state(id, |element_state, cx| {
-                self.element
-                    .as_mut()
-                    .unwrap()
-                    .layout(state, element_state, cx)
+                self.element.as_mut().unwrap().layout(element_state, cx)
             });
             (layout_id, None)
         } else {
-            let (layout_id, frame_state) = self.element.as_mut().unwrap().layout(state, None, cx);
+            let (layout_id, frame_state) = self.element.as_mut().unwrap().layout(None, cx);
             (layout_id, Some(frame_state))
         };
 
@@ -287,7 +260,7 @@ impl<V, E: Element<V>> DrawableElement<V, E> {
         layout_id
     }
 
-    fn paint(mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> Option<E::State> {
+    fn paint(mut self, cx: &mut WindowContext) -> Option<E::State> {
         match self.phase {
             ElementDrawPhase::LayoutRequested {
                 layout_id,
@@ -304,7 +277,7 @@ impl<V, E: Element<V>> DrawableElement<V, E> {
                     self.element
                         .take()
                         .unwrap()
-                        .paint(bounds, view_state, &mut frame_state, cx);
+                        .paint(bounds, &mut frame_state, cx);
                     Some(frame_state)
                 } else {
                     let element_id = self
@@ -315,12 +288,10 @@ impl<V, E: Element<V>> DrawableElement<V, E> {
                         .expect("if we don't have frame state, we should have element state");
                     cx.with_element_state(element_id, |element_state, cx| {
                         let mut element_state = element_state.unwrap();
-                        self.element.take().unwrap().paint(
-                            bounds,
-                            view_state,
-                            &mut element_state,
-                            cx,
-                        );
+                        self.element
+                            .take()
+                            .unwrap()
+                            .paint(bounds, &mut element_state, cx);
                         ((), element_state)
                     });
                     None
@@ -334,11 +305,10 @@ impl<V, E: Element<V>> DrawableElement<V, E> {
     fn measure(
         &mut self,
         available_space: Size<AvailableSpace>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> Size<Pixels> {
         if matches!(&self.phase, ElementDrawPhase::Start) {
-            self.layout(view_state, cx);
+            self.layout(cx);
         }
 
         let layout_id = match &mut self.phase {
@@ -376,22 +346,20 @@ impl<V, E: Element<V>> DrawableElement<V, E> {
         mut self,
         origin: Point<Pixels>,
         available_space: Size<AvailableSpace>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> Option<E::State> {
-        self.measure(available_space, view_state, cx);
-        cx.with_absolute_element_offset(origin, |cx| self.paint(view_state, cx))
+        self.measure(available_space, cx);
+        cx.with_absolute_element_offset(origin, |cx| self.paint(cx))
     }
 }
 
-// impl<V: 'static, E: Element<V>> Element<V> for DrawableElement<V, E> {
-//     type State = <E::Element as Element<V>>::State;
+// impl<V: 'static, E: Element> Element for DrawableElement<V, E> {
+//     type State = <E::Element as Element>::State;
 
 //     fn layout(
 //         &mut self,
-//         view_state: &mut V,
 //         element_state: Option<Self::State>,
-//         cx: &mut ViewContext<V>,
+//         cx: &mut WindowContext,
 //     ) -> (LayoutId, Self::State) {
 
 //     }
@@ -399,15 +367,14 @@ impl<V, E: Element<V>> DrawableElement<V, E> {
 //     fn paint(
 //         self,
 //         bounds: Bounds<Pixels>,
-//         view_state: &mut V,
 //         element_state: &mut Self::State,
-//         cx: &mut ViewContext<V>,
+//         cx: &mut WindowContext,
 //     ) {
 //         todo!()
 //     }
 // }
 
-// impl<V: 'static, E: 'static + Element<V>> RenderOnce<V> for DrawableElement<V, E> {
+// impl<V: 'static, E: 'static + Element> RenderOnce for DrawableElement<V, E> {
 //     type Element = Self;
 
 //     fn element_id(&self) -> Option<ElementId> {
@@ -419,81 +386,71 @@ impl<V, E: Element<V>> DrawableElement<V, E> {
 //     }
 // }
 
-impl<V, E> ElementObject<V> for Option<DrawableElement<V, E>>
+impl<E> ElementObject for Option<DrawableElement<E>>
 where
-    E: Element<V>,
+    E: Element,
     E::State: 'static,
 {
     fn element_id(&self) -> Option<ElementId> {
         self.as_ref().unwrap().element_id()
     }
 
-    fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
-        DrawableElement::layout(self.as_mut().unwrap(), view_state, cx)
+    fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
+        DrawableElement::layout(self.as_mut().unwrap(), cx)
     }
 
-    fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
-        DrawableElement::paint(self.take().unwrap(), view_state, cx);
+    fn paint(&mut self, cx: &mut WindowContext) {
+        DrawableElement::paint(self.take().unwrap(), cx);
     }
 
     fn measure(
         &mut self,
         available_space: Size<AvailableSpace>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> Size<Pixels> {
-        DrawableElement::measure(self.as_mut().unwrap(), available_space, view_state, cx)
+        DrawableElement::measure(self.as_mut().unwrap(), available_space, cx)
     }
 
     fn draw(
         &mut self,
         origin: Point<Pixels>,
         available_space: Size<AvailableSpace>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
-        DrawableElement::draw(
-            self.take().unwrap(),
-            origin,
-            available_space,
-            view_state,
-            cx,
-        );
+        DrawableElement::draw(self.take().unwrap(), origin, available_space, cx);
     }
 }
 
-pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
+pub struct AnyElement(Box<dyn ElementObject>);
 
-impl<V: 'static> AnyElement<V> {
+impl AnyElement {
     pub fn new<E>(element: E) -> Self
     where
-        V: 'static,
-        E: 'static + Element<V>,
+        E: 'static + Element,
         E::State: Any,
     {
-        AnyElement(Box::new(Some(DrawableElement::new(element))) as Box<dyn ElementObject<V>>)
+        AnyElement(Box::new(Some(DrawableElement::new(element))) as Box<dyn ElementObject>)
     }
 
     pub fn element_id(&self) -> Option<ElementId> {
         self.0.element_id()
     }
 
-    pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
-        self.0.layout(view_state, cx)
+    pub fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
+        self.0.layout(cx)
     }
 
-    pub fn paint(mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
-        self.0.paint(view_state, cx)
+    pub fn paint(mut self, cx: &mut WindowContext) {
+        self.0.paint(cx)
     }
 
     /// Initializes this element and performs layout within the given available space to determine its size.
     pub fn measure(
         &mut self,
         available_space: Size<AvailableSpace>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> Size<Pixels> {
-        self.0.measure(available_space, view_state, cx)
+        self.0.measure(available_space, cx)
     }
 
     /// Initializes this element and performs layout in the available space, then paints it at the given origin.
@@ -501,43 +458,35 @@ impl<V: 'static> AnyElement<V> {
         mut self,
         origin: Point<Pixels>,
         available_space: Size<AvailableSpace>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
-        self.0.draw(origin, available_space, view_state, cx)
+        self.0.draw(origin, available_space, cx)
     }
 
     /// Converts this `AnyElement` into a trait object that can be stored and manipulated.
-    pub fn into_any(self) -> AnyElement<V> {
+    pub fn into_any(self) -> AnyElement {
         AnyElement::new(self)
     }
 }
 
-impl<V: 'static> Element<V> for AnyElement<V> {
+impl Element for AnyElement {
     type State = ();
 
     fn layout(
         &mut self,
-        view_state: &mut V,
         _: Option<Self::State>,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
-        let layout_id = self.layout(view_state, cx);
+        let layout_id = self.layout(cx);
         (layout_id, ())
     }
 
-    fn paint(
-        self,
-        _bounds: Bounds<Pixels>,
-        view_state: &mut V,
-        _: &mut Self::State,
-        cx: &mut ViewContext<V>,
-    ) {
-        self.paint(view_state, cx);
+    fn paint(self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut WindowContext) {
+        self.paint(cx);
     }
 }
 
-impl<V: 'static> RenderOnce<V> for AnyElement<V> {
+impl RenderOnce for AnyElement {
     type Element = Self;
 
     fn element_id(&self) -> Option<ElementId> {
@@ -549,13 +498,13 @@ impl<V: 'static> RenderOnce<V> for AnyElement<V> {
     }
 }
 
-// impl<V, E, F> Element<V> for Option<F>
+// impl<V, E, F> Element for Option<F>
 // where
 //     V: 'static,
-//     E: Element<V>,
-//     F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
+//     E: Element,
+//     F: FnOnce(&mut V, &mut WindowContext<'_, V>) -> E + 'static,
 // {
-//     type State = Option<AnyElement<V>>;
+//     type State = Option<AnyElement>;
 
 //     fn element_id(&self) -> Option<ElementId> {
 //         None
@@ -563,9 +512,8 @@ impl<V: 'static> RenderOnce<V> for AnyElement<V> {
 
 //     fn layout(
 //         &mut self,
-//         view_state: &mut V,
 //         _: Option<Self::State>,
-//         cx: &mut ViewContext<V>,
+//         cx: &mut WindowContext,
 //     ) -> (LayoutId, Self::State) {
 //         let render = self.take().unwrap();
 //         let mut element = (render)(view_state, cx).into_any();
@@ -576,19 +524,18 @@ impl<V: 'static> RenderOnce<V> for AnyElement<V> {
 //     fn paint(
 //         self,
 //         _bounds: Bounds<Pixels>,
-//         view_state: &mut V,
 //         rendered_element: &mut Self::State,
-//         cx: &mut ViewContext<V>,
+//         cx: &mut WindowContext,
 //     ) {
 //         rendered_element.take().unwrap().paint(view_state, cx);
 //     }
 // }
 
-// impl<V, E, F> RenderOnce<V> for Option<F>
+// impl<V, E, F> RenderOnce for Option<F>
 // where
 //     V: 'static,
-//     E: Element<V>,
-//     F: FnOnce(&mut V, &mut ViewContext<V>) -> E + 'static,
+//     E: Element,
+//     F: FnOnce(&mut V, &mut WindowContext) -> E + 'static,
 // {
 //     type Element = Self;
 

crates/gpui2/src/elements/div.rs 🔗

@@ -3,7 +3,7 @@ use crate::{
     BorrowWindow, Bounds, ClickEvent, DispatchPhase, Element, ElementId, FocusEvent, FocusHandle,
     KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent, MouseMoveEvent,
     MouseUpEvent, ParentElement, Pixels, Point, Render, RenderOnce, ScrollWheelEvent, SharedString,
-    Size, Style, StyleRefinement, Styled, Task, View, ViewContext, Visibility,
+    Size, Style, StyleRefinement, Styled, Task, View, Visibility, WindowContext,
 };
 use collections::HashMap;
 use refineable::Refineable;
@@ -12,7 +12,6 @@ use std::{
     any::{Any, TypeId},
     cell::RefCell,
     fmt::Debug,
-    marker::PhantomData,
     mem,
     rc::Rc,
     time::Duration,
@@ -28,30 +27,24 @@ pub struct GroupStyle {
     pub style: StyleRefinement,
 }
 
-pub trait InteractiveElement<V: 'static>: Sized + Element<V> {
-    fn interactivity(&mut self) -> &mut Interactivity<V>;
+pub trait InteractiveElement: Sized + Element {
+    fn interactivity(&mut self) -> &mut Interactivity;
 
     fn group(mut self, group: impl Into<SharedString>) -> Self {
         self.interactivity().group = Some(group.into());
         self
     }
 
-    fn id(mut self, id: impl Into<ElementId>) -> Stateful<V, Self> {
+    fn id(mut self, id: impl Into<ElementId>) -> Stateful<Self> {
         self.interactivity().element_id = Some(id.into());
 
-        Stateful {
-            element: self,
-            view_type: PhantomData,
-        }
+        Stateful { element: self }
     }
 
-    fn track_focus(mut self, focus_handle: &FocusHandle) -> Focusable<V, Self> {
+    fn track_focus(mut self, focus_handle: &FocusHandle) -> Focusable<Self> {
         self.interactivity().focusable = true;
         self.interactivity().tracked_focus_handle = Some(focus_handle.clone());
-        Focusable {
-            element: self,
-            view_type: PhantomData,
-        }
+        Focusable { element: self }
     }
 
     fn key_context<C, E>(mut self, key_context: C) -> Self
@@ -85,15 +78,15 @@ pub trait InteractiveElement<V: 'static>: Sized + Element<V> {
     fn on_mouse_down(
         mut self,
         button: MouseButton,
-        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
+        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
     ) -> Self {
         self.interactivity().mouse_down_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+            move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble
                     && event.button == button
                     && bounds.contains_point(&event.position)
                 {
-                    handler(view, event, cx)
+                    (listener)(event, cx)
                 }
             },
         ));
@@ -102,12 +95,12 @@ pub trait InteractiveElement<V: 'static>: Sized + Element<V> {
 
     fn on_any_mouse_down(
         mut self,
-        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
+        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
     ) -> Self {
         self.interactivity().mouse_down_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+            move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                    handler(view, event, cx)
+                    (listener)(event, cx)
                 }
             },
         ));
@@ -117,43 +110,43 @@ pub trait InteractiveElement<V: 'static>: Sized + Element<V> {
     fn on_mouse_up(
         mut self,
         button: MouseButton,
-        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
+        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
     ) -> Self {
-        self.interactivity().mouse_up_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+        self.interactivity()
+            .mouse_up_listeners
+            .push(Box::new(move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble
                     && event.button == button
                     && bounds.contains_point(&event.position)
                 {
-                    handler(view, event, cx)
+                    (listener)(event, cx)
                 }
-            },
-        ));
+            }));
         self
     }
 
     fn on_any_mouse_up(
         mut self,
-        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
+        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
     ) -> Self {
-        self.interactivity().mouse_up_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+        self.interactivity()
+            .mouse_up_listeners
+            .push(Box::new(move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                    handler(view, event, cx)
+                    (listener)(event, cx)
                 }
-            },
-        ));
+            }));
         self
     }
 
     fn on_mouse_down_out(
         mut self,
-        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
+        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
     ) -> Self {
         self.interactivity().mouse_down_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+            move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Capture && !bounds.contains_point(&event.position) {
-                    handler(view, event, cx)
+                    (listener)(event, cx)
                 }
             },
         ));
@@ -163,29 +156,29 @@ pub trait InteractiveElement<V: 'static>: Sized + Element<V> {
     fn on_mouse_up_out(
         mut self,
         button: MouseButton,
-        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
+        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
     ) -> Self {
-        self.interactivity().mouse_up_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+        self.interactivity()
+            .mouse_up_listeners
+            .push(Box::new(move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Capture
                     && event.button == button
                     && !bounds.contains_point(&event.position)
                 {
-                    handler(view, event, cx);
+                    (listener)(event, cx);
                 }
-            },
-        ));
+            }));
         self
     }
 
     fn on_mouse_move(
         mut self,
-        handler: impl Fn(&mut V, &MouseMoveEvent, &mut ViewContext<V>) + 'static,
+        listener: impl Fn(&MouseMoveEvent, &mut WindowContext) + 'static,
     ) -> Self {
         self.interactivity().mouse_move_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+            move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                    handler(view, event, cx);
+                    (listener)(event, cx);
                 }
             },
         ));
@@ -194,29 +187,29 @@ pub trait InteractiveElement<V: 'static>: Sized + Element<V> {
 
     fn on_scroll_wheel(
         mut self,
-        handler: impl Fn(&mut V, &ScrollWheelEvent, &mut ViewContext<V>) + 'static,
+        listener: impl Fn(&ScrollWheelEvent, &mut WindowContext) + 'static,
     ) -> Self {
         self.interactivity().scroll_wheel_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+            move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                    handler(view, event, cx);
+                    (listener)(event, cx);
                 }
             },
         ));
         self
     }
 
-    /// Capture the given action, fires during the capture phase
+    /// Capture the given action, before normal action dispatch can fire
     fn capture_action<A: Action>(
         mut self,
-        listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
+        listener: impl Fn(&A, &mut WindowContext) + 'static,
     ) -> Self {
         self.interactivity().action_listeners.push((
             TypeId::of::<A>(),
-            Box::new(move |view, action, phase, cx| {
+            Box::new(move |action, phase, cx| {
                 let action = action.downcast_ref().unwrap();
                 if phase == DispatchPhase::Capture {
-                    listener(view, action, cx)
+                    (listener)(action, cx)
                 }
             }),
         ));
@@ -224,10 +217,7 @@ pub trait InteractiveElement<V: 'static>: Sized + Element<V> {
     }
 
     /// Add a listener for the given action, fires during the bubble event phase
-    fn on_action<A: Action>(
-        mut self,
-        listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
-    ) -> Self {
+    fn on_action<A: Action>(mut self, listener: impl Fn(&A, &mut WindowContext) + 'static) -> Self {
         // NOTE: this debug assert has the side-effect of working around
         // a bug where a crate consisting only of action definitions does
         // not register the actions in debug builds:
@@ -244,10 +234,10 @@ pub trait InteractiveElement<V: 'static>: Sized + Element<V> {
         // );
         self.interactivity().action_listeners.push((
             TypeId::of::<A>(),
-            Box::new(move |view, action, phase, cx| {
+            Box::new(move |action, phase, cx| {
                 let action = action.downcast_ref().unwrap();
                 if phase == DispatchPhase::Bubble {
-                    listener(view, action, cx)
+                    (listener)(action, cx)
                 }
             }),
         ));
@@ -256,24 +246,53 @@ pub trait InteractiveElement<V: 'static>: Sized + Element<V> {
 
     fn on_key_down(
         mut self,
-        listener: impl Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + 'static,
+        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
     ) -> Self {
         self.interactivity()
             .key_down_listeners
-            .push(Box::new(move |view, event, phase, cx| {
-                listener(view, event, phase, cx)
+            .push(Box::new(move |event, phase, cx| {
+                if phase == DispatchPhase::Bubble {
+                    (listener)(event, cx)
+                }
             }));
         self
     }
 
-    fn on_key_up(
+    fn capture_key_down(
         mut self,
-        listener: impl Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + 'static,
+        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
+    ) -> Self {
+        self.interactivity()
+            .key_down_listeners
+            .push(Box::new(move |event, phase, cx| {
+                if phase == DispatchPhase::Capture {
+                    listener(event, cx)
+                }
+            }));
+        self
+    }
+
+    fn on_key_up(mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) -> Self {
+        self.interactivity()
+            .key_up_listeners
+            .push(Box::new(move |event, phase, cx| {
+                if phase == DispatchPhase::Bubble {
+                    listener(event, cx)
+                }
+            }));
+        self
+    }
+
+    fn capture_key_up(
+        mut self,
+        listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static,
     ) -> Self {
         self.interactivity()
             .key_up_listeners
-            .push(Box::new(move |view, event, phase, cx| {
-                listener(view, event, phase, cx)
+            .push(Box::new(move |event, phase, cx| {
+                if phase == DispatchPhase::Capture {
+                    listener(event, cx)
+                }
             }));
         self
     }
@@ -302,25 +321,22 @@ pub trait InteractiveElement<V: 'static>: Sized + Element<V> {
 
     fn on_drop<W: 'static>(
         mut self,
-        listener: impl Fn(&mut V, View<W>, &mut ViewContext<V>) + 'static,
+        listener: impl Fn(&View<W>, &mut WindowContext) + 'static,
     ) -> Self {
         self.interactivity().drop_listeners.push((
             TypeId::of::<W>(),
-            Box::new(move |view, dragged_view, cx| {
-                listener(view, dragged_view.downcast().unwrap(), cx);
+            Box::new(move |dragged_view, cx| {
+                listener(&dragged_view.downcast().unwrap(), cx);
             }),
         ));
         self
     }
 }
 
-pub trait StatefulInteractiveElement<V: 'static, E: Element<V>>: InteractiveElement<V> {
-    fn focusable(mut self) -> Focusable<V, Self> {
+pub trait StatefulInteractiveElement: InteractiveElement {
+    fn focusable(mut self) -> Focusable<Self> {
         self.interactivity().focusable = true;
-        Focusable {
-            element: self,
-            view_type: PhantomData,
-        }
+        Focusable { element: self }
     }
 
     fn overflow_scroll(mut self) -> Self {
@@ -362,40 +378,33 @@ pub trait StatefulInteractiveElement<V: 'static, E: Element<V>>: InteractiveElem
         self
     }
 
-    fn on_click(
-        mut self,
-        listener: impl Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + 'static,
-    ) -> Self
+    fn on_click(mut self, listener: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self
     where
         Self: Sized,
     {
         self.interactivity()
             .click_listeners
-            .push(Box::new(move |view, event, cx| listener(view, event, cx)));
+            .push(Box::new(move |event, cx| listener(event, cx)));
         self
     }
 
-    fn on_drag<W>(
-        mut self,
-        listener: impl Fn(&mut V, &mut ViewContext<V>) -> View<W> + 'static,
-    ) -> Self
+    fn on_drag<W>(mut self, listener: impl Fn(&mut WindowContext) -> View<W> + 'static) -> Self
     where
         Self: Sized,
-        W: 'static + Render<W>,
+        W: 'static + Render,
     {
         debug_assert!(
             self.interactivity().drag_listener.is_none(),
             "calling on_drag more than once on the same element is not supported"
         );
-        self.interactivity().drag_listener =
-            Some(Box::new(move |view_state, cursor_offset, cx| AnyDrag {
-                view: listener(view_state, cx).into(),
-                cursor_offset,
-            }));
+        self.interactivity().drag_listener = Some(Box::new(move |cursor_offset, cx| AnyDrag {
+            view: listener(cx).into(),
+            cursor_offset,
+        }));
         self
     }
 
-    fn on_hover(mut self, listener: impl 'static + Fn(&mut V, bool, &mut ViewContext<V>)) -> Self
+    fn on_hover(mut self, listener: impl Fn(&bool, &mut WindowContext) + 'static) -> Self
     where
         Self: Sized,
     {
@@ -407,10 +416,7 @@ pub trait StatefulInteractiveElement<V: 'static, E: Element<V>>: InteractiveElem
         self
     }
 
-    fn tooltip(
-        mut self,
-        build_tooltip: impl Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static,
-    ) -> Self
+    fn tooltip(mut self, build_tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self
     where
         Self: Sized,
     {
@@ -418,14 +424,13 @@ pub trait StatefulInteractiveElement<V: 'static, E: Element<V>>: InteractiveElem
             self.interactivity().tooltip_builder.is_none(),
             "calling tooltip more than once on the same element is not supported"
         );
-        self.interactivity().tooltip_builder =
-            Some(Rc::new(move |view_state, cx| build_tooltip(view_state, cx)));
+        self.interactivity().tooltip_builder = Some(Rc::new(build_tooltip));
 
         self
     }
 }
 
-pub trait FocusableElement<V: 'static>: InteractiveElement<V> {
+pub trait FocusableElement: InteractiveElement {
     fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
     where
         Self: Sized,
@@ -442,49 +447,41 @@ pub trait FocusableElement<V: 'static>: InteractiveElement<V> {
         self
     }
 
-    fn on_focus(
-        mut self,
-        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
-    ) -> Self
+    fn on_focus(mut self, listener: impl Fn(&FocusEvent, &mut WindowContext) + 'static) -> Self
     where
         Self: Sized,
     {
-        self.interactivity().focus_listeners.push(Box::new(
-            move |view, focus_handle, event, cx| {
+        self.interactivity()
+            .focus_listeners
+            .push(Box::new(move |focus_handle, event, cx| {
                 if event.focused.as_ref() == Some(focus_handle) {
-                    listener(view, event, cx)
+                    listener(event, cx)
                 }
-            },
-        ));
+            }));
         self
     }
 
-    fn on_blur(
-        mut self,
-        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
-    ) -> Self
+    fn on_blur(mut self, listener: impl Fn(&FocusEvent, &mut WindowContext) + 'static) -> Self
     where
         Self: Sized,
     {
-        self.interactivity().focus_listeners.push(Box::new(
-            move |view, focus_handle, event, cx| {
+        self.interactivity()
+            .focus_listeners
+            .push(Box::new(move |focus_handle, event, cx| {
                 if event.blurred.as_ref() == Some(focus_handle) {
-                    listener(view, event, cx)
+                    listener(event, cx)
                 }
-            },
-        ));
+            }));
         self
     }
 
-    fn on_focus_in(
-        mut self,
-        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
-    ) -> Self
+    fn on_focus_in(mut self, listener: impl Fn(&FocusEvent, &mut WindowContext) + 'static) -> Self
     where
         Self: Sized,
     {
-        self.interactivity().focus_listeners.push(Box::new(
-            move |view, focus_handle, event, cx| {
+        self.interactivity()
+            .focus_listeners
+            .push(Box::new(move |focus_handle, event, cx| {
                 let descendant_blurred = event
                     .blurred
                     .as_ref()
@@ -495,22 +492,19 @@ pub trait FocusableElement<V: 'static>: InteractiveElement<V> {
                     .map_or(false, |focused| focus_handle.contains(focused, cx));
 
                 if !descendant_blurred && descendant_focused {
-                    listener(view, event, cx)
+                    listener(event, cx)
                 }
-            },
-        ));
+            }));
         self
     }
 
-    fn on_focus_out(
-        mut self,
-        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
-    ) -> Self
+    fn on_focus_out(mut self, listener: impl Fn(&FocusEvent, &mut WindowContext) + 'static) -> Self
     where
         Self: Sized,
     {
-        self.interactivity().focus_listeners.push(Box::new(
-            move |view, focus_handle, event, cx| {
+        self.interactivity()
+            .focus_listeners
+            .push(Box::new(move |focus_handle, event, cx| {
                 let descendant_blurred = event
                     .blurred
                     .as_ref()
@@ -520,93 +514,79 @@ pub trait FocusableElement<V: 'static>: InteractiveElement<V> {
                     .as_ref()
                     .map_or(false, |focused| focus_handle.contains(focused, cx));
                 if descendant_blurred && !descendant_focused {
-                    listener(view, event, cx)
+                    listener(event, cx)
                 }
-            },
-        ));
+            }));
         self
     }
 }
 
-pub type FocusListeners<V> = SmallVec<[FocusListener<V>; 2]>;
+pub type FocusListeners = SmallVec<[FocusListener; 2]>;
 
-pub type FocusListener<V> =
-    Box<dyn Fn(&mut V, &FocusHandle, &FocusEvent, &mut ViewContext<V>) + 'static>;
+pub type FocusListener = Box<dyn Fn(&FocusHandle, &FocusEvent, &mut WindowContext) + 'static>;
 
-pub type MouseDownListener<V> = Box<
-    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
->;
-pub type MouseUpListener<V> = Box<
-    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
->;
+pub type MouseDownListener =
+    Box<dyn Fn(&MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut WindowContext) + 'static>;
+pub type MouseUpListener =
+    Box<dyn Fn(&MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut WindowContext) + 'static>;
 
-pub type MouseMoveListener<V> = Box<
-    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
->;
+pub type MouseMoveListener =
+    Box<dyn Fn(&MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut WindowContext) + 'static>;
 
-pub type ScrollWheelListener<V> = Box<
-    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
-        + 'static,
->;
+pub type ScrollWheelListener =
+    Box<dyn Fn(&ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut WindowContext) + 'static>;
 
-pub type ClickListener<V> = Box<dyn Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + 'static>;
+pub type ClickListener = Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>;
 
-pub type DragListener<V> =
-    Box<dyn Fn(&mut V, Point<Pixels>, &mut ViewContext<V>) -> AnyDrag + 'static>;
+pub type DragListener = Box<dyn Fn(Point<Pixels>, &mut WindowContext) -> AnyDrag + 'static>;
 
-type DropListener<V> = dyn Fn(&mut V, AnyView, &mut ViewContext<V>) + 'static;
+type DropListener = dyn Fn(AnyView, &mut WindowContext) + 'static;
 
-pub type HoverListener<V> = Box<dyn Fn(&mut V, bool, &mut ViewContext<V>) + 'static>;
+pub type TooltipBuilder = Rc<dyn Fn(&mut WindowContext) -> AnyView + 'static>;
 
-pub type TooltipBuilder<V> = Rc<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static>;
+pub type KeyDownListener = Box<dyn Fn(&KeyDownEvent, DispatchPhase, &mut WindowContext) + 'static>;
 
-pub type KeyDownListener<V> =
-    Box<dyn Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + 'static>;
+pub type KeyUpListener = Box<dyn Fn(&KeyUpEvent, DispatchPhase, &mut WindowContext) + 'static>;
 
-pub type KeyUpListener<V> =
-    Box<dyn Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + 'static>;
+pub type ActionListener = Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + 'static>;
 
-pub type ActionListener<V> =
-    Box<dyn Fn(&mut V, &dyn Any, DispatchPhase, &mut ViewContext<V>) + 'static>;
-
-pub fn div<V: 'static>() -> Div<V> {
+pub fn div() -> Div {
     Div {
         interactivity: Interactivity::default(),
         children: SmallVec::default(),
     }
 }
 
-pub struct Div<V> {
-    interactivity: Interactivity<V>,
-    children: SmallVec<[AnyElement<V>; 2]>,
+pub struct Div {
+    interactivity: Interactivity,
+    children: SmallVec<[AnyElement; 2]>,
 }
 
-impl<V> Styled for Div<V> {
+impl Styled for Div {
     fn style(&mut self) -> &mut StyleRefinement {
         &mut self.interactivity.base_style
     }
 }
 
-impl<V: 'static> InteractiveElement<V> for Div<V> {
-    fn interactivity(&mut self) -> &mut Interactivity<V> {
+impl InteractiveElement for Div {
+    fn interactivity(&mut self) -> &mut Interactivity {
         &mut self.interactivity
     }
 }
 
-impl<V: 'static> ParentElement<V> for Div<V> {
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
+impl ParentElement for Div {
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
         &mut self.children
     }
 }
 
-impl<V: 'static> Element<V> for Div<V> {
+impl Element for Div {
     type State = DivState;
 
     fn layout(
         &mut self,
-        view_state: &mut V,
         element_state: Option<Self::State>,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
         let mut child_layout_ids = SmallVec::new();
         let mut interactivity = mem::take(&mut self.interactivity);
@@ -618,7 +598,7 @@ impl<V: 'static> Element<V> for Div<V> {
                     child_layout_ids = self
                         .children
                         .iter_mut()
-                        .map(|child| child.layout(view_state, cx))
+                        .map(|child| child.layout(cx))
                         .collect::<SmallVec<_>>();
                     cx.request_layout(&style, child_layout_ids.iter().copied())
                 })
@@ -637,9 +617,8 @@ impl<V: 'static> Element<V> for Div<V> {
     fn paint(
         self,
         bounds: Bounds<Pixels>,
-        view_state: &mut V,
         element_state: &mut Self::State,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
         let mut child_min = point(Pixels::MAX, Pixels::MAX);
         let mut child_max = Point::default();
@@ -675,7 +654,7 @@ impl<V: 'static> Element<V> for Div<V> {
                             cx.with_content_mask(style.overflow_mask(bounds), |cx| {
                                 cx.with_element_offset(scroll_offset, |cx| {
                                     for child in self.children {
-                                        child.paint(view_state, cx);
+                                        child.paint(cx);
                                     }
                                 })
                             })
@@ -687,7 +666,7 @@ impl<V: 'static> Element<V> for Div<V> {
     }
 }
 
-impl<V: 'static> RenderOnce<V> for Div<V> {
+impl RenderOnce for Div {
     type Element = Self;
 
     fn element_id(&self) -> Option<ElementId> {
@@ -710,12 +689,12 @@ impl DivState {
     }
 }
 
-pub struct Interactivity<V> {
+pub struct Interactivity {
     pub element_id: Option<ElementId>,
     pub key_context: KeyContext,
     pub focusable: bool,
     pub tracked_focus_handle: Option<FocusHandle>,
-    pub focus_listeners: FocusListeners<V>,
+    pub focus_listeners: FocusListeners,
     pub group: Option<SharedString>,
     pub base_style: StyleRefinement,
     pub focus_style: StyleRefinement,
@@ -726,29 +705,26 @@ pub struct Interactivity<V> {
     pub group_active_style: Option<GroupStyle>,
     pub drag_over_styles: SmallVec<[(TypeId, StyleRefinement); 2]>,
     pub group_drag_over_styles: SmallVec<[(TypeId, GroupStyle); 2]>,
-    pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
-    pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
-    pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
-    pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
-    pub key_down_listeners: SmallVec<[KeyDownListener<V>; 2]>,
-    pub key_up_listeners: SmallVec<[KeyUpListener<V>; 2]>,
-    pub action_listeners: SmallVec<[(TypeId, ActionListener<V>); 8]>,
-    pub drop_listeners: SmallVec<[(TypeId, Box<DropListener<V>>); 2]>,
-    pub click_listeners: SmallVec<[ClickListener<V>; 2]>,
-    pub drag_listener: Option<DragListener<V>>,
-    pub hover_listener: Option<HoverListener<V>>,
-    pub tooltip_builder: Option<TooltipBuilder<V>>,
+    pub mouse_down_listeners: SmallVec<[MouseDownListener; 2]>,
+    pub mouse_up_listeners: SmallVec<[MouseUpListener; 2]>,
+    pub mouse_move_listeners: SmallVec<[MouseMoveListener; 2]>,
+    pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener; 2]>,
+    pub key_down_listeners: SmallVec<[KeyDownListener; 2]>,
+    pub key_up_listeners: SmallVec<[KeyUpListener; 2]>,
+    pub action_listeners: SmallVec<[(TypeId, ActionListener); 8]>,
+    pub drop_listeners: SmallVec<[(TypeId, Box<DropListener>); 2]>,
+    pub click_listeners: SmallVec<[ClickListener; 2]>,
+    pub drag_listener: Option<DragListener>,
+    pub hover_listener: Option<Box<dyn Fn(&bool, &mut WindowContext)>>,
+    pub tooltip_builder: Option<TooltipBuilder>,
 }
 
-impl<V> Interactivity<V>
-where
-    V: 'static,
-{
+impl Interactivity {
     pub fn layout(
         &mut self,
         element_state: Option<InteractiveElementState>,
-        cx: &mut ViewContext<V>,
-        f: impl FnOnce(Style, &mut ViewContext<V>) -> LayoutId,
+        cx: &mut WindowContext,
+        f: impl FnOnce(Style, &mut WindowContext) -> LayoutId,
     ) -> (LayoutId, InteractiveElementState) {
         let mut element_state = element_state.unwrap_or_default();
 
@@ -774,8 +750,8 @@ where
         bounds: Bounds<Pixels>,
         content_size: Size<Pixels>,
         element_state: &mut InteractiveElementState,
-        cx: &mut ViewContext<V>,
-        f: impl FnOnce(Style, Point<Pixels>, &mut ViewContext<V>),
+        cx: &mut WindowContext,
+        f: impl FnOnce(Style, Point<Pixels>, &mut WindowContext),
     ) {
         let style = self.compute_style(Some(bounds), element_state, cx);
 
@@ -786,27 +762,27 @@ where
             }
         }
 
-        for listener in self.mouse_down_listeners {
-            cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
-                listener(state, event, &bounds, phase, cx);
+        for listener in self.mouse_down_listeners.drain(..) {
+            cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
+                listener(event, &bounds, phase, cx);
             })
         }
 
-        for listener in self.mouse_up_listeners {
-            cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
-                listener(state, event, &bounds, phase, cx);
+        for listener in self.mouse_up_listeners.drain(..) {
+            cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
+                listener(event, &bounds, phase, cx);
             })
         }
 
-        for listener in self.mouse_move_listeners {
-            cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
-                listener(state, event, &bounds, phase, cx);
+        for listener in self.mouse_move_listeners.drain(..) {
+            cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
+                listener(event, &bounds, phase, cx);
             })
         }
 
-        for listener in self.scroll_wheel_listeners {
-            cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
-                listener(state, event, &bounds, phase, cx);
+        for listener in self.scroll_wheel_listeners.drain(..) {
+            cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
+                listener(event, &bounds, phase, cx);
             })
         }
 
@@ -817,7 +793,7 @@ where
 
         if let Some(group_bounds) = hover_group_bounds {
             let hovered = group_bounds.contains_point(&cx.mouse_position());
-            cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
+            cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
                 if phase == DispatchPhase::Capture {
                     if group_bounds.contains_point(&event.position) != hovered {
                         cx.notify();
@@ -830,7 +806,7 @@ where
             || (cx.active_drag.is_some() && !self.drag_over_styles.is_empty())
         {
             let hovered = bounds.contains_point(&cx.mouse_position());
-            cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
+            cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
                 if phase == DispatchPhase::Capture {
                     if bounds.contains_point(&event.position) != hovered {
                         cx.notify();
@@ -840,8 +816,8 @@ where
         }
 
         if cx.active_drag.is_some() {
-            let drop_listeners = self.drop_listeners;
-            cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| {
+            let drop_listeners = mem::take(&mut self.drop_listeners);
+            cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
                     if let Some(drag_state_type) =
                         cx.active_drag.as_ref().map(|drag| drag.view.entity_type())
@@ -852,7 +828,7 @@ where
                                     .active_drag
                                     .take()
                                     .expect("checked for type drag state type above");
-                                listener(view, drag.view.clone(), cx);
+                                listener(drag.view.clone(), cx);
                                 cx.notify();
                                 cx.stop_propagation();
                             }
@@ -872,7 +848,7 @@ where
                 if let Some(drag_listener) = drag_listener {
                     let active_state = element_state.clicked_state.clone();
 
-                    cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| {
+                    cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
                         if cx.active_drag.is_some() {
                             if phase == DispatchPhase::Capture {
                                 cx.notify();
@@ -883,7 +859,7 @@ where
                         {
                             *active_state.borrow_mut() = ElementClickedState::default();
                             let cursor_offset = event.position - bounds.origin;
-                            let drag = drag_listener(view_state, cursor_offset, cx);
+                            let drag = drag_listener(cursor_offset, cx);
                             cx.active_drag = Some(drag);
                             cx.notify();
                             cx.stop_propagation();
@@ -891,21 +867,21 @@ where
                     });
                 }
 
-                cx.on_mouse_event(move |view_state, event: &MouseUpEvent, phase, cx| {
+                cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
                     if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
                         let mouse_click = ClickEvent {
                             down: mouse_down.clone(),
                             up: event.clone(),
                         };
                         for listener in &click_listeners {
-                            listener(view_state, &mouse_click, cx);
+                            listener(&mouse_click, cx);
                         }
                     }
                     *pending_mouse_down.borrow_mut() = None;
                     cx.notify();
                 });
             } else {
-                cx.on_mouse_event(move |_view_state, event: &MouseDownEvent, phase, cx| {
+                cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
                     if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
                         *pending_mouse_down.borrow_mut() = Some(event.clone());
                         cx.notify();
@@ -918,7 +894,7 @@ where
             let was_hovered = element_state.hover_state.clone();
             let has_mouse_down = element_state.pending_mouse_down.clone();
 
-            cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| {
+            cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
                 if phase != DispatchPhase::Bubble {
                     return;
                 }
@@ -930,7 +906,7 @@ where
                     *was_hovered = is_hovered;
                     drop(was_hovered);
 
-                    hover_listener(view_state, is_hovered, cx);
+                    hover_listener(&is_hovered, cx);
                 }
             });
         }
@@ -939,7 +915,7 @@ where
             let active_tooltip = element_state.active_tooltip.clone();
             let pending_mouse_down = element_state.pending_mouse_down.clone();
 
-            cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
+            cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
                 if phase != DispatchPhase::Bubble {
                     return;
                 }
@@ -956,12 +932,12 @@ where
                         let active_tooltip = active_tooltip.clone();
                         let tooltip_builder = tooltip_builder.clone();
 
-                        move |view, mut cx| async move {
+                        move |mut cx| async move {
                             cx.background_executor().timer(TOOLTIP_DELAY).await;
-                            view.update(&mut cx, move |view_state, cx| {
+                            cx.update(|_, cx| {
                                 active_tooltip.borrow_mut().replace(ActiveTooltip {
                                     tooltip: Some(AnyTooltip {
-                                        view: tooltip_builder(view_state, cx),
+                                        view: tooltip_builder(cx),
                                         cursor_offset: cx.mouse_position(),
                                     }),
                                     _task: None,
@@ -979,7 +955,7 @@ where
             });
 
             let active_tooltip = element_state.active_tooltip.clone();
-            cx.on_mouse_event(move |_, _: &MouseDownEvent, _, _| {
+            cx.on_mouse_event(move |_: &MouseDownEvent, _, _| {
                 active_tooltip.borrow_mut().take();
             });
 
@@ -992,7 +968,7 @@ where
 
         let active_state = element_state.clicked_state.clone();
         if !active_state.borrow().is_clicked() {
-            cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
+            cx.on_mouse_event(move |_: &MouseUpEvent, phase, cx| {
                 if phase == DispatchPhase::Capture {
                     *active_state.borrow_mut() = ElementClickedState::default();
                     cx.notify();
@@ -1003,7 +979,7 @@ where
                 .group_active_style
                 .as_ref()
                 .and_then(|group_active| GroupBounds::get(&group_active.group, cx));
-            cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
+            cx.on_mouse_event(move |down: &MouseDownEvent, phase, cx| {
                 if phase == DispatchPhase::Bubble {
                     let group = active_group_bounds
                         .map_or(false, |bounds| bounds.contains_point(&down.position));
@@ -1025,7 +1001,7 @@ where
             let line_height = cx.line_height();
             let scroll_max = (content_size - bounds.size).max(&Size::default());
 
-            cx.on_mouse_event(move |_, event: &ScrollWheelEvent, phase, cx| {
+            cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
                     let mut scroll_offset = scroll_offset.borrow_mut();
                     let old_scroll_offset = *scroll_offset;
@@ -1062,15 +1038,15 @@ where
             self.key_context.clone(),
             element_state.focus_handle.clone(),
             |_, cx| {
-                for listener in self.key_down_listeners {
-                    cx.on_key_event(move |state, event: &KeyDownEvent, phase, cx| {
-                        listener(state, event, phase, cx);
+                for listener in self.key_down_listeners.drain(..) {
+                    cx.on_key_event(move |event: &KeyDownEvent, phase, cx| {
+                        listener(event, phase, cx);
                     })
                 }
 
-                for listener in self.key_up_listeners {
-                    cx.on_key_event(move |state, event: &KeyUpEvent, phase, cx| {
-                        listener(state, event, phase, cx);
+                for listener in self.key_up_listeners.drain(..) {
+                    cx.on_key_event(move |event: &KeyUpEvent, phase, cx| {
+                        listener(event, phase, cx);
                     })
                 }
 
@@ -1081,9 +1057,7 @@ where
                 if let Some(focus_handle) = element_state.focus_handle.as_ref() {
                     for listener in self.focus_listeners {
                         let focus_handle = focus_handle.clone();
-                        cx.on_focus_changed(move |view, event, cx| {
-                            listener(view, &focus_handle, event, cx)
-                        });
+                        cx.on_focus_changed(move |event, cx| listener(&focus_handle, event, cx));
                     }
                 }
 
@@ -1100,7 +1074,7 @@ where
         &self,
         bounds: Option<Bounds<Pixels>>,
         element_state: &mut InteractiveElementState,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> Style {
         let mut style = Style::default();
         style.refine(&self.base_style);
@@ -1171,7 +1145,7 @@ where
     }
 }
 
-impl<V: 'static> Default for Interactivity<V> {
+impl Default for Interactivity {
     fn default() -> Self {
         Self {
             element_id: None,
@@ -1259,31 +1233,25 @@ impl GroupBounds {
     }
 }
 
-pub struct Focusable<V, E> {
+pub struct Focusable<E> {
     element: E,
-    view_type: PhantomData<V>,
 }
 
-impl<V: 'static + Render<V>, E: InteractiveElement<V>> FocusableElement<V> for Focusable<V, E> {}
+impl<E: InteractiveElement> FocusableElement for Focusable<E> {}
 
-impl<V, E> InteractiveElement<V> for Focusable<V, E>
+impl<E> InteractiveElement for Focusable<E>
 where
-    V: 'static + Render<V>,
-    E: InteractiveElement<V>,
+    E: InteractiveElement,
 {
-    fn interactivity(&mut self) -> &mut Interactivity<V> {
+    fn interactivity(&mut self) -> &mut Interactivity {
         self.element.interactivity()
     }
 }
 
-impl<V: 'static + Render<V>, E: StatefulInteractiveElement<V, E>> StatefulInteractiveElement<V, E>
-    for Focusable<V, E>
-{
-}
+impl<E: StatefulInteractiveElement> StatefulInteractiveElement for Focusable<E> {}
 
-impl<V, E> Styled for Focusable<V, E>
+impl<E> Styled for Focusable<E>
 where
-    V: 'static,
     E: Styled,
 {
     fn style(&mut self) -> &mut StyleRefinement {

crates/gpui2/src/elements/img.rs 🔗

@@ -1,17 +1,17 @@
 use crate::{
-    BorrowWindow, Bounds, Element, InteractiveElement, InteractiveElementState, Interactivity,
-    LayoutId, Pixels, RenderOnce, SharedString, StyleRefinement, Styled, ViewContext,
+    Bounds, Element, InteractiveElement, InteractiveElementState, Interactivity, LayoutId, Pixels,
+    RenderOnce, SharedString, StyleRefinement, Styled, WindowContext,
 };
 use futures::FutureExt;
 use util::ResultExt;
 
-pub struct Img<V: 'static> {
-    interactivity: Interactivity<V>,
+pub struct Img {
+    interactivity: Interactivity,
     uri: Option<SharedString>,
     grayscale: bool,
 }
 
-pub fn img<V: 'static>() -> Img<V> {
+pub fn img() -> Img {
     Img {
         interactivity: Interactivity::default(),
         uri: None,
@@ -19,10 +19,7 @@ pub fn img<V: 'static>() -> Img<V> {
     }
 }
 
-impl<V> Img<V>
-where
-    V: 'static,
-{
+impl Img {
     pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
         self.uri = Some(uri.into());
         self
@@ -34,14 +31,13 @@ where
     }
 }
 
-impl<V> Element<V> for Img<V> {
+impl Element for Img {
     type State = InteractiveElementState;
 
     fn layout(
         &mut self,
-        _view_state: &mut V,
         element_state: Option<Self::State>,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
         self.interactivity.layout(element_state, cx, |style, cx| {
             cx.request_layout(&style, None)
@@ -51,9 +47,8 @@ impl<V> Element<V> for Img<V> {
     fn paint(
         self,
         bounds: Bounds<Pixels>,
-        _view_state: &mut V,
         element_state: &mut Self::State,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
         self.interactivity.paint(
             bounds,
@@ -78,7 +73,7 @@ impl<V> Element<V> for Img<V> {
                                 .log_err()
                         });
                     } else {
-                        cx.spawn(|_, mut cx| async move {
+                        cx.spawn(|mut cx| async move {
                             if image_future.await.ok().is_some() {
                                 cx.on_next_frame(|cx| cx.notify());
                             }
@@ -91,7 +86,7 @@ impl<V> Element<V> for Img<V> {
     }
 }
 
-impl<V: 'static> RenderOnce<V> for Img<V> {
+impl RenderOnce for Img {
     type Element = Self;
 
     fn element_id(&self) -> Option<crate::ElementId> {
@@ -103,14 +98,14 @@ impl<V: 'static> RenderOnce<V> for Img<V> {
     }
 }
 
-impl<V> Styled for Img<V> {
+impl Styled for Img {
     fn style(&mut self) -> &mut StyleRefinement {
         &mut self.interactivity.base_style
     }
 }
 
-impl<V> InteractiveElement<V> for Img<V> {
-    fn interactivity(&mut self) -> &mut Interactivity<V> {
+impl InteractiveElement for Img {
+    fn interactivity(&mut self) -> &mut Interactivity {
         &mut self.interactivity
     }
 }

crates/gpui2/src/elements/overlay.rs 🔗

@@ -3,15 +3,15 @@ use taffy::style::{Display, Position};
 
 use crate::{
     point, AnyElement, BorrowWindow, Bounds, Element, LayoutId, ParentElement, Pixels, Point,
-    RenderOnce, Size, Style,
+    RenderOnce, Size, Style, WindowContext,
 };
 
 pub struct OverlayState {
     child_layout_ids: SmallVec<[LayoutId; 4]>,
 }
 
-pub struct Overlay<V> {
-    children: SmallVec<[AnyElement<V>; 2]>,
+pub struct Overlay {
+    children: SmallVec<[AnyElement; 2]>,
     anchor_corner: AnchorCorner,
     fit_mode: OverlayFitMode,
     // todo!();
@@ -21,7 +21,7 @@ pub struct Overlay<V> {
 
 /// overlay gives you a floating element that will avoid overflowing the window bounds.
 /// Its children should have no margin to avoid measurement issues.
-pub fn overlay<V: 'static>() -> Overlay<V> {
+pub fn overlay() -> Overlay {
     Overlay {
         children: SmallVec::new(),
         anchor_corner: AnchorCorner::TopLeft,
@@ -30,7 +30,7 @@ pub fn overlay<V: 'static>() -> Overlay<V> {
     }
 }
 
-impl<V> Overlay<V> {
+impl Overlay {
     /// Sets which corner of the overlay should be anchored to the current position.
     pub fn anchor(mut self, anchor: AnchorCorner) -> Self {
         self.anchor_corner = anchor;
@@ -51,25 +51,24 @@ impl<V> Overlay<V> {
     }
 }
 
-impl<V: 'static> ParentElement<V> for Overlay<V> {
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
+impl ParentElement for Overlay {
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
         &mut self.children
     }
 }
 
-impl<V: 'static> Element<V> for Overlay<V> {
+impl Element for Overlay {
     type State = OverlayState;
 
     fn layout(
         &mut self,
-        view_state: &mut V,
         _: Option<Self::State>,
-        cx: &mut crate::ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (crate::LayoutId, Self::State) {
         let child_layout_ids = self
             .children
             .iter_mut()
-            .map(|child| child.layout(view_state, cx))
+            .map(|child| child.layout(cx))
             .collect::<SmallVec<_>>();
 
         let mut overlay_style = Style::default();
@@ -84,9 +83,8 @@ impl<V: 'static> Element<V> for Overlay<V> {
     fn paint(
         self,
         bounds: crate::Bounds<crate::Pixels>,
-        view_state: &mut V,
         element_state: &mut Self::State,
-        cx: &mut crate::ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
         if element_state.child_layout_ids.is_empty() {
             return;
@@ -147,13 +145,13 @@ impl<V: 'static> Element<V> for Overlay<V> {
 
         cx.with_element_offset(desired.origin - bounds.origin, |cx| {
             for child in self.children {
-                child.paint(view_state, cx);
+                child.paint(cx);
             }
         })
     }
 }
 
-impl<V: 'static> RenderOnce<V> for Overlay<V> {
+impl RenderOnce for Overlay {
     type Element = Self;
 
     fn element_id(&self) -> Option<crate::ElementId> {

crates/gpui2/src/elements/svg.rs 🔗

@@ -1,49 +1,43 @@
 use crate::{
     Bounds, Element, ElementId, InteractiveElement, InteractiveElementState, Interactivity,
-    LayoutId, Pixels, RenderOnce, SharedString, StyleRefinement, Styled, ViewContext,
+    LayoutId, Pixels, RenderOnce, SharedString, StyleRefinement, Styled, WindowContext,
 };
 use util::ResultExt;
 
-pub struct Svg<V: 'static> {
-    interactivity: Interactivity<V>,
+pub struct Svg {
+    interactivity: Interactivity,
     path: Option<SharedString>,
 }
 
-pub fn svg<V: 'static>() -> Svg<V> {
+pub fn svg() -> Svg {
     Svg {
         interactivity: Interactivity::default(),
         path: None,
     }
 }
 
-impl<V> Svg<V> {
+impl Svg {
     pub fn path(mut self, path: impl Into<SharedString>) -> Self {
         self.path = Some(path.into());
         self
     }
 }
 
-impl<V> Element<V> for Svg<V> {
+impl Element for Svg {
     type State = InteractiveElementState;
 
     fn layout(
         &mut self,
-        _view_state: &mut V,
         element_state: Option<Self::State>,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
         self.interactivity.layout(element_state, cx, |style, cx| {
             cx.request_layout(&style, None)
         })
     }
 
-    fn paint(
-        self,
-        bounds: Bounds<Pixels>,
-        _view_state: &mut V,
-        element_state: &mut Self::State,
-        cx: &mut ViewContext<V>,
-    ) where
+    fn paint(self, bounds: Bounds<Pixels>, element_state: &mut Self::State, cx: &mut WindowContext)
+    where
         Self: Sized,
     {
         self.interactivity
@@ -55,7 +49,7 @@ impl<V> Element<V> for Svg<V> {
     }
 }
 
-impl<V: 'static> RenderOnce<V> for Svg<V> {
+impl RenderOnce for Svg {
     type Element = Self;
 
     fn element_id(&self) -> Option<ElementId> {
@@ -67,14 +61,14 @@ impl<V: 'static> RenderOnce<V> for Svg<V> {
     }
 }
 
-impl<V> Styled for Svg<V> {
+impl Styled for Svg {
     fn style(&mut self) -> &mut StyleRefinement {
         &mut self.interactivity.base_style
     }
 }
 
-impl<V> InteractiveElement<V> for Svg<V> {
-    fn interactivity(&mut self) -> &mut Interactivity<V> {
+impl InteractiveElement for Svg {
+    fn interactivity(&mut self) -> &mut Interactivity {
         &mut self.interactivity
     }
 }

crates/gpui2/src/elements/text.rs 🔗

@@ -1,6 +1,6 @@
 use crate::{
-    BorrowWindow, Bounds, Element, ElementId, LayoutId, Pixels, RenderOnce, SharedString, Size,
-    TextRun, ViewContext, WindowContext, WrappedLine,
+    Bounds, Element, ElementId, LayoutId, Pixels, RenderOnce, SharedString, Size, TextRun,
+    WindowContext, WrappedLine,
 };
 use anyhow::anyhow;
 use parking_lot::{Mutex, MutexGuard};
@@ -8,32 +8,25 @@ use smallvec::SmallVec;
 use std::{cell::Cell, rc::Rc, sync::Arc};
 use util::ResultExt;
 
-impl<V: 'static> Element<V> for &'static str {
+impl Element for &'static str {
     type State = TextState;
 
     fn layout(
         &mut self,
-        _: &mut V,
         _: Option<Self::State>,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
         let mut state = TextState::default();
         let layout_id = state.layout(SharedString::from(*self), None, cx);
         (layout_id, state)
     }
 
-    fn paint(
-        self,
-        bounds: Bounds<Pixels>,
-        _: &mut V,
-        state: &mut TextState,
-        cx: &mut ViewContext<V>,
-    ) {
+    fn paint(self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut WindowContext) {
         state.paint(bounds, self, cx)
     }
 }
 
-impl<V: 'static> RenderOnce<V> for &'static str {
+impl RenderOnce for &'static str {
     type Element = Self;
 
     fn element_id(&self) -> Option<ElementId> {
@@ -45,37 +38,30 @@ impl<V: 'static> RenderOnce<V> for &'static str {
     }
 }
 
-impl<V: 'static> Element<V> for SharedString {
+impl Element for SharedString {
     type State = TextState;
 
     fn layout(
         &mut self,
-        _: &mut V,
         _: Option<Self::State>,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
         let mut state = TextState::default();
         let layout_id = state.layout(self.clone(), None, cx);
         (layout_id, state)
     }
 
-    fn paint(
-        self,
-        bounds: Bounds<Pixels>,
-        _: &mut V,
-        state: &mut TextState,
-        cx: &mut ViewContext<V>,
-    ) {
+    fn paint(self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut WindowContext) {
         let text_str: &str = self.as_ref();
         state.paint(bounds, text_str, cx)
     }
 }
 
-impl<V: 'static> RenderOnce<V> for SharedString {
+impl RenderOnce for SharedString {
     type Element = Self;
 
     fn element_id(&self) -> Option<ElementId> {
-        Some(self.clone().into())
+        None
     }
 
     fn render_once(self) -> Self::Element {
@@ -102,110 +88,25 @@ impl StyledText {
     }
 }
 
-impl<V: 'static> Element<V> for StyledText {
+impl Element for StyledText {
     type State = TextState;
 
     fn layout(
         &mut self,
-        _view: &mut V,
-        element_state: Option<Self::State>,
-        cx: &mut ViewContext<V>,
+        _: Option<Self::State>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
-        let element_state = element_state.unwrap_or_default();
-        let text_system = cx.text_system().clone();
-        let text_style = cx.text_style();
-        let font_size = text_style.font_size.to_pixels(cx.rem_size());
-        let line_height = text_style
-            .line_height
-            .to_pixels(font_size.into(), cx.rem_size());
-        let text = self.text.clone();
-
-        let rem_size = cx.rem_size();
-
-        let runs = if let Some(runs) = self.runs.take() {
-            runs
-        } else {
-            vec![text_style.to_run(text.len())]
-        };
-
-        let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
-            let element_state = element_state.clone();
-            move |known_dimensions, available_space| {
-                let wrap_width = known_dimensions.width.or(match available_space.width {
-                    crate::AvailableSpace::Definite(x) => Some(x),
-                    _ => None,
-                });
-
-                if let Some(text_state) = element_state.0.lock().as_ref() {
-                    if text_state.size.is_some()
-                        && (wrap_width.is_none() || wrap_width == text_state.wrap_width)
-                    {
-                        return text_state.size.unwrap();
-                    }
-                }
-
-                let Some(lines) = text_system
-                    .shape_text(
-                        &text,
-                        font_size,
-                        &runs[..],
-                        wrap_width, // Wrap if we know the width.
-                    )
-                    .log_err()
-                else {
-                    element_state.lock().replace(TextStateInner {
-                        lines: Default::default(),
-                        line_height,
-                        wrap_width,
-                        size: Some(Size::default()),
-                    });
-                    return Size::default();
-                };
-
-                let mut size: Size<Pixels> = Size::default();
-                for line in &lines {
-                    let line_size = line.size(line_height);
-                    size.height += line_size.height;
-                    size.width = size.width.max(line_size.width);
-                }
-
-                element_state.lock().replace(TextStateInner {
-                    lines,
-                    line_height,
-                    wrap_width,
-                    size: Some(size),
-                });
-
-                size
-            }
-        });
-
-        (layout_id, element_state)
+        let mut state = TextState::default();
+        let layout_id = state.layout(self.text.clone(), self.runs.take(), cx);
+        (layout_id, state)
     }
 
-    fn paint(
-        self,
-        bounds: Bounds<Pixels>,
-        _: &mut V,
-        element_state: &mut Self::State,
-        cx: &mut ViewContext<V>,
-    ) {
-        let element_state = element_state.lock();
-        let element_state = element_state
-            .as_ref()
-            .ok_or_else(|| anyhow!("measurement has not been performed on {}", &self.text))
-            .unwrap();
-
-        let line_height = element_state.line_height;
-        let mut line_origin = bounds.origin;
-        for line in &element_state.lines {
-            line.paint(line_origin, line_height, cx).log_err();
-            line_origin.y += line.size(line_height).height;
-        }
+    fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
+        state.paint(bounds, &self.text, cx)
     }
 }
 
-impl<V: 'static> RenderOnce<V> for StyledText {
+impl RenderOnce for StyledText {
     type Element = Self;
 
     fn element_id(&self) -> Option<crate::ElementId> {
@@ -327,7 +228,7 @@ impl TextState {
 }
 
 struct InteractiveText {
-    id: ElementId,
+    element_id: ElementId,
     text: StyledText,
 }
 
@@ -336,28 +237,27 @@ struct InteractiveTextState {
     clicked_range_ixs: Rc<Cell<SmallVec<[usize; 1]>>>,
 }
 
-impl<V: 'static> Element<V> for InteractiveText {
+impl Element for InteractiveText {
     type State = InteractiveTextState;
 
     fn layout(
         &mut self,
-        view_state: &mut V,
-        element_state: Option<Self::State>,
-        cx: &mut ViewContext<V>,
+        state: Option<Self::State>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
         if let Some(InteractiveTextState {
             text_state,
             clicked_range_ixs,
-        }) = element_state
+        }) = state
         {
-            let (layout_id, text_state) = self.text.layout(view_state, Some(text_state), cx);
+            let (layout_id, text_state) = self.text.layout(Some(text_state), cx);
             let element_state = InteractiveTextState {
                 text_state,
                 clicked_range_ixs,
             };
             (layout_id, element_state)
         } else {
-            let (layout_id, text_state) = self.text.layout(view_state, None, cx);
+            let (layout_id, text_state) = self.text.layout(None, cx);
             let element_state = InteractiveTextState {
                 text_state,
                 clicked_range_ixs: Rc::default(),
@@ -366,23 +266,16 @@ impl<V: 'static> Element<V> for InteractiveText {
         }
     }
 
-    fn paint(
-        self,
-        bounds: Bounds<Pixels>,
-        view_state: &mut V,
-        element_state: &mut Self::State,
-        cx: &mut ViewContext<V>,
-    ) {
-        self.text
-            .paint(bounds, view_state, &mut element_state.text_state, cx)
+    fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
+        self.text.paint(bounds, &mut state.text_state, cx)
     }
 }
 
-impl<V: 'static> RenderOnce<V> for InteractiveText {
+impl RenderOnce for InteractiveText {
     type Element = Self;
 
     fn element_id(&self) -> Option<ElementId> {
-        Some(self.id.clone())
+        Some(self.element_id.clone())
     }
 
     fn render_once(self) -> Self::Element {

crates/gpui2/src/elements/uniform_list.rs 🔗

@@ -1,7 +1,7 @@
 use crate::{
-    point, px, size, AnyElement, AvailableSpace, BorrowWindow, Bounds, Element, ElementId,
-    InteractiveElement, InteractiveElementState, Interactivity, LayoutId, Pixels, Point,
-    RenderOnce, Size, StyleRefinement, Styled, ViewContext,
+    point, px, size, AnyElement, AvailableSpace, Bounds, Element, ElementId, InteractiveElement,
+    InteractiveElementState, Interactivity, LayoutId, Pixels, Point, Render, RenderOnce, Size,
+    StyleRefinement, Styled, View, ViewContext, WindowContext,
 };
 use smallvec::SmallVec;
 use std::{cell::RefCell, cmp, ops::Range, rc::Rc};
@@ -10,31 +10,36 @@ use taffy::style::Overflow;
 /// uniform_list provides lazy rendering for a set of items that are of uniform height.
 /// When rendered into a container with overflow-y: hidden and a fixed (or max) height,
 /// uniform_list will only render the visibile subset of items.
-pub fn uniform_list<I, V, E>(
+pub fn uniform_list<I, R, V>(
+    view: View<V>,
     id: I,
     item_count: usize,
-    f: impl 'static + Fn(&mut V, Range<usize>, &mut ViewContext<V>) -> Vec<E>,
-) -> UniformList<V>
+    f: impl 'static + Fn(&mut V, Range<usize>, &mut ViewContext<V>) -> Vec<R>,
+) -> UniformList
 where
     I: Into<ElementId>,
-    V: 'static,
-    E: Element<V>,
+    R: RenderOnce,
+    V: Render,
 {
     let id = id.into();
     let mut style = StyleRefinement::default();
     style.overflow.y = Some(Overflow::Hidden);
 
+    let render_range = move |range, cx: &mut WindowContext| {
+        view.update(cx, |this, cx| {
+            f(this, range, cx)
+                .into_iter()
+                .map(|component| component.render_into_any())
+                .collect()
+        })
+    };
+
     UniformList {
         id: id.clone(),
         style,
         item_count,
         item_to_measure_index: 0,
-        render_items: Box::new(move |view, visible_range, cx| {
-            f(view, visible_range, cx)
-                .into_iter()
-                .map(|component| component.into_any())
-                .collect()
-        }),
+        render_items: Box::new(render_range),
         interactivity: Interactivity {
             element_id: Some(id.into()),
             ..Default::default()
@@ -43,19 +48,14 @@ where
     }
 }
 
-pub struct UniformList<V: 'static> {
+pub struct UniformList {
     id: ElementId,
     style: StyleRefinement,
     item_count: usize,
     item_to_measure_index: usize,
-    render_items: Box<
-        dyn for<'a> Fn(
-            &'a mut V,
-            Range<usize>,
-            &'a mut ViewContext<V>,
-        ) -> SmallVec<[AnyElement<V>; 64]>,
-    >,
-    interactivity: Interactivity<V>,
+    render_items:
+        Box<dyn for<'a> Fn(Range<usize>, &'a mut WindowContext) -> SmallVec<[AnyElement; 64]>>,
+    interactivity: Interactivity,
     scroll_handle: Option<UniformListScrollHandle>,
 }
 
@@ -89,7 +89,7 @@ impl UniformListScrollHandle {
     }
 }
 
-impl<V: 'static> Styled for UniformList<V> {
+impl Styled for UniformList {
     fn style(&mut self) -> &mut StyleRefinement {
         &mut self.style
     }
@@ -101,25 +101,24 @@ pub struct UniformListState {
     item_size: Size<Pixels>,
 }
 
-impl<V: 'static> Element<V> for UniformList<V> {
+impl Element for UniformList {
     type State = UniformListState;
 
     fn layout(
         &mut self,
-        view_state: &mut V,
-        element_state: Option<Self::State>,
-        cx: &mut ViewContext<V>,
+        state: Option<Self::State>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
         let max_items = self.item_count;
         let rem_size = cx.rem_size();
-        let item_size = element_state
+        let item_size = state
             .as_ref()
             .map(|s| s.item_size)
-            .unwrap_or_else(|| self.measure_item(view_state, None, cx));
+            .unwrap_or_else(|| self.measure_item(None, cx));
 
         let (layout_id, interactive) =
             self.interactivity
-                .layout(element_state.map(|s| s.interactive), cx, |style, cx| {
+                .layout(state.map(|s| s.interactive), cx, |style, cx| {
                     cx.request_measured_layout(
                         style,
                         rem_size,
@@ -157,9 +156,8 @@ impl<V: 'static> Element<V> for UniformList<V> {
     fn paint(
         self,
         bounds: Bounds<crate::Pixels>,
-        view_state: &mut V,
         element_state: &mut Self::State,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
         let style =
             self.interactivity
@@ -185,9 +183,7 @@ impl<V: 'static> Element<V> for UniformList<V> {
             .get_or_insert_with(Rc::default)
             .clone();
 
-        let item_height = self
-            .measure_item(view_state, Some(padded_bounds.size.width), cx)
-            .height;
+        let item_height = self.measure_item(Some(padded_bounds.size.width), cx).height;
 
         self.interactivity.paint(
             bounds,
@@ -229,7 +225,7 @@ impl<V: 'static> Element<V> for UniformList<V> {
                                 self.item_count,
                             );
 
-                        let items = (self.render_items)(view_state, visible_range.clone(), cx);
+                        let items = (self.render_items)(visible_range.clone(), cx);
                         cx.with_z_index(1, |cx| {
                             for (item, ix) in items.into_iter().zip(visible_range) {
                                 let item_origin = padded_bounds.origin
@@ -238,7 +234,7 @@ impl<V: 'static> Element<V> for UniformList<V> {
                                     AvailableSpace::Definite(padded_bounds.size.width),
                                     AvailableSpace::Definite(item_height),
                                 );
-                                item.draw(item_origin, available_space, view_state, cx);
+                                item.draw(item_origin, available_space, cx);
                             }
                         });
                     }
@@ -248,7 +244,7 @@ impl<V: 'static> Element<V> for UniformList<V> {
     }
 }
 
-impl<V> RenderOnce<V> for UniformList<V> {
+impl RenderOnce for UniformList {
     type Element = Self;
 
     fn element_id(&self) -> Option<crate::ElementId> {
@@ -260,24 +256,19 @@ impl<V> RenderOnce<V> for UniformList<V> {
     }
 }
 
-impl<V> UniformList<V> {
+impl UniformList {
     pub fn with_width_from_item(mut self, item_index: Option<usize>) -> Self {
         self.item_to_measure_index = item_index.unwrap_or(0);
         self
     }
 
-    fn measure_item(
-        &self,
-        view_state: &mut V,
-        list_width: Option<Pixels>,
-        cx: &mut ViewContext<V>,
-    ) -> Size<Pixels> {
+    fn measure_item(&self, list_width: Option<Pixels>, cx: &mut WindowContext) -> Size<Pixels> {
         if self.item_count == 0 {
             return Size::default();
         }
 
         let item_ix = cmp::min(self.item_to_measure_index, self.item_count - 1);
-        let mut items = (self.render_items)(view_state, item_ix..item_ix + 1, cx);
+        let mut items = (self.render_items)(item_ix..item_ix + 1, cx);
         let mut item_to_measure = items.pop().unwrap();
         let available_space = size(
             list_width.map_or(AvailableSpace::MinContent, |width| {
@@ -285,7 +276,7 @@ impl<V> UniformList<V> {
             }),
             AvailableSpace::MinContent,
         );
-        item_to_measure.measure(available_space, view_state, cx)
+        item_to_measure.measure(available_space, cx)
     }
 
     pub fn track_scroll(mut self, handle: UniformListScrollHandle) -> Self {
@@ -294,8 +285,8 @@ impl<V> UniformList<V> {
     }
 }
 
-impl<V> InteractiveElement<V> for UniformList<V> {
-    fn interactivity(&mut self) -> &mut crate::Interactivity<V> {
+impl InteractiveElement for UniformList {
+    fn interactivity(&mut self) -> &mut crate::Interactivity {
         &mut self.interactivity
     }
 }

crates/gpui2/src/gpui2.rs 🔗

@@ -121,7 +121,7 @@ pub trait VisualContext: Context {
         build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
     ) -> Self::Result<View<V>>
     where
-        V: 'static + Render<V>;
+        V: 'static + Render;
 
     fn update_view<V: 'static, R>(
         &mut self,
@@ -134,7 +134,7 @@ pub trait VisualContext: Context {
         build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
     ) -> Self::Result<View<V>>
     where
-        V: 'static + Render<V>;
+        V: 'static + Render;
 
     fn focus_view<V>(&mut self, view: &View<V>) -> Self::Result<()>
     where

crates/gpui2/src/input.rs 🔗

@@ -1,4 +1,6 @@
-use crate::{AsyncWindowContext, Bounds, Pixels, PlatformInputHandler, View, ViewContext};
+use crate::{
+    AsyncWindowContext, Bounds, Pixels, PlatformInputHandler, View, ViewContext, WindowContext,
+};
 use std::ops::Range;
 
 /// Implement this trait to allow views to handle textual input when implementing an editor, field, etc.
@@ -43,9 +45,9 @@ pub struct ElementInputHandler<V> {
 impl<V: 'static> ElementInputHandler<V> {
     /// Used in [Element::paint] with the element's bounds and a view context for its
     /// containing view.
-    pub fn new(element_bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) -> Self {
+    pub fn new(element_bounds: Bounds<Pixels>, view: View<V>, cx: &mut WindowContext) -> Self {
         ElementInputHandler {
-            view: cx.view().clone(),
+            view,
             element_bounds,
             cx: cx.to_async(),
         }

crates/gpui2/src/interactive.rs 🔗

@@ -1,5 +1,6 @@
 use crate::{
-    div, point, Div, Element, FocusHandle, Keystroke, Modifiers, Pixels, Point, Render, ViewContext,
+    div, point, Div, Element, FocusHandle, Keystroke, Modifiers, Pixels, Point, Render, RenderOnce,
+    ViewContext,
 };
 use smallvec::SmallVec;
 use std::{any::Any, fmt::Debug, marker::PhantomData, ops::Deref, path::PathBuf};
@@ -63,24 +64,24 @@ pub struct Drag<S, R, V, E>
 where
     R: Fn(&mut V, &mut ViewContext<V>) -> E,
     V: 'static,
-    E: Element<()>,
+    E: RenderOnce,
 {
     pub state: S,
     pub render_drag_handle: R,
-    view_type: PhantomData<V>,
+    view_element_types: PhantomData<(V, E)>,
 }
 
 impl<S, R, V, E> Drag<S, R, V, E>
 where
     R: Fn(&mut V, &mut ViewContext<V>) -> E,
     V: 'static,
-    E: Element<()>,
+    E: Element,
 {
     pub fn new(state: S, render_drag_handle: R) -> Self {
         Drag {
             state,
             render_drag_handle,
-            view_type: PhantomData,
+            view_element_types: Default::default(),
         }
     }
 }
@@ -192,8 +193,8 @@ impl Deref for MouseExitEvent {
 #[derive(Debug, Clone, Default)]
 pub struct ExternalPaths(pub(crate) SmallVec<[PathBuf; 2]>);
 
-impl Render<Self> for ExternalPaths {
-    type Element = Div<Self>;
+impl Render for ExternalPaths {
+    type Element = Div;
 
     fn render(&mut self, _: &mut ViewContext<Self>) -> Self::Element {
         div() // Intentionally left empty because the platform will render icons for the dragged files
@@ -286,7 +287,7 @@ pub struct FocusEvent {
 mod test {
     use crate::{
         self as gpui, div, Div, FocusHandle, InteractiveElement, KeyBinding, Keystroke,
-        ParentElement, Render, Stateful, TestAppContext, VisualContext,
+        ParentElement, Render, RenderOnce, Stateful, TestAppContext, VisualContext,
     };
 
     struct TestView {
@@ -297,16 +298,25 @@ mod test {
 
     actions!(TestAction);
 
-    impl Render<Self> for TestView {
-        type Element = Stateful<Self, Div<Self>>;
+    impl Render for TestView {
+        type Element = Stateful<Div>;
 
-        fn render(&mut self, _: &mut gpui::ViewContext<Self>) -> Self::Element {
+        fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
             div().id("testview").child(
                 div()
                     .key_context("parent")
-                    .on_key_down(|this: &mut TestView, _, _, _| this.saw_key_down = true)
-                    .on_action(|this: &mut TestView, _: &TestAction, _| this.saw_action = true)
-                    .child(div().key_context("nested").track_focus(&self.focus_handle)),
+                    .on_key_down(cx.listener(|this, _, _| this.saw_key_down = true))
+                    .on_action(
+                        cx.listener(|this: &mut TestView, _: &TestAction, _| {
+                            this.saw_action = true
+                        }),
+                    )
+                    .child(
+                        div()
+                            .key_context("nested")
+                            .track_focus(&self.focus_handle)
+                            .render_once(),
+                    ),
             )
         }
     }

crates/gpui2/src/style.rs 🔗

@@ -2,7 +2,7 @@ use crate::{
     black, phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask,
     Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, Font,
     FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba,
-    SharedString, Size, SizeRefinement, Styled, TextRun, ViewContext,
+    SharedString, Size, SizeRefinement, Styled, TextRun, WindowContext,
 };
 use refineable::{Cascade, Refineable};
 use smallvec::SmallVec;
@@ -313,7 +313,7 @@ impl Style {
     }
 
     /// Paints the background of an element styled with this style.
-    pub fn paint<V: 'static>(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
+    pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
         let rem_size = cx.rem_size();
 
         cx.with_z_index(0, |cx| {

crates/gpui2/src/view.rs 🔗

@@ -6,7 +6,7 @@ use crate::{
 };
 use anyhow::{Context, Result};
 use std::{
-    any::{Any, TypeId},
+    any::TypeId,
     hash::{Hash, Hasher},
 };
 
@@ -59,15 +59,15 @@ impl<V: 'static> View<V> {
         self.model.read(cx)
     }
 
-    pub fn render_with<E>(&self, component: E) -> RenderViewWith<E, V>
-    where
-        E: 'static + Element<V>,
-    {
-        RenderViewWith {
-            view: self.clone(),
-            element: Some(component),
-        }
-    }
+    // pub fn render_with<E>(&self, component: E) -> RenderViewWith<E, V>
+    // where
+    //     E: 'static + Element,
+    // {
+    //     RenderViewWith {
+    //         view: self.clone(),
+    //         element: Some(component),
+    //     }
+    // }
 
     pub fn focus_handle(&self, cx: &AppContext) -> FocusHandle
     where
@@ -77,6 +77,24 @@ impl<V: 'static> View<V> {
     }
 }
 
+impl<V: Render> Element for View<V> {
+    type State = Option<AnyElement>;
+
+    fn layout(
+        &mut self,
+        _state: Option<Self::State>,
+        cx: &mut WindowContext,
+    ) -> (LayoutId, Self::State) {
+        let mut element = self.update(cx, |view, cx| view.render(cx).into_any());
+        let layout_id = element.layout(cx);
+        (layout_id, Some(element))
+    }
+
+    fn paint(self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut WindowContext) {
+        element.take().unwrap().paint(cx);
+    }
+}
+
 impl<V> Clone for View<V> {
     fn clone(&self) -> Self {
         Self {
@@ -151,8 +169,8 @@ impl<V> Eq for WeakView<V> {}
 #[derive(Clone, Debug)]
 pub struct AnyView {
     model: AnyModel,
-    layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box<dyn Any>),
-    paint: fn(&AnyView, Box<dyn Any>, &mut WindowContext),
+    layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
+    paint: fn(&AnyView, AnyElement, &mut WindowContext),
 }
 
 impl AnyView {
@@ -199,7 +217,7 @@ impl AnyView {
     }
 }
 
-impl<V: 'static + Render<V>> From<View<V>> for AnyView {
+impl<V: Render> From<View<V>> for AnyView {
     fn from(value: View<V>) -> Self {
         AnyView {
             model: value.model.into_any(),
@@ -209,36 +227,24 @@ impl<V: 'static + Render<V>> From<View<V>> for AnyView {
     }
 }
 
-impl<V: 'static + Render<V>, ParentV: 'static> Element<ParentV> for View<V> {
-    type State = Option<AnyElement<V>>;
+impl Element for AnyView {
+    type State = Option<AnyElement>;
 
     fn layout(
         &mut self,
-        _parent_view: &mut ParentV,
         _state: Option<Self::State>,
-        cx: &mut ViewContext<ParentV>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::State) {
-        self.update(cx, |view, cx| {
-            let mut element = view.render(cx).into_any();
-            let layout_id = element.layout(view, cx);
-            (layout_id, Some(element))
-        })
+        let (layout_id, state) = (self.layout)(self, cx);
+        (layout_id, Some(state))
     }
 
-    fn paint(
-        self,
-        _: Bounds<Pixels>,
-        _parent: &mut ParentV,
-        element: &mut Self::State,
-        cx: &mut ViewContext<ParentV>,
-    ) {
-        self.update(cx, |view, cx| {
-            element.take().unwrap().paint(view, cx);
-        });
+    fn paint(self, _: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
+        (self.paint)(&self, state.take().unwrap(), cx)
     }
 }
 
-impl<V: 'static + Render<V>, ParentV: 'static> RenderOnce<ParentV> for View<V> {
+impl<V: 'static + Render> RenderOnce for View<V> {
     type Element = View<V>;
 
     fn element_id(&self) -> Option<ElementId> {
@@ -250,31 +256,7 @@ impl<V: 'static + Render<V>, ParentV: 'static> RenderOnce<ParentV> for View<V> {
     }
 }
 
-impl<V: 'static> Element<V> for AnyView {
-    type State = Option<Box<dyn Any>>;
-
-    fn layout(
-        &mut self,
-        _view_state: &mut V,
-        _element_state: Option<Self::State>,
-        cx: &mut ViewContext<V>,
-    ) -> (LayoutId, Self::State) {
-        let (layout_id, rendered_element) = (self.layout)(self, cx);
-        (layout_id, Some(rendered_element))
-    }
-
-    fn paint(
-        mut self,
-        _bounds: Bounds<Pixels>,
-        _view_state: &mut V,
-        rendered_element: &mut Self::State,
-        cx: &mut ViewContext<V>,
-    ) {
-        (self.paint)(&mut self, rendered_element.take().unwrap(), cx)
-    }
-}
-
-impl<ParentV: 'static> RenderOnce<ParentV> for AnyView {
+impl RenderOnce for AnyView {
     type Element = Self;
 
     fn element_id(&self) -> Option<ElementId> {
@@ -288,8 +270,8 @@ impl<ParentV: 'static> RenderOnce<ParentV> for AnyView {
 
 pub struct AnyWeakView {
     model: AnyWeakModel,
-    layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, Box<dyn Any>),
-    paint: fn(&AnyView, Box<dyn Any>, &mut WindowContext),
+    layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
+    paint: fn(&AnyView, AnyElement, &mut WindowContext),
 }
 
 impl AnyWeakView {
@@ -303,7 +285,7 @@ impl AnyWeakView {
     }
 }
 
-impl<V: 'static + Render<V>> From<WeakView<V>> for AnyWeakView {
+impl<V: 'static + Render> From<WeakView<V>> for AnyWeakView {
     fn from(view: WeakView<V>) -> Self {
         Self {
             model: view.model.into(),
@@ -313,88 +295,40 @@ impl<V: 'static + Render<V>> From<WeakView<V>> for AnyWeakView {
     }
 }
 
-pub struct RenderViewWith<E, V> {
-    view: View<V>,
-    element: Option<E>,
-}
-
-impl<E, ParentV, V> Element<ParentV> for RenderViewWith<E, V>
+impl<T, E> Render for T
 where
-    E: 'static + Element<V>,
-    ParentV: 'static,
-    V: 'static,
+    T: 'static + FnMut(&mut WindowContext) -> E,
+    E: 'static + Send + Element,
 {
-    type State = Option<AnyElement<V>>;
+    type Element = E;
 
-    fn layout(
-        &mut self,
-        _: &mut ParentV,
-        _: Option<Self::State>,
-        cx: &mut ViewContext<ParentV>,
-    ) -> (LayoutId, Self::State) {
-        self.view.update(cx, |view, cx| {
-            let mut element = self.element.take().unwrap().into_any();
-            let layout_id = element.layout(view, cx);
-            (layout_id, Some(element))
-        })
-    }
-
-    fn paint(
-        self,
-        _: Bounds<Pixels>,
-        _: &mut ParentV,
-        element: &mut Self::State,
-        cx: &mut ViewContext<ParentV>,
-    ) {
-        self.view
-            .update(cx, |view, cx| element.take().unwrap().paint(view, cx))
-    }
-}
-
-impl<E, V, ParentV> RenderOnce<ParentV> for RenderViewWith<E, V>
-where
-    E: 'static + Element<V>,
-    V: 'static,
-    ParentV: 'static,
-{
-    type Element = Self;
-
-    fn element_id(&self) -> Option<ElementId> {
-        self.element.as_ref().unwrap().element_id()
-    }
-
-    fn render_once(self) -> Self::Element {
-        self
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+        (self)(cx)
     }
 }
 
 mod any_view {
-    use crate::{AnyElement, AnyView, BorrowWindow, LayoutId, Render, WindowContext};
-    use std::any::Any;
+    use crate::{AnyElement, AnyView, BorrowWindow, Element, LayoutId, Render, WindowContext};
 
-    pub(crate) fn layout<V: 'static + Render<V>>(
+    pub(crate) fn layout<V: 'static + Render>(
         view: &AnyView,
         cx: &mut WindowContext,
-    ) -> (LayoutId, Box<dyn Any>) {
+    ) -> (LayoutId, AnyElement) {
         cx.with_element_id(Some(view.model.entity_id), |cx| {
             let view = view.clone().downcast::<V>().unwrap();
-            view.update(cx, |view, cx| {
-                let mut element = AnyElement::new(view.render(cx));
-                let layout_id = element.layout(view, cx);
-                (layout_id, Box::new(element) as Box<dyn Any>)
-            })
+            let mut element = view.update(cx, |view, cx| view.render(cx).into_any());
+            let layout_id = element.layout(cx);
+            (layout_id, element)
         })
     }
 
-    pub(crate) fn paint<V: 'static + Render<V>>(
+    pub(crate) fn paint<V: 'static + Render>(
         view: &AnyView,
-        element: Box<dyn Any>,
+        element: AnyElement,
         cx: &mut WindowContext,
     ) {
         cx.with_element_id(Some(view.model.entity_id), |cx| {
-            let view = view.clone().downcast::<V>().unwrap();
-            let element = element.downcast::<AnyElement<V>>().unwrap();
-            view.update(cx, |view, cx| element.paint(view, cx))
+            element.paint(cx);
         })
     }
 }

crates/gpui2/src/window.rs 🔗

@@ -187,7 +187,7 @@ impl Drop for FocusHandle {
 
 /// FocusableView allows users of your view to easily
 /// focus it (using cx.focus_view(view))
-pub trait FocusableView: 'static + Render<Self> {
+pub trait FocusableView: 'static + Render {
     fn focus_handle(&self, cx: &AppContext) -> FocusHandle;
 }
 
@@ -1436,6 +1436,82 @@ impl<'a> WindowContext<'a> {
             .dispatch_tree
             .bindings_for_action(action)
     }
+
+    pub fn listener_for<V: Render, E>(
+        &self,
+        view: &View<V>,
+        f: impl Fn(&mut V, &E, &mut ViewContext<V>) + 'static,
+    ) -> impl Fn(&E, &mut WindowContext) + 'static {
+        let view = view.downgrade();
+        move |e: &E, cx: &mut WindowContext| {
+            view.update(cx, |view, cx| f(view, e, cx)).ok();
+        }
+    }
+
+    pub fn constructor_for<V: Render, R>(
+        &self,
+        view: &View<V>,
+        f: impl Fn(&mut V, &mut ViewContext<V>) -> R + 'static,
+    ) -> impl Fn(&mut WindowContext) -> R + 'static {
+        let view = view.clone();
+        move |cx: &mut WindowContext| view.update(cx, |view, cx| f(view, cx))
+    }
+
+    //========== ELEMENT RELATED FUNCTIONS ===========
+    pub fn with_key_dispatch<R>(
+        &mut self,
+        context: KeyContext,
+        focus_handle: Option<FocusHandle>,
+        f: impl FnOnce(Option<FocusHandle>, &mut Self) -> R,
+    ) -> R {
+        let window = &mut self.window;
+        window
+            .current_frame
+            .dispatch_tree
+            .push_node(context.clone());
+        if let Some(focus_handle) = focus_handle.as_ref() {
+            window
+                .current_frame
+                .dispatch_tree
+                .make_focusable(focus_handle.id);
+        }
+        let result = f(focus_handle, self);
+
+        self.window.current_frame.dispatch_tree.pop_node();
+
+        result
+    }
+
+    /// Register a focus listener for the current frame only. It will be cleared
+    /// on the next frame render. You should use this method only from within elements,
+    /// and we may want to enforce that better via a different context type.
+    // todo!() Move this to `FrameContext` to emphasize its individuality?
+    pub fn on_focus_changed(
+        &mut self,
+        listener: impl Fn(&FocusEvent, &mut WindowContext) + 'static,
+    ) {
+        self.window
+            .current_frame
+            .focus_listeners
+            .push(Box::new(move |event, cx| {
+                listener(event, cx);
+            }));
+    }
+
+    /// Set an input handler, such as [ElementInputHandler], which interfaces with the
+    /// platform to receive textual input with proper integration with concerns such
+    /// as IME interactions.
+    pub fn handle_input(
+        &mut self,
+        focus_handle: &FocusHandle,
+        input_handler: impl PlatformInputHandler,
+    ) {
+        if focus_handle.is_focused(self) {
+            self.window
+                .platform_window
+                .set_input_handler(Box::new(input_handler));
+        }
+    }
 }
 
 impl Context for WindowContext<'_> {
@@ -1520,7 +1596,7 @@ impl VisualContext for WindowContext<'_> {
         build_view_state: impl FnOnce(&mut ViewContext<'_, V>) -> V,
     ) -> Self::Result<View<V>>
     where
-        V: 'static + Render<V>,
+        V: 'static + Render,
     {
         let slot = self.app.entities.reserve();
         let view = View {
@@ -1559,7 +1635,7 @@ impl VisualContext for WindowContext<'_> {
         build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
     ) -> Self::Result<View<V>>
     where
-        V: 'static + Render<V>,
+        V: 'static + Render,
     {
         let slot = self.app.entities.reserve();
         let view = View {
@@ -1617,6 +1693,10 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
         self.borrow_mut()
     }
 
+    fn app(&self) -> &AppContext {
+        self.borrow()
+    }
+
     fn window(&self) -> &Window {
         self.borrow()
     }
@@ -2124,49 +2204,6 @@ impl<'a, V: 'static> ViewContext<'a, V> {
         )
     }
 
-    /// Register a focus listener for the current frame only. It will be cleared
-    /// on the next frame render. You should use this method only from within elements,
-    /// and we may want to enforce that better via a different context type.
-    // todo!() Move this to `FrameContext` to emphasize its individuality?
-    pub fn on_focus_changed(
-        &mut self,
-        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
-    ) {
-        let handle = self.view().downgrade();
-        self.window
-            .current_frame
-            .focus_listeners
-            .push(Box::new(move |event, cx| {
-                handle
-                    .update(cx, |view, cx| listener(view, event, cx))
-                    .log_err();
-            }));
-    }
-
-    pub fn with_key_dispatch<R>(
-        &mut self,
-        context: KeyContext,
-        focus_handle: Option<FocusHandle>,
-        f: impl FnOnce(Option<FocusHandle>, &mut Self) -> R,
-    ) -> R {
-        let window = &mut self.window;
-        window
-            .current_frame
-            .dispatch_tree
-            .push_node(context.clone());
-        if let Some(focus_handle) = focus_handle.as_ref() {
-            window
-                .current_frame
-                .dispatch_tree
-                .make_focusable(focus_handle.id);
-        }
-        let result = f(focus_handle, self);
-
-        self.window.current_frame.dispatch_tree.pop_node();
-
-        result
-    }
-
     pub fn spawn<Fut, R>(
         &mut self,
         f: impl FnOnce(WeakView<V>, AsyncWindowContext) -> Fut,
@@ -2243,21 +2280,6 @@ impl<'a, V: 'static> ViewContext<'a, V> {
             });
     }
 
-    /// Set an input handler, such as [ElementInputHandler], which interfaces with the
-    /// platform to receive textual input with proper integration with concerns such
-    /// as IME interactions.
-    pub fn handle_input(
-        &mut self,
-        focus_handle: &FocusHandle,
-        input_handler: impl PlatformInputHandler,
-    ) {
-        if focus_handle.is_focused(self) {
-            self.window
-                .platform_window
-                .set_input_handler(Box::new(input_handler));
-        }
-    }
-
     pub fn emit<Evt>(&mut self, event: Evt)
     where
         Evt: 'static,
@@ -2284,6 +2306,16 @@ impl<'a, V: 'static> ViewContext<'a, V> {
     {
         self.defer(|_, cx| cx.emit(Manager::Dismiss))
     }
+
+    pub fn listener<E>(
+        &self,
+        f: impl Fn(&mut V, &E, &mut ViewContext<V>) + 'static,
+    ) -> impl Fn(&E, &mut WindowContext) + 'static {
+        let view = self.view().downgrade();
+        move |e: &E, cx: &mut WindowContext| {
+            view.update(cx, |view, cx| f(view, e, cx)).ok();
+        }
+    }
 }
 
 impl<V> Context for ViewContext<'_, V> {
@@ -2335,7 +2367,7 @@ impl<V> Context for ViewContext<'_, V> {
 }
 
 impl<V: 'static> VisualContext for ViewContext<'_, V> {
-    fn build_view<W: Render<W> + 'static>(
+    fn build_view<W: Render + 'static>(
         &mut self,
         build_view_state: impl FnOnce(&mut ViewContext<'_, W>) -> W,
     ) -> Self::Result<View<W>> {
@@ -2355,7 +2387,7 @@ impl<V: 'static> VisualContext for ViewContext<'_, V> {
         build_view: impl FnOnce(&mut ViewContext<'_, W>) -> W,
     ) -> Self::Result<View<W>>
     where
-        W: 'static + Render<W>,
+        W: 'static + Render,
     {
         self.window_cx.replace_root_view(build_view)
     }
@@ -2400,7 +2432,7 @@ pub struct WindowHandle<V> {
     state_type: PhantomData<V>,
 }
 
-impl<V: 'static + Render<V>> WindowHandle<V> {
+impl<V: 'static + Render> WindowHandle<V> {
     pub fn new(id: WindowId) -> Self {
         WindowHandle {
             any_handle: AnyWindowHandle {

crates/gpui2_macros/src/derive_render_once.rs 🔗

@@ -1,37 +1,17 @@
 use proc_macro::TokenStream;
 use quote::quote;
-use syn::{parse_macro_input, parse_quote, DeriveInput};
+use syn::{parse_macro_input, DeriveInput};
 
 pub fn derive_render_once(input: TokenStream) -> TokenStream {
     let ast = parse_macro_input!(input as DeriveInput);
     let type_name = &ast.ident;
-
-    let mut trait_generics = ast.generics.clone();
-    let view_type = if let Some(view_type) = specified_view_type(&ast) {
-        quote! { #view_type }
-    } else {
-        if let Some(first_type_param) = ast.generics.params.iter().find_map(|param| {
-            if let syn::GenericParam::Type(type_param) = param {
-                Some(type_param.ident.clone())
-            } else {
-                None
-            }
-        }) {
-            quote! { #first_type_param }
-        } else {
-            trait_generics.params.push(parse_quote! { V: 'static });
-            quote! { V }
-        }
-    };
-
-    let (impl_generics, _, where_clause) = trait_generics.split_for_impl();
-    let (_, type_generics, _) = ast.generics.split_for_impl();
+    let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl();
 
     let gen = quote! {
-        impl #impl_generics gpui::RenderOnce<#view_type> for #type_name #type_generics
+        impl #impl_generics gpui::RenderOnce for #type_name #type_generics
         #where_clause
         {
-            type Element = gpui::CompositeElement<#view_type, Self>;
+            type Element = gpui::CompositeElement<Self>;
 
             fn element_id(&self) -> Option<ElementId> {
                 None
@@ -45,20 +25,3 @@ pub fn derive_render_once(input: TokenStream) -> TokenStream {
 
     gen.into()
 }
-
-fn specified_view_type(ast: &DeriveInput) -> Option<proc_macro2::Ident> {
-    ast.attrs.iter().find_map(|attr| {
-        if attr.path.is_ident("view") {
-            if let Ok(syn::Meta::NameValue(meta_name_value)) = attr.parse_meta() {
-                if let syn::Lit::Str(lit_str) = meta_name_value.lit {
-                    return Some(
-                        lit_str
-                            .parse::<syn::Ident>()
-                            .expect("Failed to parse view_type"),
-                    );
-                }
-            }
-        }
-        None
-    })
-}

crates/picker2/src/picker2.rs 🔗

@@ -1,7 +1,7 @@
 use editor::Editor;
 use gpui::{
     div, prelude::*, uniform_list, AppContext, Div, FocusHandle, FocusableView, MouseButton,
-    Render, Task, UniformListScrollHandle, View, ViewContext, WindowContext,
+    MouseDownEvent, Render, Task, UniformListScrollHandle, View, ViewContext, WindowContext,
 };
 use std::{cmp, sync::Arc};
 use ui::{prelude::*, v_stack, Divider, Label, TextColor};
@@ -15,7 +15,7 @@ pub struct Picker<D: PickerDelegate> {
 }
 
 pub trait PickerDelegate: Sized + 'static {
-    type ListItem: RenderOnce<Picker<Self>>;
+    type ListItem: RenderOnce;
 
     fn match_count(&self) -> usize;
     fn selected_index(&self) -> usize;
@@ -180,21 +180,21 @@ impl<D: PickerDelegate> Picker<D> {
     }
 }
 
-impl<D: PickerDelegate> Render<Self> for Picker<D> {
-    type Element = Div<Self>;
+impl<D: PickerDelegate> Render for Picker<D> {
+    type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         div()
             .key_context("picker")
             .size_full()
             .elevation_2(cx)
-            .on_action(Self::select_next)
-            .on_action(Self::select_prev)
-            .on_action(Self::select_first)
-            .on_action(Self::select_last)
-            .on_action(Self::cancel)
-            .on_action(Self::confirm)
-            .on_action(Self::secondary_confirm)
+            .on_action(cx.listener(Self::select_next))
+            .on_action(cx.listener(Self::select_prev))
+            .on_action(cx.listener(Self::select_first))
+            .on_action(cx.listener(Self::select_last))
+            .on_action(cx.listener(Self::cancel))
+            .on_action(cx.listener(Self::confirm))
+            .on_action(cx.listener(Self::secondary_confirm))
             .child(
                 v_stack()
                     .py_0p5()
@@ -208,31 +208,37 @@ impl<D: PickerDelegate> Render<Self> for Picker<D> {
                         .p_1()
                         .grow()
                         .child(
-                            uniform_list("candidates", self.delegate.match_count(), {
-                                move |this: &mut Self, visible_range, cx| {
-                                    let selected_ix = this.delegate.selected_index();
-                                    visible_range
-                                        .map(|ix| {
-                                            div()
-                                                .on_mouse_down(
-                                                    MouseButton::Left,
-                                                    move |this: &mut Self, event, cx| {
-                                                        this.handle_click(
-                                                            ix,
-                                                            event.modifiers.command,
-                                                            cx,
-                                                        )
-                                                    },
-                                                )
-                                                .child(this.delegate.render_match(
-                                                    ix,
-                                                    ix == selected_ix,
-                                                    cx,
-                                                ))
-                                        })
-                                        .collect()
-                                }
-                            })
+                            uniform_list(
+                                cx.view().clone(),
+                                "candidates",
+                                self.delegate.match_count(),
+                                {
+                                    let selected_index = self.delegate.selected_index();
+
+                                    move |picker, visible_range, cx| {
+                                        visible_range
+                                            .map(|ix| {
+                                                div()
+                                                    .on_mouse_down(
+                                                        MouseButton::Left,
+                                                        cx.listener(move |this, event: &MouseDownEvent, cx| {
+                                                            this.handle_click(
+                                                                ix,
+                                                                event.modifiers.command,
+                                                                cx,
+                                                            )
+                                                        }),
+                                                    )
+                                                    .child(picker.delegate.render_match(
+                                                        ix,
+                                                        ix == selected_index,
+                                                        cx,
+                                                    ))
+                                            })
+                                            .collect()
+                                    }
+                                },
+                            )
                             .track_scroll(self.scroll_handle.clone()),
                         )
                         .max_h_72()

crates/project_panel2/src/project_panel.rs 🔗

@@ -10,9 +10,9 @@ use anyhow::{anyhow, Result};
 use gpui::{
     actions, div, px, uniform_list, Action, AppContext, AssetSource, AsyncWindowContext,
     ClipboardItem, Div, EventEmitter, FocusHandle, Focusable, FocusableView, InteractiveElement,
-    Model, MouseButton, ParentElement, Pixels, Point, PromptLevel, Render, RenderOnce, Stateful,
-    StatefulInteractiveElement, Styled, Task, UniformListScrollHandle, View, ViewContext,
-    VisualContext as _, WeakView, WindowContext,
+    Model, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Render,
+    RenderOnce, Stateful, StatefulInteractiveElement, Styled, Task, UniformListScrollHandle, View,
+    ViewContext, VisualContext as _, WeakView, WindowContext,
 };
 use menu::{Confirm, SelectNext, SelectPrev};
 use project::{
@@ -1339,7 +1339,7 @@ impl ProjectPanel {
         editor: Option<&View<Editor>>,
         padding: Pixels,
         cx: &mut ViewContext<Self>,
-    ) -> Div<Self> {
+    ) -> Div {
         let show_editor = details.is_editing && !details.is_processing;
 
         let theme = cx.theme();
@@ -1378,7 +1378,7 @@ impl ProjectPanel {
         details: EntryDetails,
         // dragged_entry_destination: &mut Option<Arc<Path>>,
         cx: &mut ViewContext<Self>,
-    ) -> Stateful<Self, Div<Self>> {
+    ) -> Stateful<Div> {
         let kind = details.kind;
         let settings = ProjectPanelSettings::get_global(cx);
         const INDENT_SIZE: Pixels = px(16.0);
@@ -1396,7 +1396,7 @@ impl ProjectPanel {
                 this.bg(cx.theme().colors().element_selected)
             })
             .hover(|style| style.bg(cx.theme().colors().element_hover))
-            .on_click(move |this, event, cx| {
+            .on_click(cx.listener(move |this, event: &gpui::ClickEvent, cx| {
                 if !show_editor {
                     if kind.is_dir() {
                         this.toggle_expanded(entry_id, cx);
@@ -1408,10 +1408,13 @@ impl ProjectPanel {
                         }
                     }
                 }
-            })
-            .on_mouse_down(MouseButton::Right, move |this, event, cx| {
-                this.deploy_context_menu(event.position, entry_id, cx);
-            })
+            }))
+            .on_mouse_down(
+                MouseButton::Right,
+                cx.listener(move |this, event: &MouseDownEvent, cx| {
+                    this.deploy_context_menu(event.position, entry_id, cx);
+                }),
+            )
         // .on_drop::<ProjectEntryId>(|this, event, cx| {
         //     this.move_entry(
         //         *dragged_entry,
@@ -1423,10 +1426,10 @@ impl ProjectPanel {
     }
 }
 
-impl Render<Self> for ProjectPanel {
-    type Element = Focusable<Self, Stateful<Self, Div<Self>>>;
+impl Render for ProjectPanel {
+    type Element = Focusable<Stateful<Div>>;
 
-    fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> Self::Element {
+    fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
         let has_worktree = self.visible_entries.len() != 0;
 
         if has_worktree {
@@ -1434,40 +1437,43 @@ impl Render<Self> for ProjectPanel {
                 .id("project-panel")
                 .size_full()
                 .key_context("ProjectPanel")
-                .on_action(Self::select_next)
-                .on_action(Self::select_prev)
-                .on_action(Self::expand_selected_entry)
-                .on_action(Self::collapse_selected_entry)
-                .on_action(Self::collapse_all_entries)
-                .on_action(Self::new_file)
-                .on_action(Self::new_directory)
-                .on_action(Self::rename)
-                .on_action(Self::delete)
-                .on_action(Self::confirm)
-                .on_action(Self::open_file)
-                .on_action(Self::cancel)
-                .on_action(Self::cut)
-                .on_action(Self::copy)
-                .on_action(Self::copy_path)
-                .on_action(Self::copy_relative_path)
-                .on_action(Self::paste)
-                .on_action(Self::reveal_in_finder)
-                .on_action(Self::open_in_terminal)
-                .on_action(Self::new_search_in_directory)
+                .on_action(cx.listener(Self::select_next))
+                .on_action(cx.listener(Self::select_prev))
+                .on_action(cx.listener(Self::expand_selected_entry))
+                .on_action(cx.listener(Self::collapse_selected_entry))
+                .on_action(cx.listener(Self::collapse_all_entries))
+                .on_action(cx.listener(Self::new_file))
+                .on_action(cx.listener(Self::new_directory))
+                .on_action(cx.listener(Self::rename))
+                .on_action(cx.listener(Self::delete))
+                .on_action(cx.listener(Self::confirm))
+                .on_action(cx.listener(Self::open_file))
+                .on_action(cx.listener(Self::cancel))
+                .on_action(cx.listener(Self::cut))
+                .on_action(cx.listener(Self::copy))
+                .on_action(cx.listener(Self::copy_path))
+                .on_action(cx.listener(Self::copy_relative_path))
+                .on_action(cx.listener(Self::paste))
+                .on_action(cx.listener(Self::reveal_in_finder))
+                .on_action(cx.listener(Self::open_in_terminal))
+                .on_action(cx.listener(Self::new_search_in_directory))
                 .track_focus(&self.focus_handle)
                 .child(
                     uniform_list(
+                        cx.view().clone(),
                         "entries",
                         self.visible_entries
                             .iter()
                             .map(|(_, worktree_entries)| worktree_entries.len())
                             .sum(),
-                        |this: &mut Self, range, cx| {
-                            let mut items = Vec::new();
-                            this.for_each_visible_entry(range, cx, |id, details, cx| {
-                                items.push(this.render_entry(id, details, cx));
-                            });
-                            items
+                        {
+                            |this, range, cx| {
+                                let mut items = Vec::new();
+                                this.for_each_visible_entry(range, cx, |id, details, cx| {
+                                    items.push(this.render_entry(id, details, cx));
+                                });
+                                items
+                            }
                         },
                     )
                     .size_full()

crates/rich_text2/src/rich_text.rs 🔗

@@ -56,12 +56,12 @@ pub struct Mention {
 }
 
 impl RichText {
-    pub fn element<V: 'static>(
+    pub fn element(
         &self,
         // syntax: Arc<SyntaxTheme>,
         //  style: RichTextStyle,
         // cx: &mut ViewContext<V>,
-    ) -> AnyElement<V> {
+    ) -> AnyElement {
         todo!();
 
         // let mut region_id = 0;

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

@@ -5,8 +5,8 @@ use ui::prelude::*;
 
 pub struct ColorsStory;
 
-impl Render<Self> for ColorsStory {
-    type Element = Div<Self>;
+impl Render for ColorsStory {
+    type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         let color_scales = default_color_scales();

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

@@ -27,7 +27,7 @@ impl FocusStory {
 }
 
 impl Render<Self> for FocusStory {
-    type Element = Focusable<Self, Stateful<Self, Div<Self>>>;
+    type Element = Focusable<Stateful<Div>>;
 
     fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
         let theme = cx.theme();
@@ -42,18 +42,20 @@ impl Render<Self> for FocusStory {
             .id("parent")
             .focusable()
             .key_context("parent")
-            .on_action(|_, action: &ActionA, cx| {
+            .on_action(cx.listener(|_, action: &ActionA, cx| {
                 println!("Action A dispatched on parent");
-            })
-            .on_action(|_, action: &ActionB, cx| {
+            }))
+            .on_action(cx.listener(|_, action: &ActionB, cx| {
                 println!("Action B dispatched on parent");
-            })
-            .on_focus(|_, _, _| println!("Parent focused"))
-            .on_blur(|_, _, _| println!("Parent blurred"))
-            .on_focus_in(|_, _, _| println!("Parent focus_in"))
-            .on_focus_out(|_, _, _| println!("Parent focus_out"))
-            .on_key_down(|_, event, phase, _| println!("Key down on parent {:?}", event))
-            .on_key_up(|_, event, phase, _| println!("Key up on parent {:?}", event))
+            }))
+            .on_focus(cx.listener(|_, _, _| println!("Parent focused")))
+            .on_blur(cx.listener(|_, _, _| println!("Parent blurred")))
+            .on_focus_in(cx.listener(|_, _, _| println!("Parent focus_in")))
+            .on_focus_out(cx.listener(|_, _, _| println!("Parent focus_out")))
+            .on_key_down(
+                cx.listener(|_, event, phase, _| println!("Key down on parent {:?}", event)),
+            )
+            .on_key_up(cx.listener(|_, event, phase, _| println!("Key up on parent {:?}", event)))
             .size_full()
             .bg(color_1)
             .focus(|style| style.bg(color_2))
@@ -61,38 +63,42 @@ impl Render<Self> for FocusStory {
                 div()
                     .track_focus(&self.child_1_focus)
                     .key_context("child-1")
-                    .on_action(|_, action: &ActionB, cx| {
+                    .on_action(cx.listener(|_, action: &ActionB, cx| {
                         println!("Action B dispatched on child 1 during");
-                    })
+                    }))
                     .w_full()
                     .h_6()
                     .bg(color_4)
                     .focus(|style| style.bg(color_5))
                     .in_focus(|style| style.bg(color_6))
-                    .on_focus(|_, _, _| println!("Child 1 focused"))
-                    .on_blur(|_, _, _| println!("Child 1 blurred"))
-                    .on_focus_in(|_, _, _| println!("Child 1 focus_in"))
-                    .on_focus_out(|_, _, _| println!("Child 1 focus_out"))
-                    .on_key_down(|_, event, phase, _| println!("Key down on child 1 {:?}", event))
-                    .on_key_up(|_, event, phase, _| println!("Key up on child 1 {:?}", event))
+                    .on_focus(cx.listener(|_, _, _| println!("Child 1 focused")))
+                    .on_blur(cx.listener(|_, _, _| println!("Child 1 blurred")))
+                    .on_focus_in(cx.listener(|_, _, _| println!("Child 1 focus_in")))
+                    .on_focus_out(cx.listener(|_, _, _| println!("Child 1 focus_out")))
+                    .on_key_down(
+                        cx.listener(|_, event, _| println!("Key down on child 1 {:?}", event)),
+                    )
+                    .on_key_up(cx.listener(|_, event, _| println!("Key up on child 1 {:?}", event)))
                     .child("Child 1"),
             )
             .child(
                 div()
                     .track_focus(&self.child_2_focus)
                     .key_context("child-2")
-                    .on_action(|_, action: &ActionC, cx| {
+                    .on_action(cx.listener(|_, action: &ActionC, cx| {
                         println!("Action C dispatched on child 2");
-                    })
+                    }))
                     .w_full()
                     .h_6()
                     .bg(color_4)
-                    .on_focus(|_, _, _| println!("Child 2 focused"))
-                    .on_blur(|_, _, _| println!("Child 2 blurred"))
-                    .on_focus_in(|_, _, _| println!("Child 2 focus_in"))
-                    .on_focus_out(|_, _, _| println!("Child 2 focus_out"))
-                    .on_key_down(|_, event, phase, _| println!("Key down on child 2 {:?}", event))
-                    .on_key_up(|_, event, phase, _| println!("Key up on child 2 {:?}", event))
+                    .on_focus(cx.listener(|_, _, _| println!("Child 2 focused")))
+                    .on_blur(cx.listener(|_, _, _| println!("Child 2 blurred")))
+                    .on_focus_in(cx.listener(|_, _, _| println!("Child 2 focus_in")))
+                    .on_focus_out(cx.listener(|_, _, _| println!("Child 2 focus_out")))
+                    .on_key_down(
+                        cx.listener(|_, event, _| println!("Key down on child 2 {:?}", event)),
+                    )
+                    .on_key_up(cx.listener(|_, event, _| println!("Key up on child 2 {:?}", event)))
                     .child("Child 2"),
             )
     }

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

@@ -11,8 +11,8 @@ impl KitchenSinkStory {
     }
 }
 
-impl Render<Self> for KitchenSinkStory {
-    type Element = Stateful<Self, Div<Self>>;
+impl Render for KitchenSinkStory {
+    type Element = Stateful<Div>;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         let component_stories = ComponentStory::iter()

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

@@ -11,8 +11,8 @@ impl TextStory {
     }
 }
 
-impl Render<Self> for TextStory {
-    type Element = Div<Self>;
+impl Render for TextStory {
+    type Element = Div;
 
     fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
         v_stack()

crates/terminal_view2/src/terminal_panel.rs 🔗

@@ -335,8 +335,8 @@ impl TerminalPanel {
 
 impl EventEmitter<PanelEvent> for TerminalPanel {}
 
-impl Render<Self> for TerminalPanel {
-    type Element = Div<Self>;
+impl Render for TerminalPanel {
+    type Element = Div;
 
     fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
         div().child(self.pane.clone())

crates/terminal_view2/src/terminal_view.rs 🔗

@@ -9,10 +9,10 @@ pub mod terminal_panel;
 // use crate::terminal_element::TerminalElement;
 use editor::{scroll::autoscroll::Autoscroll, Editor};
 use gpui::{
-    actions, div, Action, AnyElement, AppContext, DispatchPhase, Div, Element, EventEmitter,
-    FocusEvent, FocusHandle, Focusable, FocusableElement, FocusableView, InputHandler,
-    InteractiveElement, KeyDownEvent, Keystroke, Model, MouseButton, ParentElement, Pixels, Render,
-    SharedString, Styled, Task, View, ViewContext, VisualContext, WeakView,
+    actions, div, Action, AnyElement, AppContext, Div, Element, EventEmitter, FocusEvent,
+    FocusHandle, Focusable, FocusableElement, FocusableView, InputHandler, InteractiveElement,
+    KeyDownEvent, Keystroke, Model, MouseButton, MouseDownEvent, ParentElement, Pixels, Render,
+    SharedString, Styled, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
 };
 use language::Bias;
 use persistence::TERMINAL_DB;
@@ -63,7 +63,6 @@ pub struct SendKeystroke(String);
 actions!(Clear, Copy, Paste, ShowCharacterPalette, SearchTest);
 
 pub fn init(cx: &mut AppContext) {
-    workspace::ui::init(cx);
     terminal_panel::init(cx);
     terminal::init(cx);
 
@@ -84,7 +83,7 @@ pub struct TerminalView {
     has_new_content: bool,
     //Currently using iTerm bell, show bell emoji in tab until input is received
     has_bell: bool,
-    context_menu: Option<View<ContextMenu<Self>>>,
+    context_menu: Option<View<ContextMenu>>,
     blink_state: bool,
     blinking_on: bool,
     blinking_paused: bool,
@@ -505,12 +504,7 @@ pub fn regex_search_for_query(query: &project::search::SearchQuery) -> Option<Re
 }
 
 impl TerminalView {
-    fn key_down(
-        &mut self,
-        event: &KeyDownEvent,
-        _dispatch_phase: DispatchPhase,
-        cx: &mut ViewContext<Self>,
-    ) {
+    fn key_down(&mut self, event: &KeyDownEvent, cx: &mut ViewContext<Self>) {
         self.clear_bel(cx);
         self.pause_cursor_blinking(cx);
 
@@ -537,8 +531,8 @@ impl TerminalView {
     }
 }
 
-impl Render<Self> for TerminalView {
-    type Element = Focusable<Self, Div<Self>>;
+impl Render for TerminalView {
+    type Element = Focusable<Div>;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         let terminal_handle = self.terminal.clone().downgrade();
@@ -552,14 +546,14 @@ impl Render<Self> for TerminalView {
                 div()
                     .z_index(0)
                     .absolute()
-                    .on_key_down(Self::key_down)
-                    .on_action(TerminalView::send_text)
-                    .on_action(TerminalView::send_keystroke)
-                    .on_action(TerminalView::copy)
-                    .on_action(TerminalView::paste)
-                    .on_action(TerminalView::clear)
-                    .on_action(TerminalView::show_character_palette)
-                    .on_action(TerminalView::select_all)
+                    .on_key_down(cx.listener(Self::key_down))
+                    .on_action(cx.listener(TerminalView::send_text))
+                    .on_action(cx.listener(TerminalView::send_keystroke))
+                    .on_action(cx.listener(TerminalView::copy))
+                    .on_action(cx.listener(TerminalView::paste))
+                    .on_action(cx.listener(TerminalView::clear))
+                    .on_action(cx.listener(TerminalView::show_character_palette))
+                    .on_action(cx.listener(TerminalView::select_all))
                     // todo!()
                     .child(
                         "TERMINAL HERE", //     TerminalElement::new(
@@ -569,10 +563,13 @@ impl Render<Self> for TerminalView {
                                          //     self.can_navigate_to_selected_word,
                                          // )
                     )
-                    .on_mouse_down(MouseButton::Right, |this, event, cx| {
-                        this.deploy_context_menu(event.position, cx);
-                        cx.notify();
-                    }),
+                    .on_mouse_down(
+                        MouseButton::Right,
+                        cx.listener(|this, event: &MouseDownEvent, cx| {
+                            this.deploy_context_menu(event.position, cx);
+                            cx.notify();
+                        }),
+                    ),
             )
             .children(
                 self.context_menu
@@ -580,8 +577,8 @@ impl Render<Self> for TerminalView {
                     .map(|context_menu| div().z_index(1).absolute().child(context_menu)),
             )
             .track_focus(&self.focus_handle)
-            .on_focus_in(Self::focus_in)
-            .on_focus_out(Self::focus_out)
+            .on_focus_in(cx.listener(Self::focus_in))
+            .on_focus_out(cx.listener(Self::focus_out))
     }
 }
 
@@ -746,11 +743,7 @@ impl Item for TerminalView {
         Some(self.terminal().read(cx).title().into())
     }
 
-    fn tab_content<T: 'static>(
-        &self,
-        _detail: Option<usize>,
-        cx: &gpui::AppContext,
-    ) -> AnyElement<T> {
+    fn tab_content(&self, _detail: Option<usize>, cx: &WindowContext) -> AnyElement {
         let title = self.terminal().read(cx).title();
 
         div()

crates/theme2/src/story.rs 🔗

@@ -1,11 +1,11 @@
-use gpui::{div, Div, Element, ParentElement, SharedString, Styled, ViewContext};
+use gpui::{div, Div, Element, ParentElement, SharedString, Styled, WindowContext};
 
 use crate::ActiveTheme;
 
 pub struct Story {}
 
 impl Story {
-    pub fn container<V: 'static>(cx: &mut ViewContext<V>) -> Div<V> {
+    pub fn container(cx: &mut WindowContext) -> Div {
         div()
             .size_full()
             .flex()
@@ -16,21 +16,18 @@ impl Story {
             .bg(cx.theme().colors().background)
     }
 
-    pub fn title<V: 'static>(cx: &mut ViewContext<V>, title: SharedString) -> impl Element<V> {
+    pub fn title(cx: &mut WindowContext, title: SharedString) -> impl Element {
         div()
             .text_xl()
             .text_color(cx.theme().colors().text)
             .child(title)
     }
 
-    pub fn title_for<V: 'static, T>(cx: &mut ViewContext<V>) -> impl Element<V> {
+    pub fn title_for<T>(cx: &mut WindowContext) -> impl Element {
         Self::title(cx, std::any::type_name::<T>().into())
     }
 
-    pub fn label<V: 'static>(
-        cx: &mut ViewContext<V>,
-        label: impl Into<SharedString>,
-    ) -> impl Element<V> {
+    pub fn label(cx: &mut WindowContext, label: impl Into<SharedString>) -> impl Element {
         div()
             .mt_4()
             .mb_2()

crates/theme2/src/styles/players.rs 🔗

@@ -147,8 +147,8 @@ mod stories {
 
     pub struct PlayerStory;
 
-    impl Render<Self> for PlayerStory {
-        type Element = Div<Self>;
+    impl Render for PlayerStory {
+        type Element = Div;
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
             Story::container(cx).child(
@@ -156,7 +156,7 @@ mod stories {
                     .flex()
                     .flex_col()
                     .gap_4()
-                    .child(Story::title_for::<_, PlayerColors>(cx))
+                    .child(Story::title_for::<PlayerColors>(cx))
                     .child(Story::label(cx, "Player Colors"))
                     .child(
                         div()

crates/theme2/src/theme2.rs 🔗

@@ -63,6 +63,12 @@ impl ActiveTheme for AppContext {
     }
 }
 
+// impl<'a> ActiveTheme for WindowContext<'a> {
+//     fn theme(&self) -> &Arc<Theme> {
+//         &ThemeSettings::get_global(self.app()).active_theme
+//     }
+// }
+
 pub struct ThemeFamily {
     pub id: String,
     pub name: SharedString,

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

@@ -7,10 +7,10 @@ pub struct Avatar {
     shape: Shape,
 }
 
-impl<V: 'static> Component<V> for Avatar {
-    type Rendered = Img<V>;
+impl Component for Avatar {
+    type Rendered = Img;
 
-    fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, _: &mut WindowContext) -> Self::Rendered {
         let mut img = img();
 
         if self.shape == Shape::Circle {
@@ -51,12 +51,12 @@ mod stories {
 
     pub struct AvatarStory;
 
-    impl Render<Self> for AvatarStory {
-        type Element = Div<Self>;
+    impl Render for AvatarStory {
+        type Element = Div;
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
             Story::container(cx)
-                .child(Story::title_for::<_, Avatar>(cx))
+                .child(Story::title_for::<Avatar>(cx))
                 .child(Story::label(cx, "Default"))
                 .child(Avatar::new(
                     "https://avatars.githubusercontent.com/u/1714999?v=4",

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

@@ -1,7 +1,7 @@
-use std::sync::Arc;
+use std::rc::Rc;
 
 use gpui::{
-    DefiniteLength, Div, Hsla, MouseButton, RenderOnce, Stateful, StatefulInteractiveElement,
+    DefiniteLength, Div, Hsla, MouseButton, MouseDownEvent, RenderOnce, StatefulInteractiveElement,
     WindowContext,
 };
 
@@ -10,19 +10,19 @@ use crate::{h_stack, Icon, IconButton, IconElement, Label, LineHeightStyle, Text
 
 /// Provides the flexibility to use either a standard
 /// button or an icon button in a given context.
-pub enum ButtonOrIconButton<V: 'static> {
-    Button(Button<V>),
-    IconButton(IconButton<V>),
+pub enum ButtonOrIconButton {
+    Button(Button),
+    IconButton(IconButton),
 }
 
-impl<V: 'static> From<Button<V>> for ButtonOrIconButton<V> {
-    fn from(value: Button<V>) -> Self {
+impl From<Button> for ButtonOrIconButton {
+    fn from(value: Button) -> Self {
         Self::Button(value)
     }
 }
 
-impl<V: 'static> From<IconButton<V>> for ButtonOrIconButton<V> {
-    fn from(value: IconButton<V>) -> Self {
+impl From<IconButton> for ButtonOrIconButton {
+    fn from(value: IconButton) -> Self {
         Self::IconButton(value)
     }
 }
@@ -64,25 +64,10 @@ impl ButtonVariant {
     }
 }
 
-pub type ClickHandler<V> = Arc<dyn Fn(&mut V, &mut ViewContext<V>)>;
-
-struct ButtonHandlers<V: 'static> {
-    click: Option<ClickHandler<V>>,
-}
-
-unsafe impl<S> Send for ButtonHandlers<S> {}
-unsafe impl<S> Sync for ButtonHandlers<S> {}
-
-impl<V: 'static> Default for ButtonHandlers<V> {
-    fn default() -> Self {
-        Self { click: None }
-    }
-}
-
 #[derive(RenderOnce)]
-pub struct Button<V: 'static> {
+pub struct Button {
     disabled: bool,
-    handlers: ButtonHandlers<V>,
+    click_handler: Option<Rc<dyn Fn(&MouseDownEvent, &mut WindowContext)>>,
     icon: Option<Icon>,
     icon_position: Option<IconPosition>,
     label: SharedString,
@@ -91,11 +76,10 @@ pub struct Button<V: 'static> {
     color: Option<TextColor>,
 }
 
-impl<V: 'static> Component<V> for Button<V> {
-    type Rendered = Stateful<V, Div<V>>;
+impl Component for Button {
+    type Rendered = gpui::Stateful<Div>;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        let _view: &mut V = view;
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         let (icon_color, label_color) = match (self.disabled, self.color) {
             (true, _) => (TextColor::Disabled, TextColor::Disabled),
             (_, None) => (TextColor::Default, TextColor::Default),
@@ -133,9 +117,9 @@ impl<V: 'static> Component<V> for Button<V> {
             button = button.w(width).justify_center();
         }
 
-        if let Some(click_handler) = self.handlers.click.clone() {
-            button = button.on_mouse_down(MouseButton::Left, move |state, event, cx| {
-                click_handler(state, cx);
+        if let Some(click_handler) = self.click_handler.clone() {
+            button = button.on_mouse_down(MouseButton::Left, move |event, cx| {
+                click_handler(event, cx);
             });
         }
 
@@ -143,11 +127,11 @@ impl<V: 'static> Component<V> for Button<V> {
     }
 }
 
-impl<V: 'static> Button<V> {
+impl Button {
     pub fn new(label: impl Into<SharedString>) -> Self {
         Self {
             disabled: false,
-            handlers: ButtonHandlers::default(),
+            click_handler: None,
             icon: None,
             icon_position: None,
             label: label.into(),
@@ -184,8 +168,11 @@ impl<V: 'static> Button<V> {
         self
     }
 
-    pub fn on_click(mut self, handler: ClickHandler<V>) -> Self {
-        self.handlers.click = Some(handler);
+    pub fn on_click(
+        mut self,
+        handler: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
+    ) -> Self {
+        self.click_handler = Some(Rc::new(handler));
         self
     }
 
@@ -218,76 +205,29 @@ impl<V: 'static> Button<V> {
     fn render_icon(&self, icon_color: TextColor) -> Option<IconElement> {
         self.icon.map(|i| IconElement::new(i).color(icon_color))
     }
-
-    pub fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
-        let (icon_color, label_color) = match (self.disabled, self.color) {
-            (true, _) => (TextColor::Disabled, TextColor::Disabled),
-            (_, None) => (TextColor::Default, TextColor::Default),
-            (_, Some(color)) => (TextColor::from(color), color),
-        };
-
-        let mut button = h_stack()
-            .id(SharedString::from(format!("{}", self.label)))
-            .relative()
-            .p_1()
-            .text_ui()
-            .rounded_md()
-            .bg(self.variant.bg_color(cx))
-            .cursor_pointer()
-            .hover(|style| style.bg(self.variant.bg_color_hover(cx)))
-            .active(|style| style.bg(self.variant.bg_color_active(cx)));
-
-        match (self.icon, self.icon_position) {
-            (Some(_), Some(IconPosition::Left)) => {
-                button = button
-                    .gap_1()
-                    .child(self.render_label(label_color))
-                    .children(self.render_icon(icon_color))
-            }
-            (Some(_), Some(IconPosition::Right)) => {
-                button = button
-                    .gap_1()
-                    .children(self.render_icon(icon_color))
-                    .child(self.render_label(label_color))
-            }
-            (_, _) => button = button.child(self.render_label(label_color)),
-        }
-
-        if let Some(width) = self.width {
-            button = button.w(width).justify_center();
-        }
-
-        if let Some(click_handler) = self.handlers.click.clone() {
-            button = button.on_mouse_down(MouseButton::Left, move |state, event, cx| {
-                click_handler(state, cx);
-            });
-        }
-
-        button
-    }
 }
 
 #[derive(RenderOnce)]
-pub struct ButtonGroup<V: 'static> {
-    buttons: Vec<Button<V>>,
+pub struct ButtonGroup {
+    buttons: Vec<Button>,
 }
 
-impl<V: 'static> Component<V> for ButtonGroup<V> {
-    type Rendered = Div<V>;
+impl Component for ButtonGroup {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         let mut group = h_stack();
 
         for button in self.buttons.into_iter() {
-            group = group.child(button.render(view, cx));
+            group = group.child(button.render(cx));
         }
 
         group
     }
 }
 
-impl<V: 'static> ButtonGroup<V> {
-    pub fn new(buttons: Vec<Button<V>>) -> Self {
+impl ButtonGroup {
+    pub fn new(buttons: Vec<Button>) -> Self {
         Self { buttons }
     }
 }
@@ -304,14 +244,14 @@ mod stories {
 
     pub struct ButtonStory;
 
-    impl Render<Self> for ButtonStory {
-        type Element = Div<Self>;
+    impl Render for ButtonStory {
+        type Element = Div;
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
             let states = InteractionState::iter();
 
             Story::container(cx)
-                .child(Story::title_for::<_, Button<Self>>(cx))
+                .child(Story::title_for::<Button>(cx))
                 .child(
                     div()
                         .flex()
@@ -454,7 +394,7 @@ mod stories {
                 .child(
                     Button::new("Label")
                         .variant(ButtonVariant::Ghost)
-                        .on_click(Arc::new(|_view, _cx| println!("Button clicked."))),
+                        .on_click(|_, cx| println!("Button clicked.")),
                 )
         }
     }

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

@@ -1,10 +1,10 @@
-use gpui::{div, prelude::*, Div, Element, ElementId, RenderOnce, Stateful, Styled, ViewContext};
-use std::sync::Arc;
+use gpui::{div, prelude::*, Div, Element, ElementId, RenderOnce, Styled, WindowContext};
+
 use theme2::ActiveTheme;
 
 use crate::{Icon, IconElement, Selection, TextColor};
 
-pub type CheckHandler<V> = Arc<dyn Fn(Selection, &mut V, &mut ViewContext<V>) + Send + Sync>;
+pub type CheckHandler = Box<dyn Fn(&Selection, &mut WindowContext) + 'static>;
 
 /// # Checkbox
 ///
@@ -12,17 +12,17 @@ pub type CheckHandler<V> = Arc<dyn Fn(Selection, &mut V, &mut ViewContext<V>) +
 /// Each checkbox works independently from other checkboxes in the list,
 /// therefore checking an additional box does not affect any other selections.
 #[derive(RenderOnce)]
-pub struct Checkbox<V: 'static> {
+pub struct Checkbox {
     id: ElementId,
     checked: Selection,
     disabled: bool,
-    on_click: Option<CheckHandler<V>>,
+    on_click: Option<CheckHandler>,
 }
 
-impl<V: 'static> Component<V> for Checkbox<V> {
-    type Rendered = Stateful<V, Div<V>>;
+impl Component for Checkbox {
+    type Rendered = gpui::Stateful<Div>;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         let group_id = format!("checkbox_group_{:?}", self.id);
 
         let icon = match self.checked {
@@ -137,13 +137,11 @@ impl<V: 'static> Component<V> for Checkbox<V> {
             )
             .when_some(
                 self.on_click.filter(|_| !self.disabled),
-                |this, on_click| {
-                    this.on_click(move |view, _, cx| on_click(self.checked.inverse(), view, cx))
-                },
+                |this, on_click| this.on_click(move |_, cx| on_click(&self.checked.inverse(), cx)),
             )
     }
 }
-impl<V: 'static> Checkbox<V> {
+impl Checkbox {
     pub fn new(id: impl Into<ElementId>, checked: Selection) -> Self {
         Self {
             id: id.into(),
@@ -160,13 +158,13 @@ impl<V: 'static> Checkbox<V> {
 
     pub fn on_click(
         mut self,
-        handler: impl 'static + Fn(Selection, &mut V, &mut ViewContext<V>) + Send + Sync,
+        handler: impl 'static + Fn(&Selection, &mut WindowContext) + Send + Sync,
     ) -> Self {
-        self.on_click = Some(Arc::new(handler));
+        self.on_click = Some(Box::new(handler));
         self
     }
 
-    pub fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
+    pub fn render(self, cx: &mut WindowContext) -> impl Element {
         let group_id = format!("checkbox_group_{:?}", self.id);
 
         let icon = match self.checked {
@@ -281,9 +279,7 @@ impl<V: 'static> Checkbox<V> {
             )
             .when_some(
                 self.on_click.filter(|_| !self.disabled),
-                |this, on_click| {
-                    this.on_click(move |view, _, cx| on_click(self.checked.inverse(), view, cx))
-                },
+                |this, on_click| this.on_click(move |_, cx| on_click(&self.checked.inverse(), cx)),
             )
     }
 }
@@ -295,16 +291,16 @@ pub use stories::*;
 mod stories {
     use super::*;
     use crate::{h_stack, Story};
-    use gpui::{Div, Render};
+    use gpui::{Div, Render, ViewContext};
 
     pub struct CheckboxStory;
 
-    impl Render<Self> for CheckboxStory {
-        type Element = Div<Self>;
+    impl Render for CheckboxStory {
+        type Element = Div;
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
             Story::container(cx)
-                .child(Story::title_for::<_, Checkbox<Self>>(cx))
+                .child(Story::title_for::<Checkbox>(cx))
                 .child(Story::label(cx, "Default"))
                 .child(
                     h_stack()

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

@@ -4,44 +4,39 @@ use std::rc::Rc;
 use crate::{prelude::*, v_stack, List};
 use crate::{ListItem, ListSeparator, ListSubHeader};
 use gpui::{
-    overlay, px, Action, AnchorCorner, AnyElement, AppContext, Bounds, DispatchPhase, Div,
-    EventEmitter, FocusHandle, FocusableView, LayoutId, ManagedView, Manager, MouseButton,
-    MouseDownEvent, Pixels, Point, Render, RenderOnce, View, VisualContext, WeakView,
+    overlay, px, Action, AnchorCorner, AnyElement, AppContext, Bounds, ClickEvent, DispatchPhase,
+    Div, EventEmitter, FocusHandle, FocusableView, LayoutId, ManagedView, Manager, MouseButton,
+    MouseDownEvent, Pixels, Point, Render, RenderOnce, View, VisualContext,
 };
 
-pub enum ContextMenuItem<V: 'static> {
+pub enum ContextMenuItem {
     Separator(ListSeparator),
     Header(ListSubHeader),
-    Entry(
-        ListItem<ContextMenu<V>>,
-        Rc<dyn Fn(&mut V, &mut ViewContext<V>)>,
-    ),
+    Entry(ListItem, Rc<dyn Fn(&ClickEvent, &mut WindowContext)>),
 }
 
-pub struct ContextMenu<V: 'static> {
-    items: Vec<ContextMenuItem<V>>,
+pub struct ContextMenu {
+    items: Vec<ContextMenuItem>,
     focus_handle: FocusHandle,
-    handle: WeakView<V>,
 }
 
-impl<V: 'static> FocusableView for ContextMenu<V> {
+impl FocusableView for ContextMenu {
     fn focus_handle(&self, _cx: &AppContext) -> FocusHandle {
         self.focus_handle.clone()
     }
 }
 
-impl<V: 'static> EventEmitter<Manager> for ContextMenu<V> {}
+impl EventEmitter<Manager> for ContextMenu {}
 
-impl<V: 'static> ContextMenu<V> {
+impl ContextMenu {
     pub fn build(
-        cx: &mut ViewContext<V>,
-        f: impl FnOnce(Self, &mut ViewContext<Self>) -> Self,
+        cx: &mut WindowContext,
+        f: impl FnOnce(Self, &mut WindowContext) -> Self,
     ) -> View<Self> {
-        let handle = cx.view().downgrade();
+        // let handle = cx.view().downgrade();
         cx.build_view(|cx| {
             f(
                 Self {
-                    handle,
                     items: Default::default(),
                     focus_handle: cx.focus_handle(),
                 },
@@ -63,15 +58,15 @@ impl<V: 'static> ContextMenu<V> {
 
     pub fn entry(
         mut self,
-        view: ListItem<Self>,
-        on_click: impl Fn(&mut V, &mut ViewContext<V>) + 'static,
+        view: ListItem,
+        on_click: impl Fn(&ClickEvent, &mut WindowContext) + 'static,
     ) -> Self {
         self.items
             .push(ContextMenuItem::Entry(view, Rc::new(on_click)));
         self
     }
 
-    pub fn action(self, view: ListItem<Self>, action: Box<dyn Action>) -> Self {
+    pub fn action(self, view: ListItem, action: Box<dyn Action>) -> Self {
         // todo: add the keybindings to the list entry
         self.entry(view, move |_, cx| cx.dispatch_action(action.boxed_clone()))
     }
@@ -86,21 +81,23 @@ impl<V: 'static> ContextMenu<V> {
     }
 }
 
-impl<V: 'static> Render<Self> for ContextMenu<V> {
-    type Element = Div<Self>;
+impl Render for ContextMenu {
+    type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         div().elevation_2(cx).flex().flex_row().child(
             v_stack()
                 .min_w(px(200.))
                 .track_focus(&self.focus_handle)
-                .on_mouse_down_out(|this: &mut Self, _, cx| this.cancel(&Default::default(), cx))
+                .on_mouse_down_out(
+                    cx.listener(|this: &mut Self, _, cx| this.cancel(&Default::default(), cx)),
+                )
                 // .on_action(ContextMenu::select_first)
                 // .on_action(ContextMenu::select_last)
                 // .on_action(ContextMenu::select_next)
                 // .on_action(ContextMenu::select_prev)
-                .on_action(ContextMenu::confirm)
-                .on_action(ContextMenu::cancel)
+                .on_action(cx.listener(ContextMenu::confirm))
+                .on_action(cx.listener(ContextMenu::cancel))
                 .flex_none()
                 // .bg(cx.theme().colors().elevated_surface_background)
                 // .border()
@@ -113,12 +110,13 @@ impl<V: 'static> Render<Self> for ContextMenu<V> {
                         ContextMenuItem::Header(header) => header.clone().render_into_any(),
                         ContextMenuItem::Entry(entry, callback) => {
                             let callback = callback.clone();
-                            let handle = self.handle.clone();
+                            let dismiss = cx.listener(|_, _, cx| cx.emit(Manager::Dismiss));
+
                             entry
                                 .clone()
-                                .on_click(move |this, cx| {
-                                    handle.update(cx, |view, cx| callback(view, cx)).ok();
-                                    cx.emit(Manager::Dismiss);
+                                .on_click(move |event, cx| {
+                                    callback(event, cx);
+                                    dismiss(event, cx)
                                 })
                                 .render_into_any()
                         }
@@ -128,22 +126,21 @@ impl<V: 'static> Render<Self> for ContextMenu<V> {
     }
 }
 
-pub struct MenuHandle<V: 'static, M: ManagedView> {
+pub struct MenuHandle<M: ManagedView> {
     id: ElementId,
-    child_builder: Option<Box<dyn FnOnce(bool) -> AnyElement<V> + 'static>>,
-    menu_builder: Option<Rc<dyn Fn(&mut V, &mut ViewContext<V>) -> View<M> + 'static>>,
-
+    child_builder: Option<Box<dyn FnOnce(bool) -> AnyElement + 'static>>,
+    menu_builder: Option<Rc<dyn Fn(&mut WindowContext) -> View<M> + 'static>>,
     anchor: Option<AnchorCorner>,
     attach: Option<AnchorCorner>,
 }
 
-impl<V: 'static, M: ManagedView> MenuHandle<V, M> {
-    pub fn menu(mut self, f: impl Fn(&mut V, &mut ViewContext<V>) -> View<M> + 'static) -> Self {
+impl<M: ManagedView> MenuHandle<M> {
+    pub fn menu(mut self, f: impl Fn(&mut WindowContext) -> View<M> + 'static) -> Self {
         self.menu_builder = Some(Rc::new(f));
         self
     }
 
-    pub fn child<R: RenderOnce<V>>(mut self, f: impl FnOnce(bool) -> R + 'static) -> Self {
+    pub fn child<R: RenderOnce>(mut self, f: impl FnOnce(bool) -> R + 'static) -> Self {
         self.child_builder = Some(Box::new(|b| f(b).render_once().into_any()));
         self
     }
@@ -162,7 +159,7 @@ impl<V: 'static, M: ManagedView> MenuHandle<V, M> {
     }
 }
 
-pub fn menu_handle<V: 'static, M: ManagedView>(id: impl Into<ElementId>) -> MenuHandle<V, M> {
+pub fn menu_handle<M: ManagedView>(id: impl Into<ElementId>) -> MenuHandle<M> {
     MenuHandle {
         id: id.into(),
         child_builder: None,
@@ -172,21 +169,20 @@ pub fn menu_handle<V: 'static, M: ManagedView>(id: impl Into<ElementId>) -> Menu
     }
 }
 
-pub struct MenuHandleState<V, M> {
+pub struct MenuHandleState<M> {
     menu: Rc<RefCell<Option<View<M>>>>,
     position: Rc<RefCell<Point<Pixels>>>,
     child_layout_id: Option<LayoutId>,
-    child_element: Option<AnyElement<V>>,
-    menu_element: Option<AnyElement<V>>,
+    child_element: Option<AnyElement>,
+    menu_element: Option<AnyElement>,
 }
-impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
-    type State = MenuHandleState<V, M>;
+impl<M: ManagedView> Element for MenuHandle<M> {
+    type State = MenuHandleState<M>;
 
     fn layout(
         &mut self,
-        view_state: &mut V,
         element_state: Option<Self::State>,
-        cx: &mut crate::ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (gpui::LayoutId, Self::State) {
         let (menu, position) = if let Some(element_state) = element_state {
             (element_state.menu, element_state.position)
@@ -197,14 +193,14 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
         let mut menu_layout_id = None;
 
         let menu_element = menu.borrow_mut().as_mut().map(|menu| {
-            let mut overlay = overlay::<V>().snap_to_window();
+            let mut overlay = overlay().snap_to_window();
             if let Some(anchor) = self.anchor {
                 overlay = overlay.anchor(anchor);
             }
             overlay = overlay.position(*position.borrow());
 
             let mut element = overlay.child(menu.clone()).into_any();
-            menu_layout_id = Some(element.layout(view_state, cx));
+            menu_layout_id = Some(element.layout(cx));
             element
         });
 
@@ -215,7 +211,7 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
 
         let child_layout_id = child_element
             .as_mut()
-            .map(|child_element| child_element.layout(view_state, cx));
+            .map(|child_element| child_element.layout(cx));
 
         let layout_id = cx.request_layout(
             &gpui::Style::default(),
@@ -237,16 +233,15 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
     fn paint(
         self,
         bounds: Bounds<gpui::Pixels>,
-        view_state: &mut V,
         element_state: &mut Self::State,
-        cx: &mut crate::ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
         if let Some(child) = element_state.child_element.take() {
-            child.paint(view_state, cx);
+            child.paint(cx);
         }
 
         if let Some(menu) = element_state.menu_element.take() {
-            menu.paint(view_state, cx);
+            menu.paint(cx);
             return;
         }
 
@@ -258,7 +253,7 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
         let attach = self.attach.clone();
         let child_layout_id = element_state.child_layout_id.clone();
 
-        cx.on_mouse_event(move |view_state, event: &MouseDownEvent, phase, cx| {
+        cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
             if phase == DispatchPhase::Bubble
                 && event.button == MouseButton::Right
                 && bounds.contains_point(&event.position)
@@ -266,9 +261,9 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
                 cx.stop_propagation();
                 cx.prevent_default();
 
-                let new_menu = (builder)(view_state, cx);
+                let new_menu = (builder)(cx);
                 let menu2 = menu.clone();
-                cx.subscribe(&new_menu, move |this, modal, e, cx| match e {
+                cx.subscribe(&new_menu, move |modal, e, cx| match e {
                     &Manager::Dismiss => {
                         *menu2.borrow_mut() = None;
                         cx.notify();
@@ -291,7 +286,7 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
     }
 }
 
-impl<V: 'static, M: ManagedView> RenderOnce<V> for MenuHandle<V, M> {
+impl<M: ManagedView> RenderOnce for MenuHandle<M> {
     type Element = Self;
 
     fn element_id(&self) -> Option<gpui::ElementId> {
@@ -314,11 +309,7 @@ mod stories {
 
     actions!(PrintCurrentDate, PrintBestFood);
 
-    fn build_menu<V: Render<V>>(
-        cx: &mut ViewContext<V>,
-        header: impl Into<SharedString>,
-    ) -> View<ContextMenu<V>> {
-        let handle = cx.view().clone();
+    fn build_menu(cx: &mut WindowContext, header: impl Into<SharedString>) -> View<ContextMenu> {
         ContextMenu::build(cx, |menu, _| {
             menu.header(header)
                 .separator()
@@ -338,18 +329,18 @@ mod stories {
 
     pub struct ContextMenuStory;
 
-    impl Render<Self> for ContextMenuStory {
-        type Element = Div<Self>;
+    impl Render for ContextMenuStory {
+        type Element = Div;
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
             Story::container(cx)
-                .on_action(|_, _: &PrintCurrentDate, _| {
+                .on_action(|_: &PrintCurrentDate, _| {
                     println!("printing unix time!");
                     if let Ok(unix_time) = std::time::UNIX_EPOCH.elapsed() {
                         println!("Current Unix time is {:?}", unix_time.as_secs());
                     }
                 })
-                .on_action(|_, _: &PrintBestFood, _| {
+                .on_action(|_: &PrintBestFood, _| {
                     println!("burrito");
                 })
                 .flex()
@@ -369,7 +360,7 @@ mod stories {
                                         "RIGHT CLICK ME"
                                     })
                                 })
-                                .menu(move |_, cx| build_menu(cx, "top left")),
+                                .menu(move |cx| build_menu(cx, "top left")),
                         )
                         .child(
                             menu_handle("test1")
@@ -382,7 +373,7 @@ mod stories {
                                 })
                                 .anchor(AnchorCorner::BottomLeft)
                                 .attach(AnchorCorner::TopLeft)
-                                .menu(move |_, cx| build_menu(cx, "bottom left")),
+                                .menu(move |cx| build_menu(cx, "bottom left")),
                         ),
                 )
                 .child(
@@ -400,7 +391,7 @@ mod stories {
                                     })
                                 })
                                 .anchor(AnchorCorner::TopRight)
-                                .menu(move |_, cx| build_menu(cx, "top right")),
+                                .menu(move |cx| build_menu(cx, "top right")),
                         )
                         .child(
                             menu_handle("test4")
@@ -413,7 +404,7 @@ mod stories {
                                 })
                                 .anchor(AnchorCorner::BottomRight)
                                 .attach(AnchorCorner::TopRight)
-                                .menu(move |_, cx| build_menu(cx, "bottom right")),
+                                .menu(move |cx| build_menu(cx, "bottom right")),
                         ),
                 )
         }

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

@@ -2,16 +2,16 @@ use crate::prelude::*;
 use crate::{v_stack, ButtonGroup};
 
 #[derive(RenderOnce)]
-pub struct Details<V: 'static> {
+pub struct Details {
     text: &'static str,
     meta: Option<&'static str>,
-    actions: Option<ButtonGroup<V>>,
+    actions: Option<ButtonGroup>,
 }
 
-impl<V: 'static> Component<V> for Details<V> {
-    type Rendered = Div<V>;
+impl Component for Details {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         v_stack()
             .p_1()
             .gap_0p5()
@@ -24,7 +24,7 @@ impl<V: 'static> Component<V> for Details<V> {
     }
 }
 
-impl<V: 'static> Details<V> {
+impl Details {
     pub fn new(text: &'static str) -> Self {
         Self {
             text,
@@ -38,7 +38,7 @@ impl<V: 'static> Details<V> {
         self
     }
 
-    pub fn actions(mut self, actions: ButtonGroup<V>) -> Self {
+    pub fn actions(mut self, actions: ButtonGroup) -> Self {
         self.actions = Some(actions);
         self
     }
@@ -56,12 +56,12 @@ mod stories {
 
     pub struct DetailsStory;
 
-    impl Render<Self> for DetailsStory {
-        type Element = Div<Self>;
+    impl Render for DetailsStory {
+        type Element = Div;
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
             Story::container(cx)
-                .child(Story::title_for::<_, Details<Self>>(cx))
+                .child(Story::title_for::<Details>(cx))
                 .child(Story::label(cx, "Default"))
                 .child(Details::new("The quick brown fox jumps over the lazy dog"))
                 .child(Story::label(cx, "With meta"))

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

@@ -13,10 +13,10 @@ pub struct Divider {
     inset: bool,
 }
 
-impl<V: 'static> Component<V> for Divider {
-    type Rendered = Div<V>;
+impl Component for Divider {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         div()
             .map(|this| match self.direction {
                 DividerDirection::Horizontal => {
@@ -50,7 +50,7 @@ impl Divider {
         self
     }
 
-    fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
+    fn render(self, cx: &mut WindowContext) -> impl Element {
         div()
             .map(|this| match self.direction {
                 DividerDirection::Horizontal => {

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

@@ -5,7 +5,7 @@ use crate::{prelude::*, v_stack};
 /// Create an elevated surface.
 ///
 /// Must be used inside of a relative parent element
-pub fn elevated_surface<V: 'static>(level: ElevationIndex, cx: &mut ViewContext<V>) -> Div<V> {
+pub fn elevated_surface(level: ElevationIndex, cx: &mut WindowContext) -> Div {
     let colors = cx.theme().colors();
 
     // let shadow = BoxShadow {
@@ -23,6 +23,6 @@ pub fn elevated_surface<V: 'static>(level: ElevationIndex, cx: &mut ViewContext<
         .shadow(level.shadow())
 }
 
-pub fn modal<V: 'static>(cx: &mut ViewContext<V>) -> Div<V> {
+pub fn modal(cx: &mut WindowContext) -> Div {
     elevated_surface(ElevationIndex::ModalSurface, cx)
 }

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

@@ -6,10 +6,10 @@ pub struct Facepile {
     players: Vec<Player>,
 }
 
-impl<V: 'static> Component<V> for Facepile {
-    type Rendered = Div<V>;
+impl Component for Facepile {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         let player_count = self.players.len();
         let player_list = self.players.iter().enumerate().map(|(ix, player)| {
             let isnt_last = ix < player_count - 1;
@@ -31,34 +31,3 @@ impl Facepile {
 }
 
 use gpui::{Div, RenderOnce};
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::{static_players, Story};
-    use gpui::{Div, Render};
-
-    pub struct FacepileStory;
-
-    impl Render<Self> for FacepileStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            let players = static_players();
-
-            Story::container(cx)
-                .child(Story::title_for::<_, Facepile>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(
-                    div()
-                        .flex()
-                        .gap_3()
-                        .child(Facepile::new(players.clone().into_iter().take(1)))
-                        .child(Facepile::new(players.clone().into_iter().take(2)))
-                        .child(Facepile::new(players.clone().into_iter().take(3))),
-                )
-        }
-    }
-}

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

@@ -136,10 +136,10 @@ pub struct IconElement {
     size: IconSize,
 }
 
-impl<V: 'static> Component<V> for IconElement {
-    type Rendered = Svg<V>;
+impl Component for IconElement {
+    type Rendered = Svg;
 
-    fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         let svg_size = match self.size {
             IconSize::Small => rems(0.75),
             IconSize::Medium => rems(0.9375),
@@ -180,7 +180,7 @@ impl IconElement {
         self
     }
 
-    fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
+    fn render(self, cx: &mut WindowContext) -> impl Element {
         let svg_size = match self.size {
             IconSize::Small => rems(0.75),
             IconSize::Medium => rems(0.9375),
@@ -208,14 +208,14 @@ mod stories {
 
     pub struct IconStory;
 
-    impl Render<Self> for IconStory {
-        type Element = Div<Self>;
+    impl Render for IconStory {
+        type Element = Div;
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
             let icons = Icon::iter();
 
             Story::container(cx)
-                .child(Story::title_for::<_, IconElement>(cx))
+                .child(Story::title_for::<IconElement>(cx))
                 .child(Story::label(cx, "All Icons"))
                 .child(div().flex().gap_3().children(icons.map(IconElement::new)))
         }

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

@@ -1,33 +1,22 @@
-use crate::{h_stack, prelude::*, ClickHandler, Icon, IconElement};
-use gpui::{prelude::*, Action, AnyView, Div, MouseButton, Stateful};
-use std::sync::Arc;
-
-struct IconButtonHandlers<V: 'static> {
-    click: Option<ClickHandler<V>>,
-}
-
-impl<V: 'static> Default for IconButtonHandlers<V> {
-    fn default() -> Self {
-        Self { click: None }
-    }
-}
+use crate::{h_stack, prelude::*, Icon, IconElement};
+use gpui::{prelude::*, Action, AnyView, Div, MouseButton, MouseDownEvent, Stateful};
 
 #[derive(RenderOnce)]
-pub struct IconButton<V: 'static> {
+pub struct IconButton {
     id: ElementId,
     icon: Icon,
     color: TextColor,
     variant: ButtonVariant,
     state: InteractionState,
     selected: bool,
-    tooltip: Option<Box<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static>>,
-    handlers: IconButtonHandlers<V>,
+    tooltip: Option<Box<dyn Fn(&mut WindowContext) -> AnyView + 'static>>,
+    on_mouse_down: Option<Box<dyn Fn(&MouseDownEvent, &mut WindowContext) + 'static>>,
 }
 
-impl<V: 'static> Component<V> for IconButton<V> {
-    type Rendered = Stateful<V, Div<V>>;
+impl Component for IconButton {
+    type Rendered = Stateful<Div>;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         let icon_color = match (self.state, self.color) {
             (InteractionState::Disabled, _) => TextColor::Disabled,
             (InteractionState::Active, _) => TextColor::Selected,
@@ -65,16 +54,16 @@ impl<V: 'static> Component<V> for IconButton<V> {
             .active(|style| style.bg(bg_active_color))
             .child(IconElement::new(self.icon).color(icon_color));
 
-        if let Some(click_handler) = self.handlers.click.clone() {
-            button = button.on_mouse_down(MouseButton::Left, move |state, event, cx| {
+        if let Some(click_handler) = self.on_mouse_down {
+            button = button.on_mouse_down(MouseButton::Left, move |event, cx| {
                 cx.stop_propagation();
-                click_handler(state, cx);
+                click_handler(event, cx);
             })
         }
 
         if let Some(tooltip) = self.tooltip {
             if !self.selected {
-                button = button.tooltip(move |view: &mut V, cx| (tooltip)(view, cx))
+                button = button.tooltip(move |cx| tooltip(cx))
             }
         }
 
@@ -82,7 +71,7 @@ impl<V: 'static> Component<V> for IconButton<V> {
     }
 }
 
-impl<V: 'static> IconButton<V> {
+impl IconButton {
     pub fn new(id: impl Into<ElementId>, icon: Icon) -> Self {
         Self {
             id: id.into(),
@@ -92,7 +81,7 @@ impl<V: 'static> IconButton<V> {
             state: InteractionState::default(),
             selected: false,
             tooltip: None,
-            handlers: IconButtonHandlers::default(),
+            on_mouse_down: None,
         }
     }
 
@@ -121,16 +110,16 @@ impl<V: 'static> IconButton<V> {
         self
     }
 
-    pub fn tooltip(
-        mut self,
-        tooltip: impl Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static,
-    ) -> Self {
+    pub fn tooltip(mut self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self {
         self.tooltip = Some(Box::new(tooltip));
         self
     }
 
-    pub fn on_click(mut self, handler: impl 'static + Fn(&mut V, &mut ViewContext<V>)) -> Self {
-        self.handlers.click = Some(Arc::new(handler));
+    pub fn on_click(
+        mut self,
+        handler: impl 'static + Fn(&MouseDownEvent, &mut WindowContext),
+    ) -> Self {
+        self.on_mouse_down = Some(Box::new(handler));
         self
     }
 

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

@@ -4,10 +4,10 @@ use gpui::{px, Div, RenderOnce};
 #[derive(RenderOnce)]
 pub struct UnreadIndicator;
 
-impl<V: 'static> Component<V> for UnreadIndicator {
-    type Rendered = Div<V>;
+impl Component for UnreadIndicator {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         div()
             .rounded_full()
             .border_2()
@@ -24,7 +24,7 @@ impl UnreadIndicator {
         Self
     }
 
-    fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
+    fn render(self, cx: &mut WindowContext) -> impl Element {
         div()
             .rounded_full()
             .border_2()

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

@@ -18,10 +18,10 @@ pub struct Input {
     is_active: bool,
 }
 
-impl<V: 'static> Component<V> for Input {
-    type Rendered = Stateful<V, Div<V>>;
+impl Component for Input {
+    type Rendered = Stateful<Div>;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         let (input_bg, input_hover_bg, input_active_bg) = match self.variant {
             InputVariant::Ghost => (
                 cx.theme().colors().ghost_element_background,
@@ -118,12 +118,12 @@ mod stories {
 
     pub struct InputStory;
 
-    impl Render<Self> for InputStory {
-        type Element = Div<Self>;
+    impl Render for InputStory {
+        type Element = Div;
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
             Story::container(cx)
-                .child(Story::title_for::<_, Input>(cx))
+                .child(Story::title_for::<Input>(cx))
                 .child(Story::label(cx, "Default"))
                 .child(div().flex().child(Input::new("Search")))
         }

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

@@ -10,10 +10,10 @@ pub struct KeyBinding {
     key_binding: gpui::KeyBinding,
 }
 
-impl<V: 'static> Component<V> for KeyBinding {
-    type Rendered = Div<V>;
+impl Component for KeyBinding {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         div()
             .flex()
             .gap_2()
@@ -49,11 +49,10 @@ pub struct Key {
     key: SharedString,
 }
 
-impl<V: 'static> Component<V> for Key {
-    type Rendered = Div<V>;
+impl Component for Key {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        let _view: &mut V = view;
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         div()
             .px_2()
             .py_0()
@@ -89,15 +88,15 @@ mod stories {
         gpui::KeyBinding::new(key, NoAction {}, None)
     }
 
-    impl Render<Self> for KeybindingStory {
-        type Element = Div<Self>;
+    impl Render for KeybindingStory {
+        type Element = Div;
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
             let all_modifier_permutations =
                 ["ctrl", "alt", "cmd", "shift"].into_iter().permutations(2);
 
             Story::container(cx)
-                .child(Story::title_for::<_, KeyBinding>(cx))
+                .child(Story::title_for::<KeyBinding>(cx))
                 .child(Story::label(cx, "Single Key"))
                 .child(KeyBinding::new(binding("Z")))
                 .child(Story::label(cx, "Single Key with Modifier"))

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

@@ -68,10 +68,10 @@ pub struct Label {
     strikethrough: bool,
 }
 
-impl<V: 'static> Component<V> for Label {
-    type Rendered = Div<V>;
+impl Component for Label {
+    type Rendered = Div;
 
-    fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         div()
             .when(self.strikethrough, |this| {
                 this.relative().child(
@@ -136,10 +136,10 @@ pub struct HighlightedLabel {
     strikethrough: bool,
 }
 
-impl<V: 'static> Component<V> for HighlightedLabel {
-    type Rendered = Div<V>;
+impl Component for HighlightedLabel {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         let highlight_color = cx.theme().colors().text_accent;
         let mut text_style = cx.text_style().clone();
 
@@ -242,12 +242,12 @@ mod stories {
 
     pub struct LabelStory;
 
-    impl Render<Self> for LabelStory {
-        type Element = Div<Self>;
+    impl Render for LabelStory {
+        type Element = Div;
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
             Story::container(cx)
-                .child(Story::title_for::<_, Label>(cx))
+                .child(Story::title_for::<Label>(cx))
                 .child(Story::label(cx, "Default"))
                 .child(Label::new("Hello, world!"))
                 .child(Story::label(cx, "Highlighted"))

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

@@ -1,8 +1,9 @@
-use gpui::{div, AnyElement, Div, RenderOnce, Stateful, StatefulInteractiveElement};
+use gpui::{
+    div, px, AnyElement, ClickEvent, Div, RenderOnce, Stateful, StatefulInteractiveElement,
+};
 use smallvec::SmallVec;
 use std::rc::Rc;
 
-use crate::settings::user_settings;
 use crate::{
     disclosure_control, h_stack, v_stack, Avatar, Icon, IconElement, IconSize, Label, Toggle,
 };
@@ -33,10 +34,10 @@ pub struct ListHeader {
     toggle: Toggle,
 }
 
-impl<V: 'static> Component<V> for ListHeader {
-    type Rendered = Div<V>;
+impl Component for ListHeader {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         let disclosure_control = disclosure_control(self.toggle);
 
         let meta = match self.meta {
@@ -118,7 +119,7 @@ impl ListHeader {
     }
 
     // before_ship!("delete")
-    // fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
+    // fn render<V: 'static>(self,  cx: &mut WindowContext) -> impl Element<V> {
     //     let disclosure_control = disclosure_control(self.toggle);
 
     //     let meta = match self.meta {
@@ -200,10 +201,10 @@ impl ListSubHeader {
     }
 }
 
-impl<V: 'static> Component<V> for ListSubHeader {
-    type Rendered = Div<V>;
+impl Component for ListSubHeader {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         h_stack().flex_1().w_full().relative().py_1().child(
             div()
                 .h_6()
@@ -238,7 +239,7 @@ pub enum ListEntrySize {
 }
 
 #[derive(RenderOnce)]
-pub struct ListItem<V: 'static> {
+pub struct ListItem {
     id: ElementId,
     disabled: bool,
     // TODO: Reintroduce this
@@ -250,10 +251,10 @@ pub struct ListItem<V: 'static> {
     size: ListEntrySize,
     toggle: Toggle,
     variant: ListItemVariant,
-    on_click: Option<Rc<dyn Fn(&mut V, &mut ViewContext<V>) + 'static>>,
+    on_click: Option<Rc<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
 }
 
-impl<V> Clone for ListItem<V> {
+impl Clone for ListItem {
     fn clone(&self) -> Self {
         Self {
             id: self.id.clone(),
@@ -270,7 +271,7 @@ impl<V> Clone for ListItem<V> {
     }
 }
 
-impl<V: 'static> ListItem<V> {
+impl ListItem {
     pub fn new(id: impl Into<ElementId>, label: Label) -> Self {
         Self {
             id: id.into(),
@@ -286,7 +287,7 @@ impl<V: 'static> ListItem<V> {
         }
     }
 
-    pub fn on_click(mut self, handler: impl Fn(&mut V, &mut ViewContext<V>) + 'static) -> Self {
+    pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self {
         self.on_click = Some(Rc::new(handler));
         self
     }
@@ -327,12 +328,10 @@ impl<V: 'static> ListItem<V> {
     }
 }
 
-impl<V: 'static> Component<V> for ListItem<V> {
-    type Rendered = Stateful<V, Div<V>>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        let settings = user_settings(cx);
+impl Component for ListItem {
+    type Rendered = Stateful<Div>;
 
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         let left_content = match self.left_slot.clone() {
             Some(GraphicSlot::Icon(i)) => Some(
                 h_stack().child(
@@ -359,10 +358,9 @@ impl<V: 'static> Component<V> for ListItem<V> {
             })
             .on_click({
                 let on_click = self.on_click.clone();
-
-                move |view: &mut V, event, cx| {
+                move |event, cx| {
                     if let Some(on_click) = &on_click {
-                        (on_click)(view, cx)
+                        (on_click)(event, cx)
                     }
                 }
             })
@@ -378,7 +376,7 @@ impl<V: 'static> Component<V> for ListItem<V> {
                     // .ml(rems(0.75 * self.indent_level as f32))
                     .children((0..self.indent_level).map(|_| {
                         div()
-                            .w(*settings.list_indent_depth)
+                            .w(px(4.))
                             .h_full()
                             .flex()
                             .justify_center()
@@ -409,28 +407,28 @@ impl ListSeparator {
     }
 }
 
-impl<V: 'static> Component<V> for ListSeparator {
-    type Rendered = Div<V>;
+impl Component for ListSeparator {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         div().h_px().w_full().bg(cx.theme().colors().border_variant)
     }
 }
 
 #[derive(RenderOnce)]
-pub struct List<V: 'static> {
+pub struct List {
     /// Message to display when the list is empty
     /// Defaults to "No items"
     empty_message: SharedString,
     header: Option<ListHeader>,
     toggle: Toggle,
-    children: SmallVec<[AnyElement<V>; 2]>,
+    children: SmallVec<[AnyElement; 2]>,
 }
 
-impl<V: 'static> Component<V> for List<V> {
-    type Rendered = Div<V>;
+impl Component for List {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         let list_content = match (self.children.is_empty(), self.toggle) {
             (false, _) => div().children(self.children),
             (true, Toggle::Toggled(false)) => div(),
@@ -447,7 +445,7 @@ impl<V: 'static> Component<V> for List<V> {
     }
 }
 
-impl<V: 'static> List<V> {
+impl List {
     pub fn new() -> Self {
         Self {
             empty_message: "No items".into(),
@@ -473,8 +471,8 @@ impl<V: 'static> List<V> {
     }
 }
 
-impl<V: 'static> ParentElement<V> for List<V> {
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
+impl ParentElement for List {
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
         &mut self.children
     }
 }

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

@@ -1,22 +1,21 @@
-use gpui::{AnyElement, Div, RenderOnce, Stateful};
+use gpui::{AnyElement, Div, RenderOnce};
 use smallvec::SmallVec;
 
 use crate::{h_stack, prelude::*, v_stack, Button, Icon, IconButton, Label};
 
 #[derive(RenderOnce)]
-pub struct Modal<V: 'static> {
+pub struct Modal {
     id: ElementId,
     title: Option<SharedString>,
-    primary_action: Option<Button<V>>,
-    secondary_action: Option<Button<V>>,
-    children: SmallVec<[AnyElement<V>; 2]>,
+    primary_action: Option<Button>,
+    secondary_action: Option<Button>,
+    children: SmallVec<[AnyElement; 2]>,
 }
 
-impl<V: 'static> Component<V> for Modal<V> {
-    type Rendered = Stateful<V, Div<V>>;
+impl Component for Modal {
+    type Rendered = gpui::Stateful<Div>;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        let _view: &mut V = view;
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         v_stack()
             .id(self.id.clone())
             .w_96()
@@ -52,7 +51,7 @@ impl<V: 'static> Component<V> for Modal<V> {
     }
 }
 
-impl<V: 'static> Modal<V> {
+impl Modal {
     pub fn new(id: impl Into<ElementId>) -> Self {
         Self {
             id: id.into(),
@@ -68,19 +67,19 @@ impl<V: 'static> Modal<V> {
         self
     }
 
-    pub fn primary_action(mut self, action: Button<V>) -> Self {
+    pub fn primary_action(mut self, action: Button) -> Self {
         self.primary_action = Some(action);
         self
     }
 
-    pub fn secondary_action(mut self, action: Button<V>) -> Self {
+    pub fn secondary_action(mut self, action: Button) -> Self {
         self.secondary_action = Some(action);
         self
     }
 }
 
-impl<V: 'static> ParentElement<V> for Modal<V> {
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
+impl ParentElement for Modal {
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
         &mut self.children
     }
 }

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

@@ -22,7 +22,7 @@ impl NotificationToast {
         self
     }
 
-    fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
+    fn render(self, cx: &mut WindowContext) -> impl Element {
         h_stack()
             .z_index(5)
             .absolute()

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

@@ -1,7 +1,6 @@
 use crate::{h_stack, prelude::*, v_stack, KeyBinding, Label};
 use gpui::prelude::*;
 use gpui::Div;
-use gpui::Stateful;
 
 #[derive(RenderOnce)]
 pub struct Palette {
@@ -12,10 +11,10 @@ pub struct Palette {
     default_order: OrderMethod,
 }
 
-impl<V: 'static> Component<V> for Palette {
-    type Rendered = Stateful<V, Div<V>>;
+impl Component for Palette {
+    type Rendered = gpui::Stateful<Div>;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         v_stack()
             .id(self.id)
             .w_96()
@@ -116,10 +115,10 @@ pub struct PaletteItem {
     pub key_binding: Option<KeyBinding>,
 }
 
-impl<V: 'static> Component<V> for PaletteItem {
-    type Rendered = Div<V>;
+impl Component for PaletteItem {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         div()
             .flex()
             .flex_row()
@@ -173,13 +172,13 @@ mod stories {
 
     pub struct PaletteStory;
 
-    impl Render<Self> for PaletteStory {
-        type Element = Div<Self>;
+    impl Render for PaletteStory {
+        type Element = Div;
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
             {
                 Story::container(cx)
-                    .child(Story::title_for::<_, Palette>(cx))
+                    .child(Story::title_for::<Palette>(cx))
                     .child(Story::label(cx, "Default"))
                     .child(Palette::new("palette-1"))
                     .child(Story::label(cx, "With Items"))

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

@@ -1,8 +1,8 @@
-use gpui::{prelude::*, AbsoluteLength, AnyElement, Div, RenderOnce, Stateful};
+use gpui::px;
+use gpui::{prelude::*, AbsoluteLength, AnyElement, Div, RenderOnce};
 use smallvec::SmallVec;
 
 use crate::prelude::*;
-use crate::settings::user_settings;
 use crate::v_stack;
 
 #[derive(Default, Debug, PartialEq, Eq, Hash, Clone, Copy)]
@@ -39,20 +39,20 @@ pub enum PanelSide {
 use std::collections::HashSet;
 
 #[derive(RenderOnce)]
-pub struct Panel<V: 'static> {
+pub struct Panel {
     id: ElementId,
     current_side: PanelSide,
     /// Defaults to PanelAllowedSides::LeftAndRight
     allowed_sides: PanelAllowedSides,
     initial_width: AbsoluteLength,
     width: Option<AbsoluteLength>,
-    children: SmallVec<[AnyElement<V>; 2]>,
+    children: SmallVec<[AnyElement; 2]>,
 }
 
-impl<V: 'static> Component<V> for Panel<V> {
-    type Rendered = Stateful<V, Div<V>>;
+impl Component for Panel {
+    type Rendered = gpui::Stateful<Div>;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         let current_size = self.width.unwrap_or(self.initial_width);
 
         v_stack()
@@ -73,15 +73,13 @@ impl<V: 'static> Component<V> for Panel<V> {
     }
 }
 
-impl<V: 'static> Panel<V> {
+impl Panel {
     pub fn new(id: impl Into<ElementId>, cx: &mut WindowContext) -> Self {
-        let settings = user_settings(cx);
-
         Self {
             id: id.into(),
             current_side: PanelSide::default(),
             allowed_sides: PanelAllowedSides::default(),
-            initial_width: *settings.default_panel_size,
+            initial_width: px(320.).into(),
             width: None,
             children: SmallVec::new(),
         }
@@ -117,8 +115,8 @@ impl<V: 'static> Panel<V> {
     }
 }
 
-impl<V: 'static> ParentElement<V> for Panel<V> {
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
+impl ParentElement for Panel {
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
         &mut self.children
     }
 }
@@ -134,12 +132,12 @@ mod stories {
 
     pub struct PanelStory;
 
-    impl Render<Self> for PanelStory {
-        type Element = Div<Self>;
+    impl Render for PanelStory {
+        type Element = Div;
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
             Story::container(cx)
-                .child(Story::title_for::<_, Panel<Self>>(cx))
+                .child(Story::title_for::<Panel>(cx))
                 .child(Story::label(cx, "Default"))
                 .child(
                     Panel::new("panel", cx).child(

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

@@ -1,4 +1,4 @@
-use gpui::{Hsla, ViewContext};
+use gpui::Hsla;
 
 use crate::prelude::*;
 
@@ -156,11 +156,11 @@ impl Player {
         self
     }
 
-    pub fn cursor_color<V: 'static>(&self, cx: &mut ViewContext<V>) -> Hsla {
+    pub fn cursor_color(&self, cx: &mut WindowContext) -> Hsla {
         cx.theme().styles.player.0[self.index % cx.theme().styles.player.0.len()].cursor
     }
 
-    pub fn selection_color<V: 'static>(&self, cx: &mut ViewContext<V>) -> Hsla {
+    pub fn selection_color(&self, cx: &mut WindowContext) -> Hsla {
         cx.theme().styles.player.0[self.index % cx.theme().styles.player.0.len()].selection
     }
 

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

@@ -8,10 +8,10 @@ pub struct PlayerStack {
     player_with_call_status: PlayerWithCallStatus,
 }
 
-impl<V: 'static> Component<V> for PlayerStack {
-    type Rendered = Div<V>;
+impl Component for PlayerStack {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         let player = self.player_with_call_status.get_player();
 
         let followers = self

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

@@ -5,13 +5,13 @@ use crate::StyledExt;
 /// Horizontally stacks elements.
 ///
 /// Sets `flex()`, `flex_row()`, `items_center()`
-pub fn h_stack<V: 'static>() -> Div<V> {
+pub fn h_stack() -> Div {
     div().h_flex()
 }
 
 /// Vertically stacks elements.
 ///
 /// Sets `flex()`, `flex_col()`
-pub fn v_stack<V: 'static>() -> Div<V> {
+pub fn v_stack() -> Div {
     div().v_flex()
 }

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

@@ -1,276 +1,276 @@
-use crate::prelude::*;
-use crate::{Icon, IconElement, Label, TextColor};
-use gpui::{prelude::*, red, Div, ElementId, Render, RenderOnce, Stateful, View};
+// use crate::prelude::*;
+// use crate::{Icon, IconElement, Label, TextColor};
+// use gpui::{prelude::*, red, Div, ElementId, Render, RenderOnce, View};
 
-#[derive(RenderOnce, Clone)]
-pub struct Tab {
-    id: ElementId,
-    title: String,
-    icon: Option<Icon>,
-    current: bool,
-    dirty: bool,
-    fs_status: FileSystemStatus,
-    git_status: GitStatus,
-    diagnostic_status: DiagnosticStatus,
-    close_side: IconSide,
-}
+// #[derive(RenderOnce, Clone)]
+// pub struct Tab {
+//     id: ElementId,
+//     title: String,
+//     icon: Option<Icon>,
+//     current: bool,
+//     dirty: bool,
+//     fs_status: FileSystemStatus,
+//     git_status: GitStatus,
+//     diagnostic_status: DiagnosticStatus,
+//     close_side: IconSide,
+// }
 
-#[derive(Clone, Debug)]
-struct TabDragState {
-    title: String,
-}
+// #[derive(Clone, Debug)]
+// struct TabDragState {
+//     title: String,
+// }
 
-impl Render<Self> for TabDragState {
-    type Element = Div<Self>;
+// impl Render for TabDragState {
+//     type Element = Div;
 
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-        div().w_8().h_4().bg(red())
-    }
-}
+//     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+//         div().w_8().h_4().bg(red())
+//     }
+// }
 
-impl<V: 'static> Component<V> for Tab {
-    type Rendered = Stateful<V, Div<V>>;
+// impl Component for Tab {
+//     type Rendered = gpui::Stateful<Div>;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        let has_fs_conflict = self.fs_status == FileSystemStatus::Conflict;
-        let is_deleted = self.fs_status == FileSystemStatus::Deleted;
+//     fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+//         let has_fs_conflict = self.fs_status == FileSystemStatus::Conflict;
+//         let is_deleted = self.fs_status == FileSystemStatus::Deleted;
 
-        let label = match (self.git_status, is_deleted) {
-            (_, true) | (GitStatus::Deleted, false) => Label::new(self.title.clone())
-                .color(TextColor::Hidden)
-                .set_strikethrough(true),
-            (GitStatus::None, false) => Label::new(self.title.clone()),
-            (GitStatus::Created, false) => Label::new(self.title.clone()).color(TextColor::Created),
-            (GitStatus::Modified, false) => {
-                Label::new(self.title.clone()).color(TextColor::Modified)
-            }
-            (GitStatus::Renamed, false) => Label::new(self.title.clone()).color(TextColor::Accent),
-            (GitStatus::Conflict, false) => Label::new(self.title.clone()),
-        };
+//         let label = match (self.git_status, is_deleted) {
+//             (_, true) | (GitStatus::Deleted, false) => Label::new(self.title.clone())
+//                 .color(TextColor::Hidden)
+//                 .set_strikethrough(true),
+//             (GitStatus::None, false) => Label::new(self.title.clone()),
+//             (GitStatus::Created, false) => Label::new(self.title.clone()).color(TextColor::Created),
+//             (GitStatus::Modified, false) => {
+//                 Label::new(self.title.clone()).color(TextColor::Modified)
+//             }
+//             (GitStatus::Renamed, false) => Label::new(self.title.clone()).color(TextColor::Accent),
+//             (GitStatus::Conflict, false) => Label::new(self.title.clone()),
+//         };
 
-        let close_icon = || IconElement::new(Icon::Close).color(TextColor::Muted);
+//         let close_icon = || IconElement::new(Icon::Close).color(TextColor::Muted);
 
-        let (tab_bg, tab_hover_bg, tab_active_bg) = match self.current {
-            false => (
-                cx.theme().colors().tab_inactive_background,
-                cx.theme().colors().ghost_element_hover,
-                cx.theme().colors().ghost_element_active,
-            ),
-            true => (
-                cx.theme().colors().tab_active_background,
-                cx.theme().colors().element_hover,
-                cx.theme().colors().element_active,
-            ),
-        };
+//         let (tab_bg, tab_hover_bg, tab_active_bg) = match self.current {
+//             false => (
+//                 cx.theme().colors().tab_inactive_background,
+//                 cx.theme().colors().ghost_element_hover,
+//                 cx.theme().colors().ghost_element_active,
+//             ),
+//             true => (
+//                 cx.theme().colors().tab_active_background,
+//                 cx.theme().colors().element_hover,
+//                 cx.theme().colors().element_active,
+//             ),
+//         };
 
-        let drag_state = TabDragState {
-            title: self.title.clone(),
-        };
+//         let drag_state = TabDragState {
+//             title: self.title.clone(),
+//         };
 
-        div()
-            .id(self.id.clone())
-            .on_drag(move |_view, cx| cx.build_view(|cx| drag_state.clone()))
-            .drag_over::<TabDragState>(|d| d.bg(cx.theme().colors().drop_target_background))
-            .on_drop(|_view, state: View<TabDragState>, cx| {
-                eprintln!("{:?}", state.read(cx));
-            })
-            .px_2()
-            .py_0p5()
-            .flex()
-            .items_center()
-            .justify_center()
-            .bg(tab_bg)
-            .hover(|h| h.bg(tab_hover_bg))
-            .active(|a| a.bg(tab_active_bg))
-            .child(
-                div()
-                    .px_1()
-                    .flex()
-                    .items_center()
-                    .gap_1p5()
-                    .children(has_fs_conflict.then(|| {
-                        IconElement::new(Icon::ExclamationTriangle)
-                            .size(crate::IconSize::Small)
-                            .color(TextColor::Warning)
-                    }))
-                    .children(self.icon.map(IconElement::new))
-                    .children(if self.close_side == IconSide::Left {
-                        Some(close_icon())
-                    } else {
-                        None
-                    })
-                    .child(label)
-                    .children(if self.close_side == IconSide::Right {
-                        Some(close_icon())
-                    } else {
-                        None
-                    }),
-            )
-    }
-}
+//         div()
+//             .id(self.id.clone())
+//             .on_drag(move |_view, cx| cx.build_view(|cx| drag_state.clone()))
+//             .drag_over::<TabDragState>(|d| d.bg(cx.theme().colors().drop_target_background))
+//             .on_drop(|_view, state: View<TabDragState>, cx| {
+//                 eprintln!("{:?}", state.read(cx));
+//             })
+//             .px_2()
+//             .py_0p5()
+//             .flex()
+//             .items_center()
+//             .justify_center()
+//             .bg(tab_bg)
+//             .hover(|h| h.bg(tab_hover_bg))
+//             .active(|a| a.bg(tab_active_bg))
+//             .child(
+//                 div()
+//                     .px_1()
+//                     .flex()
+//                     .items_center()
+//                     .gap_1p5()
+//                     .children(has_fs_conflict.then(|| {
+//                         IconElement::new(Icon::ExclamationTriangle)
+//                             .size(crate::IconSize::Small)
+//                             .color(TextColor::Warning)
+//                     }))
+//                     .children(self.icon.map(IconElement::new))
+//                     .children(if self.close_side == IconSide::Left {
+//                         Some(close_icon())
+//                     } else {
+//                         None
+//                     })
+//                     .child(label)
+//                     .children(if self.close_side == IconSide::Right {
+//                         Some(close_icon())
+//                     } else {
+//                         None
+//                     }),
+//             )
+//     }
+// }
 
-impl Tab {
-    pub fn new(id: impl Into<ElementId>) -> Self {
-        Self {
-            id: id.into(),
-            title: "untitled".to_string(),
-            icon: None,
-            current: false,
-            dirty: false,
-            fs_status: FileSystemStatus::None,
-            git_status: GitStatus::None,
-            diagnostic_status: DiagnosticStatus::None,
-            close_side: IconSide::Right,
-        }
-    }
+// impl Tab {
+//     pub fn new(id: impl Into<ElementId>) -> Self {
+//         Self {
+//             id: id.into(),
+//             title: "untitled".to_string(),
+//             icon: None,
+//             current: false,
+//             dirty: false,
+//             fs_status: FileSystemStatus::None,
+//             git_status: GitStatus::None,
+//             diagnostic_status: DiagnosticStatus::None,
+//             close_side: IconSide::Right,
+//         }
+//     }
 
-    pub fn current(mut self, current: bool) -> Self {
-        self.current = current;
-        self
-    }
+//     pub fn current(mut self, current: bool) -> Self {
+//         self.current = current;
+//         self
+//     }
 
-    pub fn title(mut self, title: String) -> Self {
-        self.title = title;
-        self
-    }
+//     pub fn title(mut self, title: String) -> Self {
+//         self.title = title;
+//         self
+//     }
 
-    pub fn icon<I>(mut self, icon: I) -> Self
-    where
-        I: Into<Option<Icon>>,
-    {
-        self.icon = icon.into();
-        self
-    }
+//     pub fn icon<I>(mut self, icon: I) -> Self
+//     where
+//         I: Into<Option<Icon>>,
+//     {
+//         self.icon = icon.into();
+//         self
+//     }
 
-    pub fn dirty(mut self, dirty: bool) -> Self {
-        self.dirty = dirty;
-        self
-    }
+//     pub fn dirty(mut self, dirty: bool) -> Self {
+//         self.dirty = dirty;
+//         self
+//     }
 
-    pub fn fs_status(mut self, fs_status: FileSystemStatus) -> Self {
-        self.fs_status = fs_status;
-        self
-    }
+//     pub fn fs_status(mut self, fs_status: FileSystemStatus) -> Self {
+//         self.fs_status = fs_status;
+//         self
+//     }
 
-    pub fn git_status(mut self, git_status: GitStatus) -> Self {
-        self.git_status = git_status;
-        self
-    }
+//     pub fn git_status(mut self, git_status: GitStatus) -> Self {
+//         self.git_status = git_status;
+//         self
+//     }
 
-    pub fn diagnostic_status(mut self, diagnostic_status: DiagnosticStatus) -> Self {
-        self.diagnostic_status = diagnostic_status;
-        self
-    }
+//     pub fn diagnostic_status(mut self, diagnostic_status: DiagnosticStatus) -> Self {
+//         self.diagnostic_status = diagnostic_status;
+//         self
+//     }
 
-    pub fn close_side(mut self, close_side: IconSide) -> Self {
-        self.close_side = close_side;
-        self
-    }
-}
+//     pub fn close_side(mut self, close_side: IconSide) -> Self {
+//         self.close_side = close_side;
+//         self
+//     }
+// }
 
-#[cfg(feature = "stories")]
-pub use stories::*;
+// #[cfg(feature = "stories")]
+// pub use stories::*;
 
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::{h_stack, v_stack, Icon, Story};
-    use strum::IntoEnumIterator;
+// #[cfg(feature = "stories")]
+// mod stories {
+//     use super::*;
+//     use crate::{h_stack, v_stack, Icon, Story};
+//     use strum::IntoEnumIterator;
 
-    pub struct TabStory;
+//     pub struct TabStory;
 
-    impl Render<Self> for TabStory {
-        type Element = Div<Self>;
+//     impl Render for TabStory {
+//         type Element = Div;
 
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            let git_statuses = GitStatus::iter();
-            let fs_statuses = FileSystemStatus::iter();
+//         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+//             let git_statuses = GitStatus::iter();
+//             let fs_statuses = FileSystemStatus::iter();
 
-            Story::container(cx)
-                .child(Story::title_for::<_, Tab>(cx))
-                .child(
-                    h_stack().child(
-                        v_stack()
-                            .gap_2()
-                            .child(Story::label(cx, "Default"))
-                            .child(Tab::new("default")),
-                    ),
-                )
-                .child(
-                    h_stack().child(
-                        v_stack().gap_2().child(Story::label(cx, "Current")).child(
-                            h_stack()
-                                .gap_4()
-                                .child(
-                                    Tab::new("current")
-                                        .title("Current".to_string())
-                                        .current(true),
-                                )
-                                .child(
-                                    Tab::new("not_current")
-                                        .title("Not Current".to_string())
-                                        .current(false),
-                                ),
-                        ),
-                    ),
-                )
-                .child(
-                    h_stack().child(
-                        v_stack()
-                            .gap_2()
-                            .child(Story::label(cx, "Titled"))
-                            .child(Tab::new("titled").title("label".to_string())),
-                    ),
-                )
-                .child(
-                    h_stack().child(
-                        v_stack()
-                            .gap_2()
-                            .child(Story::label(cx, "With Icon"))
-                            .child(
-                                Tab::new("with_icon")
-                                    .title("label".to_string())
-                                    .icon(Some(Icon::Envelope)),
-                            ),
-                    ),
-                )
-                .child(
-                    h_stack().child(
-                        v_stack()
-                            .gap_2()
-                            .child(Story::label(cx, "Close Side"))
-                            .child(
-                                h_stack()
-                                    .gap_4()
-                                    .child(
-                                        Tab::new("left")
-                                            .title("Left".to_string())
-                                            .close_side(IconSide::Left),
-                                    )
-                                    .child(Tab::new("right").title("Right".to_string())),
-                            ),
-                    ),
-                )
-                .child(
-                    v_stack()
-                        .gap_2()
-                        .child(Story::label(cx, "Git Status"))
-                        .child(h_stack().gap_4().children(git_statuses.map(|git_status| {
-                            Tab::new("git_status")
-                                .title(git_status.to_string())
-                                .git_status(git_status)
-                        }))),
-                )
-                .child(
-                    v_stack()
-                        .gap_2()
-                        .child(Story::label(cx, "File System Status"))
-                        .child(h_stack().gap_4().children(fs_statuses.map(|fs_status| {
-                            Tab::new("file_system_status")
-                                .title(fs_status.to_string())
-                                .fs_status(fs_status)
-                        }))),
-                )
-        }
-    }
-}
+//             Story::container(cx)
+//                 .child(Story::title_for::<_, Tab>(cx))
+//                 .child(
+//                     h_stack().child(
+//                         v_stack()
+//                             .gap_2()
+//                             .child(Story::label(cx, "Default"))
+//                             .child(Tab::new("default")),
+//                     ),
+//                 )
+//                 .child(
+//                     h_stack().child(
+//                         v_stack().gap_2().child(Story::label(cx, "Current")).child(
+//                             h_stack()
+//                                 .gap_4()
+//                                 .child(
+//                                     Tab::new("current")
+//                                         .title("Current".to_string())
+//                                         .current(true),
+//                                 )
+//                                 .child(
+//                                     Tab::new("not_current")
+//                                         .title("Not Current".to_string())
+//                                         .current(false),
+//                                 ),
+//                         ),
+//                     ),
+//                 )
+//                 .child(
+//                     h_stack().child(
+//                         v_stack()
+//                             .gap_2()
+//                             .child(Story::label(cx, "Titled"))
+//                             .child(Tab::new("titled").title("label".to_string())),
+//                     ),
+//                 )
+//                 .child(
+//                     h_stack().child(
+//                         v_stack()
+//                             .gap_2()
+//                             .child(Story::label(cx, "With Icon"))
+//                             .child(
+//                                 Tab::new("with_icon")
+//                                     .title("label".to_string())
+//                                     .icon(Some(Icon::Envelope)),
+//                             ),
+//                     ),
+//                 )
+//                 .child(
+//                     h_stack().child(
+//                         v_stack()
+//                             .gap_2()
+//                             .child(Story::label(cx, "Close Side"))
+//                             .child(
+//                                 h_stack()
+//                                     .gap_4()
+//                                     .child(
+//                                         Tab::new("left")
+//                                             .title("Left".to_string())
+//                                             .close_side(IconSide::Left),
+//                                     )
+//                                     .child(Tab::new("right").title("Right".to_string())),
+//                             ),
+//                     ),
+//                 )
+//                 .child(
+//                     v_stack()
+//                         .gap_2()
+//                         .child(Story::label(cx, "Git Status"))
+//                         .child(h_stack().gap_4().children(git_statuses.map(|git_status| {
+//                             Tab::new("git_status")
+//                                 .title(git_status.to_string())
+//                                 .git_status(git_status)
+//                         }))),
+//                 )
+//                 .child(
+//                     v_stack()
+//                         .gap_2()
+//                         .child(Story::label(cx, "File System Status"))
+//                         .child(h_stack().gap_4().children(fs_statuses.map(|fs_status| {
+//                             Tab::new("file_system_status")
+//                                 .title(fs_status.to_string())
+//                                 .fs_status(fs_status)
+//                         }))),
+//                 )
+//         }
+//     }
+// }

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

@@ -23,15 +23,15 @@ pub enum ToastOrigin {
 ///
 /// Only one toast may be visible at a time.
 #[derive(RenderOnce)]
-pub struct Toast<V: 'static> {
+pub struct Toast {
     origin: ToastOrigin,
-    children: SmallVec<[AnyElement<V>; 2]>,
+    children: SmallVec<[AnyElement; 2]>,
 }
 
-impl<V: 'static> Component<V> for Toast<V> {
-    type Rendered = Div<V>;
+impl Component for Toast {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         let mut div = div();
 
         if self.origin == ToastOrigin::Bottom {
@@ -54,7 +54,7 @@ impl<V: 'static> Component<V> for Toast<V> {
     }
 }
 
-impl<V: 'static> Toast<V> {
+impl Toast {
     pub fn new(origin: ToastOrigin) -> Self {
         Self {
             origin,
@@ -62,7 +62,7 @@ impl<V: 'static> Toast<V> {
         }
     }
 
-    fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
+    fn render(self, cx: &mut WindowContext) -> impl Element {
         let mut div = div();
 
         if self.origin == ToastOrigin::Bottom {
@@ -85,8 +85,8 @@ impl<V: 'static> Toast<V> {
     }
 }
 
-impl<V: 'static> ParentElement<V> for Toast<V> {
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
+impl ParentElement for Toast {
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
         &mut self.children
     }
 }
@@ -104,12 +104,12 @@ mod stories {
 
     pub struct ToastStory;
 
-    impl Render<Self> for ToastStory {
-        type Element = Div<Self>;
+    impl Render for ToastStory {
+        type Element = Div;
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
             Story::container(cx)
-                .child(Story::title_for::<_, Toast<Self>>(cx))
+                .child(Story::title_for::<Toast>(cx))
                 .child(Story::label(cx, "Default"))
                 .child(Toast::new(ToastOrigin::Bottom).child(Label::new("label")))
         }

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

@@ -44,7 +44,7 @@ impl From<bool> for Toggle {
     }
 }
 
-pub fn disclosure_control<V: 'static>(toggle: Toggle) -> impl Element<V> {
+pub fn disclosure_control(toggle: Toggle) -> impl Element {
     match (toggle.is_toggleable(), toggle.is_toggled()) {
         (false, _) => div(),
         (_, true) => div().child(

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

@@ -4,10 +4,10 @@ use gpui::{Div, RenderOnce};
 #[derive(RenderOnce)]
 pub struct ToolDivider;
 
-impl<V: 'static> Component<V> for ToolDivider {
-    type Rendered = Div<V>;
+impl Component for ToolDivider {
+    type Rendered = Div;
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         div().w_px().h_3().bg(cx.theme().colors().border)
     }
 }
@@ -17,7 +17,7 @@ impl ToolDivider {
         Self
     }
 
-    fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
+    fn render(self, cx: &mut WindowContext) -> impl Element {
         div().w_px().h_3().bg(cx.theme().colors().border)
     }
 }

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

@@ -67,8 +67,8 @@ impl Tooltip {
     }
 }
 
-impl Render<Self> for Tooltip {
-    type Element = Overlay<Self>;
+impl Render for Tooltip {
+    type Element = Overlay;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         let ui_font = ThemeSettings::get_global(cx).ui_font.family.clone();

crates/ui2/src/lib.rs 🔗

@@ -17,34 +17,15 @@
 mod components;
 mod elevation;
 pub mod prelude;
-pub mod settings;
-mod static_data;
 mod styled_ext;
-mod to_extract;
 pub mod utils;
 
 pub use components::*;
-use gpui::actions;
 pub use prelude::*;
-pub use static_data::*;
+// pub use static_data::*;
 pub use styled_ext::*;
-pub use to_extract::*;
-
-// This needs to be fully qualified with `crate::` otherwise we get a panic
-// at:
-//   thread '<unnamed>' panicked at crates/gpui2/src/platform/mac/platform.rs:66:81:
-//   called `Option::unwrap()` on a `None` value
-//
-// AFAICT this is something to do with conflicting names between crates and modules that
-// interfaces with declaring the `ClassDecl`.
-pub use crate::settings::*;
 
 #[cfg(feature = "stories")]
 mod story;
 #[cfg(feature = "stories")]
 pub use story::*;
-actions!(NoAction);
-
-pub fn binding(key: &str) -> gpui::KeyBinding {
-    gpui::KeyBinding::new(key, NoAction {}, None)
-}

crates/ui2/src/settings.rs 🔗

@@ -1,74 +0,0 @@
-use std::ops::Deref;
-
-use gpui::{rems, AbsoluteLength, AppContext, WindowContext};
-
-use crate::prelude::*;
-
-pub fn init(cx: &mut AppContext) {
-    cx.set_global(FakeSettings::default());
-}
-
-/// Returns the user settings.
-pub fn user_settings(cx: &WindowContext) -> FakeSettings {
-    cx.global::<FakeSettings>().clone()
-}
-
-pub fn user_settings_mut<'cx>(cx: &'cx mut WindowContext) -> &'cx mut FakeSettings {
-    cx.global_mut::<FakeSettings>()
-}
-
-#[derive(Clone)]
-pub enum SettingValue<T> {
-    UserDefined(T),
-    Default(T),
-}
-
-impl<T> Deref for SettingValue<T> {
-    type Target = T;
-
-    fn deref(&self) -> &Self::Target {
-        match self {
-            Self::UserDefined(value) => value,
-            Self::Default(value) => value,
-        }
-    }
-}
-
-#[derive(Clone)]
-pub struct TitlebarSettings {
-    pub show_project_owner: SettingValue<bool>,
-    pub show_git_status: SettingValue<bool>,
-    pub show_git_controls: SettingValue<bool>,
-}
-
-impl Default for TitlebarSettings {
-    fn default() -> Self {
-        Self {
-            show_project_owner: SettingValue::Default(true),
-            show_git_status: SettingValue::Default(true),
-            show_git_controls: SettingValue::Default(true),
-        }
-    }
-}
-
-// These should be merged into settings
-#[derive(Clone)]
-pub struct FakeSettings {
-    pub default_panel_size: SettingValue<AbsoluteLength>,
-    pub list_disclosure_style: SettingValue<DisclosureControlStyle>,
-    pub list_indent_depth: SettingValue<AbsoluteLength>,
-    pub titlebar: TitlebarSettings,
-}
-
-impl Default for FakeSettings {
-    fn default() -> Self {
-        Self {
-            titlebar: TitlebarSettings::default(),
-            list_disclosure_style: SettingValue::Default(DisclosureControlStyle::ChevronOnHover),
-            list_indent_depth: SettingValue::Default(rems(0.3).into()),
-            default_panel_size: SettingValue::Default(rems(16.).into()),
-        }
-    }
-}
-
-impl FakeSettings {}

crates/ui2/src/static_data.rs 🔗

@@ -1,1123 +0,0 @@
-use std::path::PathBuf;
-use std::str::FromStr;
-use std::sync::Arc;
-
-use chrono::DateTime;
-use gpui::{AppContext, ViewContext};
-use rand::Rng;
-use theme2::ActiveTheme;
-
-use crate::{
-    binding, Buffer, BufferRow, BufferRows, Button, EditorPane, FileSystemStatus, GitStatus,
-    HighlightedLine, HighlightedText, Icon, KeyBinding, Label, ListEntrySize, ListItem, Livestream,
-    MicStatus, Notification, NotificationAction, PaletteItem, Player, PlayerCallStatus,
-    PlayerWithCallStatus, PublicPlayer, ScreenShareStatus, Symbol, Tab, TextColor, Toggle,
-    VideoStatus,
-};
-
-pub fn static_tabs_example() -> Vec<Tab> {
-    vec![
-        Tab::new("wip.rs")
-            .title("wip.rs".to_string())
-            .icon(Icon::FileRust)
-            .current(false)
-            .fs_status(FileSystemStatus::Deleted),
-        Tab::new("Cargo.toml")
-            .title("Cargo.toml".to_string())
-            .icon(Icon::FileToml)
-            .current(false)
-            .git_status(GitStatus::Modified),
-        Tab::new("Channels Panel")
-            .title("Channels Panel".to_string())
-            .icon(Icon::Hash)
-            .current(false),
-        Tab::new("channels_panel.rs")
-            .title("channels_panel.rs".to_string())
-            .icon(Icon::FileRust)
-            .current(true)
-            .git_status(GitStatus::Modified),
-        Tab::new("workspace.rs")
-            .title("workspace.rs".to_string())
-            .current(false)
-            .icon(Icon::FileRust)
-            .git_status(GitStatus::Modified),
-        Tab::new("icon_button.rs")
-            .title("icon_button.rs".to_string())
-            .icon(Icon::FileRust)
-            .current(false),
-        Tab::new("storybook.rs")
-            .title("storybook.rs".to_string())
-            .icon(Icon::FileRust)
-            .current(false)
-            .git_status(GitStatus::Created),
-        Tab::new("theme.rs")
-            .title("theme.rs".to_string())
-            .icon(Icon::FileRust)
-            .current(false),
-        Tab::new("theme_registry.rs")
-            .title("theme_registry.rs".to_string())
-            .icon(Icon::FileRust)
-            .current(false),
-        Tab::new("styleable_helpers.rs")
-            .title("styleable_helpers.rs".to_string())
-            .icon(Icon::FileRust)
-            .current(false),
-    ]
-}
-
-pub fn static_tabs_1() -> Vec<Tab> {
-    vec![
-        Tab::new("project_panel.rs")
-            .title("project_panel.rs".to_string())
-            .icon(Icon::FileRust)
-            .current(false)
-            .fs_status(FileSystemStatus::Deleted),
-        Tab::new("tab_bar.rs")
-            .title("tab_bar.rs".to_string())
-            .icon(Icon::FileRust)
-            .current(false)
-            .git_status(GitStatus::Modified),
-        Tab::new("workspace.rs")
-            .title("workspace.rs".to_string())
-            .icon(Icon::FileRust)
-            .current(false),
-        Tab::new("tab.rs")
-            .title("tab.rs".to_string())
-            .icon(Icon::FileRust)
-            .current(true)
-            .git_status(GitStatus::Modified),
-    ]
-}
-
-pub fn static_tabs_2() -> Vec<Tab> {
-    vec![
-        Tab::new("tab_bar.rs")
-            .title("tab_bar.rs".to_string())
-            .icon(Icon::FileRust)
-            .current(false)
-            .fs_status(FileSystemStatus::Deleted),
-        Tab::new("static_data.rs")
-            .title("static_data.rs".to_string())
-            .icon(Icon::FileRust)
-            .current(true)
-            .git_status(GitStatus::Modified),
-    ]
-}
-
-pub fn static_tabs_3() -> Vec<Tab> {
-    vec![Tab::new("static_tabs_3")
-        .git_status(GitStatus::Created)
-        .current(true)]
-}
-
-pub fn static_players() -> Vec<Player> {
-    vec![
-        Player::new(
-            0,
-            "https://avatars.githubusercontent.com/u/1714999?v=4".into(),
-            "nathansobo".into(),
-        ),
-        Player::new(
-            1,
-            "https://avatars.githubusercontent.com/u/326587?v=4".into(),
-            "maxbrunsfeld".into(),
-        ),
-        Player::new(
-            2,
-            "https://avatars.githubusercontent.com/u/482957?v=4".into(),
-            "as-cii".into(),
-        ),
-        Player::new(
-            3,
-            "https://avatars.githubusercontent.com/u/1714999?v=4".into(),
-            "iamnbutler".into(),
-        ),
-        Player::new(
-            4,
-            "https://avatars.githubusercontent.com/u/1486634?v=4".into(),
-            "maxdeviant".into(),
-        ),
-    ]
-}
-
-#[derive(Debug)]
-pub struct PlayerData {
-    pub url: String,
-    pub name: String,
-}
-
-pub fn static_player_data() -> Vec<PlayerData> {
-    vec![
-        PlayerData {
-            url: "https://avatars.githubusercontent.com/u/1714999?v=4".into(),
-            name: "iamnbutler".into(),
-        },
-        PlayerData {
-            url: "https://avatars.githubusercontent.com/u/326587?v=4".into(),
-            name: "maxbrunsfeld".into(),
-        },
-        PlayerData {
-            url: "https://avatars.githubusercontent.com/u/482957?v=4".into(),
-            name: "as-cii".into(),
-        },
-        PlayerData {
-            url: "https://avatars.githubusercontent.com/u/1789?v=4".into(),
-            name: "nathansobo".into(),
-        },
-        PlayerData {
-            url: "https://avatars.githubusercontent.com/u/1486634?v=4".into(),
-            name: "ForLoveOfCats".into(),
-        },
-        PlayerData {
-            url: "https://avatars.githubusercontent.com/u/2690773?v=4".into(),
-            name: "SomeoneToIgnore".into(),
-        },
-        PlayerData {
-            url: "https://avatars.githubusercontent.com/u/19867440?v=4".into(),
-            name: "JosephTLyons".into(),
-        },
-        PlayerData {
-            url: "https://avatars.githubusercontent.com/u/24362066?v=4".into(),
-            name: "osiewicz".into(),
-        },
-        PlayerData {
-            url: "https://avatars.githubusercontent.com/u/22121886?v=4".into(),
-            name: "KCaverly".into(),
-        },
-        PlayerData {
-            url: "https://avatars.githubusercontent.com/u/1486634?v=4".into(),
-            name: "maxdeviant".into(),
-        },
-    ]
-}
-
-pub fn create_static_players(player_data: Vec<PlayerData>) -> Vec<Player> {
-    let mut players = Vec::new();
-    for data in player_data {
-        players.push(Player::new(players.len(), data.url, data.name));
-    }
-    players
-}
-
-pub fn static_player_1(data: &Vec<PlayerData>) -> Player {
-    Player::new(1, data[0].url.clone(), data[0].name.clone())
-}
-
-pub fn static_player_2(data: &Vec<PlayerData>) -> Player {
-    Player::new(2, data[1].url.clone(), data[1].name.clone())
-}
-
-pub fn static_player_3(data: &Vec<PlayerData>) -> Player {
-    Player::new(3, data[2].url.clone(), data[2].name.clone())
-}
-
-pub fn static_player_4(data: &Vec<PlayerData>) -> Player {
-    Player::new(4, data[3].url.clone(), data[3].name.clone())
-}
-
-pub fn static_player_5(data: &Vec<PlayerData>) -> Player {
-    Player::new(5, data[4].url.clone(), data[4].name.clone())
-}
-
-pub fn static_player_6(data: &Vec<PlayerData>) -> Player {
-    Player::new(6, data[5].url.clone(), data[5].name.clone())
-}
-
-pub fn static_player_7(data: &Vec<PlayerData>) -> Player {
-    Player::new(7, data[6].url.clone(), data[6].name.clone())
-}
-
-pub fn static_player_8(data: &Vec<PlayerData>) -> Player {
-    Player::new(8, data[7].url.clone(), data[7].name.clone())
-}
-
-pub fn static_player_9(data: &Vec<PlayerData>) -> Player {
-    Player::new(9, data[8].url.clone(), data[8].name.clone())
-}
-
-pub fn static_player_10(data: &Vec<PlayerData>) -> Player {
-    Player::new(10, data[9].url.clone(), data[9].name.clone())
-}
-
-pub fn static_livestream() -> Livestream {
-    Livestream {
-        players: random_players_with_call_status(7),
-        channel: Some("gpui2-ui".to_string()),
-    }
-}
-
-pub fn populate_player_call_status(
-    player: Player,
-    followers: Option<Vec<Player>>,
-) -> PlayerCallStatus {
-    let mut rng = rand::thread_rng();
-    let in_current_project: bool = rng.gen();
-    let disconnected: bool = rng.gen();
-    let voice_activity: f32 = rng.gen();
-    let mic_status = if rng.gen_bool(0.5) {
-        MicStatus::Muted
-    } else {
-        MicStatus::Unmuted
-    };
-    let video_status = if rng.gen_bool(0.5) {
-        VideoStatus::On
-    } else {
-        VideoStatus::Off
-    };
-    let screen_share_status = if rng.gen_bool(0.5) {
-        ScreenShareStatus::Shared
-    } else {
-        ScreenShareStatus::NotShared
-    };
-    PlayerCallStatus {
-        mic_status,
-        voice_activity,
-        video_status,
-        screen_share_status,
-        in_current_project,
-        disconnected,
-        following: None,
-        followers,
-    }
-}
-
-pub fn random_players_with_call_status(number_of_players: usize) -> Vec<PlayerWithCallStatus> {
-    let players = create_static_players(static_player_data());
-    let mut player_status = vec![];
-    for i in 0..number_of_players {
-        let followers = if i == 0 {
-            Some(vec![
-                players[1].clone(),
-                players[3].clone(),
-                players[5].clone(),
-                players[6].clone(),
-            ])
-        } else if i == 1 {
-            Some(vec![players[2].clone(), players[6].clone()])
-        } else {
-            None
-        };
-        let call_status = populate_player_call_status(players[i].clone(), followers);
-        player_status.push(PlayerWithCallStatus::new(players[i].clone(), call_status));
-    }
-    player_status
-}
-
-pub fn static_players_with_call_status() -> Vec<PlayerWithCallStatus> {
-    let players = static_players();
-    let mut player_0_status = PlayerCallStatus::new();
-    let player_1_status = PlayerCallStatus::new();
-    let player_2_status = PlayerCallStatus::new();
-    let mut player_3_status = PlayerCallStatus::new();
-    let mut player_4_status = PlayerCallStatus::new();
-
-    player_0_status.screen_share_status = ScreenShareStatus::Shared;
-    player_0_status.followers = Some(vec![players[1].clone(), players[3].clone()]);
-
-    player_3_status.voice_activity = 0.5;
-    player_4_status.mic_status = MicStatus::Muted;
-    player_4_status.in_current_project = false;
-
-    vec![
-        PlayerWithCallStatus::new(players[0].clone(), player_0_status),
-        PlayerWithCallStatus::new(players[1].clone(), player_1_status),
-        PlayerWithCallStatus::new(players[2].clone(), player_2_status),
-        PlayerWithCallStatus::new(players[3].clone(), player_3_status),
-        PlayerWithCallStatus::new(players[4].clone(), player_4_status),
-    ]
-}
-
-pub fn static_new_notification_items_2<V: 'static>() -> Vec<Notification<V>> {
-    vec![
-        Notification::new_icon_message(
-            "notif-1",
-            "You were mentioned in a note.",
-            DateTime::parse_from_rfc3339("2023-11-02T11:59:57Z")
-                .unwrap()
-                .naive_local(),
-            Icon::AtSign,
-            Arc::new(|_, _| {}),
-        ),
-        Notification::new_actor_with_actions(
-            "notif-2",
-            "as-cii sent you a contact request.",
-            DateTime::parse_from_rfc3339("2023-11-02T12:09:07Z")
-                .unwrap()
-                .naive_local(),
-            PublicPlayer::new("as-cii", "http://github.com/as-cii.png?s=50"),
-            [
-                NotificationAction::new(
-                    Button::new("Decline"),
-                    "Decline Request",
-                    (Some(Icon::XCircle), "Declined"),
-                ),
-                NotificationAction::new(
-                    Button::new("Accept").variant(crate::ButtonVariant::Filled),
-                    "Accept Request",
-                    (Some(Icon::Check), "Accepted"),
-                ),
-            ],
-        ),
-        Notification::new_icon_message(
-            "notif-3",
-            "You were mentioned #design.",
-            DateTime::parse_from_rfc3339("2023-11-02T12:09:07Z")
-                .unwrap()
-                .naive_local(),
-            Icon::MessageBubbles,
-            Arc::new(|_, _| {}),
-        ),
-        Notification::new_actor_with_actions(
-            "notif-4",
-            "as-cii sent you a contact request.",
-            DateTime::parse_from_rfc3339("2023-11-01T12:09:07Z")
-                .unwrap()
-                .naive_local(),
-            PublicPlayer::new("as-cii", "http://github.com/as-cii.png?s=50"),
-            [
-                NotificationAction::new(
-                    Button::new("Decline"),
-                    "Decline Request",
-                    (Some(Icon::XCircle), "Declined"),
-                ),
-                NotificationAction::new(
-                    Button::new("Accept").variant(crate::ButtonVariant::Filled),
-                    "Accept Request",
-                    (Some(Icon::Check), "Accepted"),
-                ),
-            ],
-        ),
-        Notification::new_icon_message(
-            "notif-5",
-            "You were mentioned in a note.",
-            DateTime::parse_from_rfc3339("2023-10-28T12:09:07Z")
-                .unwrap()
-                .naive_local(),
-            Icon::AtSign,
-            Arc::new(|_, _| {}),
-        ),
-        Notification::new_actor_with_actions(
-            "notif-6",
-            "as-cii sent you a contact request.",
-            DateTime::parse_from_rfc3339("2022-10-25T12:09:07Z")
-                .unwrap()
-                .naive_local(),
-            PublicPlayer::new("as-cii", "http://github.com/as-cii.png?s=50"),
-            [
-                NotificationAction::new(
-                    Button::new("Decline"),
-                    "Decline Request",
-                    (Some(Icon::XCircle), "Declined"),
-                ),
-                NotificationAction::new(
-                    Button::new("Accept").variant(crate::ButtonVariant::Filled),
-                    "Accept Request",
-                    (Some(Icon::Check), "Accepted"),
-                ),
-            ],
-        ),
-        Notification::new_icon_message(
-            "notif-7",
-            "You were mentioned in a note.",
-            DateTime::parse_from_rfc3339("2022-10-14T12:09:07Z")
-                .unwrap()
-                .naive_local(),
-            Icon::AtSign,
-            Arc::new(|_, _| {}),
-        ),
-        Notification::new_actor_with_actions(
-            "notif-8",
-            "as-cii sent you a contact request.",
-            DateTime::parse_from_rfc3339("2021-10-12T12:09:07Z")
-                .unwrap()
-                .naive_local(),
-            PublicPlayer::new("as-cii", "http://github.com/as-cii.png?s=50"),
-            [
-                NotificationAction::new(
-                    Button::new("Decline"),
-                    "Decline Request",
-                    (Some(Icon::XCircle), "Declined"),
-                ),
-                NotificationAction::new(
-                    Button::new("Accept").variant(crate::ButtonVariant::Filled),
-                    "Accept Request",
-                    (Some(Icon::Check), "Accepted"),
-                ),
-            ],
-        ),
-        Notification::new_icon_message(
-            "notif-9",
-            "You were mentioned in a note.",
-            DateTime::parse_from_rfc3339("2021-02-02T12:09:07Z")
-                .unwrap()
-                .naive_local(),
-            Icon::AtSign,
-            Arc::new(|_, _| {}),
-        ),
-        Notification::new_actor_with_actions(
-            "notif-10",
-            "as-cii sent you a contact request.",
-            DateTime::parse_from_rfc3339("1969-07-20T00:00:00Z")
-                .unwrap()
-                .naive_local(),
-            PublicPlayer::new("as-cii", "http://github.com/as-cii.png?s=50"),
-            [
-                NotificationAction::new(
-                    Button::new("Decline"),
-                    "Decline Request",
-                    (Some(Icon::XCircle), "Declined"),
-                ),
-                NotificationAction::new(
-                    Button::new("Accept").variant(crate::ButtonVariant::Filled),
-                    "Accept Request",
-                    (Some(Icon::Check), "Accepted"),
-                ),
-            ],
-        ),
-    ]
-}
-
-pub fn static_project_panel_project_items<V>() -> Vec<ListItem<V>> {
-    vec![
-        ListItem::new("zed", Label::new("zed"))
-            .left_icon(Icon::FolderOpen.into())
-            .indent_level(0)
-            .toggle(Toggle::Toggled(true)),
-        ListItem::new(".cargo", Label::new(".cargo"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(1),
-        ListItem::new(".config", Label::new(".config"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(1),
-        ListItem::new(".git", Label::new(".git").color(TextColor::Hidden))
-            .left_icon(Icon::Folder.into())
-            .indent_level(1),
-        ListItem::new(".cargo", Label::new(".cargo"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(1),
-        ListItem::new(".idea", Label::new(".idea").color(TextColor::Hidden))
-            .left_icon(Icon::Folder.into())
-            .indent_level(1),
-        ListItem::new("assets", Label::new("assets"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(1)
-            .toggle(Toggle::Toggled(true)),
-        ListItem::new(
-            "cargo-target",
-            Label::new("cargo-target").color(TextColor::Hidden),
-        )
-        .left_icon(Icon::Folder.into())
-        .indent_level(1),
-        ListItem::new("crates", Label::new("crates"))
-            .left_icon(Icon::FolderOpen.into())
-            .indent_level(1)
-            .toggle(Toggle::Toggled(true)),
-        ListItem::new("activity_indicator", Label::new("activity_indicator"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2),
-        ListItem::new("ai", Label::new("ai"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2),
-        ListItem::new("audio", Label::new("audio"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2),
-        ListItem::new("auto_update", Label::new("auto_update"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2),
-        ListItem::new("breadcrumbs", Label::new("breadcrumbs"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2),
-        ListItem::new("call", Label::new("call"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2),
-        ListItem::new("sqlez", Label::new("sqlez").color(TextColor::Modified))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2)
-            .toggle(Toggle::Toggled(false)),
-        ListItem::new("gpui2", Label::new("gpui2"))
-            .left_icon(Icon::FolderOpen.into())
-            .indent_level(2)
-            .toggle(Toggle::Toggled(true)),
-        ListItem::new("src", Label::new("src"))
-            .left_icon(Icon::FolderOpen.into())
-            .indent_level(3)
-            .toggle(Toggle::Toggled(true)),
-        ListItem::new("derive_element.rs", Label::new("derive_element.rs"))
-            .left_icon(Icon::FileRust.into())
-            .indent_level(4),
-        ListItem::new(
-            "storybook",
-            Label::new("storybook").color(TextColor::Modified),
-        )
-        .left_icon(Icon::FolderOpen.into())
-        .indent_level(1)
-        .toggle(Toggle::Toggled(true)),
-        ListItem::new("docs", Label::new("docs").color(TextColor::Default))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2)
-            .toggle(Toggle::Toggled(true)),
-        ListItem::new("src", Label::new("src").color(TextColor::Modified))
-            .left_icon(Icon::FolderOpen.into())
-            .indent_level(3)
-            .toggle(Toggle::Toggled(true)),
-        ListItem::new("ui", Label::new("ui").color(TextColor::Modified))
-            .left_icon(Icon::FolderOpen.into())
-            .indent_level(4)
-            .toggle(Toggle::Toggled(true)),
-        ListItem::new(
-            "component",
-            Label::new("component").color(TextColor::Created),
-        )
-        .left_icon(Icon::FolderOpen.into())
-        .indent_level(5)
-        .toggle(Toggle::Toggled(true)),
-        ListItem::new(
-            "facepile.rs",
-            Label::new("facepile.rs").color(TextColor::Default),
-        )
-        .left_icon(Icon::FileRust.into())
-        .indent_level(6),
-        ListItem::new(
-            "follow_group.rs",
-            Label::new("follow_group.rs").color(TextColor::Default),
-        )
-        .left_icon(Icon::FileRust.into())
-        .indent_level(6),
-        ListItem::new(
-            "list_item.rs",
-            Label::new("list_item.rs").color(TextColor::Created),
-        )
-        .left_icon(Icon::FileRust.into())
-        .indent_level(6),
-        ListItem::new("tab.rs", Label::new("tab.rs").color(TextColor::Default))
-            .left_icon(Icon::FileRust.into())
-            .indent_level(6),
-        ListItem::new("target", Label::new("target").color(TextColor::Hidden))
-            .left_icon(Icon::Folder.into())
-            .indent_level(1),
-        ListItem::new(".dockerignore", Label::new(".dockerignore"))
-            .left_icon(Icon::FileGeneric.into())
-            .indent_level(1),
-        ListItem::new(
-            ".DS_Store",
-            Label::new(".DS_Store").color(TextColor::Hidden),
-        )
-        .left_icon(Icon::FileGeneric.into())
-        .indent_level(1),
-        ListItem::new("Cargo.lock", Label::new("Cargo.lock"))
-            .left_icon(Icon::FileLock.into())
-            .indent_level(1),
-        ListItem::new("Cargo.toml", Label::new("Cargo.toml"))
-            .left_icon(Icon::FileToml.into())
-            .indent_level(1),
-        ListItem::new("Dockerfile", Label::new("Dockerfile"))
-            .left_icon(Icon::FileGeneric.into())
-            .indent_level(1),
-        ListItem::new("Procfile", Label::new("Procfile"))
-            .left_icon(Icon::FileGeneric.into())
-            .indent_level(1),
-        ListItem::new("README.md", Label::new("README.md"))
-            .left_icon(Icon::FileDoc.into())
-            .indent_level(1),
-    ]
-}
-
-pub fn static_project_panel_single_items<V>() -> Vec<ListItem<V>> {
-    vec![
-        ListItem::new("todo.md", Label::new("todo.md"))
-            .left_icon(Icon::FileDoc.into())
-            .indent_level(0),
-        ListItem::new("README.md", Label::new("README.md"))
-            .left_icon(Icon::FileDoc.into())
-            .indent_level(0),
-        ListItem::new("config.json", Label::new("config.json"))
-            .left_icon(Icon::FileGeneric.into())
-            .indent_level(0),
-    ]
-}
-
-pub fn static_collab_panel_current_call<V>() -> Vec<ListItem<V>> {
-    vec![
-        ListItem::new("as-cii", Label::new("as-cii"))
-            .left_avatar("http://github.com/as-cii.png?s=50"),
-        ListItem::new("nathansobo", Label::new("nathansobo"))
-            .left_avatar("http://github.com/nathansobo.png?s=50"),
-        ListItem::new("maxbrunsfeld", Label::new("maxbrunsfeld"))
-            .left_avatar("http://github.com/maxbrunsfeld.png?s=50"),
-    ]
-}
-
-pub fn static_collab_panel_channels<V>() -> Vec<ListItem<V>> {
-    vec![
-        ListItem::new("zed", Label::new("zed"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(0),
-        ListItem::new("community", Label::new("community"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(1),
-        ListItem::new("dashboards", Label::new("dashboards"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListItem::new("feedback", Label::new("feedback"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListItem::new(
-            "teams-in-channels-alpha",
-            Label::new("teams-in-channels-alpha"),
-        )
-        .left_icon(Icon::Hash.into())
-        .size(ListEntrySize::Medium)
-        .indent_level(2),
-        ListItem::new("current-projects", Label::new("current-projects"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(1),
-        ListItem::new("codegen", Label::new("codegen"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListItem::new("gpui2", Label::new("gpui2"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListItem::new("livestreaming", Label::new("livestreaming"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListItem::new("open-source", Label::new("open-source"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListItem::new("replace", Label::new("replace"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListItem::new("semantic-index", Label::new("semantic-index"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListItem::new("vim", Label::new("vim"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListItem::new("web-tech", Label::new("web-tech"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-    ]
-}
-
-pub fn example_editor_actions() -> Vec<PaletteItem> {
-    vec![
-        PaletteItem::new("New File").key_binding(KeyBinding::new(binding("cmd-n"))),
-        PaletteItem::new("Open File").key_binding(KeyBinding::new(binding("cmd-o"))),
-        PaletteItem::new("Save File").key_binding(KeyBinding::new(binding("cmd-s"))),
-        PaletteItem::new("Cut").key_binding(KeyBinding::new(binding("cmd-x"))),
-        PaletteItem::new("Copy").key_binding(KeyBinding::new(binding("cmd-c"))),
-        PaletteItem::new("Paste").key_binding(KeyBinding::new(binding("cmd-v"))),
-        PaletteItem::new("Undo").key_binding(KeyBinding::new(binding("cmd-z"))),
-        PaletteItem::new("Redo").key_binding(KeyBinding::new(binding("cmd-shift-z"))),
-        PaletteItem::new("Find").key_binding(KeyBinding::new(binding("cmd-f"))),
-        PaletteItem::new("Replace").key_binding(KeyBinding::new(binding("cmd-r"))),
-        PaletteItem::new("Jump to Line"),
-        PaletteItem::new("Select All"),
-        PaletteItem::new("Deselect All"),
-        PaletteItem::new("Switch Document"),
-        PaletteItem::new("Insert Line Below"),
-        PaletteItem::new("Insert Line Above"),
-        PaletteItem::new("Move Line Up"),
-        PaletteItem::new("Move Line Down"),
-        PaletteItem::new("Toggle Comment"),
-        PaletteItem::new("Delete Line"),
-    ]
-}
-
-pub fn empty_editor_example(cx: &mut ViewContext<EditorPane>) -> EditorPane {
-    EditorPane::new(
-        cx,
-        static_tabs_example(),
-        PathBuf::from_str("crates/ui/src/static_data.rs").unwrap(),
-        vec![],
-        empty_buffer_example(),
-    )
-}
-
-pub fn empty_buffer_example() -> Buffer {
-    Buffer::new("empty-buffer").set_rows(Some(BufferRows::default()))
-}
-
-pub fn hello_world_rust_editor_example(cx: &mut ViewContext<EditorPane>) -> EditorPane {
-    EditorPane::new(
-        cx,
-        static_tabs_example(),
-        PathBuf::from_str("crates/ui/src/static_data.rs").unwrap(),
-        vec![Symbol(vec![
-            HighlightedText {
-                text: "fn ".into(),
-                color: cx.theme().syntax_color("keyword"),
-            },
-            HighlightedText {
-                text: "main".into(),
-                color: cx.theme().syntax_color("function"),
-            },
-        ])],
-        hello_world_rust_buffer_example(cx),
-    )
-}
-
-pub fn hello_world_rust_buffer_example(cx: &AppContext) -> Buffer {
-    Buffer::new("hello-world-rust-buffer")
-        .set_title("hello_world.rs".to_string())
-        .set_path("src/hello_world.rs".to_string())
-        .set_language("rust".to_string())
-        .set_rows(Some(BufferRows {
-            show_line_numbers: true,
-            rows: hello_world_rust_buffer_rows(cx),
-        }))
-}
-
-pub fn hello_world_rust_buffer_rows(cx: &AppContext) -> Vec<BufferRow> {
-    let show_line_number = true;
-
-    vec![
-        BufferRow {
-            line_number: 1,
-            code_action: false,
-            current: true,
-            line: Some(HighlightedLine {
-                highlighted_texts: vec![
-                    HighlightedText {
-                        text: "fn ".into(),
-                        color: cx.theme().syntax_color("keyword"),
-                    },
-                    HighlightedText {
-                        text: "main".into(),
-                        color: cx.theme().syntax_color("function"),
-                    },
-                    HighlightedText {
-                        text: "() {".into(),
-                        color: cx.theme().colors().text,
-                    },
-                ],
-            }),
-            cursors: None,
-            status: GitStatus::None,
-            show_line_number,
-        },
-        BufferRow {
-            line_number: 2,
-            code_action: false,
-            current: false,
-            line: Some(HighlightedLine {
-                highlighted_texts: vec![HighlightedText {
-                    text: "    // Statements here are executed when the compiled binary is called."
-                        .into(),
-                    color: cx.theme().syntax_color("comment"),
-                }],
-            }),
-            cursors: None,
-            status: GitStatus::None,
-            show_line_number,
-        },
-        BufferRow {
-            line_number: 3,
-            code_action: false,
-            current: false,
-            line: None,
-            cursors: None,
-            status: GitStatus::None,
-            show_line_number,
-        },
-        BufferRow {
-            line_number: 4,
-            code_action: false,
-            current: false,
-            line: Some(HighlightedLine {
-                highlighted_texts: vec![HighlightedText {
-                    text: "    // Print text to the console.".into(),
-                    color: cx.theme().syntax_color("comment"),
-                }],
-            }),
-            cursors: None,
-            status: GitStatus::None,
-            show_line_number,
-        },
-        BufferRow {
-            line_number: 5,
-            code_action: false,
-            current: false,
-            line: Some(HighlightedLine {
-                highlighted_texts: vec![
-                    HighlightedText {
-                        text: "    println!(".into(),
-                        color: cx.theme().colors().text,
-                    },
-                    HighlightedText {
-                        text: "\"Hello, world!\"".into(),
-                        color: cx.theme().syntax_color("string"),
-                    },
-                    HighlightedText {
-                        text: ");".into(),
-                        color: cx.theme().colors().text,
-                    },
-                ],
-            }),
-            cursors: None,
-            status: GitStatus::None,
-            show_line_number,
-        },
-        BufferRow {
-            line_number: 6,
-            code_action: false,
-            current: false,
-            line: Some(HighlightedLine {
-                highlighted_texts: vec![HighlightedText {
-                    text: "}".into(),
-                    color: cx.theme().colors().text,
-                }],
-            }),
-            cursors: None,
-            status: GitStatus::None,
-            show_line_number,
-        },
-    ]
-}
-
-pub fn hello_world_rust_editor_with_status_example(cx: &mut ViewContext<EditorPane>) -> EditorPane {
-    EditorPane::new(
-        cx,
-        static_tabs_example(),
-        PathBuf::from_str("crates/ui/src/static_data.rs").unwrap(),
-        vec![Symbol(vec![
-            HighlightedText {
-                text: "fn ".into(),
-                color: cx.theme().syntax_color("keyword"),
-            },
-            HighlightedText {
-                text: "main".into(),
-                color: cx.theme().syntax_color("function"),
-            },
-        ])],
-        hello_world_rust_buffer_with_status_example(cx),
-    )
-}
-
-pub fn hello_world_rust_buffer_with_status_example(cx: &AppContext) -> Buffer {
-    Buffer::new("hello-world-rust-buffer-with-status")
-        .set_title("hello_world.rs".to_string())
-        .set_path("src/hello_world.rs".to_string())
-        .set_language("rust".to_string())
-        .set_rows(Some(BufferRows {
-            show_line_numbers: true,
-            rows: hello_world_rust_with_status_buffer_rows(cx),
-        }))
-}
-
-pub fn hello_world_rust_with_status_buffer_rows(cx: &AppContext) -> Vec<BufferRow> {
-    let show_line_number = true;
-
-    vec![
-        BufferRow {
-            line_number: 1,
-            code_action: false,
-            current: true,
-            line: Some(HighlightedLine {
-                highlighted_texts: vec![
-                    HighlightedText {
-                        text: "fn ".into(),
-                        color: cx.theme().syntax_color("keyword"),
-                    },
-                    HighlightedText {
-                        text: "main".into(),
-                        color: cx.theme().syntax_color("function"),
-                    },
-                    HighlightedText {
-                        text: "() {".into(),
-                        color: cx.theme().colors().text,
-                    },
-                ],
-            }),
-            cursors: None,
-            status: GitStatus::None,
-            show_line_number,
-        },
-        BufferRow {
-            line_number: 2,
-            code_action: false,
-            current: false,
-            line: Some(HighlightedLine {
-                highlighted_texts: vec![HighlightedText {
-                    text: "// Statements here are executed when the compiled binary is called."
-                        .into(),
-                    color: cx.theme().syntax_color("comment"),
-                }],
-            }),
-            cursors: None,
-            status: GitStatus::Modified,
-            show_line_number,
-        },
-        BufferRow {
-            line_number: 3,
-            code_action: false,
-            current: false,
-            line: None,
-            cursors: None,
-            status: GitStatus::None,
-            show_line_number,
-        },
-        BufferRow {
-            line_number: 4,
-            code_action: false,
-            current: false,
-            line: Some(HighlightedLine {
-                highlighted_texts: vec![HighlightedText {
-                    text: "    // Print text to the console.".into(),
-                    color: cx.theme().syntax_color("comment"),
-                }],
-            }),
-            cursors: None,
-            status: GitStatus::None,
-            show_line_number,
-        },
-        BufferRow {
-            line_number: 5,
-            code_action: false,
-            current: false,
-            line: Some(HighlightedLine {
-                highlighted_texts: vec![
-                    HighlightedText {
-                        text: "    println!(".into(),
-                        color: cx.theme().colors().text,
-                    },
-                    HighlightedText {
-                        text: "\"Hello, world!\"".into(),
-                        color: cx.theme().syntax_color("string"),
-                    },
-                    HighlightedText {
-                        text: ");".into(),
-                        color: cx.theme().colors().text,
-                    },
-                ],
-            }),
-            cursors: None,
-            status: GitStatus::None,
-            show_line_number,
-        },
-        BufferRow {
-            line_number: 6,
-            code_action: false,
-            current: false,
-            line: Some(HighlightedLine {
-                highlighted_texts: vec![HighlightedText {
-                    text: "}".into(),
-                    color: cx.theme().colors().text,
-                }],
-            }),
-            cursors: None,
-            status: GitStatus::None,
-            show_line_number,
-        },
-        BufferRow {
-            line_number: 7,
-            code_action: false,
-            current: false,
-            line: Some(HighlightedLine {
-                highlighted_texts: vec![HighlightedText {
-                    text: "".into(),
-                    color: cx.theme().colors().text,
-                }],
-            }),
-            cursors: None,
-            status: GitStatus::Created,
-            show_line_number,
-        },
-        BufferRow {
-            line_number: 8,
-            code_action: false,
-            current: false,
-            line: Some(HighlightedLine {
-                highlighted_texts: vec![HighlightedText {
-                    text: "// Marshall and Nate were here".into(),
-                    color: cx.theme().syntax_color("comment"),
-                }],
-            }),
-            cursors: None,
-            status: GitStatus::Created,
-            show_line_number,
-        },
-    ]
-}
-
-pub fn terminal_buffer(cx: &AppContext) -> Buffer {
-    Buffer::new("terminal")
-        .set_title(Some("zed — fish".into()))
-        .set_rows(Some(BufferRows {
-            show_line_numbers: false,
-            rows: terminal_buffer_rows(cx),
-        }))
-}
-
-pub fn terminal_buffer_rows(cx: &AppContext) -> Vec<BufferRow> {
-    let show_line_number = false;
-
-    vec![
-        BufferRow {
-            line_number: 1,
-            code_action: false,
-            current: false,
-            line: Some(HighlightedLine {
-                highlighted_texts: vec![
-                    HighlightedText {
-                        text: "maxdeviant ".into(),
-                        color: cx.theme().syntax_color("keyword"),
-                    },
-                    HighlightedText {
-                        text: "in ".into(),
-                        color: cx.theme().colors().text,
-                    },
-                    HighlightedText {
-                        text: "profaned-capital ".into(),
-                        color: cx.theme().syntax_color("function"),
-                    },
-                    HighlightedText {
-                        text: "in ".into(),
-                        color: cx.theme().colors().text,
-                    },
-                    HighlightedText {
-                        text: "~/p/zed ".into(),
-                        color: cx.theme().syntax_color("function"),
-                    },
-                    HighlightedText {
-                        text: "on ".into(),
-                        color: cx.theme().colors().text,
-                    },
-                    HighlightedText {
-                        text: " gpui2-ui ".into(),
-                        color: cx.theme().syntax_color("keyword"),
-                    },
-                ],
-            }),
-            cursors: None,
-            status: GitStatus::None,
-            show_line_number,
-        },
-        BufferRow {
-            line_number: 2,
-            code_action: false,
-            current: false,
-            line: Some(HighlightedLine {
-                highlighted_texts: vec![HighlightedText {
-                    text: "λ ".into(),
-                    color: cx.theme().syntax_color("string"),
-                }],
-            }),
-            cursors: None,
-            status: GitStatus::None,
-            show_line_number,
-        },
-    ]
-}

crates/ui2/src/story.rs 🔗

@@ -5,7 +5,7 @@ use crate::prelude::*;
 pub struct Story {}
 
 impl Story {
-    pub fn container<V: 'static>(cx: &mut ViewContext<V>) -> Div<V> {
+    pub fn container(cx: &mut gpui::WindowContext) -> Div {
         div()
             .size_full()
             .flex()
@@ -15,24 +15,18 @@ impl Story {
             .bg(cx.theme().colors().background)
     }
 
-    pub fn title<V: 'static>(
-        cx: &mut ViewContext<V>,
-        title: impl Into<SharedString>,
-    ) -> impl Element<V> {
+    pub fn title(cx: &mut WindowContext, title: impl Into<SharedString>) -> impl Element {
         div()
             .text_xl()
             .text_color(cx.theme().colors().text)
             .child(title.into())
     }
 
-    pub fn title_for<V: 'static, T>(cx: &mut ViewContext<V>) -> impl Element<V> {
+    pub fn title_for<T>(cx: &mut WindowContext) -> impl Element {
         Self::title(cx, std::any::type_name::<T>())
     }
 
-    pub fn label<V: 'static>(
-        cx: &mut ViewContext<V>,
-        label: impl Into<SharedString>,
-    ) -> impl Element<V> {
+    pub fn label(cx: &mut WindowContext, label: impl Into<SharedString>) -> impl Element {
         div()
             .mt_4()
             .mb_2()

crates/ui2/src/styled_ext.rs 🔗

@@ -1,9 +1,9 @@
-use gpui::{Styled, ViewContext};
+use gpui::{Styled, WindowContext};
 use theme2::ActiveTheme;
 
 use crate::{ElevationIndex, UITextSize};
 
-fn elevated<E: Styled, V: 'static>(this: E, cx: &mut ViewContext<V>, index: ElevationIndex) -> E {
+fn elevated<E: Styled>(this: E, cx: &mut WindowContext, index: ElevationIndex) -> E {
     this.bg(cx.theme().colors().elevated_surface_background)
         .z_index(index.z_index())
         .rounded_lg()
@@ -65,7 +65,7 @@ pub trait StyledExt: Styled + Sized {
     /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`
     ///
     /// Example Elements: Title Bar, Panel, Tab Bar, Editor
-    fn elevation_1<V: 'static>(self, cx: &mut ViewContext<V>) -> Self {
+    fn elevation_1(self, cx: &mut WindowContext) -> Self {
         elevated(self, cx, ElevationIndex::Surface)
     }
 
@@ -74,7 +74,7 @@ pub trait StyledExt: Styled + Sized {
     /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`
     ///
     /// Examples: Notifications, Palettes, Detached/Floating Windows, Detached/Floating Panels
-    fn elevation_2<V: 'static>(self, cx: &mut ViewContext<V>) -> Self {
+    fn elevation_2(self, cx: &mut WindowContext) -> Self {
         elevated(self, cx, ElevationIndex::ElevatedSurface)
     }
 
@@ -89,7 +89,7 @@ pub trait StyledExt: Styled + Sized {
     /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`
     ///
     /// Examples: Settings Modal, Channel Management, Wizards/Setup UI, Dialogs
-    fn elevation_4<V: 'static>(self, cx: &mut ViewContext<V>) -> Self {
+    fn elevation_4(self, cx: &mut WindowContext) -> Self {
         elevated(self, cx, ElevationIndex::ModalSurface)
     }
 }

crates/ui2/src/to_extract.rs 🔗

@@ -1,47 +0,0 @@
-mod assistant_panel;
-mod breadcrumb;
-mod buffer;
-mod buffer_search;
-mod chat_panel;
-mod collab_panel;
-mod command_palette;
-mod copilot;
-mod editor_pane;
-mod language_selector;
-mod multi_buffer;
-mod notifications_panel;
-mod panes;
-mod project_panel;
-mod recent_projects;
-mod status_bar;
-mod tab_bar;
-mod terminal;
-mod theme_selector;
-mod title_bar;
-mod toolbar;
-mod traffic_lights;
-mod workspace;
-
-pub use assistant_panel::*;
-pub use breadcrumb::*;
-pub use buffer::*;
-pub use buffer_search::*;
-pub use chat_panel::*;
-pub use collab_panel::*;
-pub use command_palette::*;
-pub use copilot::*;
-pub use editor_pane::*;
-pub use language_selector::*;
-pub use multi_buffer::*;
-pub use notifications_panel::*;
-pub use panes::*;
-pub use project_panel::*;
-pub use recent_projects::*;
-pub use status_bar::*;
-pub use tab_bar::*;
-pub use terminal::*;
-pub use theme_selector::*;
-pub use title_bar::*;
-pub use toolbar::*;
-pub use traffic_lights::*;
-pub use workspace::*;

crates/ui2/src/to_extract/assistant_panel.rs 🔗

@@ -1,97 +0,0 @@
-use crate::prelude::*;
-use crate::{Icon, IconButton, Label, Panel, PanelSide};
-use gpui::{prelude::*, rems, AbsoluteLength, RenderOnce};
-
-#[derive(RenderOnce)]
-pub struct AssistantPanel {
-    id: ElementId,
-    current_side: PanelSide,
-}
-
-impl<V: 'static> Component<V> for AssistantPanel {
-    type Rendered = Panel<V>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        Panel::new(self.id.clone(), cx)
-            .children(vec![div()
-                .flex()
-                .flex_col()
-                .h_full()
-                .px_2()
-                .gap_2()
-                // Header
-                .child(
-                    div()
-                        .flex()
-                        .justify_between()
-                        .gap_2()
-                        .child(
-                            div()
-                                .flex()
-                                .child(IconButton::new("menu", Icon::Menu))
-                                .child(Label::new("New Conversation")),
-                        )
-                        .child(
-                            div()
-                                .flex()
-                                .items_center()
-                                .gap_px()
-                                .child(IconButton::new("split_message", Icon::SplitMessage))
-                                .child(IconButton::new("quote", Icon::Quote))
-                                .child(IconButton::new("magic_wand", Icon::MagicWand))
-                                .child(IconButton::new("plus", Icon::Plus))
-                                .child(IconButton::new("maximize", Icon::Maximize)),
-                        ),
-                )
-                // Chat Body
-                .child(
-                    div()
-                        .id("chat-body")
-                        .w_full()
-                        .flex()
-                        .flex_col()
-                        .gap_3()
-                        .overflow_y_scroll()
-                        .child(Label::new("Is this thing on?")),
-                )
-                .into_any()])
-            .side(self.current_side)
-            .width(AbsoluteLength::Rems(rems(32.)))
-    }
-}
-
-impl AssistantPanel {
-    pub fn new(id: impl Into<ElementId>) -> Self {
-        Self {
-            id: id.into(),
-            current_side: PanelSide::default(),
-        }
-    }
-
-    pub fn side(mut self, side: PanelSide) -> Self {
-        self.current_side = side;
-        self
-    }
-}
-
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::Story;
-    use gpui::{Div, Render};
-    pub struct AssistantPanelStory;
-
-    impl Render<Self> for AssistantPanelStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, AssistantPanel>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(AssistantPanel::new("assistant-panel"))
-        }
-    }
-}

crates/ui2/src/to_extract/breadcrumb.rs 🔗

@@ -1,118 +0,0 @@
-use crate::{h_stack, prelude::*, HighlightedText};
-use gpui::{prelude::*, Div, Stateful};
-use std::path::PathBuf;
-
-#[derive(Clone)]
-pub struct Symbol(pub Vec<HighlightedText>);
-
-#[derive(RenderOnce)]
-pub struct Breadcrumb {
-    path: PathBuf,
-    symbols: Vec<Symbol>,
-}
-
-impl<V: 'static> Component<V> for Breadcrumb {
-    type Rendered = Stateful<V, Div<V>>;
-
-    fn render(self, view_state: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        let symbols_len = self.symbols.len();
-        h_stack()
-            .id("breadcrumb")
-            .px_1()
-            .text_ui_sm()
-            .text_color(cx.theme().colors().text_muted)
-            .rounded_md()
-            .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
-            .active(|style| style.bg(cx.theme().colors().ghost_element_active))
-            .child(SharedString::from(
-                self.path.clone().to_str().unwrap().to_string(),
-            ))
-            .child(if !self.symbols.is_empty() {
-                self.render_separator(cx)
-            } else {
-                div()
-            })
-            .child(
-                div().flex().children(
-                    self.symbols
-                        .iter()
-                        .enumerate()
-                        // TODO: Could use something like `intersperse` here instead.
-                        .flat_map(|(ix, symbol)| {
-                            let mut items =
-                                vec![div().flex().children(symbol.0.iter().map(|segment| {
-                                    div().child(segment.text.clone()).text_color(segment.color)
-                                }))];
-
-                            let is_last_segment = ix == symbols_len - 1;
-                            if !is_last_segment {
-                                items.push(self.render_separator(cx));
-                            }
-
-                            items
-                        })
-                        .collect::<Vec<_>>(),
-                ),
-            )
-    }
-}
-
-impl Breadcrumb {
-    pub fn new(path: PathBuf, symbols: Vec<Symbol>) -> Self {
-        Self { path, symbols }
-    }
-
-    fn render_separator<V: 'static>(&self, cx: &WindowContext) -> Div<V> {
-        div()
-            .child(" › ")
-            .text_color(cx.theme().colors().text_muted)
-    }
-}
-
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::Story;
-    use gpui::Render;
-    use std::str::FromStr;
-
-    pub struct BreadcrumbStory;
-
-    impl Render<Self> for BreadcrumbStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, Breadcrumb>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(Breadcrumb::new(
-                    PathBuf::from_str("crates/ui/src/components/toolbar.rs").unwrap(),
-                    vec![
-                        Symbol(vec![
-                            HighlightedText {
-                                text: "impl ".into(),
-                                color: cx.theme().syntax_color("keyword"),
-                            },
-                            HighlightedText {
-                                text: "BreadcrumbStory".into(),
-                                color: cx.theme().syntax_color("function"),
-                            },
-                        ]),
-                        Symbol(vec![
-                            HighlightedText {
-                                text: "fn ".into(),
-                                color: cx.theme().syntax_color("keyword"),
-                            },
-                            HighlightedText {
-                                text: "render".into(),
-                                color: cx.theme().syntax_color("function"),
-                            },
-                        ]),
-                    ],
-                ))
-        }
-    }
-}

crates/ui2/src/to_extract/buffer.rs 🔗

@@ -1,281 +0,0 @@
-use gpui::{Div, Hsla, RenderOnce, WindowContext};
-
-use crate::prelude::*;
-use crate::{h_stack, v_stack, Icon, IconElement};
-
-#[derive(Default, PartialEq, Copy, Clone)]
-pub struct PlayerCursor {
-    color: Hsla,
-    index: usize,
-}
-
-#[derive(Default, PartialEq, Clone)]
-pub struct HighlightedText {
-    pub text: SharedString,
-    pub color: Hsla,
-}
-
-#[derive(Default, PartialEq, Clone)]
-pub struct HighlightedLine {
-    pub highlighted_texts: Vec<HighlightedText>,
-}
-
-#[derive(Default, PartialEq, Clone)]
-pub struct BufferRow {
-    pub line_number: usize,
-    pub code_action: bool,
-    pub current: bool,
-    pub line: Option<HighlightedLine>,
-    pub cursors: Option<Vec<PlayerCursor>>,
-    pub status: GitStatus,
-    pub show_line_number: bool,
-}
-
-#[derive(Clone)]
-pub struct BufferRows {
-    pub show_line_numbers: bool,
-    pub rows: Vec<BufferRow>,
-}
-
-impl Default for BufferRows {
-    fn default() -> Self {
-        Self {
-            show_line_numbers: true,
-            rows: vec![BufferRow {
-                line_number: 1,
-                code_action: false,
-                current: true,
-                line: None,
-                cursors: None,
-                status: GitStatus::None,
-                show_line_number: true,
-            }],
-        }
-    }
-}
-
-impl BufferRow {
-    pub fn new(line_number: usize) -> Self {
-        Self {
-            line_number,
-            code_action: false,
-            current: false,
-            line: None,
-            cursors: None,
-            status: GitStatus::None,
-            show_line_number: true,
-        }
-    }
-
-    pub fn set_line(mut self, line: Option<HighlightedLine>) -> Self {
-        self.line = line;
-        self
-    }
-
-    pub fn set_cursors(mut self, cursors: Option<Vec<PlayerCursor>>) -> Self {
-        self.cursors = cursors;
-        self
-    }
-
-    pub fn add_cursor(mut self, cursor: PlayerCursor) -> Self {
-        if let Some(cursors) = &mut self.cursors {
-            cursors.push(cursor);
-        } else {
-            self.cursors = Some(vec![cursor]);
-        }
-        self
-    }
-
-    pub fn set_status(mut self, status: GitStatus) -> Self {
-        self.status = status;
-        self
-    }
-
-    pub fn set_show_line_number(mut self, show_line_number: bool) -> Self {
-        self.show_line_number = show_line_number;
-        self
-    }
-
-    pub fn set_code_action(mut self, code_action: bool) -> Self {
-        self.code_action = code_action;
-        self
-    }
-
-    pub fn set_current(mut self, current: bool) -> Self {
-        self.current = current;
-        self
-    }
-}
-
-#[derive(RenderOnce, Clone)]
-pub struct Buffer {
-    id: ElementId,
-    rows: Option<BufferRows>,
-    readonly: bool,
-    language: Option<String>,
-    title: Option<String>,
-    path: Option<String>,
-}
-
-impl<V: 'static> Component<V> for Buffer {
-    type Rendered = Div<V>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        let rows = self.render_rows(cx);
-
-        v_stack()
-            .flex_1()
-            .w_full()
-            .h_full()
-            .bg(cx.theme().colors().editor_background)
-            .children(rows)
-    }
-}
-
-impl Buffer {
-    pub fn new(id: impl Into<ElementId>) -> Self {
-        Self {
-            id: id.into(),
-            rows: Some(BufferRows::default()),
-            readonly: false,
-            language: None,
-            title: Some("untitled".to_string()),
-            path: None,
-        }
-    }
-
-    pub fn set_title<T: Into<Option<String>>>(mut self, title: T) -> Self {
-        self.title = title.into();
-        self
-    }
-
-    pub fn set_path<P: Into<Option<String>>>(mut self, path: P) -> Self {
-        self.path = path.into();
-        self
-    }
-
-    pub fn set_readonly(mut self, readonly: bool) -> Self {
-        self.readonly = readonly;
-        self
-    }
-
-    pub fn set_rows<R: Into<Option<BufferRows>>>(mut self, rows: R) -> Self {
-        self.rows = rows.into();
-        self
-    }
-
-    pub fn set_language<L: Into<Option<String>>>(mut self, language: L) -> Self {
-        self.language = language.into();
-        self
-    }
-
-    fn render_row<V: 'static>(row: BufferRow, cx: &WindowContext) -> impl Element<V> {
-        let line_background = if row.current {
-            cx.theme().colors().editor_active_line_background
-        } else {
-            cx.theme().styles.system.transparent
-        };
-
-        let line_number_color = if row.current {
-            cx.theme().colors().text
-        } else {
-            cx.theme().syntax_color("comment")
-        };
-
-        h_stack()
-            .bg(line_background)
-            .w_full()
-            .gap_2()
-            .px_1()
-            .child(
-                h_stack()
-                    .w_4()
-                    .h_full()
-                    .px_0p5()
-                    .when(row.code_action, |c| {
-                        div().child(IconElement::new(Icon::Bolt))
-                    }),
-            )
-            .when(row.show_line_number, |this| {
-                this.child(
-                    h_stack().justify_end().px_0p5().w_3().child(
-                        div()
-                            .text_color(line_number_color)
-                            .child(SharedString::from(row.line_number.to_string())),
-                    ),
-                )
-            })
-            .child(div().mx_0p5().w_1().h_full().bg(row.status.hsla(cx)))
-            .children(row.line.map(|line| {
-                div()
-                    .flex()
-                    .children(line.highlighted_texts.iter().map(|highlighted_text| {
-                        div()
-                            .text_color(highlighted_text.color)
-                            .child(highlighted_text.text.clone())
-                    }))
-            }))
-    }
-
-    fn render_rows<V: 'static>(&self, cx: &WindowContext) -> Vec<impl Element<V>> {
-        match &self.rows {
-            Some(rows) => rows
-                .rows
-                .iter()
-                .map(|row| Self::render_row(row.clone(), cx))
-                .collect(),
-            None => vec![],
-        }
-    }
-
-    fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
-        let rows = self.render_rows(cx);
-
-        v_stack()
-            .flex_1()
-            .w_full()
-            .h_full()
-            .bg(cx.theme().colors().editor_background)
-            .children(rows)
-    }
-}
-
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::{
-        empty_buffer_example, hello_world_rust_buffer_example,
-        hello_world_rust_buffer_with_status_example, Story,
-    };
-    use gpui::{rems, Div, Render};
-
-    pub struct BufferStory;
-
-    impl Render<Self> for BufferStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, Buffer>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(div().w(rems(64.)).h_96().child(empty_buffer_example()))
-                .child(Story::label(cx, "Hello World (Rust)"))
-                .child(
-                    div()
-                        .w(rems(64.))
-                        .h_96()
-                        .child(hello_world_rust_buffer_example(cx)),
-                )
-                .child(Story::label(cx, "Hello World (Rust) with Status"))
-                .child(
-                    div()
-                        .w(rems(64.))
-                        .h_96()
-                        .child(hello_world_rust_buffer_with_status_example(cx)),
-                )
-        }
-    }
-}

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

@@ -1,45 +0,0 @@
-use crate::prelude::*;
-use crate::{h_stack, Icon, IconButton, Input, TextColor};
-use gpui::{Div, Render, RenderOnce, View, VisualContext};
-
-#[derive(Clone)]
-pub struct BufferSearch {
-    is_replace_open: bool,
-}
-
-impl BufferSearch {
-    pub fn new() -> Self {
-        Self {
-            is_replace_open: false,
-        }
-    }
-
-    fn toggle_replace(&mut self, cx: &mut ViewContext<Self>) {
-        self.is_replace_open = !self.is_replace_open;
-
-        cx.notify();
-    }
-
-    pub fn view(cx: &mut WindowContext) -> View<Self> {
-        cx.build_view(|cx| Self::new())
-    }
-}
-
-impl Render<Self> for BufferSearch {
-    type Element = Div<Self>;
-
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> {
-        h_stack()
-            .bg(cx.theme().colors().toolbar_background)
-            .p_2()
-            .child(
-                h_stack().child(Input::new("Search")).child(
-                    IconButton::<Self>::new("replace", Icon::Replace)
-                        .when(self.is_replace_open, |this| this.color(TextColor::Accent))
-                        .on_click(|buffer_search, cx| {
-                            buffer_search.toggle_replace(cx);
-                        }),
-                ),
-            )
-    }
-}

crates/ui2/src/to_extract/chat_panel.rs 🔗

@@ -1,158 +0,0 @@
-use crate::{prelude::*, Icon, IconButton, Input, Label};
-use chrono::NaiveDateTime;
-use gpui::{prelude::*, Div, Stateful};
-
-#[derive(RenderOnce)]
-pub struct ChatPanel {
-    element_id: ElementId,
-    messages: Vec<ChatMessage>,
-}
-
-impl<V: 'static> Component<V> for ChatPanel {
-    type Rendered = Stateful<V, Div<V>>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        div()
-            .id(self.element_id.clone())
-            .flex()
-            .flex_col()
-            .justify_between()
-            .h_full()
-            .px_2()
-            .gap_2()
-            // Header
-            .child(
-                div()
-                    .flex()
-                    .justify_between()
-                    .py_2()
-                    .child(div().flex().child(Label::new("#design")))
-                    .child(
-                        div()
-                            .flex()
-                            .items_center()
-                            .gap_px()
-                            .child(IconButton::new("file", Icon::File))
-                            .child(IconButton::new("audio_on", Icon::AudioOn)),
-                    ),
-            )
-            .child(
-                div()
-                    .flex()
-                    .flex_col()
-                    // Chat Body
-                    .child(
-                        div()
-                            .id("chat-body")
-                            .w_full()
-                            .flex()
-                            .flex_col()
-                            .gap_3()
-                            .overflow_y_scroll()
-                            .children(self.messages),
-                    )
-                    // Composer
-                    .child(div().flex().my_2().child(Input::new("Message #design"))),
-            )
-    }
-}
-
-impl ChatPanel {
-    pub fn new(element_id: impl Into<ElementId>) -> Self {
-        Self {
-            element_id: element_id.into(),
-            messages: Vec::new(),
-        }
-    }
-
-    pub fn messages(mut self, messages: Vec<ChatMessage>) -> Self {
-        self.messages = messages;
-        self
-    }
-}
-
-#[derive(RenderOnce)]
-pub struct ChatMessage {
-    author: String,
-    text: String,
-    sent_at: NaiveDateTime,
-}
-
-impl<V: 'static> Component<V> for ChatMessage {
-    type Rendered = Div<V>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        div()
-            .flex()
-            .flex_col()
-            .child(
-                div()
-                    .flex()
-                    .gap_2()
-                    .child(Label::new(self.author.clone()))
-                    .child(
-                        Label::new(self.sent_at.format("%m/%d/%Y").to_string())
-                            .color(TextColor::Muted),
-                    ),
-            )
-            .child(div().child(Label::new(self.text.clone())))
-    }
-}
-
-impl ChatMessage {
-    pub fn new(author: String, text: String, sent_at: NaiveDateTime) -> Self {
-        Self {
-            author,
-            text,
-            sent_at,
-        }
-    }
-}
-
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use chrono::DateTime;
-    use gpui::{Div, Render};
-
-    use crate::{Panel, Story};
-
-    use super::*;
-
-    pub struct ChatPanelStory;
-
-    impl Render<Self> for ChatPanelStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, ChatPanel>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(
-                    Panel::new("chat-panel-1-outer", cx)
-                        .child(ChatPanel::new("chat-panel-1-inner")),
-                )
-                .child(Story::label(cx, "With Mesages"))
-                .child(Panel::new("chat-panel-2-outer", cx).child(
-                    ChatPanel::new("chat-panel-2-inner").messages(vec![
-                        ChatMessage::new(
-                            "osiewicz".to_string(),
-                            "is this thing on?".to_string(),
-                            DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z")
-                                .unwrap()
-                                .naive_local(),
-                        ),
-                        ChatMessage::new(
-                            "maxdeviant".to_string(),
-                            "Reading you loud and clear!".to_string(),
-                            DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z")
-                                .unwrap()
-                                .naive_local(),
-                        ),
-                    ]),
-                ))
-        }
-    }
-}

crates/ui2/src/to_extract/collab_panel.rs 🔗

@@ -1,118 +0,0 @@
-use crate::{
-    prelude::*, static_collab_panel_channels, static_collab_panel_current_call, v_stack, Icon,
-    List, ListHeader, Toggle,
-};
-use gpui::{prelude::*, Div, Stateful};
-
-#[derive(RenderOnce)]
-pub struct CollabPanel {
-    id: ElementId,
-}
-
-impl<V: 'static> Component<V> for CollabPanel {
-    type Rendered = Stateful<V, Div<V>>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        v_stack()
-            .id(self.id.clone())
-            .h_full()
-            .bg(cx.theme().colors().surface_background)
-            .child(
-                v_stack()
-                    .id("crdb")
-                    .w_full()
-                    .overflow_y_scroll()
-                    .child(
-                        div()
-                            .pb_1()
-                            .border_color(cx.theme().colors().border)
-                            .border_b()
-                            .child(
-                                List::new()
-                                    .header(
-                                        ListHeader::new("CRDB")
-                                            .left_icon(Icon::Hash.into())
-                                            .toggle(Toggle::Toggled(true)),
-                                    )
-                                    .toggle(Toggle::Toggled(true))
-                                    .children(static_collab_panel_current_call()),
-                            ),
-                    )
-                    .child(
-                        v_stack().id("channels").py_1().child(
-                            List::new()
-                                .header(ListHeader::new("CHANNELS").toggle(Toggle::Toggled(true)))
-                                .empty_message("No channels yet. Add a channel to get started.")
-                                .toggle(Toggle::Toggled(true))
-                                .children(static_collab_panel_channels()),
-                        ),
-                    )
-                    .child(
-                        v_stack().id("contacts-online").py_1().child(
-                            List::new()
-                                .header(
-                                    ListHeader::new("CONTACTS – ONLINE")
-                                        .toggle(Toggle::Toggled(true)),
-                                )
-                                .toggle(Toggle::Toggled(true))
-                                .children(static_collab_panel_current_call()),
-                        ),
-                    )
-                    .child(
-                        v_stack().id("contacts-offline").py_1().child(
-                            List::new()
-                                .header(
-                                    ListHeader::new("CONTACTS – OFFLINE")
-                                        .toggle(Toggle::Toggled(false)),
-                                )
-                                .toggle(Toggle::Toggled(false))
-                                .children(static_collab_panel_current_call()),
-                        ),
-                    ),
-            )
-            .child(
-                div()
-                    .h_7()
-                    .px_2()
-                    .border_t()
-                    .border_color(cx.theme().colors().border)
-                    .flex()
-                    .items_center()
-                    .child(
-                        div()
-                            .text_ui_sm()
-                            .text_color(cx.theme().colors().text_placeholder)
-                            .child("Find..."),
-                    ),
-            )
-    }
-}
-
-impl CollabPanel {
-    pub fn new(id: impl Into<ElementId>) -> Self {
-        Self { id: id.into() }
-    }
-}
-
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::Story;
-    use gpui::{Div, Render};
-
-    pub struct CollabPanelStory;
-
-    impl Render<Self> for CollabPanelStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, CollabPanel>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(CollabPanel::new("collab-panel"))
-        }
-    }
-}

crates/ui2/src/to_extract/command_palette.rs 🔗

@@ -1,53 +0,0 @@
-use crate::prelude::*;
-use crate::{example_editor_actions, OrderMethod, Palette};
-
-#[derive(RenderOnce)]
-pub struct CommandPalette {
-    id: ElementId,
-}
-
-impl<V: 'static> Component<V> for CommandPalette {
-    type Rendered = Stateful<V, Div<V>>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        div().id(self.id.clone()).child(
-            Palette::new("palette")
-                .items(example_editor_actions())
-                .placeholder("Execute a command...")
-                .empty_string("No items found.")
-                .default_order(OrderMethod::Ascending),
-        )
-    }
-}
-
-impl CommandPalette {
-    pub fn new(id: impl Into<ElementId>) -> Self {
-        Self { id: id.into() }
-    }
-}
-
-use gpui::{Div, RenderOnce, Stateful};
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use gpui::{Div, Render};
-
-    use crate::Story;
-
-    use super::*;
-
-    pub struct CommandPaletteStory;
-
-    impl Render<Self> for CommandPaletteStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, CommandPalette>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(CommandPalette::new("command-palette"))
-        }
-    }
-}

crates/ui2/src/to_extract/copilot.rs 🔗

@@ -1,49 +0,0 @@
-use crate::{prelude::*, Button, Label, Modal, TextColor};
-
-#[derive(RenderOnce)]
-pub struct CopilotModal {
-    id: ElementId,
-}
-
-impl<V: 'static> Component<V> for CopilotModal {
-    type Rendered = Stateful<V, Div<V>>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        div().id(self.id.clone()).child(
-                Modal::new("some-id")
-                    .title("Connect Copilot to Zed")
-                    .child(Label::new("You can update your settings or sign out from the Copilot menu in the status bar.").color(TextColor::Muted))
-                    .primary_action(Button::new("Connect to Github").variant(ButtonVariant::Filled)),
-            )
-    }
-}
-
-impl CopilotModal {
-    pub fn new(id: impl Into<ElementId>) -> Self {
-        Self { id: id.into() }
-    }
-}
-
-use gpui::{Div, RenderOnce, Stateful};
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::Story;
-    use gpui::{Div, Render};
-
-    pub struct CopilotModalStory;
-
-    impl Render<Self> for CopilotModalStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, CopilotModal>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(CopilotModal::new("copilot-modal"))
-        }
-    }
-}

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

@@ -1,77 +0,0 @@
-use std::path::PathBuf;
-
-use gpui::{Div, Render, RenderOnce, View, VisualContext};
-
-use crate::prelude::*;
-use crate::{
-    hello_world_rust_editor_with_status_example, v_stack, Breadcrumb, Buffer, BufferSearch, Icon,
-    IconButton, Symbol, Tab, TabBar, TextColor, Toolbar,
-};
-
-#[derive(Clone)]
-pub struct EditorPane {
-    tabs: Vec<Tab>,
-    path: PathBuf,
-    symbols: Vec<Symbol>,
-    buffer: Buffer,
-    buffer_search: View<BufferSearch>,
-    is_buffer_search_open: bool,
-}
-
-impl EditorPane {
-    pub fn new(
-        cx: &mut ViewContext<Self>,
-        tabs: Vec<Tab>,
-        path: PathBuf,
-        symbols: Vec<Symbol>,
-        buffer: Buffer,
-    ) -> Self {
-        Self {
-            tabs,
-            path,
-            symbols,
-            buffer,
-            buffer_search: BufferSearch::view(cx),
-            is_buffer_search_open: false,
-        }
-    }
-
-    pub fn toggle_buffer_search(&mut self, cx: &mut ViewContext<Self>) {
-        self.is_buffer_search_open = !self.is_buffer_search_open;
-
-        cx.notify();
-    }
-
-    pub fn view(cx: &mut WindowContext) -> View<Self> {
-        cx.build_view(|cx| hello_world_rust_editor_with_status_example(cx))
-    }
-}
-
-impl Render<Self> for EditorPane {
-    type Element = Div<Self>;
-
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> {
-        v_stack()
-            .w_full()
-            .h_full()
-            .flex_1()
-            .child(TabBar::new("editor-pane-tabs", self.tabs.clone()).can_navigate((false, true)))
-            .child(
-                Toolbar::new()
-                    .left_item(Breadcrumb::new(self.path.clone(), self.symbols.clone()))
-                    .right_items(vec![
-                        IconButton::<Self>::new("toggle_inlay_hints", Icon::InlayHint),
-                        IconButton::<Self>::new("buffer_search", Icon::MagnifyingGlass)
-                            .when(self.is_buffer_search_open, |this| {
-                                this.color(TextColor::Accent)
-                            })
-                            .on_click(|editor: &mut Self, cx| {
-                                editor.toggle_buffer_search(cx);
-                            }),
-                        IconButton::new("inline_assist", Icon::MagicWand),
-                    ]),
-            )
-            .children(Some(self.buffer_search.clone()).filter(|_| self.is_buffer_search_open))
-            .child(self.buffer.clone())
-    }
-}

crates/ui2/src/to_extract/language_selector.rs 🔗

@@ -1,83 +0,0 @@
-use crate::prelude::*;
-use crate::{OrderMethod, Palette, PaletteItem};
-
-#[derive(RenderOnce)]
-pub struct LanguageSelector {
-    id: ElementId,
-}
-
-impl<V: 'static> Component<V> for LanguageSelector {
-    type Rendered = Stateful<V, Div<V>>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        div().id(self.id.clone()).child(
-            Palette::new("palette")
-                .items(vec![
-                    PaletteItem::new("C"),
-                    PaletteItem::new("C++"),
-                    PaletteItem::new("CSS"),
-                    PaletteItem::new("Elixir"),
-                    PaletteItem::new("Elm"),
-                    PaletteItem::new("ERB"),
-                    PaletteItem::new("Rust (current)"),
-                    PaletteItem::new("Scheme"),
-                    PaletteItem::new("TOML"),
-                    PaletteItem::new("TypeScript"),
-                ])
-                .placeholder("Select a language...")
-                .empty_string("No matches")
-                .default_order(OrderMethod::Ascending),
-        )
-    }
-}
-
-impl LanguageSelector {
-    pub fn new(id: impl Into<ElementId>) -> Self {
-        Self { id: id.into() }
-    }
-
-    fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
-        div().id(self.id.clone()).child(
-            Palette::new("palette")
-                .items(vec![
-                    PaletteItem::new("C"),
-                    PaletteItem::new("C++"),
-                    PaletteItem::new("CSS"),
-                    PaletteItem::new("Elixir"),
-                    PaletteItem::new("Elm"),
-                    PaletteItem::new("ERB"),
-                    PaletteItem::new("Rust (current)"),
-                    PaletteItem::new("Scheme"),
-                    PaletteItem::new("TOML"),
-                    PaletteItem::new("TypeScript"),
-                ])
-                .placeholder("Select a language...")
-                .empty_string("No matches")
-                .default_order(OrderMethod::Ascending),
-        )
-    }
-}
-
-use gpui::{Div, RenderOnce, Stateful};
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::Story;
-    use gpui::{Div, Render};
-
-    pub struct LanguageSelectorStory;
-
-    impl Render<Self> for LanguageSelectorStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, LanguageSelector>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(LanguageSelector::new("language-selector"))
-        }
-    }
-}

crates/ui2/src/to_extract/multi_buffer.rs 🔗

@@ -1,68 +0,0 @@
-use crate::prelude::*;
-use crate::{v_stack, Buffer, Icon, IconButton, Label};
-
-#[derive(RenderOnce)]
-pub struct MultiBuffer {
-    buffers: Vec<Buffer>,
-}
-
-impl<V: 'static> Component<V> for MultiBuffer {
-    type Rendered = Div<V>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        v_stack()
-            .w_full()
-            .h_full()
-            .flex_1()
-            .children(self.buffers.clone().into_iter().map(|buffer| {
-                v_stack()
-                    .child(
-                        div()
-                            .flex()
-                            .items_center()
-                            .justify_between()
-                            .p_4()
-                            .bg(cx.theme().colors().editor_subheader_background)
-                            .child(Label::new("main.rs"))
-                            .child(IconButton::new("arrow_up_right", Icon::ArrowUpRight)),
-                    )
-                    .child(buffer)
-            }))
-    }
-}
-
-impl MultiBuffer {
-    pub fn new(buffers: Vec<Buffer>) -> Self {
-        Self { buffers }
-    }
-}
-
-use gpui::{Div, RenderOnce};
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::{hello_world_rust_buffer_example, Story};
-    use gpui::{Div, Render};
-
-    pub struct MultiBufferStory;
-
-    impl Render<Self> for MultiBufferStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, MultiBuffer>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(MultiBuffer::new(vec![
-                    hello_world_rust_buffer_example(cx),
-                    hello_world_rust_buffer_example(cx),
-                    hello_world_rust_buffer_example(cx),
-                    hello_world_rust_buffer_example(cx),
-                    hello_world_rust_buffer_example(cx),
-                ]))
-        }
-    }
-}

crates/ui2/src/to_extract/notifications_panel.rs 🔗

@@ -1,379 +0,0 @@
-use crate::{
-    h_stack, prelude::*, static_new_notification_items_2, utils::naive_format_distance_from_now,
-    v_stack, Avatar, ButtonOrIconButton, ClickHandler, Icon, IconElement, Label, LineHeightStyle,
-    ListHeader, ListHeaderMeta, ListSeparator, PublicPlayer, TextColor, UnreadIndicator,
-};
-use gpui::{prelude::*, Div, Stateful};
-
-#[derive(RenderOnce)]
-pub struct NotificationsPanel {
-    id: ElementId,
-}
-
-impl<V: 'static> Component<V> for NotificationsPanel {
-    type Rendered = Stateful<V, Div<V>>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        div()
-            .id(self.id.clone())
-            .flex()
-            .flex_col()
-            .size_full()
-            .bg(cx.theme().colors().surface_background)
-            .child(
-                ListHeader::new("Notifications").meta(Some(ListHeaderMeta::Tools(vec![
-                    Icon::AtSign,
-                    Icon::BellOff,
-                    Icon::MailOpen,
-                ]))),
-            )
-            .child(ListSeparator::new())
-            .child(
-                v_stack()
-                    .id("notifications-panel-scroll-view")
-                    .py_1()
-                    .overflow_y_scroll()
-                    .flex_1()
-                    .child(
-                        div()
-                            .mx_2()
-                            .p_1()
-                            // TODO: Add cursor style
-                            // .cursor(Cursor::IBeam)
-                            .bg(cx.theme().colors().element_background)
-                            .border()
-                            .border_color(cx.theme().colors().border_variant)
-                            .child(
-                                Label::new("Search...")
-                                    .color(TextColor::Placeholder)
-                                    .line_height_style(LineHeightStyle::UILabel),
-                            ),
-                    )
-                    .child(v_stack().px_1().children(static_new_notification_items_2())),
-            )
-    }
-}
-
-impl NotificationsPanel {
-    pub fn new(id: impl Into<ElementId>) -> Self {
-        Self { id: id.into() }
-    }
-}
-
-pub struct NotificationAction<V: 'static> {
-    button: ButtonOrIconButton<V>,
-    tooltip: SharedString,
-    /// Shows after action is chosen
-    ///
-    /// For example, if the action is "Accept" the taken message could be:
-    ///
-    /// - `(None,"Accepted")` - "Accepted"
-    ///
-    /// - `(Some(Icon::Check),"Accepted")` - ✓ "Accepted"
-    taken_message: (Option<Icon>, SharedString),
-}
-
-impl<V: 'static> NotificationAction<V> {
-    pub fn new(
-        button: impl Into<ButtonOrIconButton<V>>,
-        tooltip: impl Into<SharedString>,
-        (icon, taken_message): (Option<Icon>, impl Into<SharedString>),
-    ) -> Self {
-        Self {
-            button: button.into(),
-            tooltip: tooltip.into(),
-            taken_message: (icon, taken_message.into()),
-        }
-    }
-}
-
-pub enum ActorOrIcon {
-    Actor(PublicPlayer),
-    Icon(Icon),
-}
-
-pub struct NotificationMeta<V: 'static> {
-    items: Vec<(Option<Icon>, SharedString, Option<ClickHandler<V>>)>,
-}
-
-struct NotificationHandlers<V: 'static> {
-    click: Option<ClickHandler<V>>,
-}
-
-impl<V: 'static> Default for NotificationHandlers<V> {
-    fn default() -> Self {
-        Self { click: None }
-    }
-}
-
-#[derive(RenderOnce)]
-pub struct Notification<V: 'static> {
-    id: ElementId,
-    slot: ActorOrIcon,
-    message: SharedString,
-    date_received: NaiveDateTime,
-    meta: Option<NotificationMeta<V>>,
-    actions: Option<[NotificationAction<V>; 2]>,
-    unread: bool,
-    new: bool,
-    action_taken: Option<NotificationAction<V>>,
-    handlers: NotificationHandlers<V>,
-}
-
-impl<V: 'static> Component<V> for Notification<V> {
-    type Rendered = Stateful<V, Div<V>>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        div()
-            .relative()
-            .id(self.id.clone())
-            .p_1()
-            .flex()
-            .flex_col()
-            .w_full()
-            .children(
-                Some(
-                    div()
-                        .absolute()
-                        .left(px(3.0))
-                        .top_3()
-                        .z_index(2)
-                        .child(UnreadIndicator::new()),
-                )
-                .filter(|_| self.unread),
-            )
-            .child(
-                v_stack()
-                    .z_index(1)
-                    .gap_1()
-                    .w_full()
-                    .child(
-                        h_stack()
-                            .w_full()
-                            .gap_2()
-                            .child(self.render_slot(cx))
-                            .child(div().flex_1().child(Label::new(self.message.clone()))),
-                    )
-                    .child(
-                        h_stack()
-                            .justify_between()
-                            .child(
-                                h_stack()
-                                    .gap_1()
-                                    .child(
-                                        Label::new(naive_format_distance_from_now(
-                                            self.date_received,
-                                            true,
-                                            true,
-                                        ))
-                                        .color(TextColor::Muted),
-                                    )
-                                    .child(self.render_meta_items(cx)),
-                            )
-                            .child(match (self.actions, self.action_taken) {
-                                // Show nothing
-                                (None, _) => div(),
-                                // Show the taken_message
-                                (Some(_), Some(action_taken)) => h_stack()
-                                    .children(action_taken.taken_message.0.map(|icon| {
-                                        IconElement::new(icon).color(crate::TextColor::Muted)
-                                    }))
-                                    .child(
-                                        Label::new(action_taken.taken_message.1.clone())
-                                            .color(TextColor::Muted),
-                                    ),
-                                // Show the actions
-                                (Some(actions), None) => {
-                                    h_stack().children(actions.map(|action| match action.button {
-                                        ButtonOrIconButton::Button(button) => {
-                                            button.render_into_any()
-                                        }
-                                        ButtonOrIconButton::IconButton(icon_button) => {
-                                            icon_button.render_into_any()
-                                        }
-                                    }))
-                                }
-                            }),
-                    ),
-            )
-    }
-}
-
-impl<V> Notification<V> {
-    fn new(
-        id: ElementId,
-        message: SharedString,
-        date_received: NaiveDateTime,
-        slot: ActorOrIcon,
-        click_action: Option<ClickHandler<V>>,
-    ) -> Self {
-        let handlers = if click_action.is_some() {
-            NotificationHandlers {
-                click: click_action,
-            }
-        } else {
-            NotificationHandlers::default()
-        };
-
-        Self {
-            id,
-            date_received,
-            message,
-            meta: None,
-            slot,
-            actions: None,
-            unread: true,
-            new: false,
-            action_taken: None,
-            handlers,
-        }
-    }
-
-    /// Creates a new notification with an actor slot.
-    ///
-    /// Requires a click action.
-    pub fn new_actor_message(
-        id: impl Into<ElementId>,
-        message: impl Into<SharedString>,
-        date_received: NaiveDateTime,
-        actor: PublicPlayer,
-        click_action: ClickHandler<V>,
-    ) -> Self {
-        Self::new(
-            id.into(),
-            message.into(),
-            date_received,
-            ActorOrIcon::Actor(actor),
-            Some(click_action),
-        )
-    }
-
-    /// Creates a new notification with an icon slot.
-    ///
-    /// Requires a click action.
-    pub fn new_icon_message(
-        id: impl Into<ElementId>,
-        message: impl Into<SharedString>,
-        date_received: NaiveDateTime,
-        icon: Icon,
-        click_action: ClickHandler<V>,
-    ) -> Self {
-        Self::new(
-            id.into(),
-            message.into(),
-            date_received,
-            ActorOrIcon::Icon(icon),
-            Some(click_action),
-        )
-    }
-
-    /// Creates a new notification with an actor slot
-    /// and a Call To Action row.
-    ///
-    /// Cannot take a click action due to required actions.
-    pub fn new_actor_with_actions(
-        id: impl Into<ElementId>,
-        message: impl Into<SharedString>,
-        date_received: NaiveDateTime,
-        actor: PublicPlayer,
-        actions: [NotificationAction<V>; 2],
-    ) -> Self {
-        Self::new(
-            id.into(),
-            message.into(),
-            date_received,
-            ActorOrIcon::Actor(actor),
-            None,
-        )
-        .actions(actions)
-    }
-
-    /// Creates a new notification with an icon slot
-    /// and a Call To Action row.
-    ///
-    /// Cannot take a click action due to required actions.
-    pub fn new_icon_with_actions(
-        id: impl Into<ElementId>,
-        message: impl Into<SharedString>,
-        date_received: NaiveDateTime,
-        icon: Icon,
-        actions: [NotificationAction<V>; 2],
-    ) -> Self {
-        Self::new(
-            id.into(),
-            message.into(),
-            date_received,
-            ActorOrIcon::Icon(icon),
-            None,
-        )
-        .actions(actions)
-    }
-
-    fn on_click(mut self, handler: ClickHandler<V>) -> Self {
-        self.handlers.click = Some(handler);
-        self
-    }
-
-    pub fn actions(mut self, actions: [NotificationAction<V>; 2]) -> Self {
-        self.actions = Some(actions);
-        self
-    }
-
-    pub fn meta(mut self, meta: NotificationMeta<V>) -> Self {
-        self.meta = Some(meta);
-        self
-    }
-
-    fn render_meta_items(&self, cx: &mut ViewContext<V>) -> impl Element<V> {
-        if let Some(meta) = &self.meta {
-            h_stack().children(
-                meta.items
-                    .iter()
-                    .map(|(icon, text, _)| {
-                        let mut meta_el = div();
-                        if let Some(icon) = icon {
-                            meta_el = meta_el.child(IconElement::new(icon.clone()));
-                        }
-                        meta_el.child(Label::new(text.clone()).color(TextColor::Muted))
-                    })
-                    .collect::<Vec<_>>(),
-            )
-        } else {
-            div()
-        }
-    }
-
-    fn render_slot(&self, cx: &mut ViewContext<V>) -> impl Element<V> {
-        match &self.slot {
-            ActorOrIcon::Actor(actor) => Avatar::new(actor.avatar.clone()).render_into_any(),
-            ActorOrIcon::Icon(icon) => IconElement::new(icon.clone()).render_into_any(),
-        }
-    }
-}
-
-use chrono::NaiveDateTime;
-use gpui::{px, Styled};
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::{Panel, Story};
-    use gpui::{Div, Render};
-
-    pub struct NotificationsPanelStory;
-
-    impl Render<Self> for NotificationsPanelStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, NotificationsPanel>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(
-                    Panel::new("panel", cx).child(NotificationsPanel::new("notifications_panel")),
-                )
-        }
-    }
-}

crates/ui2/src/to_extract/panes.rs 🔗

@@ -1,139 +0,0 @@
-use gpui::{
-    hsla, red, AnyElement, Div, ElementId, ExternalPaths, Hsla, Length, RenderOnce, Size, Stateful,
-    View,
-};
-use smallvec::SmallVec;
-
-use crate::prelude::*;
-
-#[derive(Default, PartialEq)]
-pub enum SplitDirection {
-    #[default]
-    Horizontal,
-    Vertical,
-}
-
-#[derive(RenderOnce)]
-pub struct Pane<V: 'static> {
-    id: ElementId,
-    size: Size<Length>,
-    fill: Hsla,
-    children: SmallVec<[AnyElement<V>; 2]>,
-}
-
-impl<V: 'static> Component<V> for Pane<V> {
-    type Rendered = Stateful<V, Div<V>>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        div()
-            .id(self.id.clone())
-            .flex()
-            .flex_initial()
-            .bg(self.fill)
-            .w(self.size.width)
-            .h(self.size.height)
-            .relative()
-            .child(div().z_index(0).size_full().children(self.children))
-            .child(
-                div()
-                    .z_index(1)
-                    .id("drag-target")
-                    .drag_over::<ExternalPaths>(|d| d.bg(red()))
-                    .on_drop(|_, files: View<ExternalPaths>, cx| {
-                        eprintln!("dropped files! {:?}", files.read(cx));
-                    })
-                    .absolute()
-                    .inset_0(),
-            )
-    }
-}
-
-impl<V: 'static> Pane<V> {
-    pub fn new(id: impl Into<ElementId>, size: Size<Length>) -> Self {
-        // Fill is only here for debugging purposes, remove before release
-
-        Self {
-            id: id.into(),
-            size,
-            fill: hsla(0.3, 0.3, 0.3, 1.),
-            children: SmallVec::new(),
-        }
-    }
-
-    pub fn fill(mut self, fill: Hsla) -> Self {
-        self.fill = fill;
-        self
-    }
-}
-
-impl<V: 'static> ParentElement<V> for Pane<V> {
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
-        &mut self.children
-    }
-}
-
-#[derive(RenderOnce)]
-pub struct PaneGroup<V: 'static> {
-    groups: Vec<PaneGroup<V>>,
-    panes: Vec<Pane<V>>,
-    split_direction: SplitDirection,
-}
-
-impl<V: 'static> Component<V> for PaneGroup<V> {
-    type Rendered = Div<V>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        if !self.panes.is_empty() {
-            let el = div()
-                .flex()
-                .flex_1()
-                .gap_px()
-                .w_full()
-                .h_full()
-                .children(self.panes.into_iter().map(|pane| pane.render(view, cx)));
-
-            if self.split_direction == SplitDirection::Horizontal {
-                return el;
-            } else {
-                return el.flex_col();
-            }
-        }
-
-        if !self.groups.is_empty() {
-            let el = div()
-                .flex()
-                .flex_1()
-                .gap_px()
-                .w_full()
-                .h_full()
-                .bg(cx.theme().colors().editor_background)
-                .children(self.groups.into_iter().map(|group| group.render(view, cx)));
-
-            if self.split_direction == SplitDirection::Horizontal {
-                return el;
-            } else {
-                return el.flex_col();
-            }
-        }
-
-        unreachable!()
-    }
-}
-
-impl<V: 'static> PaneGroup<V> {
-    pub fn new_groups(groups: Vec<PaneGroup<V>>, split_direction: SplitDirection) -> Self {
-        Self {
-            groups,
-            panes: Vec::new(),
-            split_direction,
-        }
-    }
-
-    pub fn new_panes(panes: Vec<Pane<V>>, split_direction: SplitDirection) -> Self {
-        Self {
-            groups: Vec::new(),
-            panes,
-            split_direction,
-        }
-    }
-}

crates/ui2/src/to_extract/project_panel.rs 🔗

@@ -1,117 +0,0 @@
-use crate::{
-    prelude::*, static_project_panel_project_items, static_project_panel_single_items, Input, List,
-    ListHeader,
-};
-use gpui::prelude::*;
-use gpui::Div;
-use gpui::Stateful;
-
-#[derive(RenderOnce)]
-pub struct ProjectPanel {
-    id: ElementId,
-}
-
-impl<V: 'static> Component<V> for ProjectPanel {
-    type Rendered = Stateful<V, Div<V>>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        div()
-            .id(self.id.clone())
-            .flex()
-            .flex_col()
-            .size_full()
-            .bg(cx.theme().colors().surface_background)
-            .child(
-                div()
-                    .id("project-panel-contents")
-                    .w_full()
-                    .flex()
-                    .flex_col()
-                    .overflow_y_scroll()
-                    .child(
-                        List::new()
-                            .header(ListHeader::new("FILES"))
-                            .empty_message("No files in directory")
-                            .children(static_project_panel_single_items()),
-                    )
-                    .child(
-                        List::new()
-                            .header(ListHeader::new("PROJECT"))
-                            .empty_message("No folders in directory")
-                            .children(static_project_panel_project_items()),
-                    ),
-            )
-            .child(
-                Input::new("Find something...")
-                    .value("buffe".to_string())
-                    .state(InteractionState::Focused),
-            )
-    }
-}
-
-impl ProjectPanel {
-    pub fn new(id: impl Into<ElementId>) -> Self {
-        Self { id: id.into() }
-    }
-
-    fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
-        div()
-            .id(self.id.clone())
-            .flex()
-            .flex_col()
-            .size_full()
-            .bg(cx.theme().colors().surface_background)
-            .child(
-                div()
-                    .id("project-panel-contents")
-                    .w_full()
-                    .flex()
-                    .flex_col()
-                    .overflow_y_scroll()
-                    .child(
-                        List::new()
-                            .header(ListHeader::new("FILES"))
-                            .empty_message("No files in directory")
-                            .children(static_project_panel_single_items()),
-                    )
-                    .child(
-                        List::new()
-                            .header(ListHeader::new("PROJECT"))
-                            .empty_message("No folders in directory")
-                            .children(static_project_panel_project_items()),
-                    ),
-            )
-            .child(
-                Input::new("Find something...")
-                    .value("buffe".to_string())
-                    .state(InteractionState::Focused),
-            )
-    }
-}
-
-use gpui::ElementId;
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::{Panel, Story};
-    use gpui::{Div, Render};
-
-    pub struct ProjectPanelStory;
-
-    impl Render<Self> for ProjectPanelStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, ProjectPanel>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(
-                    Panel::new("project-panel-outer", cx)
-                        .child(ProjectPanel::new("project-panel-inner")),
-                )
-        }
-    }
-}

crates/ui2/src/to_extract/recent_projects.rs 🔗

@@ -1,58 +0,0 @@
-use crate::prelude::*;
-use crate::{OrderMethod, Palette, PaletteItem};
-
-#[derive(RenderOnce)]
-pub struct RecentProjects {
-    id: ElementId,
-}
-
-impl<V: 'static> Component<V> for RecentProjects {
-    type Rendered = Stateful<V, Div<V>>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        div().id(self.id.clone()).child(
-            Palette::new("palette")
-                .items(vec![
-                    PaletteItem::new("zed").sublabel(SharedString::from("~/projects/zed")),
-                    PaletteItem::new("saga").sublabel(SharedString::from("~/projects/saga")),
-                    PaletteItem::new("journal").sublabel(SharedString::from("~/journal")),
-                    PaletteItem::new("dotfiles").sublabel(SharedString::from("~/dotfiles")),
-                    PaletteItem::new("zed.dev").sublabel(SharedString::from("~/projects/zed.dev")),
-                    PaletteItem::new("laminar").sublabel(SharedString::from("~/projects/laminar")),
-                ])
-                .placeholder("Recent Projects...")
-                .empty_string("No matches")
-                .default_order(OrderMethod::Ascending),
-        )
-    }
-}
-
-impl RecentProjects {
-    pub fn new(id: impl Into<ElementId>) -> Self {
-        Self { id: id.into() }
-    }
-}
-
-use gpui::{Div, RenderOnce, Stateful};
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::Story;
-    use gpui::{Div, Render};
-
-    pub struct RecentProjectsStory;
-
-    impl Render<Self> for RecentProjectsStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, RecentProjects>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(RecentProjects::new("recent-projects"))
-        }
-    }
-}

crates/ui2/src/to_extract/status_bar.rs 🔗

@@ -1,201 +0,0 @@
-use std::sync::Arc;
-
-use gpui::{Div, RenderOnce};
-
-use crate::prelude::*;
-use crate::{Button, Icon, IconButton, TextColor, ToolDivider, Workspace};
-
-#[derive(Default, PartialEq)]
-pub enum Tool {
-    #[default]
-    ProjectPanel,
-    CollaborationPanel,
-    Terminal,
-    Assistant,
-    Feedback,
-    Diagnostics,
-}
-
-struct ToolGroup {
-    active_index: Option<usize>,
-    tools: Vec<Tool>,
-}
-
-impl Default for ToolGroup {
-    fn default() -> Self {
-        ToolGroup {
-            active_index: None,
-            tools: vec![],
-        }
-    }
-}
-
-#[derive(RenderOnce)]
-#[view = "Workspace"]
-pub struct StatusBar {
-    left_tools: Option<ToolGroup>,
-    right_tools: Option<ToolGroup>,
-    bottom_tools: Option<ToolGroup>,
-}
-
-impl Component<Workspace> for StatusBar {
-    type Rendered = Div<Workspace>;
-
-    fn render(self, view: &mut Workspace, cx: &mut ViewContext<Workspace>) -> Self::Rendered {
-        div()
-            .py_0p5()
-            .px_1()
-            .flex()
-            .items_center()
-            .justify_between()
-            .w_full()
-            .bg(cx.theme().colors().status_bar_background)
-            .child(self.left_tools(view, cx))
-            .child(self.right_tools(view, cx))
-    }
-}
-
-impl StatusBar {
-    pub fn new() -> Self {
-        Self {
-            left_tools: None,
-            right_tools: None,
-            bottom_tools: None,
-        }
-    }
-
-    pub fn left_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
-        self.left_tools = {
-            let mut tools = vec![tool];
-            tools.extend(self.left_tools.take().unwrap_or_default().tools);
-            Some(ToolGroup {
-                active_index,
-                tools,
-            })
-        };
-        self
-    }
-
-    pub fn right_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
-        self.right_tools = {
-            let mut tools = vec![tool];
-            tools.extend(self.left_tools.take().unwrap_or_default().tools);
-            Some(ToolGroup {
-                active_index,
-                tools,
-            })
-        };
-        self
-    }
-
-    pub fn bottom_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
-        self.bottom_tools = {
-            let mut tools = vec![tool];
-            tools.extend(self.left_tools.take().unwrap_or_default().tools);
-            Some(ToolGroup {
-                active_index,
-                tools,
-            })
-        };
-        self
-    }
-
-    fn left_tools(&self, workspace: &mut Workspace, cx: &WindowContext) -> impl Element<Workspace> {
-        div()
-            .flex()
-            .items_center()
-            .gap_1()
-            .child(
-                IconButton::<Workspace>::new("project_panel", Icon::FileTree)
-                    .when(workspace.is_project_panel_open(), |this| {
-                        this.color(TextColor::Accent)
-                    })
-                    .on_click(|workspace: &mut Workspace, cx| {
-                        workspace.toggle_project_panel(cx);
-                    }),
-            )
-            .child(
-                IconButton::<Workspace>::new("collab_panel", Icon::Hash)
-                    .when(workspace.is_collab_panel_open(), |this| {
-                        this.color(TextColor::Accent)
-                    })
-                    .on_click(|workspace: &mut Workspace, cx| {
-                        workspace.toggle_collab_panel();
-                    }),
-            )
-            .child(ToolDivider::new())
-            .child(IconButton::new("diagnostics", Icon::XCircle))
-    }
-
-    fn right_tools(
-        &self,
-        workspace: &mut Workspace,
-        cx: &WindowContext,
-    ) -> impl Element<Workspace> {
-        div()
-            .flex()
-            .items_center()
-            .gap_2()
-            .child(
-                div()
-                    .flex()
-                    .items_center()
-                    .gap_1()
-                    .child(Button::new("116:25"))
-                    .child(
-                        Button::<Workspace>::new("Rust").on_click(Arc::new(|workspace, cx| {
-                            workspace.toggle_language_selector(cx);
-                        })),
-                    ),
-            )
-            .child(ToolDivider::new())
-            .child(
-                div()
-                    .flex()
-                    .items_center()
-                    .gap_1()
-                    .child(
-                        IconButton::new("copilot", Icon::Copilot)
-                            .on_click(|_, _| println!("Copilot clicked.")),
-                    )
-                    .child(
-                        IconButton::new("envelope", Icon::Envelope)
-                            .on_click(|_, _| println!("Send Feedback clicked.")),
-                    ),
-            )
-            .child(ToolDivider::new())
-            .child(
-                div()
-                    .flex()
-                    .items_center()
-                    .gap_1()
-                    .child(
-                        IconButton::<Workspace>::new("terminal", Icon::Terminal)
-                            .when(workspace.is_terminal_open(), |this| {
-                                this.color(TextColor::Accent)
-                            })
-                            .on_click(|workspace: &mut Workspace, cx| {
-                                workspace.toggle_terminal(cx);
-                            }),
-                    )
-                    .child(
-                        IconButton::<Workspace>::new("chat_panel", Icon::MessageBubbles)
-                            .when(workspace.is_chat_panel_open(), |this| {
-                                this.color(TextColor::Accent)
-                            })
-                            .on_click(|workspace: &mut Workspace, cx| {
-                                workspace.toggle_chat_panel(cx);
-                            }),
-                    )
-                    .child(
-                        IconButton::<Workspace>::new("assistant_panel", Icon::Ai)
-                            .when(workspace.is_assistant_panel_open(), |this| {
-                                this.color(TextColor::Accent)
-                            })
-                            .on_click(|workspace: &mut Workspace, cx| {
-                                workspace.toggle_assistant_panel(cx);
-                            }),
-                    ),
-            )
-    }
-}

crates/ui2/src/to_extract/tab_bar.rs 🔗

@@ -1,156 +0,0 @@
-use crate::{prelude::*, Icon, IconButton, Tab};
-use gpui::prelude::*;
-use gpui::Div;
-use gpui::Stateful;
-
-#[derive(RenderOnce)]
-pub struct TabBar {
-    id: ElementId,
-    /// Backwards, Forwards
-    can_navigate: (bool, bool),
-    tabs: Vec<Tab>,
-}
-
-impl<V: 'static> Component<V> for TabBar {
-    type Rendered = Stateful<V, Div<V>>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        let (can_navigate_back, can_navigate_forward) = self.can_navigate;
-
-        div()
-            .group("tab_bar")
-            .id(self.id.clone())
-            .w_full()
-            .flex()
-            .bg(cx.theme().colors().tab_bar_background)
-            // Left Side
-            .child(
-                div()
-                    .relative()
-                    .px_1()
-                    .flex()
-                    .flex_none()
-                    .gap_2()
-                    // Nav Buttons
-                    .child(
-                        div()
-                            .right_0()
-                            .flex()
-                            .items_center()
-                            .gap_px()
-                            .child(
-                                IconButton::new("arrow_left", Icon::ArrowLeft)
-                                    .state(InteractionState::Enabled.if_enabled(can_navigate_back)),
-                            )
-                            .child(
-                                IconButton::new("arrow_right", Icon::ArrowRight).state(
-                                    InteractionState::Enabled.if_enabled(can_navigate_forward),
-                                ),
-                            ),
-                    ),
-            )
-            .child(
-                div().w_0().flex_1().h_full().child(
-                    div()
-                        .id("tabs")
-                        .flex()
-                        .overflow_x_scroll()
-                        .children(self.tabs.clone()),
-                ),
-            )
-            // Right Side
-            .child(
-                div()
-                    // We only use absolute here since we don't
-                    // have opacity or `hidden()` yet
-                    .absolute()
-                    .neg_top_7()
-                    .px_1()
-                    .flex()
-                    .flex_none()
-                    .gap_2()
-                    .group_hover("tab_bar", |this| this.top_0())
-                    // Nav Buttons
-                    .child(
-                        div()
-                            .flex()
-                            .items_center()
-                            .gap_px()
-                            .child(IconButton::new("plus", Icon::Plus))
-                            .child(IconButton::new("split", Icon::Split)),
-                    ),
-            )
-    }
-}
-
-impl TabBar {
-    pub fn new(id: impl Into<ElementId>, tabs: Vec<Tab>) -> Self {
-        Self {
-            id: id.into(),
-            can_navigate: (false, false),
-            tabs,
-        }
-    }
-
-    pub fn can_navigate(mut self, can_navigate: (bool, bool)) -> Self {
-        self.can_navigate = can_navigate;
-        self
-    }
-}
-
-use gpui::ElementId;
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::Story;
-    use gpui::{Div, Render};
-
-    pub struct TabBarStory;
-
-    impl Render<Self> for TabBarStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, TabBar>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(TabBar::new(
-                    "tab-bar",
-                    vec![
-                        Tab::new(1)
-                            .title("Cargo.toml".to_string())
-                            .current(false)
-                            .git_status(GitStatus::Modified),
-                        Tab::new(2)
-                            .title("Channels Panel".to_string())
-                            .current(false),
-                        Tab::new(3)
-                            .title("channels_panel.rs".to_string())
-                            .current(true)
-                            .git_status(GitStatus::Modified),
-                        Tab::new(4)
-                            .title("workspace.rs".to_string())
-                            .current(false)
-                            .git_status(GitStatus::Modified),
-                        Tab::new(5)
-                            .title("icon_button.rs".to_string())
-                            .current(false),
-                        Tab::new(6)
-                            .title("storybook.rs".to_string())
-                            .current(false)
-                            .git_status(GitStatus::Created),
-                        Tab::new(7).title("theme.rs".to_string()).current(false),
-                        Tab::new(8)
-                            .title("theme_registry.rs".to_string())
-                            .current(false),
-                        Tab::new(9)
-                            .title("styleable_helpers.rs".to_string())
-                            .current(false),
-                    ],
-                ))
-        }
-    }
-}

crates/ui2/src/to_extract/terminal.rs 🔗

@@ -1,166 +0,0 @@
-use crate::prelude::*;
-use crate::{Icon, IconButton, Pane, Tab};
-use gpui::{relative, rems, Div, RenderOnce, Size};
-
-#[derive(RenderOnce)]
-pub struct Terminal;
-
-impl<V: 'static> Component<V> for Terminal {
-    type Rendered = Div<V>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        let can_navigate_back = true;
-        let can_navigate_forward = false;
-
-        div()
-            .flex()
-            .flex_col()
-            .w_full()
-            .child(
-                // Terminal Tabs.
-                div()
-                    .w_full()
-                    .flex()
-                    .bg(cx.theme().colors().surface_background)
-                    .child(
-                        div().px_1().flex().flex_none().gap_2().child(
-                            div()
-                                .flex()
-                                .items_center()
-                                .gap_px()
-                                .child(
-                                    IconButton::new("arrow_left", Icon::ArrowLeft).state(
-                                        InteractionState::Enabled.if_enabled(can_navigate_back),
-                                    ),
-                                )
-                                .child(IconButton::new("arrow_right", Icon::ArrowRight).state(
-                                    InteractionState::Enabled.if_enabled(can_navigate_forward),
-                                )),
-                        ),
-                    )
-                    .child(
-                        div().w_0().flex_1().h_full().child(
-                            div()
-                                .flex()
-                                .child(
-                                    Tab::new(1)
-                                        .title("zed — fish".to_string())
-                                        .icon(Icon::Terminal)
-                                        .close_side(IconSide::Right)
-                                        .current(true),
-                                )
-                                .child(
-                                    Tab::new(2)
-                                        .title("zed — fish".to_string())
-                                        .icon(Icon::Terminal)
-                                        .close_side(IconSide::Right)
-                                        .current(false),
-                                ),
-                        ),
-                    ),
-            )
-            // Terminal Pane.
-            .child(
-                Pane::new(
-                    "terminal",
-                    Size {
-                        width: relative(1.).into(),
-                        height: rems(36.).into(),
-                    },
-                )
-                .child(crate::static_data::terminal_buffer(cx)),
-            )
-    }
-}
-
-impl Terminal {
-    pub fn new() -> Self {
-        Self
-    }
-
-    fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
-        let can_navigate_back = true;
-        let can_navigate_forward = false;
-
-        div()
-            .flex()
-            .flex_col()
-            .w_full()
-            .child(
-                // Terminal Tabs.
-                div()
-                    .w_full()
-                    .flex()
-                    .bg(cx.theme().colors().surface_background)
-                    .child(
-                        div().px_1().flex().flex_none().gap_2().child(
-                            div()
-                                .flex()
-                                .items_center()
-                                .gap_px()
-                                .child(
-                                    IconButton::new("arrow_left", Icon::ArrowLeft).state(
-                                        InteractionState::Enabled.if_enabled(can_navigate_back),
-                                    ),
-                                )
-                                .child(IconButton::new("arrow_right", Icon::ArrowRight).state(
-                                    InteractionState::Enabled.if_enabled(can_navigate_forward),
-                                )),
-                        ),
-                    )
-                    .child(
-                        div().w_0().flex_1().h_full().child(
-                            div()
-                                .flex()
-                                .child(
-                                    Tab::new(1)
-                                        .title("zed — fish".to_string())
-                                        .icon(Icon::Terminal)
-                                        .close_side(IconSide::Right)
-                                        .current(true),
-                                )
-                                .child(
-                                    Tab::new(2)
-                                        .title("zed — fish".to_string())
-                                        .icon(Icon::Terminal)
-                                        .close_side(IconSide::Right)
-                                        .current(false),
-                                ),
-                        ),
-                    ),
-            )
-            // Terminal Pane.
-            .child(
-                Pane::new(
-                    "terminal",
-                    Size {
-                        width: relative(1.).into(),
-                        height: rems(36.).into(),
-                    },
-                )
-                .child(crate::static_data::terminal_buffer(cx)),
-            )
-    }
-}
-
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::Story;
-    use gpui::{Div, Render};
-    pub struct TerminalStory;
-
-    impl Render<Self> for TerminalStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, Terminal>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(Terminal::new())
-        }
-    }
-}

crates/ui2/src/to_extract/theme_selector.rs 🔗

@@ -1,66 +0,0 @@
-use crate::prelude::*;
-use crate::{OrderMethod, Palette, PaletteItem};
-
-#[derive(RenderOnce)]
-pub struct ThemeSelector {
-    id: ElementId,
-}
-
-impl<V: 'static> Component<V> for ThemeSelector {
-    type Rendered = Div<V>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        let cx: &mut ViewContext<V> = cx;
-        div().child(
-            Palette::new(self.id.clone())
-                .items(vec![
-                    PaletteItem::new("One Dark"),
-                    PaletteItem::new("Rosé Pine"),
-                    PaletteItem::new("Rosé Pine Moon"),
-                    PaletteItem::new("Sandcastle"),
-                    PaletteItem::new("Solarized Dark"),
-                    PaletteItem::new("Summercamp"),
-                    PaletteItem::new("Atelier Cave Light"),
-                    PaletteItem::new("Atelier Dune Light"),
-                    PaletteItem::new("Atelier Estuary Light"),
-                    PaletteItem::new("Atelier Forest Light"),
-                    PaletteItem::new("Atelier Heath Light"),
-                ])
-                .placeholder("Select Theme...")
-                .empty_string("No matches")
-                .default_order(OrderMethod::Ascending),
-        )
-    }
-}
-
-impl ThemeSelector {
-    pub fn new(id: impl Into<ElementId>) -> Self {
-        Self { id: id.into() }
-    }
-}
-
-use gpui::{Div, RenderOnce};
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use gpui::{Div, Render};
-
-    use crate::Story;
-
-    use super::*;
-
-    pub struct ThemeSelectorStory;
-
-    impl Render<Self> for ThemeSelectorStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, ThemeSelector>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(ThemeSelector::new("theme-selector"))
-        }
-    }
-}

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

@@ -1,218 +0,0 @@
-use std::sync::atomic::AtomicBool;
-use std::sync::Arc;
-
-use gpui::{Div, Render, RenderOnce, View, VisualContext};
-
-use crate::prelude::*;
-use crate::settings::user_settings;
-use crate::{
-    Avatar, Button, Icon, IconButton, MicStatus, PlayerStack, PlayerWithCallStatus,
-    ScreenShareStatus, TextColor, ToolDivider, TrafficLights,
-};
-
-#[derive(Clone)]
-pub struct Livestream {
-    pub players: Vec<PlayerWithCallStatus>,
-    pub channel: Option<String>, // projects
-                                 // windows
-}
-
-#[derive(Clone)]
-pub struct TitleBar {
-    /// If the window is active from the OS's perspective.
-    is_active: Arc<AtomicBool>,
-    livestream: Option<Livestream>,
-    mic_status: MicStatus,
-    is_deafened: bool,
-    screen_share_status: ScreenShareStatus,
-}
-
-impl TitleBar {
-    pub fn new(cx: &mut ViewContext<Self>) -> Self {
-        let is_active = Arc::new(AtomicBool::new(true));
-        let active = is_active.clone();
-
-        // cx.observe_window_activation(move |_, is_active, cx| {
-        //     active.store(is_active, std::sync::atomic::Ordering::SeqCst);
-        //     cx.notify();
-        // })
-        // .detach();
-
-        Self {
-            is_active,
-            livestream: None,
-            mic_status: MicStatus::Unmuted,
-            is_deafened: false,
-            screen_share_status: ScreenShareStatus::NotShared,
-        }
-    }
-
-    pub fn set_livestream(mut self, livestream: Option<Livestream>) -> Self {
-        self.livestream = livestream;
-        self
-    }
-
-    pub fn is_mic_muted(&self) -> bool {
-        self.mic_status == MicStatus::Muted
-    }
-
-    pub fn toggle_mic_status(&mut self, cx: &mut ViewContext<Self>) {
-        self.mic_status = self.mic_status.inverse();
-
-        // Undeafen yourself when unmuting the mic while deafened.
-        if self.is_deafened && self.mic_status == MicStatus::Unmuted {
-            self.is_deafened = false;
-        }
-
-        cx.notify();
-    }
-
-    pub fn toggle_deafened(&mut self, cx: &mut ViewContext<Self>) {
-        self.is_deafened = !self.is_deafened;
-        self.mic_status = MicStatus::Muted;
-
-        cx.notify()
-    }
-
-    pub fn toggle_screen_share_status(&mut self, cx: &mut ViewContext<Self>) {
-        self.screen_share_status = self.screen_share_status.inverse();
-
-        cx.notify();
-    }
-
-    pub fn view(cx: &mut WindowContext, livestream: Option<Livestream>) -> View<Self> {
-        cx.build_view(|cx| Self::new(cx).set_livestream(livestream))
-    }
-}
-
-impl Render<Self> for TitleBar {
-    type Element = Div<Self>;
-
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> {
-        let settings = user_settings(cx);
-
-        // let has_focus = cx.window_is_active();
-        let has_focus = true;
-
-        let player_list = if let Some(livestream) = &self.livestream {
-            livestream.players.clone().into_iter()
-        } else {
-            vec![].into_iter()
-        };
-
-        div()
-            .flex()
-            .items_center()
-            .justify_between()
-            .w_full()
-            .bg(cx.theme().colors().background)
-            .py_1()
-            .child(
-                div()
-                    .flex()
-                    .items_center()
-                    .h_full()
-                    .gap_4()
-                    .px_2()
-                    .child(TrafficLights::new().window_has_focus(has_focus))
-                    // === Project Info === //
-                    .child(
-                        div()
-                            .flex()
-                            .items_center()
-                            .gap_1()
-                            .when(*settings.titlebar.show_project_owner, |this| {
-                                this.child(Button::new("iamnbutler"))
-                            })
-                            .child(Button::new("zed"))
-                            .child(Button::new("nate/gpui2-ui-components")),
-                    )
-                    .children(player_list.map(|p| PlayerStack::new(p)))
-                    .child(IconButton::new("plus", Icon::Plus)),
-            )
-            .child(
-                div()
-                    .flex()
-                    .items_center()
-                    .child(
-                        div()
-                            .px_2()
-                            .flex()
-                            .items_center()
-                            .gap_1()
-                            .child(IconButton::new("folder_x", Icon::FolderX))
-                            .child(IconButton::new("exit", Icon::Exit)),
-                    )
-                    .child(ToolDivider::new())
-                    .child(
-                        div()
-                            .px_2()
-                            .flex()
-                            .items_center()
-                            .gap_1()
-                            .child(
-                                IconButton::<TitleBar>::new("toggle_mic_status", Icon::Mic)
-                                    .when(self.is_mic_muted(), |this| this.color(TextColor::Error))
-                                    .on_click(|title_bar: &mut TitleBar, cx| {
-                                        title_bar.toggle_mic_status(cx)
-                                    }),
-                            )
-                            .child(
-                                IconButton::<TitleBar>::new("toggle_deafened", Icon::AudioOn)
-                                    .when(self.is_deafened, |this| this.color(TextColor::Error))
-                                    .on_click(|title_bar: &mut TitleBar, cx| {
-                                        title_bar.toggle_deafened(cx)
-                                    }),
-                            )
-                            .child(
-                                IconButton::<TitleBar>::new("toggle_screen_share", Icon::Screen)
-                                    .when(
-                                        self.screen_share_status == ScreenShareStatus::Shared,
-                                        |this| this.color(TextColor::Accent),
-                                    )
-                                    .on_click(|title_bar: &mut TitleBar, cx| {
-                                        title_bar.toggle_screen_share_status(cx)
-                                    }),
-                            ),
-                    )
-                    .child(
-                        div().px_2().flex().items_center().child(
-                            Avatar::new("https://avatars.githubusercontent.com/u/1714999?v=4")
-                                .shape(Shape::RoundedRectangle),
-                        ),
-                    ),
-            )
-    }
-}
-
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::Story;
-
-    pub struct TitleBarStory {
-        title_bar: View<TitleBar>,
-    }
-
-    impl TitleBarStory {
-        pub fn view(cx: &mut WindowContext) -> View<Self> {
-            cx.build_view(|cx| Self {
-                title_bar: TitleBar::view(cx, None),
-            })
-        }
-    }
-
-    impl Render<Self> for TitleBarStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> {
-            Story::container(cx)
-                .child(Story::title_for::<_, TitleBar>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(self.title_bar.clone())
-        }
-    }
-}

crates/ui2/src/to_extract/toolbar.rs 🔗

@@ -1,130 +0,0 @@
-use gpui::{AnyElement, Div, RenderOnce};
-use smallvec::SmallVec;
-
-use crate::prelude::*;
-
-#[derive(Clone)]
-pub struct ToolbarItem {}
-
-#[derive(RenderOnce)]
-pub struct Toolbar<V: 'static> {
-    left_items: SmallVec<[AnyElement<V>; 2]>,
-    right_items: SmallVec<[AnyElement<V>; 2]>,
-}
-
-impl<V: 'static> Component<V> for Toolbar<V> {
-    type Rendered = Div<V>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        div()
-            .bg(cx.theme().colors().toolbar_background)
-            .p_2()
-            .flex()
-            .justify_between()
-            .child(div().flex().children(self.left_items))
-            .child(div().flex().children(self.right_items))
-    }
-}
-
-impl<V: 'static> Toolbar<V> {
-    pub fn new() -> Self {
-        Self {
-            left_items: SmallVec::new(),
-            right_items: SmallVec::new(),
-        }
-    }
-
-    pub fn left_item(mut self, child: impl RenderOnce<V>) -> Self
-    where
-        Self: Sized,
-    {
-        self.left_items.push(child.render_into_any());
-        self
-    }
-
-    pub fn left_items(mut self, iter: impl IntoIterator<Item = impl RenderOnce<V>>) -> Self
-    where
-        Self: Sized,
-    {
-        self.left_items
-            .extend(iter.into_iter().map(|item| item.render_into_any()));
-        self
-    }
-
-    pub fn right_item(mut self, child: impl RenderOnce<V>) -> Self
-    where
-        Self: Sized,
-    {
-        self.right_items.push(child.render_into_any());
-        self
-    }
-
-    pub fn right_items(mut self, iter: impl IntoIterator<Item = impl RenderOnce<V>>) -> Self
-    where
-        Self: Sized,
-    {
-        self.right_items
-            .extend(iter.into_iter().map(|item| item.render_into_any()));
-        self
-    }
-}
-
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use std::path::PathBuf;
-    use std::str::FromStr;
-
-    use gpui::{Div, Render};
-
-    use crate::{Breadcrumb, HighlightedText, Icon, IconButton, Story, Symbol};
-
-    use super::*;
-
-    pub struct ToolbarStory;
-
-    impl Render<Self> for ToolbarStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, Toolbar<Self>>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(
-                    Toolbar::new()
-                        .left_item(Breadcrumb::new(
-                            PathBuf::from_str("crates/ui/src/components/toolbar.rs").unwrap(),
-                            vec![
-                                Symbol(vec![
-                                    HighlightedText {
-                                        text: "impl ".into(),
-                                        color: cx.theme().syntax_color("keyword"),
-                                    },
-                                    HighlightedText {
-                                        text: "ToolbarStory".into(),
-                                        color: cx.theme().syntax_color("function"),
-                                    },
-                                ]),
-                                Symbol(vec![
-                                    HighlightedText {
-                                        text: "fn ".into(),
-                                        color: cx.theme().syntax_color("keyword"),
-                                    },
-                                    HighlightedText {
-                                        text: "render".into(),
-                                        color: cx.theme().syntax_color("function"),
-                                    },
-                                ]),
-                            ],
-                        ))
-                        .right_items(vec![
-                            IconButton::new("toggle_inlay_hints", Icon::InlayHint),
-                            IconButton::new("buffer_search", Icon::MagnifyingGlass),
-                            IconButton::new("inline_assist", Icon::MagicWand),
-                        ]),
-                )
-        }
-    }
-}

crates/ui2/src/to_extract/traffic_lights.rs 🔗

@@ -1,109 +0,0 @@
-use crate::prelude::*;
-
-#[derive(Clone, Copy)]
-enum TrafficLightColor {
-    Red,
-    Yellow,
-    Green,
-}
-
-#[derive(RenderOnce)]
-struct TrafficLight {
-    color: TrafficLightColor,
-    window_has_focus: bool,
-}
-
-impl<V: 'static> Component<V> for TrafficLight {
-    type Rendered = Div<V>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        let system_colors = &cx.theme().styles.system;
-
-        let fill = match (self.window_has_focus, self.color) {
-            (true, TrafficLightColor::Red) => system_colors.mac_os_traffic_light_red,
-            (true, TrafficLightColor::Yellow) => system_colors.mac_os_traffic_light_yellow,
-            (true, TrafficLightColor::Green) => system_colors.mac_os_traffic_light_green,
-            (false, _) => cx.theme().colors().element_background,
-        };
-
-        div().w_3().h_3().rounded_full().bg(fill)
-    }
-}
-
-impl TrafficLight {
-    fn new(color: TrafficLightColor, window_has_focus: bool) -> Self {
-        Self {
-            color,
-            window_has_focus,
-        }
-    }
-}
-
-#[derive(RenderOnce)]
-pub struct TrafficLights {
-    window_has_focus: bool,
-}
-
-impl<V: 'static> Component<V> for TrafficLights {
-    type Rendered = Div<V>;
-
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
-        div()
-            .flex()
-            .items_center()
-            .gap_2()
-            .child(TrafficLight::new(
-                TrafficLightColor::Red,
-                self.window_has_focus,
-            ))
-            .child(TrafficLight::new(
-                TrafficLightColor::Yellow,
-                self.window_has_focus,
-            ))
-            .child(TrafficLight::new(
-                TrafficLightColor::Green,
-                self.window_has_focus,
-            ))
-    }
-}
-
-impl TrafficLights {
-    pub fn new() -> Self {
-        Self {
-            window_has_focus: true,
-        }
-    }
-
-    pub fn window_has_focus(mut self, window_has_focus: bool) -> Self {
-        self.window_has_focus = window_has_focus;
-        self
-    }
-}
-
-use gpui::{Div, RenderOnce};
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use gpui::{Div, Render};
-
-    use crate::Story;
-
-    use super::*;
-
-    pub struct TrafficLightsStory;
-
-    impl Render<Self> for TrafficLightsStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx)
-                .child(Story::title_for::<_, TrafficLights>(cx))
-                .child(Story::label(cx, "Default"))
-                .child(TrafficLights::new())
-                .child(Story::label(cx, "Unfocused"))
-                .child(TrafficLights::new().window_has_focus(false))
-        }
-    }
-}

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

@@ -1,398 +0,0 @@
-use std::sync::Arc;
-
-use chrono::DateTime;
-use gpui::{px, relative, Div, Render, RenderOnce, Size, View, VisualContext};
-use settings2::Settings;
-use theme2::ThemeSettings;
-
-use crate::prelude::*;
-use crate::{
-    static_livestream, v_stack, AssistantPanel, Button, ChatMessage, ChatPanel, Checkbox,
-    CollabPanel, EditorPane, Label, LanguageSelector, NotificationsPanel, Pane, PaneGroup, Panel,
-    PanelAllowedSides, PanelSide, ProjectPanel, SplitDirection, StatusBar, Terminal, TitleBar,
-    Toast, ToastOrigin,
-};
-
-#[derive(Clone)]
-pub struct Gpui2UiDebug {
-    pub in_livestream: bool,
-    pub enable_user_settings: bool,
-    pub show_toast: bool,
-}
-
-impl Default for Gpui2UiDebug {
-    fn default() -> Self {
-        Self {
-            in_livestream: false,
-            enable_user_settings: false,
-            show_toast: false,
-        }
-    }
-}
-
-#[derive(Clone)]
-pub struct Workspace {
-    title_bar: View<TitleBar>,
-    editor_1: View<EditorPane>,
-    show_project_panel: bool,
-    show_collab_panel: bool,
-    show_chat_panel: bool,
-    show_assistant_panel: bool,
-    show_notifications_panel: bool,
-    show_terminal: bool,
-    show_debug: bool,
-    show_language_selector: bool,
-    test_checkbox_selection: Selection,
-    debug: Gpui2UiDebug,
-}
-
-impl Workspace {
-    pub fn new(cx: &mut ViewContext<Self>) -> Self {
-        Self {
-            title_bar: TitleBar::view(cx, None),
-            editor_1: EditorPane::view(cx),
-            show_project_panel: true,
-            show_collab_panel: false,
-            show_chat_panel: false,
-            show_assistant_panel: false,
-            show_terminal: true,
-            show_language_selector: false,
-            show_debug: false,
-            show_notifications_panel: true,
-            test_checkbox_selection: Selection::Unselected,
-            debug: Gpui2UiDebug::default(),
-        }
-    }
-
-    pub fn is_project_panel_open(&self) -> bool {
-        self.show_project_panel
-    }
-
-    pub fn toggle_project_panel(&mut self, cx: &mut ViewContext<Self>) {
-        self.show_project_panel = !self.show_project_panel;
-
-        self.show_collab_panel = false;
-
-        cx.notify();
-    }
-
-    pub fn is_collab_panel_open(&self) -> bool {
-        self.show_collab_panel
-    }
-
-    pub fn toggle_collab_panel(&mut self) {
-        self.show_collab_panel = !self.show_collab_panel;
-
-        self.show_project_panel = false;
-    }
-
-    pub fn is_terminal_open(&self) -> bool {
-        self.show_terminal
-    }
-
-    pub fn toggle_terminal(&mut self, cx: &mut ViewContext<Self>) {
-        self.show_terminal = !self.show_terminal;
-
-        cx.notify();
-    }
-
-    pub fn is_chat_panel_open(&self) -> bool {
-        self.show_chat_panel
-    }
-
-    pub fn toggle_chat_panel(&mut self, cx: &mut ViewContext<Self>) {
-        self.show_chat_panel = !self.show_chat_panel;
-
-        self.show_assistant_panel = false;
-        self.show_notifications_panel = false;
-
-        cx.notify();
-    }
-
-    pub fn is_notifications_panel_open(&self) -> bool {
-        self.show_notifications_panel
-    }
-
-    pub fn toggle_notifications_panel(&mut self, cx: &mut ViewContext<Self>) {
-        self.show_notifications_panel = !self.show_notifications_panel;
-
-        self.show_chat_panel = false;
-        self.show_assistant_panel = false;
-
-        cx.notify();
-    }
-
-    pub fn is_assistant_panel_open(&self) -> bool {
-        self.show_assistant_panel
-    }
-
-    pub fn toggle_assistant_panel(&mut self, cx: &mut ViewContext<Self>) {
-        self.show_assistant_panel = !self.show_assistant_panel;
-
-        self.show_chat_panel = false;
-        self.show_notifications_panel = false;
-
-        cx.notify();
-    }
-
-    pub fn is_language_selector_open(&self) -> bool {
-        self.show_language_selector
-    }
-
-    pub fn toggle_language_selector(&mut self, cx: &mut ViewContext<Self>) {
-        self.show_language_selector = !self.show_language_selector;
-
-        cx.notify();
-    }
-
-    pub fn toggle_debug(&mut self, cx: &mut ViewContext<Self>) {
-        self.show_debug = !self.show_debug;
-
-        cx.notify();
-    }
-
-    pub fn debug_toggle_user_settings(&mut self, cx: &mut ViewContext<Self>) {
-        self.debug.enable_user_settings = !self.debug.enable_user_settings;
-
-        let mut theme_settings = ThemeSettings::get_global(cx).clone();
-
-        if self.debug.enable_user_settings {
-            theme_settings.ui_font_size = 18.0.into();
-        } else {
-            theme_settings.ui_font_size = 16.0.into();
-        }
-
-        ThemeSettings::override_global(theme_settings.clone(), cx);
-
-        cx.set_rem_size(theme_settings.ui_font_size);
-
-        cx.notify();
-    }
-
-    pub fn debug_toggle_livestream(&mut self, cx: &mut ViewContext<Self>) {
-        self.debug.in_livestream = !self.debug.in_livestream;
-
-        self.title_bar = TitleBar::view(
-            cx,
-            Some(static_livestream()).filter(|_| self.debug.in_livestream),
-        );
-
-        cx.notify();
-    }
-
-    pub fn debug_toggle_toast(&mut self, cx: &mut ViewContext<Self>) {
-        self.debug.show_toast = !self.debug.show_toast;
-
-        cx.notify();
-    }
-
-    pub fn view(cx: &mut WindowContext) -> View<Self> {
-        cx.build_view(|cx| Self::new(cx))
-    }
-}
-
-impl Render<Self> for Workspace {
-    type Element = Div<Self>;
-
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> {
-        let root_group = PaneGroup::new_panes(
-            vec![Pane::new(
-                "pane-0",
-                Size {
-                    width: relative(1.).into(),
-                    height: relative(1.).into(),
-                },
-            )
-            .child(self.editor_1.clone())],
-            SplitDirection::Horizontal,
-        );
-        let ui_font = ThemeSettings::get_global(cx).ui_font.family.clone();
-
-        div()
-            .relative()
-            .size_full()
-            .flex()
-            .flex_col()
-            .font(ui_font)
-            .gap_0()
-            .justify_start()
-            .items_start()
-            .text_color(cx.theme().colors().text)
-            .bg(cx.theme().colors().background)
-            .child(self.title_bar.clone())
-            .child(
-                div()
-                    .absolute()
-                    .top_12()
-                    .left_12()
-                    .z_index(99)
-                    .bg(cx.theme().colors().background)
-                    .child(
-                        Checkbox::new("test_checkbox", self.test_checkbox_selection).on_click(
-                            |selection, workspace: &mut Workspace, cx| {
-                                workspace.test_checkbox_selection = selection;
-
-                                cx.notify();
-                            },
-                        ),
-                    ),
-            )
-            .child(
-                div()
-                    .flex_1()
-                    .w_full()
-                    .flex()
-                    .flex_row()
-                    .overflow_hidden()
-                    .border_t()
-                    .border_b()
-                    .border_color(cx.theme().colors().border)
-                    .children(
-                        Some(
-                            Panel::new("project-panel-outer", cx)
-                                .side(PanelSide::Left)
-                                .child(ProjectPanel::new("project-panel-inner")),
-                        )
-                        .filter(|_| self.is_project_panel_open()),
-                    )
-                    .children(
-                        Some(
-                            Panel::new("collab-panel-outer", cx)
-                                .child(CollabPanel::new("collab-panel-inner"))
-                                .side(PanelSide::Left),
-                        )
-                        .filter(|_| self.is_collab_panel_open()),
-                    )
-                    // .child(NotificationToast::new(
-                    //     "maxbrunsfeld has requested to add you as a contact.".into(),
-                    // ))
-                    .child(
-                        v_stack()
-                            .flex_1()
-                            .h_full()
-                            .child(div().flex().flex_1().child(root_group))
-                            .children(
-                                Some(
-                                    Panel::new("terminal-panel", cx)
-                                        .child(Terminal::new())
-                                        .allowed_sides(PanelAllowedSides::BottomOnly)
-                                        .side(PanelSide::Bottom),
-                                )
-                                .filter(|_| self.is_terminal_open()),
-                            ),
-                    )
-                    .children(
-                        Some(
-                            Panel::new("chat-panel-outer", cx)
-                                .side(PanelSide::Right)
-                                .child(ChatPanel::new("chat-panel-inner").messages(vec![
-                                    ChatMessage::new(
-                                        "osiewicz".to_string(),
-                                        "is this thing on?".to_string(),
-                                        DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z")
-                                            .unwrap()
-                                            .naive_local(),
-                                    ),
-                                    ChatMessage::new(
-                                        "maxdeviant".to_string(),
-                                        "Reading you loud and clear!".to_string(),
-                                        DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z")
-                                            .unwrap()
-                                            .naive_local(),
-                                    ),
-                                ])),
-                        )
-                        .filter(|_| self.is_chat_panel_open()),
-                    )
-                    .children(
-                        Some(
-                            Panel::new("notifications-panel-outer", cx)
-                                .side(PanelSide::Right)
-                                .child(NotificationsPanel::new("notifications-panel-inner")),
-                        )
-                        .filter(|_| self.is_notifications_panel_open()),
-                    )
-                    .children(
-                        Some(
-                            Panel::new("assistant-panel-outer", cx)
-                                .child(AssistantPanel::new("assistant-panel-inner")),
-                        )
-                        .filter(|_| self.is_assistant_panel_open()),
-                    ),
-            )
-            .child(StatusBar::new())
-            .when(self.debug.show_toast, |this| {
-                this.child(Toast::new(ToastOrigin::Bottom).child(Label::new("A toast")))
-            })
-            .children(
-                Some(
-                    div()
-                        .absolute()
-                        .top(px(50.))
-                        .left(px(640.))
-                        .z_index(8)
-                        .child(LanguageSelector::new("language-selector")),
-                )
-                .filter(|_| self.is_language_selector_open()),
-            )
-            .z_index(8)
-            // Debug
-            .child(
-                v_stack()
-                    .z_index(9)
-                    .absolute()
-                    .top_20()
-                    .left_1_4()
-                    .w_40()
-                    .gap_2()
-                    .when(self.show_debug, |this| {
-                        this.child(Button::<Workspace>::new("Toggle User Settings").on_click(
-                            Arc::new(|workspace, cx| workspace.debug_toggle_user_settings(cx)),
-                        ))
-                        .child(
-                            Button::<Workspace>::new("Toggle Toasts").on_click(Arc::new(
-                                |workspace, cx| workspace.debug_toggle_toast(cx),
-                            )),
-                        )
-                        .child(
-                            Button::<Workspace>::new("Toggle Livestream").on_click(Arc::new(
-                                |workspace, cx| workspace.debug_toggle_livestream(cx),
-                            )),
-                        )
-                    })
-                    .child(
-                        Button::<Workspace>::new("Toggle Debug")
-                            .on_click(Arc::new(|workspace, cx| workspace.toggle_debug(cx))),
-                    ),
-            )
-    }
-}
-
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use gpui::VisualContext;
-
-    pub struct WorkspaceStory {
-        workspace: View<Workspace>,
-    }
-
-    impl WorkspaceStory {
-        pub fn view(cx: &mut WindowContext) -> View<Self> {
-            cx.build_view(|cx| Self {
-                workspace: Workspace::view(cx),
-            })
-        }
-    }
-
-    impl Render<Self> for WorkspaceStory {
-        type Element = Div<Self>;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            div().child(self.workspace.clone())
-        }
-    }
-}

crates/workspace2/src/dock.rs 🔗

@@ -476,8 +476,8 @@ impl Dock {
     }
 }
 
-impl Render<Self> for Dock {
-    type Element = Div<Self>;
+impl Render for Dock {
+    type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         if let Some(entry) = self.visible_entry() {
@@ -662,8 +662,8 @@ impl PanelButtons {
 // }
 
 // here be kittens
-impl Render<Self> for PanelButtons {
-    type Element = Div<Self>;
+impl Render for PanelButtons {
+    type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         // todo!()
@@ -688,30 +688,31 @@ impl Render<Self> for PanelButtons {
                 let name = entry.panel.persistent_name();
                 let panel = entry.panel.clone();
 
-                let mut button: IconButton<Self> = if i == active_index && is_open {
+                let mut button: IconButton = if i == active_index && is_open {
                     let action = dock.toggle_action();
                     let tooltip: SharedString =
                         format!("Close {} dock", dock.position.to_label()).into();
                     IconButton::new(name, icon)
                         .state(InteractionState::Active)
                         .action(action.boxed_clone())
-                        .tooltip(move |_, cx| Tooltip::for_action(tooltip.clone(), &*action, cx))
+                        .tooltip(move |cx| Tooltip::for_action(tooltip.clone(), &*action, cx))
                 } else {
                     let action = entry.panel.toggle_action(cx);
 
                     IconButton::new(name, icon)
                         .action(action.boxed_clone())
-                        .tooltip(move |_, cx| Tooltip::for_action(name, &*action, cx))
+                        .tooltip(move |cx| Tooltip::for_action(name, &*action, cx))
                 };
 
                 Some(
                     menu_handle(name)
-                        .menu(move |_, cx| {
+                        .menu(move |cx| {
                             const POSITIONS: [DockPosition; 3] = [
                                 DockPosition::Left,
                                 DockPosition::Right,
                                 DockPosition::Bottom,
                             ];
+
                             ContextMenu::build(cx, |mut menu, cx| {
                                 for position in POSITIONS {
                                     if position != dock_position
@@ -720,7 +721,7 @@ impl Render<Self> for PanelButtons {
                                         let panel = panel.clone();
                                         menu = menu.entry(
                                             ListItem::new(
-                                                SharedString::from(format!("dock-{position:?}")),
+                                                panel.entity_id(),
                                                 Label::new(format!("Dock {}", position.to_label())),
                                             ),
                                             move |_, cx| {
@@ -780,8 +781,8 @@ pub mod test {
         }
     }
 
-    impl Render<Self> for TestPanel {
-        type Element = Div<Self>;
+    impl Render for TestPanel {
+        type Element = Div;
 
         fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
             div()

crates/workspace2/src/item.rs 🔗

@@ -104,7 +104,7 @@ pub trait Item: FocusableView + EventEmitter<ItemEvent> {
     fn tab_description(&self, _: usize, _: &AppContext) -> Option<SharedString> {
         None
     }
-    fn tab_content<V: 'static>(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<V>;
+    fn tab_content(&self, detail: Option<usize>, cx: &WindowContext) -> AnyElement;
 
     /// (model id, Item)
     fn for_each_project_item(
@@ -214,8 +214,8 @@ pub trait ItemHandle: 'static + Send {
     ) -> gpui::Subscription;
     fn tab_tooltip_text(&self, cx: &AppContext) -> Option<SharedString>;
     fn tab_description(&self, detail: usize, cx: &AppContext) -> Option<SharedString>;
-    fn tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Pane>;
-    fn dragged_tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Workspace>;
+    fn tab_content(&self, detail: Option<usize>, cx: &WindowContext) -> AnyElement;
+    fn dragged_tab_content(&self, detail: Option<usize>, cx: &WindowContext) -> AnyElement;
     fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>;
     fn project_entry_ids(&self, cx: &AppContext) -> SmallVec<[ProjectEntryId; 3]>;
     fn project_item_model_ids(&self, cx: &AppContext) -> SmallVec<[EntityId; 3]>;
@@ -307,11 +307,11 @@ impl<T: Item> ItemHandle for View<T> {
         self.read(cx).tab_description(detail, cx)
     }
 
-    fn tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Pane> {
+    fn tab_content(&self, detail: Option<usize>, cx: &WindowContext) -> AnyElement {
         self.read(cx).tab_content(detail, cx)
     }
 
-    fn dragged_tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Workspace> {
+    fn dragged_tab_content(&self, detail: Option<usize>, cx: &WindowContext) -> AnyElement {
         self.read(cx).tab_content(detail, cx)
     }
 

crates/workspace2/src/modal_layer.rs 🔗

@@ -71,8 +71,8 @@ impl ModalLayer {
     }
 }
 
-impl Render<Self> for ModalLayer {
-    type Element = Div<Self>;
+impl Render for ModalLayer {
+    type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         let Some(active_modal) = &self.active_modal else {
@@ -97,11 +97,11 @@ impl Render<Self> for ModalLayer {
                         h_stack()
                             // needed to prevent mouse events leaking to the
                             // UI below. // todo! for gpui3.
-                            .on_any_mouse_down(|_, _, cx| cx.stop_propagation())
-                            .on_any_mouse_up(|_, _, cx| cx.stop_propagation())
-                            .on_mouse_down_out(|this: &mut Self, event, cx| {
+                            .on_any_mouse_down(|_, cx| cx.stop_propagation())
+                            .on_any_mouse_up(|_, cx| cx.stop_propagation())
+                            .on_mouse_down_out(cx.listener(|this, _, cx| {
                                 this.hide_modal(cx);
-                            })
+                            }))
                             .child(active_modal.modal.clone()),
                     ),
             )

crates/workspace2/src/notifications.rs 🔗

@@ -13,9 +13,9 @@ pub enum NotificationEvent {
     Dismiss,
 }
 
-pub trait Notification: EventEmitter<NotificationEvent> + Render<Self> {}
+pub trait Notification: EventEmitter<NotificationEvent> + Render {}
 
-impl<V: EventEmitter<NotificationEvent> + Render<Self>> Notification for V {}
+impl<V: EventEmitter<NotificationEvent> + Render> Notification for V {}
 
 pub trait NotificationHandle: Send {
     fn id(&self) -> EntityId;
@@ -198,7 +198,7 @@ pub mod simple_message_notification {
 
     enum NotificationMessage {
         Text(Cow<'static, str>),
-        Element(fn(TextStyle, &AppContext) -> AnyElement<MessageNotification>),
+        Element(fn(TextStyle, &AppContext) -> AnyElement),
     }
 
     pub struct MessageNotification {
@@ -222,7 +222,7 @@ pub mod simple_message_notification {
         }
 
         pub fn new_element(
-            message: fn(TextStyle, &AppContext) -> AnyElement<MessageNotification>,
+            message: fn(TextStyle, &AppContext) -> AnyElement,
         ) -> MessageNotification {
             Self {
                 message: NotificationMessage::Element(message),
@@ -253,8 +253,8 @@ pub mod simple_message_notification {
         // }
     }
 
-    impl Render<Self> for MessageNotification {
-        type Element = Div<Self>;
+    impl Render for MessageNotification {
+        type Element = Div;
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
             todo!()

crates/workspace2/src/pane.rs 🔗

@@ -594,7 +594,7 @@ impl Pane {
         self.items.iter()
     }
 
-    pub fn items_of_type<T: Render<T>>(&self) -> impl '_ + Iterator<Item = View<T>> {
+    pub fn items_of_type<T: Render>(&self) -> impl '_ + Iterator<Item = View<T>> {
         self.items
             .iter()
             .filter_map(|item| item.to_any().downcast().ok())
@@ -1344,7 +1344,7 @@ impl Pane {
         item: &Box<dyn ItemHandle>,
         detail: usize,
         cx: &mut ViewContext<'_, Pane>,
-    ) -> impl RenderOnce<Self> {
+    ) -> impl RenderOnce {
         let label = item.tab_content(Some(detail), cx);
         let close_icon = || {
             let id = item.item_id();
@@ -1353,12 +1353,14 @@ impl Pane {
                 .id(item.item_id())
                 .invisible()
                 .group_hover("", |style| style.visible())
-                .child(IconButton::new("close_tab", Icon::Close).on_click(
-                    move |pane: &mut Self, cx| {
-                        pane.close_item_by_id(id, SaveIntent::Close, cx)
-                            .detach_and_log_err(cx);
-                    },
-                ))
+                .child(
+                    IconButton::new("close_tab", Icon::Close).on_click(cx.listener(
+                        move |pane, _, cx| {
+                            pane.close_item_by_id(id, SaveIntent::Close, cx)
+                                .detach_and_log_err(cx);
+                        },
+                    )),
+                )
         };
 
         let (text_color, tab_bg, tab_hover_bg, tab_active_bg) = match ix == self.active_item_index {
@@ -1383,9 +1385,9 @@ impl Pane {
             .id(item.item_id())
             .cursor_pointer()
             .when_some(item.tab_tooltip_text(cx), |div, text| {
-                div.tooltip(move |_, cx| cx.build_view(|cx| Tooltip::new(text.clone())).into())
+                div.tooltip(move |cx| cx.build_view(|cx| Tooltip::new(text.clone())).into())
             })
-            .on_click(move |v: &mut Self, e, cx| v.activate_item(ix, true, true, cx))
+            .on_click(cx.listener(move |v: &mut Self, e, cx| v.activate_item(ix, true, true, cx)))
             // .on_drag(move |pane, cx| pane.render_tab(ix, item.boxed_clone(), detail, cx))
             // .drag_over::<DraggedTab>(|d| d.bg(cx.theme().colors().element_drop_target))
             // .on_drop(|_view, state: View<DraggedTab>, cx| {
@@ -1437,7 +1439,7 @@ impl Pane {
             )
     }
 
-    fn render_tab_bar(&mut self, cx: &mut ViewContext<'_, Pane>) -> impl RenderOnce<Self> {
+    fn render_tab_bar(&mut self, cx: &mut ViewContext<'_, Pane>) -> impl RenderOnce {
         div()
             .group("tab_bar")
             .id("tab_bar")
@@ -1891,17 +1893,25 @@ impl FocusableView for Pane {
     }
 }
 
-impl Render<Self> for Pane {
-    type Element = Focusable<Self, Div<Self>>;
+impl Render for Pane {
+    type Element = Focusable<Div>;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         v_stack()
             .key_context("Pane")
             .track_focus(&self.focus_handle)
-            .on_action(|pane: &mut Pane, _: &SplitLeft, cx| pane.split(SplitDirection::Left, cx))
-            .on_action(|pane: &mut Pane, _: &SplitUp, cx| pane.split(SplitDirection::Up, cx))
-            .on_action(|pane: &mut Pane, _: &SplitRight, cx| pane.split(SplitDirection::Right, cx))
-            .on_action(|pane: &mut Pane, _: &SplitDown, cx| pane.split(SplitDirection::Down, cx))
+            .on_action(cx.listener(|pane: &mut Pane, _: &SplitLeft, cx| {
+                pane.split(SplitDirection::Left, cx)
+            }))
+            .on_action(
+                cx.listener(|pane: &mut Pane, _: &SplitUp, cx| pane.split(SplitDirection::Up, cx)),
+            )
+            .on_action(cx.listener(|pane: &mut Pane, _: &SplitRight, cx| {
+                pane.split(SplitDirection::Right, cx)
+            }))
+            .on_action(cx.listener(|pane: &mut Pane, _: &SplitDown, cx| {
+                pane.split(SplitDirection::Down, cx)
+            }))
             //     cx.add_action(Pane::toggle_zoom);
             //     cx.add_action(|pane: &mut Pane, action: &ActivateItem, cx| {
             //         pane.activate_item(action.0, true, true, cx);
@@ -1922,10 +1932,12 @@ impl Render<Self> for Pane {
             //     cx.add_async_action(Pane::close_items_to_the_right);
             //     cx.add_async_action(Pane::close_all_items);
             .size_full()
-            .on_action(|pane: &mut Self, action: &CloseActiveItem, cx| {
-                pane.close_active_item(action, cx)
-                    .map(|task| task.detach_and_log_err(cx));
-            })
+            .on_action(
+                cx.listener(|pane: &mut Self, action: &CloseActiveItem, cx| {
+                    pane.close_active_item(action, cx)
+                        .map(|task| task.detach_and_log_err(cx));
+                }),
+            )
             .child(self.render_tab_bar(cx))
             // .child(
             //     div()
@@ -2947,8 +2959,8 @@ struct DraggedTab {
     title: String,
 }
 
-impl Render<Self> for DraggedTab {
-    type Element = Div<Self>;
+impl Render for DraggedTab {
+    type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         div().w_8().h_4().bg(gpui::red())

crates/workspace2/src/pane_group.rs 🔗

@@ -132,7 +132,7 @@ impl PaneGroup {
         zoomed: Option<&AnyWeakView>,
         app_state: &Arc<AppState>,
         cx: &mut ViewContext<Workspace>,
-    ) -> impl RenderOnce<Workspace> {
+    ) -> impl RenderOnce {
         self.root.render(
             project,
             0,
@@ -204,7 +204,7 @@ impl Member {
         zoomed: Option<&AnyWeakView>,
         app_state: &Arc<AppState>,
         cx: &mut ViewContext<Workspace>,
-    ) -> impl RenderOnce<Workspace> {
+    ) -> impl RenderOnce {
         match self {
             Member::Pane(pane) => {
                 // todo!()
@@ -561,7 +561,7 @@ impl PaneAxis {
         zoomed: Option<&AnyWeakView>,
         app_state: &Arc<AppState>,
         cx: &mut ViewContext<Workspace>,
-    ) -> Div<Workspace> {
+    ) -> Div {
         debug_assert!(self.members.len() == self.flexes.lock().len());
 
         div()

crates/workspace2/src/status_bar.rs 🔗

@@ -9,7 +9,7 @@ use theme2::ActiveTheme;
 use ui::h_stack;
 use util::ResultExt;
 
-pub trait StatusItemView: Render<Self> {
+pub trait StatusItemView: Render {
     fn set_active_pane_item(
         &mut self,
         active_pane_item: Option<&dyn crate::ItemHandle>,
@@ -34,8 +34,8 @@ pub struct StatusBar {
     _observe_active_pane: Subscription,
 }
 
-impl Render<Self> for StatusBar {
-    type Element = Div<Self>;
+impl Render for StatusBar {
+    type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         div()
@@ -53,14 +53,14 @@ impl Render<Self> for StatusBar {
 }
 
 impl StatusBar {
-    fn render_left_tools(&self, cx: &mut ViewContext<Self>) -> impl RenderOnce<Self> {
+    fn render_left_tools(&self, cx: &mut ViewContext<Self>) -> impl RenderOnce {
         h_stack()
             .items_center()
             .gap_2()
             .children(self.left_items.iter().map(|item| item.to_any()))
     }
 
-    fn render_right_tools(&self, cx: &mut ViewContext<Self>) -> impl RenderOnce<Self> {
+    fn render_right_tools(&self, cx: &mut ViewContext<Self>) -> impl RenderOnce {
         h_stack()
             .items_center()
             .gap_2()

crates/workspace2/src/toolbar.rs 🔗

@@ -7,7 +7,7 @@ pub enum ToolbarItemEvent {
     ChangeLocation(ToolbarItemLocation),
 }
 
-pub trait ToolbarItemView: Render<Self> + EventEmitter<ToolbarItemEvent> {
+pub trait ToolbarItemView: Render + EventEmitter<ToolbarItemEvent> {
     fn set_active_pane_item(
         &mut self,
         active_pane_item: Option<&dyn crate::ItemHandle>,
@@ -51,8 +51,8 @@ pub struct Toolbar {
     items: Vec<(Box<dyn ToolbarItemViewHandle>, ToolbarItemLocation)>,
 }
 
-impl Render<Self> for Toolbar {
-    type Element = Div<Self>;
+impl Render for Toolbar {
+    type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         todo!()

crates/workspace2/src/workspace2.rs 🔗

@@ -411,7 +411,7 @@ pub enum Event {
 pub struct Workspace {
     window_self: WindowHandle<Self>,
     weak_self: WeakView<Self>,
-    workspace_actions: Vec<Box<dyn Fn(Div<Workspace>) -> Div<Workspace>>>,
+    workspace_actions: Vec<Box<dyn Fn(Div, &mut ViewContext<Self>) -> Div>>,
     zoomed: Option<AnyWeakView>,
     zoomed_position: Option<DockPosition>,
     center: PaneGroup,
@@ -3204,53 +3204,63 @@ impl Workspace {
         })
     }
 
-    fn actions(&self, div: Div<Self>) -> Div<Self> {
-        self.add_workspace_actions_listeners(div)
+    fn actions(&self, div: Div, cx: &mut ViewContext<Self>) -> Div {
+        self.add_workspace_actions_listeners(div, cx)
             //     cx.add_async_action(Workspace::open);
             //     cx.add_async_action(Workspace::follow_next_collaborator);
             //     cx.add_async_action(Workspace::close);
-            .on_action(Self::close_inactive_items_and_panes)
-            .on_action(Self::close_all_items_and_panes)
+            .on_action(cx.listener(Self::close_inactive_items_and_panes))
+            .on_action(cx.listener(Self::close_all_items_and_panes))
             //     cx.add_global_action(Workspace::close_global);
             //     cx.add_global_action(restart);
-            .on_action(Self::save_all)
-            .on_action(Self::add_folder_to_project)
-            .on_action(|workspace, _: &Unfollow, cx| {
+            .on_action(cx.listener(Self::save_all))
+            .on_action(cx.listener(Self::add_folder_to_project))
+            .on_action(cx.listener(|workspace, _: &Unfollow, cx| {
                 let pane = workspace.active_pane().clone();
                 workspace.unfollow(&pane, cx);
-            })
-            .on_action(|workspace, action: &Save, cx| {
+            }))
+            .on_action(cx.listener(|workspace, action: &Save, cx| {
                 workspace
                     .save_active_item(action.save_intent.unwrap_or(SaveIntent::Save), cx)
                     .detach_and_log_err(cx);
-            })
-            .on_action(|workspace, _: &SaveAs, cx| {
+            }))
+            .on_action(cx.listener(|workspace, _: &SaveAs, cx| {
                 workspace
                     .save_active_item(SaveIntent::SaveAs, cx)
                     .detach_and_log_err(cx);
-            })
-            .on_action(|workspace, _: &ActivatePreviousPane, cx| {
+            }))
+            .on_action(cx.listener(|workspace, _: &ActivatePreviousPane, cx| {
                 workspace.activate_previous_pane(cx)
-            })
-            .on_action(|workspace, _: &ActivateNextPane, cx| workspace.activate_next_pane(cx))
-            .on_action(|workspace, action: &ActivatePaneInDirection, cx| {
-                workspace.activate_pane_in_direction(action.0, cx)
-            })
-            .on_action(|workspace, action: &SwapPaneInDirection, cx| {
+            }))
+            .on_action(
+                cx.listener(|workspace, _: &ActivateNextPane, cx| workspace.activate_next_pane(cx)),
+            )
+            .on_action(
+                cx.listener(|workspace, action: &ActivatePaneInDirection, cx| {
+                    workspace.activate_pane_in_direction(action.0, cx)
+                }),
+            )
+            .on_action(cx.listener(|workspace, action: &SwapPaneInDirection, cx| {
                 workspace.swap_pane_in_direction(action.0, cx)
-            })
-            .on_action(|this, e: &ToggleLeftDock, cx| {
+            }))
+            .on_action(cx.listener(|this, e: &ToggleLeftDock, cx| {
                 this.toggle_dock(DockPosition::Left, cx);
-            })
-            .on_action(|workspace: &mut Workspace, _: &ToggleRightDock, cx| {
-                workspace.toggle_dock(DockPosition::Right, cx);
-            })
-            .on_action(|workspace: &mut Workspace, _: &ToggleBottomDock, cx| {
-                workspace.toggle_dock(DockPosition::Bottom, cx);
-            })
-            .on_action(|workspace: &mut Workspace, _: &CloseAllDocks, cx| {
-                workspace.close_all_docks(cx);
-            })
+            }))
+            .on_action(
+                cx.listener(|workspace: &mut Workspace, _: &ToggleRightDock, cx| {
+                    workspace.toggle_dock(DockPosition::Right, cx);
+                }),
+            )
+            .on_action(
+                cx.listener(|workspace: &mut Workspace, _: &ToggleBottomDock, cx| {
+                    workspace.toggle_dock(DockPosition::Bottom, cx);
+                }),
+            )
+            .on_action(
+                cx.listener(|workspace: &mut Workspace, _: &CloseAllDocks, cx| {
+                    workspace.close_all_docks(cx);
+                }),
+            )
         //     cx.add_action(Workspace::activate_pane_at_index);
         //     cx.add_action(|workspace: &mut Workspace, _: &ReopenClosedItem, cx| {
         //         workspace.reopen_closed_item(cx).detach();
@@ -3346,22 +3356,24 @@ impl Workspace {
     ) -> &mut Self {
         let callback = Arc::new(callback);
 
-        self.workspace_actions.push(Box::new(move |div| {
+        self.workspace_actions.push(Box::new(move |div, cx| {
             let callback = callback.clone();
-            div.on_action(move |workspace, event, cx| (callback.clone())(workspace, event, cx))
+            div.on_action(
+                cx.listener(move |workspace, event, cx| (callback.clone())(workspace, event, cx)),
+            )
         }));
         self
     }
 
-    fn add_workspace_actions_listeners(&self, mut div: Div<Workspace>) -> Div<Workspace> {
+    fn add_workspace_actions_listeners(&self, mut div: Div, cx: &mut ViewContext<Self>) -> Div {
         let mut div = div
-            .on_action(Self::close_inactive_items_and_panes)
-            .on_action(Self::close_all_items_and_panes)
-            .on_action(Self::add_folder_to_project)
-            .on_action(Self::save_all)
-            .on_action(Self::open);
+            .on_action(cx.listener(Self::close_inactive_items_and_panes))
+            .on_action(cx.listener(Self::close_all_items_and_panes))
+            .on_action(cx.listener(Self::add_folder_to_project))
+            .on_action(cx.listener(Self::save_all))
+            .on_action(cx.listener(Self::open));
         for action in self.workspace_actions.iter() {
-            div = (action)(div)
+            div = (action)(div, cx)
         }
         div
     }
@@ -3594,8 +3606,8 @@ impl FocusableView for Workspace {
     }
 }
 
-impl Render<Self> for Workspace {
-    type Element = Div<Self>;
+impl Render for Workspace {
+    type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         let mut context = KeyContext::default();
@@ -3611,7 +3623,7 @@ impl Render<Self> for Workspace {
 
         cx.set_rem_size(ui_font_size);
 
-        self.actions(div())
+        self.actions(div(), cx)
             .key_context(context)
             .relative()
             .size_full()