Merge remote-tracking branch 'origin/callback-handles' into search2

Piotr Osiewicz created

Change summary

Cargo.lock                                       |   69 -
Cargo.toml                                       |    4 
crates/auto_update2/src/update_notification.rs   |    4 
crates/channel2/Cargo.toml                       |    2 
crates/collab_ui2/Cargo.toml                     |    2 
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/live_kit_client2/build.rs                 |   12 
crates/picker2/src/picker2.rs                    |   78 
crates/project_panel2/Cargo.toml                 |    1 
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       |   65 
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              |   14 
crates/ui2/src/components/button.rs              |  132 -
crates/ui2/src/components/checkbox.rs            |   36 
crates/ui2/src/components/context_menu.rs        |  170 +-
crates/ui2/src/components/details.rs             |   18 
crates/ui2/src/components/divider.rs             |    8 
crates/ui2/src/components/elevated_surface.rs    |    4 
crates/ui2/src/components/facepile.rs            |   10 
crates/ui2/src/components/icon.rs                |   12 
crates/ui2/src/components/icon_button.rs         |   51 
crates/ui2/src/components/indicator.rs           |    8 
crates/ui2/src/components/input.rs               |   10 
crates/ui2/src/components/keybinding.rs          |   17 
crates/ui2/src/components/label.rs               |   16 
crates/ui2/src/components/list.rs                |  155 -
crates/ui2/src/components/modal.rs               |   27 
crates/ui2/src/components/notification_toast.rs  |    2 
crates/ui2/src/components/palette.rs             |   17 
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                    | 1111 ------------------
crates/ui2/src/story.rs                          |   12 
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        |  114 -
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       |  113 -
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                    |   31 
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                 |    7 
crates/workspace2/src/workspace2.rs              |  100 
crates/zed2/Cargo.toml                           |    1 
script/bump-nightly                              |    2 
script/bundle                                    |    9 
script/deploy-docs                               |  160 ++
118 files changed, 2,092 insertions(+), 6,847 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"
@@ -1398,7 +1387,7 @@ dependencies = [
  "smol",
  "sum_tree",
  "tempfile",
- "text",
+ "text2",
  "thiserror",
  "time",
  "tiny_http",
@@ -1869,7 +1858,7 @@ dependencies = [
  "editor2",
  "feature_flags2",
  "futures 0.3.28",
- "fuzzy",
+ "fuzzy2",
  "gpui2",
  "language2",
  "lazy_static",
@@ -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"
@@ -6763,7 +6739,6 @@ dependencies = [
  "anyhow",
  "client2",
  "collections",
- "context_menu",
  "db2",
  "editor2",
  "futures 0.3.28",
@@ -8884,45 +8859,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"
@@ -11663,7 +11599,6 @@ dependencies = [
  "fs2",
  "fsevent",
  "futures 0.3.28",
- "fuzzy",
  "go_to_line2",
  "gpui2",
  "ignore",

Cargo.toml 🔗

@@ -97,8 +97,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/channel2/Cargo.toml 🔗

@@ -18,7 +18,7 @@ db = { package = "db2", path = "../db2" }
 gpui = { package = "gpui2", path = "../gpui2" }
 util = { path = "../util" }
 rpc = { package = "rpc2", path = "../rpc2" }
-text = { path = "../text" }
+text = { package = "text2", path = "../text2" }
 language = { package = "language2", path = "../language2" }
 settings = { package = "settings2", path = "../settings2" }
 feature_flags = { package = "feature_flags2", path = "../feature_flags2" }

crates/collab_ui2/Cargo.toml 🔗

@@ -33,7 +33,7 @@ collections = { path = "../collections" }
 # drag_and_drop = { path = "../drag_and_drop" }
 editor = { package="editor2", path = "../editor2" }
 #feedback = { path = "../feedback" }
-fuzzy = { path = "../fuzzy" }
+fuzzy = { package = "fuzzy2", path = "../fuzzy2" }
 gpui = { package = "gpui2", path = "../gpui2" }
 language = { package = "language2", path = "../language2" }
 menu = { package = "menu2",  path = "../menu2" }

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()))
                     })
@@ -4355,11 +4360,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,
@@ -4367,7 +4372,7 @@ impl Editor {
                             cx,
                         );
                     },
-                ),
+                )),
             )
         } else {
             None
@@ -4382,7 +4387,7 @@ impl Editor {
         line_height: Pixels,
         gutter_margin: Pixels,
         cx: &mut ViewContext<Self>,
-    ) -> Vec<Option<IconButton<Self>>> {
+    ) -> Vec<Option<IconButton>> {
         fold_data
             .iter()
             .enumerate()
@@ -4395,14 +4400,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)
                         })
                     })
@@ -4423,7 +4428,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,
@@ -7782,7 +7787,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,
@@ -7790,10 +7795,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()
                                 }
                             }),
@@ -9383,7 +9390,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 {
@@ -9997,10 +10004,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 🔗

@@ -127,7 +127,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))
@@ -144,7 +144,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));
@@ -568,7 +568,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))
@@ -590,7 +590,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))
@@ -618,7 +618,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,
@@ -629,8 +629,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/live_kit_client2/build.rs 🔗

@@ -61,12 +61,14 @@ fn build_bridge(swift_target: &SwiftTarget) {
 
     let swift_package_root = swift_package_root();
     let swift_target_folder = swift_target_folder();
+    let swift_cache_folder = swift_cache_folder();
     if !Command::new("swift")
         .arg("build")
         .arg("--disable-automatic-resolution")
         .args(["--configuration", &env::var("PROFILE").unwrap()])
         .args(["--triple", &swift_target.target.triple])
         .args(["--build-path".into(), swift_target_folder])
+        .args(["--cache-path".into(), swift_cache_folder])
         .current_dir(&swift_package_root)
         .status()
         .unwrap()
@@ -133,9 +135,17 @@ fn swift_package_root() -> PathBuf {
 }
 
 fn swift_target_folder() -> PathBuf {
+    let target = env::var("TARGET").unwrap();
     env::current_dir()
         .unwrap()
-        .join(format!("../../target/{SWIFT_PACKAGE_NAME}"))
+        .join(format!("../../target/{target}/{SWIFT_PACKAGE_NAME}_target"))
+}
+
+fn swift_cache_folder() -> PathBuf {
+    let target = env::var("TARGET").unwrap();
+    env::current_dir()
+        .unwrap()
+        .join(format!("../../target/{target}/{SWIFT_PACKAGE_NAME}_cache"))
 }
 
 fn copy_dir(source: &Path, destination: &Path) {

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/Cargo.toml 🔗

@@ -9,7 +9,6 @@ path = "src/project_panel.rs"
 doctest = false
 
 [dependencies]
-context_menu = { path = "../context_menu" }
 collections = { path = "../collections" }
 db = { path = "../db2", package = "db2" }
 editor = { path = "../editor2", package = "editor2" }

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;
@@ -31,7 +31,7 @@ use workspace::{
     notifications::NotifyResultExt,
     register_deserializable_item,
     searchable::{SearchEvent, SearchOptions, SearchableItem},
-    ui::{ContextMenu, Icon, IconElement, Label, ListEntry},
+    ui::{ContextMenu, Icon, IconElement, Label, ListItem},
     CloseActiveItem, NewCenterTerminal, Pane, ToolbarItemLocation, Workspace, WorkspaceId,
 };
 
@@ -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,
@@ -300,9 +299,9 @@ impl TerminalView {
         cx: &mut ViewContext<Self>,
     ) {
         self.context_menu = Some(ContextMenu::build(cx, |menu, _| {
-            menu.action(ListEntry::new(Label::new("Clear")), Box::new(Clear))
+            menu.action(ListItem::new("clear", Label::new("Clear")), Box::new(Clear))
                 .action(
-                    ListEntry::new(Label::new("Close")),
+                    ListItem::new("close", Label::new("Close")),
                     Box::new(CloseActiveItem { save_intent: None }),
                 )
         }));
@@ -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 {
+        fn render(&mut self, cx: &mut WindowContext) -> 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.callback(|_view, _, 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)),
             )
     }
 }
@@ -299,8 +295,8 @@ mod stories {
 
     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)

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

@@ -1,47 +1,42 @@
 use std::cell::RefCell;
 use std::rc::Rc;
 
-use crate::{prelude::*, v_stack, List, ListItem};
-use crate::{ListEntry, ListSeparator, ListSubHeader};
+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> {
+pub enum ContextMenuItem {
     Separator(ListSeparator),
     Header(ListSubHeader),
-    Entry(
-        ListEntry<ContextMenu<V>>,
-        Rc<dyn Fn(&mut V, &mut ViewContext<V>)>,
-    ),
+    Entry(ListItem, Rc<dyn Fn(&ClickEvent, &mut WindowContext)>),
 }
 
-pub struct ContextMenu<V> {
-    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: ListEntry<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: ListEntry<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,64 +81,66 @@ 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()
                 // .border_color(cx.theme().colors().border)
-                .child(List::new(
-                    self.items
-                        .iter()
-                        .map(|item| match item {
-                            ContextMenuItem::Separator(separator) => {
-                                ListItem::Separator(separator.clone())
-                            }
-                            ContextMenuItem::Header(header) => ListItem::Header(header.clone()),
-                            ContextMenuItem::Entry(entry, callback) => {
-                                let callback = callback.clone();
-                                let handle = self.handle.clone();
-                                ListItem::Entry(entry.clone().on_click(move |this, cx| {
-                                    handle.update(cx, |view, cx| callback(view, cx)).ok();
-                                    cx.emit(Manager::Dismiss);
-                                }))
-                            }
-                        })
-                        .collect(),
-                )),
+                .child(
+                    List::new().children(self.items.iter().map(|item| match item {
+                        ContextMenuItem::Separator(separator) => {
+                            separator.clone().render_into_any()
+                        }
+                        ContextMenuItem::Header(header) => header.clone().render_into_any(),
+                        ContextMenuItem::Entry(entry, callback) => {
+                            let callback = callback.clone();
+                            let dismiss = cx.listener(|_, _, cx| cx.emit(Manager::Dismiss));
+
+                            entry
+                                .clone()
+                                .on_click(move |event, cx| {
+                                    callback(event, cx);
+                                    dismiss(event, cx)
+                                })
+                                .render_into_any()
+                        }
+                    })),
+                ),
         )
     }
 }
 
-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,28 +309,31 @@ mod stories {
 
     actions!(PrintCurrentDate, PrintBestFood);
 
-    fn build_menu<V: Render<V>>(
-        cx: &mut ViewContext<V>,
+    fn build_menu<V: Render>(
+        cx: &mut WindowContext,
         header: impl Into<SharedString>,
-    ) -> View<ContextMenu<V>> {
-        let handle = cx.view().clone();
+    ) -> View<ContextMenu> {
         ContextMenu::build(cx, |menu, _| {
             menu.header(header)
                 .separator()
-                .entry(ListEntry::new(Label::new("Print current time")), |v, cx| {
-                    println!("dispatching PrintCurrentTime action");
-                    cx.dispatch_action(PrintCurrentDate.boxed_clone())
-                })
-                .entry(ListEntry::new(Label::new("Print best food")), |v, cx| {
-                    cx.dispatch_action(PrintBestFood.boxed_clone())
-                })
+                .entry(
+                    ListItem::new("Print current time", Label::new("Print current time")),
+                    |v, cx| {
+                        println!("dispatching PrintCurrentTime action");
+                        cx.dispatch_action(PrintCurrentDate.boxed_clone())
+                    },
+                )
+                .entry(
+                    ListItem::new("Print best food", Label::new("Print best food")),
+                    |v, cx| cx.dispatch_action(PrintBestFood.boxed_clone()),
+                )
         })
     }
 
     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)

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,8 +56,8 @@ 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)

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;
@@ -42,8 +42,8 @@ mod stories {
 
     pub struct FacepileStory;
 
-    impl Render<Self> for FacepileStory {
-        type Element = Div<Self>;
+    impl Render for FacepileStory {
+        type Element = Div;
 
         fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
             let players = static_players();

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

@@ -140,10 +140,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),
@@ -184,7 +184,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),
@@ -212,8 +212,8 @@ 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();

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,8 +118,8 @@ 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)

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,8 +88,8 @@ 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 =

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,8 +242,8 @@ 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)

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

@@ -1,7 +1,9 @@
-use gpui::{div, 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,
 };
@@ -32,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 {
@@ -117,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 {
@@ -177,7 +179,7 @@ impl ListHeader {
     // }
 }
 
-#[derive(Clone)]
+#[derive(RenderOnce, Clone)]
 pub struct ListSubHeader {
     label: SharedString,
     left_icon: Option<Icon>,
@@ -197,8 +199,12 @@ impl ListSubHeader {
         self.left_icon = left_icon;
         self
     }
+}
 
-    fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
+impl Component for ListSubHeader {
+    type Rendered = Div;
+
+    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         h_stack().flex_1().w_full().relative().py_1().child(
             div()
                 .h_6()
@@ -232,55 +238,9 @@ pub enum ListEntrySize {
     Medium,
 }
 
-#[derive(Clone)]
-pub enum ListItem<V: 'static> {
-    Entry(ListEntry<V>),
-    Separator(ListSeparator),
-    Header(ListSubHeader),
-}
-
-impl<V: 'static> From<ListEntry<V>> for ListItem<V> {
-    fn from(entry: ListEntry<V>) -> Self {
-        Self::Entry(entry)
-    }
-}
-
-impl<V: 'static> From<ListSeparator> for ListItem<V> {
-    fn from(entry: ListSeparator) -> Self {
-        Self::Separator(entry)
-    }
-}
-
-impl<V: 'static> From<ListSubHeader> for ListItem<V> {
-    fn from(entry: ListSubHeader) -> Self {
-        Self::Header(entry)
-    }
-}
-
-impl<V: 'static> ListItem<V> {
-    pub fn new(label: Label) -> Self {
-        Self::Entry(ListEntry::new(label))
-    }
-
-    pub fn as_entry(&mut self) -> Option<&mut ListEntry<V>> {
-        if let Self::Entry(entry) = self {
-            Some(entry)
-        } else {
-            None
-        }
-    }
-
-    fn render(self, view: &mut V, ix: usize, cx: &mut ViewContext<V>) -> Div<V> {
-        match self {
-            ListItem::Entry(entry) => div().child(entry.render(ix, cx)),
-            ListItem::Separator(separator) => div().child(separator.render(view, cx)),
-            ListItem::Header(header) => div().child(header.render(view, cx)),
-        }
-    }
-}
-
-// #[derive(RenderOnce)]
-pub struct ListEntry<V> {
+#[derive(RenderOnce)]
+pub struct ListItem {
+    id: ElementId,
     disabled: bool,
     // TODO: Reintroduce this
     // disclosure_control_style: DisclosureControlVisibility,
@@ -291,12 +251,13 @@ pub struct ListEntry<V> {
     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 ListEntry<V> {
+impl Clone for ListItem {
     fn clone(&self) -> Self {
         Self {
+            id: self.id.clone(),
             disabled: self.disabled,
             indent_level: self.indent_level,
             label: self.label.clone(),
@@ -310,9 +271,10 @@ impl<V> Clone for ListEntry<V> {
     }
 }
 
-impl<V: 'static> ListEntry<V> {
-    pub fn new(label: Label) -> Self {
+impl ListItem {
+    pub fn new(id: impl Into<ElementId>, label: Label) -> Self {
         Self {
+            id: id.into(),
             disabled: false,
             indent_level: 0,
             label,
@@ -325,7 +287,7 @@ impl<V: 'static> ListEntry<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
     }
@@ -364,10 +326,12 @@ impl<V: 'static> ListEntry<V> {
         self.size = size;
         self
     }
+}
 
-    fn render(self, ix: usize, cx: &mut ViewContext<V>) -> Stateful<V, Div<V>> {
-        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(
@@ -386,7 +350,7 @@ impl<V: 'static> ListEntry<V> {
             ListEntrySize::Medium => div().h_7(),
         };
         div()
-            .id(ix)
+            .id(self.id)
             .relative()
             .hover(|mut style| {
                 style.background = Some(cx.theme().colors().editor_background.into());
@@ -394,10 +358,9 @@ impl<V: 'static> ListEntry<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)
                     }
                 }
             })
@@ -413,7 +376,7 @@ impl<V: 'static> ListEntry<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()
@@ -444,35 +407,30 @@ 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> {
-    items: Vec<ListItem<V>>,
+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; 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 {
-        let list_content = match (self.items.is_empty(), self.toggle) {
-            (false, _) => div().children(
-                self.items
-                    .into_iter()
-                    .enumerate()
-                    .map(|(ix, item)| item.render(view, ix, cx)),
-            ),
+    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(),
             (true, _) => {
                 div().child(Label::new(self.empty_message.clone()).color(TextColor::Muted))
@@ -487,13 +445,13 @@ impl<V: 'static> Component<V> for List<V> {
     }
 }
 
-impl<V: 'static> List<V> {
-    pub fn new(items: Vec<ListItem<V>>) -> Self {
+impl List {
+    pub fn new() -> Self {
         Self {
-            items,
             empty_message: "No items".into(),
             header: None,
             toggle: Toggle::NotToggleable,
+            children: SmallVec::new(),
         }
     }
 
@@ -511,25 +469,10 @@ impl<V: 'static> List<V> {
         self.toggle = toggle;
         self
     }
+}
 
-    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
-        let list_content = match (self.items.is_empty(), self.toggle) {
-            (false, _) => div().children(
-                self.items
-                    .into_iter()
-                    .enumerate()
-                    .map(|(ix, item)| item.render(view, ix, cx)),
-            ),
-            (true, Toggle::Toggled(false)) => div(),
-            (true, _) => {
-                div().child(Label::new(self.empty_message.clone()).color(TextColor::Muted))
-            }
-        };
-
-        v_stack()
-            .w_full()
-            .py_1()
-            .children(self.header.map(|header| header))
-            .child(list_content)
+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,8 +172,8 @@ 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 {
             {

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<Self>>(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<Self>>(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,1111 +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, HighlightedText};
-use crate::{
-    Buffer, BufferRow, BufferRows, Button, EditorPane, FileSystemStatus, GitStatus,
-    HighlightedLine, Icon, KeyBinding, Label, ListEntry, ListEntrySize, Livestream, MicStatus,
-    Notification, PaletteItem, Player, PlayerCallStatus, PlayerWithCallStatus, PublicPlayer,
-    ScreenShareStatus, Symbol, Tab, TextColor, Toggle, VideoStatus,
-};
-use crate::{ListItem, NotificationAction};
-
-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![
-        ListEntry::new(Label::new("zed"))
-            .left_icon(Icon::FolderOpen.into())
-            .indent_level(0)
-            .toggle(Toggle::Toggled(true)),
-        ListEntry::new(Label::new(".cargo"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(1),
-        ListEntry::new(Label::new(".config"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(1),
-        ListEntry::new(Label::new(".git").color(TextColor::Hidden))
-            .left_icon(Icon::Folder.into())
-            .indent_level(1),
-        ListEntry::new(Label::new(".cargo"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(1),
-        ListEntry::new(Label::new(".idea").color(TextColor::Hidden))
-            .left_icon(Icon::Folder.into())
-            .indent_level(1),
-        ListEntry::new(Label::new("assets"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(1)
-            .toggle(Toggle::Toggled(true)),
-        ListEntry::new(Label::new("cargo-target").color(TextColor::Hidden))
-            .left_icon(Icon::Folder.into())
-            .indent_level(1),
-        ListEntry::new(Label::new("crates"))
-            .left_icon(Icon::FolderOpen.into())
-            .indent_level(1)
-            .toggle(Toggle::Toggled(true)),
-        ListEntry::new(Label::new("activity_indicator"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2),
-        ListEntry::new(Label::new("ai"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2),
-        ListEntry::new(Label::new("audio"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2),
-        ListEntry::new(Label::new("auto_update"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2),
-        ListEntry::new(Label::new("breadcrumbs"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2),
-        ListEntry::new(Label::new("call"))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2),
-        ListEntry::new(Label::new("sqlez").color(TextColor::Modified))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2)
-            .toggle(Toggle::Toggled(false)),
-        ListEntry::new(Label::new("gpui2"))
-            .left_icon(Icon::FolderOpen.into())
-            .indent_level(2)
-            .toggle(Toggle::Toggled(true)),
-        ListEntry::new(Label::new("src"))
-            .left_icon(Icon::FolderOpen.into())
-            .indent_level(3)
-            .toggle(Toggle::Toggled(true)),
-        ListEntry::new(Label::new("derive_element.rs"))
-            .left_icon(Icon::FileRust.into())
-            .indent_level(4),
-        ListEntry::new(Label::new("storybook").color(TextColor::Modified))
-            .left_icon(Icon::FolderOpen.into())
-            .indent_level(1)
-            .toggle(Toggle::Toggled(true)),
-        ListEntry::new(Label::new("docs").color(TextColor::Default))
-            .left_icon(Icon::Folder.into())
-            .indent_level(2)
-            .toggle(Toggle::Toggled(true)),
-        ListEntry::new(Label::new("src").color(TextColor::Modified))
-            .left_icon(Icon::FolderOpen.into())
-            .indent_level(3)
-            .toggle(Toggle::Toggled(true)),
-        ListEntry::new(Label::new("ui").color(TextColor::Modified))
-            .left_icon(Icon::FolderOpen.into())
-            .indent_level(4)
-            .toggle(Toggle::Toggled(true)),
-        ListEntry::new(Label::new("component").color(TextColor::Created))
-            .left_icon(Icon::FolderOpen.into())
-            .indent_level(5)
-            .toggle(Toggle::Toggled(true)),
-        ListEntry::new(Label::new("facepile.rs").color(TextColor::Default))
-            .left_icon(Icon::FileRust.into())
-            .indent_level(6),
-        ListEntry::new(Label::new("follow_group.rs").color(TextColor::Default))
-            .left_icon(Icon::FileRust.into())
-            .indent_level(6),
-        ListEntry::new(Label::new("list_item.rs").color(TextColor::Created))
-            .left_icon(Icon::FileRust.into())
-            .indent_level(6),
-        ListEntry::new(Label::new("tab.rs").color(TextColor::Default))
-            .left_icon(Icon::FileRust.into())
-            .indent_level(6),
-        ListEntry::new(Label::new("target").color(TextColor::Hidden))
-            .left_icon(Icon::Folder.into())
-            .indent_level(1),
-        ListEntry::new(Label::new(".dockerignore"))
-            .left_icon(Icon::FileGeneric.into())
-            .indent_level(1),
-        ListEntry::new(Label::new(".DS_Store").color(TextColor::Hidden))
-            .left_icon(Icon::FileGeneric.into())
-            .indent_level(1),
-        ListEntry::new(Label::new("Cargo.lock"))
-            .left_icon(Icon::FileLock.into())
-            .indent_level(1),
-        ListEntry::new(Label::new("Cargo.toml"))
-            .left_icon(Icon::FileToml.into())
-            .indent_level(1),
-        ListEntry::new(Label::new("Dockerfile"))
-            .left_icon(Icon::FileGeneric.into())
-            .indent_level(1),
-        ListEntry::new(Label::new("Procfile"))
-            .left_icon(Icon::FileGeneric.into())
-            .indent_level(1),
-        ListEntry::new(Label::new("README.md"))
-            .left_icon(Icon::FileDoc.into())
-            .indent_level(1),
-    ]
-    .into_iter()
-    .map(From::from)
-    .collect()
-}
-
-pub fn static_project_panel_single_items<V>() -> Vec<ListItem<V>> {
-    vec![
-        ListEntry::new(Label::new("todo.md"))
-            .left_icon(Icon::FileDoc.into())
-            .indent_level(0),
-        ListEntry::new(Label::new("README.md"))
-            .left_icon(Icon::FileDoc.into())
-            .indent_level(0),
-        ListEntry::new(Label::new("config.json"))
-            .left_icon(Icon::FileGeneric.into())
-            .indent_level(0),
-    ]
-    .into_iter()
-    .map(From::from)
-    .collect()
-}
-
-pub fn static_collab_panel_current_call<V>() -> Vec<ListItem<V>> {
-    vec![
-        ListEntry::new(Label::new("as-cii")).left_avatar("http://github.com/as-cii.png?s=50"),
-        ListEntry::new(Label::new("nathansobo"))
-            .left_avatar("http://github.com/nathansobo.png?s=50"),
-        ListEntry::new(Label::new("maxbrunsfeld"))
-            .left_avatar("http://github.com/maxbrunsfeld.png?s=50"),
-    ]
-    .into_iter()
-    .map(From::from)
-    .collect()
-}
-
-pub fn static_collab_panel_channels<V>() -> Vec<ListItem<V>> {
-    vec![
-        ListEntry::new(Label::new("zed"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(0),
-        ListEntry::new(Label::new("community"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(1),
-        ListEntry::new(Label::new("dashboards"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListEntry::new(Label::new("feedback"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListEntry::new(Label::new("teams-in-channels-alpha"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListEntry::new(Label::new("current-projects"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(1),
-        ListEntry::new(Label::new("codegen"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListEntry::new(Label::new("gpui2"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListEntry::new(Label::new("livestreaming"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListEntry::new(Label::new("open-source"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListEntry::new(Label::new("replace"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListEntry::new(Label::new("semantic-index"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListEntry::new(Label::new("vim"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-        ListEntry::new(Label::new("web-tech"))
-            .left_icon(Icon::Hash.into())
-            .size(ListEntrySize::Medium)
-            .indent_level(2),
-    ]
-    .into_iter()
-    .map(From::from)
-    .collect()
-}
-
-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()
@@ -16,23 +16,23 @@ impl Story {
     }
 
     pub fn title<V: 'static>(
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
         title: impl Into<SharedString>,
-    ) -> impl Element<V> {
+    ) -> 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>,
+        cx: &mut WindowContext,
         label: impl Into<SharedString>,
-    ) -> impl Element<V> {
+    ) -> 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,114 +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(static_collab_panel_current_call())
-                                    .header(
-                                        ListHeader::new("CRDB")
-                                            .left_icon(Icon::Hash.into())
-                                            .toggle(Toggle::Toggled(true)),
-                                    )
-                                    .toggle(Toggle::Toggled(true)),
-                            ),
-                    )
-                    .child(
-                        v_stack().id("channels").py_1().child(
-                            List::new(static_collab_panel_channels())
-                                .header(ListHeader::new("CHANNELS").toggle(Toggle::Toggled(true)))
-                                .empty_message("No channels yet. Add a channel to get started.")
-                                .toggle(Toggle::Toggled(true)),
-                        ),
-                    )
-                    .child(
-                        v_stack().id("contacts-online").py_1().child(
-                            List::new(static_collab_panel_current_call())
-                                .header(
-                                    ListHeader::new("CONTACTS – ONLINE")
-                                        .toggle(Toggle::Toggled(true)),
-                                )
-                                .toggle(Toggle::Toggled(true)),
-                        ),
-                    )
-                    .child(
-                        v_stack().id("contacts-offline").py_1().child(
-                            List::new(static_collab_panel_current_call())
-                                .header(
-                                    ListHeader::new("CONTACTS – OFFLINE")
-                                        .toggle(Toggle::Toggled(false)),
-                                )
-                                .toggle(Toggle::Toggled(false)),
-                        ),
-                    ),
-            )
-            .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,113 +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(static_project_panel_single_items())
-                            .header(ListHeader::new("FILES"))
-                            .empty_message("No files in directory"),
-                    )
-                    .child(
-                        List::new(static_project_panel_project_items())
-                            .header(ListHeader::new("PROJECT"))
-                            .empty_message("No folders in directory"),
-                    ),
-            )
-            .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(static_project_panel_single_items())
-                            .header(ListHeader::new("FILES"))
-                            .empty_message("No files in directory"),
-                    )
-                    .child(
-                        List::new(static_project_panel_project_items())
-                            .header(ListHeader::new("PROJECT"))
-                            .empty_message("No folders in directory"),
-                    ),
-            )
-            .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 🔗

@@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
 use std::sync::Arc;
 use theme2::ActiveTheme;
 use ui::{
-    h_stack, menu_handle, ContextMenu, IconButton, InteractionState, Label, ListEntry, Tooltip,
+    h_stack, menu_handle, ContextMenu, IconButton, InteractionState, Label, ListItem, Tooltip,
 };
 
 pub enum PanelEvent {
@@ -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
@@ -719,10 +720,10 @@ impl Render<Self> for PanelButtons {
                                     {
                                         let panel = panel.clone();
                                         menu = menu.entry(
-                                            ListEntry::new(Label::new(format!(
-                                                "Dock {}",
-                                                position.to_label()
-                                            ))),
+                                            ListItem::new(
+                                                panel.entity_id(),
+                                                Label::new(format!("Dock {}", position.to_label())),
+                                            ),
                                             move |_, cx| {
                                                 panel.set_position(position, 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(self.toolbar.clone())
             .child(if let Some(item) = self.active_item() {
@@ -2945,8 +2957,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 🔗

@@ -10,7 +10,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>,
@@ -76,8 +76,9 @@ impl Toolbar {
     }
 }
 
-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 {
         //dbg!(&self.items.len());

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()

crates/zed2/Cargo.toml 🔗

@@ -39,7 +39,6 @@ file_finder = { package="file_finder2", path = "../file_finder2" }
 search = { package = "search2", path = "../search2" }
 fs = { package = "fs2", path = "../fs2" }
 fsevent = { path = "../fsevent" }
-fuzzy = { path = "../fuzzy" }
 go_to_line = { package = "go_to_line2", path = "../go_to_line2" }
 gpui = { package = "gpui2", path = "../gpui2" }
 install_cli = { package = "install_cli2", path = "../install_cli2" }

script/bump-nightly 🔗

@@ -1,5 +1,7 @@
 #!/bin/bash
 
+set -e
+
 branch=$(git rev-parse --abbrev-ref HEAD)
 if [ "$branch" != "main" ]; then
   echo "You must be on main to run this script"

script/bundle 🔗

@@ -10,6 +10,7 @@ local_only=false
 overwrite_local_app=false
 bundle_name=""
 zed_crate="zed"
+binary_name="Zed"
 
 # This must match the team in the provsiioning profile.
 APPLE_NOTORIZATION_TEAM="MQ55VZLNZQ"
@@ -38,7 +39,6 @@ do
             export CARGO_INCREMENTAL=true
             export CARGO_BUNDLE_SKIP_BUILD=true
             build_flag="";
-            local_arch=true
             target_dir="debug"
             ;;
         l)
@@ -50,7 +50,10 @@ do
             target_dir="debug"
             ;;
         f) overwrite_local_app=true;;
-        2) zed_crate="zed2";;
+        2)
+            zed_crate="zed2"
+            binary_name="Zed2"
+            ;;
         h)
            help_info
            exit 0
@@ -116,7 +119,7 @@ if [ "$local_arch" = false ]; then
     echo "Creating fat binaries"
     lipo \
         -create \
-        target/{x86_64-apple-darwin,aarch64-apple-darwin}/${target_dir}/Zed \
+        target/{x86_64-apple-darwin,aarch64-apple-darwin}/${target_dir}/${binary_name} \
         -output \
         "${app_path}/Contents/MacOS/${zed_crate}"
     lipo \

script/deploy-docs 🔗

@@ -0,0 +1,160 @@
+#!/bin/bash
+
+# Check if the script is run from the root of the repository
+if [ ! -f "Cargo.toml" ] || [ ! -d "crates/zed" ]; then
+    echo "Please run the script from the root of the repository."
+    exit 1
+fi
+
+# Set the environment variables
+TARGET_DIR="../zed-docs"
+PUSH_CHANGES=false
+CLEAN_FOLDERS=false
+
+# Parse command line arguments
+while getopts "pc" opt; do
+  case ${opt} in
+    p )
+      PUSH_CHANGES=true
+      ;;
+    c )
+      CLEAN_FOLDERS=true
+      ;;
+    \? )
+      echo "Invalid option: $OPTARG" 1>&2
+      exit 1
+      ;;
+  esac
+done
+
+# Check if the target documentation directory exists
+if [ ! -d "$TARGET_DIR" ]; then
+    # Prompt the user for input
+    read -p "Can't find ../zed-docs. Do you want to clone the repository (y/n)?" -n 1 -r
+    echo  # Move to a new line
+
+    if [[ $REPLY =~ ^[Yy]$ ]]; then
+        # Clone the repo if the user agrees
+        git clone https://github.com/zed-industries/zed-docs.git "$TARGET_DIR"
+    else
+        # Exit if the user does not agree to clone the repo
+        echo "Exiting without cloning the repository."
+        exit 1
+    fi
+else
+    # If the directory exists, pull the latest changes
+    pushd "$TARGET_DIR" > /dev/null
+    git pull
+    popd > /dev/null
+fi
+
+if "$CLEAN_FOLDERS"; then
+  echo "Cleaning ./doc and ./debug folders..."
+  rm -rf "$TARGET_DIR/doc"
+  rm -rf "$TARGET_DIR/debug"
+fi
+
+# Build the documentation
+CARGO_TARGET_DIR="$TARGET_DIR" cargo doc --workspace --no-deps --open \
+--exclude activity_indicator \
+--exclude ai \
+--exclude assistant \
+--exclude audio \
+--exclude auto_update \
+--exclude breadcrumbs \
+--exclude call \
+--exclude channel \
+--exclude cli \
+--exclude client \
+--exclude clock \
+--exclude collab \
+--exclude collab_ui \
+--exclude collections \
+--exclude command_palette \
+--exclude component_test \
+--exclude context_menu \
+--exclude copilot \
+--exclude copilot_button \
+--exclude db \
+--exclude diagnostics \
+--exclude drag_and_drop \
+--exclude editor \
+--exclude feature_flags \
+--exclude feedback \
+--exclude file_finder \
+--exclude fs \
+--exclude fsevent \
+--exclude fuzzy \
+--exclude git \
+--exclude go_to_line \
+--exclude gpui \
+--exclude gpui_macros \
+--exclude install_cli \
+--exclude journal \
+--exclude language \
+--exclude language_selector \
+--exclude language_tools \
+--exclude live_kit_client \
+--exclude live_kit_server \
+--exclude lsp \
+--exclude media \
+--exclude menu \
+--exclude multi_buffer \
+--exclude node_runtime \
+--exclude notifications \
+--exclude outline \
+--exclude picker \
+--exclude plugin \
+--exclude plugin_macros \
+--exclude plugin_runtime \
+--exclude prettier \
+--exclude project \
+--exclude project_panel \
+--exclude project_symbols \
+--exclude quick_action_bar \
+--exclude recent_projects \
+--exclude refineable \
+--exclude rich_text \
+--exclude rope \
+--exclude rpc \
+--exclude search \
+--exclude semantic_index \
+--exclude settings \
+--exclude snippet \
+--exclude sqlez \
+--exclude sqlez_macros \
+--exclude storybook3 \
+--exclude sum_tree \
+--exclude terminal \
+--exclude terminal_view \
+--exclude text \
+--exclude theme \
+--exclude theme_importer \
+--exclude theme_selector \
+--exclude util \
+--exclude vcs_menu \
+--exclude vim \
+--exclude welcome \
+--exclude xtask \
+--exclude zed \
+--exclude zed-actions
+
+if "$PUSH_CHANGES"; then
+    # Commit the changes and push
+    pushd "$TARGET_DIR" > /dev/null
+    # Check if there are any changes to commit
+    if git diff --quiet && git diff --staged --quiet; then
+        echo "No changes to the documentation."
+    else
+        # Staging the changes
+        git add .
+
+        # Creating a commit with the current datetime
+        DATETIME=$(date +"%Y-%m-%d %H:%M:%S")
+        git commit -m "Update docs – $DATETIME"
+
+        # Pushing the changes
+        git push
+    fi
+    popd > /dev/null
+fi