Merge branch 'main' into editor2_tests

Marshall Bowers created

Change summary

Cargo.lock                                              |   59 
Cargo.toml                                              |    2 
assets/icons/copy.svg                                   |    1 
crates/auto_update2/src/auto_update.rs                  |    2 
crates/breadcrumbs2/Cargo.toml                          |   28 
crates/breadcrumbs2/src/breadcrumbs.rs                  |  204 
crates/client/src/client.rs                             |    2 
crates/collab/Cargo.toml                                |    2 
crates/collab/src/db/queries/channels.rs                |    7 
crates/collab/src/db/tests/channel_tests.rs             |   14 
crates/collab2/src/db/queries/channels.rs               |    7 
crates/collab2/src/db/tests/channel_tests.rs            |   16 
crates/collab_ui2/src/collab_panel.rs                   |   72 
crates/collab_ui2/src/collab_panel/channel_modal.rs     |  738 
crates/collab_ui2/src/collab_titlebar_item.rs           |  341 
crates/copilot_button2/Cargo.toml                       |   27 
crates/copilot_button2/src/copilot_button.rs            |  371 
crates/diagnostics2/src/diagnostics.rs                  |   72 
crates/editor2/src/editor.rs                            |   92 
crates/editor2/src/element.rs                           |  130 
crates/gpui2/src/elements/div.rs                        |    8 
crates/gpui2/src/elements/text.rs                       |   28 
crates/gpui2/src/platform.rs                            |   18 
crates/gpui2/src/platform/mac/platform.rs               |   29 
crates/gpui2/src/platform/test/platform.rs              |    4 
crates/gpui2/src/styled.rs                              |  119 
crates/language_selector2/Cargo.toml                    |   26 
crates/language_selector2/src/active_buffer_language.rs |   82 
crates/language_selector2/src/language_selector.rs      |  231 
crates/picker2/src/picker2.rs                           |    9 
crates/project/src/project.rs                           |    5 
crates/project2/src/project2.rs                         |    5 
crates/rpc2/src/rpc.rs                                  |    2 
crates/storybook2/src/stories.rs                        |    2 
crates/storybook2/src/stories/cursor.rs                 |  112 
crates/storybook2/src/stories/text.rs                   |   14 
crates/storybook2/src/story_selector.rs                 |    2 
crates/theme2/src/one_themes.rs                         |    4 
crates/ui2/src/components.rs                            |    4 
crates/ui2/src/components/button.rs                     |    1 
crates/ui2/src/components/button/button.rs              |   86 
crates/ui2/src/components/button/button_icon.rs         |   84 
crates/ui2/src/components/button/button_like.rs         |  105 
crates/ui2/src/components/button/icon_button.rs         |   41 
crates/ui2/src/components/context_menu.rs               |  222 
crates/ui2/src/components/icon.rs                       |    4 
crates/ui2/src/components/label.rs                      |   54 
crates/ui2/src/components/popover_menu.rs               |  231 
crates/ui2/src/components/right_click_menu.rs           |  185 
crates/ui2/src/components/stories/button.rs             |   16 
crates/ui2/src/components/stories/context_menu.rs       |   42 
crates/ui2/src/components/stories/icon_button.rs        |    8 
crates/ui2/src/styled_ext.rs                            |   14 
crates/workspace2/src/dock.rs                           |   12 
crates/workspace2/src/notifications.rs                  |   57 
crates/workspace2/src/pane.rs                           |  343 
crates/workspace2/src/status_bar.rs                     |   34 
crates/workspace2/src/toolbar.rs                        |   16 
crates/workspace2/src/workspace2.rs                     |   83 
crates/zed/Cargo.toml                                   |    2 
crates/zed/resources/app-icon-nightly.png               |    0 
crates/zed/resources/app-icon-nightly@2x.png            |    0 
crates/zed/src/only_instance.rs                         |    2 
crates/zed2/Cargo.toml                                  |    8 
crates/zed2/resources/app-icon-nightly.png              |    0 
crates/zed2/resources/app-icon-nightly@2x.png           |    0 
crates/zed2/src/main.rs                                 |    2 
crates/zed2/src/only_instance.rs                        |    2 
crates/zed2/src/zed2.rs                                 |   19 
test.rs                                                 | 5618 -----------
70 files changed, 3,375 insertions(+), 6,807 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -1095,6 +1095,23 @@ dependencies = [
  "workspace",
 ]
 
+[[package]]
+name = "breadcrumbs2"
+version = "0.1.0"
+dependencies = [
+ "collections",
+ "editor2",
+ "gpui2",
+ "itertools 0.10.5",
+ "language2",
+ "project2",
+ "search2",
+ "settings2",
+ "theme2",
+ "ui2",
+ "workspace2",
+]
+
 [[package]]
 name = "bromberg_sl2"
 version = "0.6.0"
@@ -1688,7 +1705,7 @@ dependencies = [
 
 [[package]]
 name = "collab"
-version = "0.29.0"
+version = "0.29.1"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -2126,6 +2143,25 @@ dependencies = [
  "workspace",
 ]
 
+[[package]]
+name = "copilot_button2"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "copilot2",
+ "editor2",
+ "fs2",
+ "futures 0.3.28",
+ "gpui2",
+ "language2",
+ "settings2",
+ "smol",
+ "theme2",
+ "util",
+ "workspace2",
+ "zed_actions2",
+]
+
 [[package]]
 name = "core-foundation"
 version = "0.9.3"
@@ -4774,6 +4810,24 @@ dependencies = [
  "workspace",
 ]
 
+[[package]]
+name = "language_selector2"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "editor2",
+ "fuzzy2",
+ "gpui2",
+ "language2",
+ "picker2",
+ "project2",
+ "settings2",
+ "theme2",
+ "ui2",
+ "util",
+ "workspace2",
+]
+
 [[package]]
 name = "language_tools"
 version = "0.1.0"
@@ -11726,6 +11780,7 @@ dependencies = [
  "audio2",
  "auto_update2",
  "backtrace",
+ "breadcrumbs2",
  "call2",
  "channel2",
  "chrono",
@@ -11735,6 +11790,7 @@ dependencies = [
  "collections",
  "command_palette2",
  "copilot2",
+ "copilot_button2",
  "ctor",
  "db2",
  "diagnostics2",
@@ -11754,6 +11810,7 @@ dependencies = [
  "isahc",
  "journal2",
  "language2",
+ "language_selector2",
  "lazy_static",
  "libc",
  "log",

Cargo.toml 🔗

@@ -9,6 +9,7 @@ members = [
     "crates/auto_update",
     "crates/auto_update2",
     "crates/breadcrumbs",
+    "crates/breadcrumbs2",
     "crates/call",
     "crates/call2",
     "crates/channel",
@@ -60,6 +61,7 @@ members = [
     "crates/language",
     "crates/language2",
     "crates/language_selector",
+    "crates/language_selector2",
     "crates/language_tools",
     "crates/live_kit_client",
     "crates/live_kit_server",

assets/icons/copy.svg 🔗

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-copy"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>

crates/auto_update2/src/auto_update.rs 🔗

@@ -102,7 +102,7 @@ pub fn init(http_client: Arc<dyn HttpClient>, server_url: String, cx: &mut AppCo
     })
     .detach();
 
-    if let Some(version) = *ZED_APP_VERSION {
+    if let Some(version) = ZED_APP_VERSION.or_else(|| cx.app_metadata().app_version) {
         let auto_updater = cx.build_model(|cx| {
             let updater = AutoUpdater::new(version, http_client, server_url);
 

crates/breadcrumbs2/Cargo.toml 🔗

@@ -0,0 +1,28 @@
+[package]
+name = "breadcrumbs2"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[lib]
+path = "src/breadcrumbs.rs"
+doctest = false
+
+[dependencies]
+collections = { path = "../collections" }
+editor = { package = "editor2", path = "../editor2" }
+gpui = { package = "gpui2", path = "../gpui2" }
+ui = { package = "ui2", path = "../ui2" }
+language = { package = "language2", path = "../language2" }
+project = { package = "project2", path = "../project2" }
+search = { package = "search2", path = "../search2" }
+settings = { package = "settings2", path = "../settings2" }
+theme = { package = "theme2", path = "../theme2" }
+workspace = { package = "workspace2", path = "../workspace2" }
+# outline = { path = "../outline" }
+itertools = "0.10"
+
+[dev-dependencies]
+editor = { package = "editor2", path = "../editor2", features = ["test-support"] }
+gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] }
+workspace = { package = "workspace2", path = "../workspace2", features = ["test-support"] }

crates/breadcrumbs2/src/breadcrumbs.rs 🔗

@@ -0,0 +1,204 @@
+use gpui::{
+    Component, Element, EventEmitter, IntoElement, ParentElement, Render, StyledText, Subscription,
+    ViewContext, WeakView,
+};
+use itertools::Itertools;
+use theme::ActiveTheme;
+use ui::{ButtonCommon, ButtonLike, ButtonStyle, Clickable, Disableable, Label};
+use workspace::{
+    item::{ItemEvent, ItemHandle},
+    ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace,
+};
+
+pub enum Event {
+    UpdateLocation,
+}
+
+pub struct Breadcrumbs {
+    pane_focused: bool,
+    active_item: Option<Box<dyn ItemHandle>>,
+    subscription: Option<Subscription>,
+    _workspace: WeakView<Workspace>,
+}
+
+impl Breadcrumbs {
+    pub fn new(workspace: &Workspace) -> Self {
+        Self {
+            pane_focused: false,
+            active_item: Default::default(),
+            subscription: Default::default(),
+            _workspace: workspace.weak_handle(),
+        }
+    }
+}
+
+impl EventEmitter<Event> for Breadcrumbs {}
+impl EventEmitter<ToolbarItemEvent> for Breadcrumbs {}
+
+impl Render for Breadcrumbs {
+    type Element = Component<ButtonLike>;
+
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+        let button = ButtonLike::new("breadcrumbs")
+            .style(ButtonStyle::Transparent)
+            .disabled(true);
+
+        let active_item = match &self.active_item {
+            Some(active_item) => active_item,
+            None => return button.into_element(),
+        };
+        let not_editor = active_item.downcast::<editor::Editor>().is_none();
+
+        let breadcrumbs = match active_item.breadcrumbs(cx.theme(), cx) {
+            Some(breadcrumbs) => breadcrumbs,
+            None => return button.into_element(),
+        }
+        .into_iter()
+        .map(|breadcrumb| {
+            StyledText::new(breadcrumb.text)
+                .with_highlights(&cx.text_style(), breadcrumb.highlights.unwrap_or_default())
+                .into_any()
+        });
+
+        let button = button.children(Itertools::intersperse_with(breadcrumbs, || {
+            Label::new(" › ").into_any_element()
+        }));
+
+        if not_editor || !self.pane_focused {
+            return button.into_element();
+        }
+
+        // let this = cx.view().downgrade();
+        button
+            .style(ButtonStyle::Filled)
+            .disabled(false)
+            .on_click(move |_, _cx| {
+                todo!("outline::toggle");
+                // this.update(cx, |this, cx| {
+                //     if let Some(workspace) = this.workspace.upgrade() {
+                //         workspace.update(cx, |_workspace, _cx| {
+                //             outline::toggle(workspace, &Default::default(), cx)
+                //         })
+                //     }
+                // })
+                // .ok();
+            })
+            .into_element()
+    }
+}
+
+// impl View for Breadcrumbs {
+//     fn ui_name() -> &'static str {
+//         "Breadcrumbs"
+//     }
+
+//     fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
+//         let active_item = match &self.active_item {
+//             Some(active_item) => active_item,
+//             None => return Empty::new().into_any(),
+//         };
+//         let not_editor = active_item.downcast::<editor::Editor>().is_none();
+
+//         let theme = theme::current(cx).clone();
+//         let style = &theme.workspace.toolbar.breadcrumbs;
+
+//         let breadcrumbs = match active_item.breadcrumbs(&theme, cx) {
+//             Some(breadcrumbs) => breadcrumbs,
+//             None => return Empty::new().into_any(),
+//         }
+//         .into_iter()
+//         .map(|breadcrumb| {
+//             Text::new(
+//                 breadcrumb.text,
+//                 theme.workspace.toolbar.breadcrumbs.default.text.clone(),
+//             )
+//             .with_highlights(breadcrumb.highlights.unwrap_or_default())
+//             .into_any()
+//         });
+
+//         let crumbs = Flex::row()
+//             .with_children(Itertools::intersperse_with(breadcrumbs, || {
+//                 Label::new(" › ", style.default.text.clone()).into_any()
+//             }))
+//             .constrained()
+//             .with_height(theme.workspace.toolbar.breadcrumb_height)
+//             .contained();
+
+//         if not_editor || !self.pane_focused {
+//             return crumbs
+//                 .with_style(style.default.container)
+//                 .aligned()
+//                 .left()
+//                 .into_any();
+//         }
+
+//         MouseEventHandler::new::<Breadcrumbs, _>(0, cx, |state, _| {
+//             let style = style.style_for(state);
+//             crumbs.with_style(style.container)
+//         })
+//         .on_click(MouseButton::Left, |_, this, cx| {
+//             if let Some(workspace) = this.workspace.upgrade(cx) {
+//                 workspace.update(cx, |workspace, cx| {
+//                     outline::toggle(workspace, &Default::default(), cx)
+//                 })
+//             }
+//         })
+//         .with_tooltip::<Breadcrumbs>(
+//             0,
+//             "Show symbol outline".to_owned(),
+//             Some(Box::new(outline::Toggle)),
+//             theme.tooltip.clone(),
+//             cx,
+//         )
+//         .aligned()
+//         .left()
+//         .into_any()
+//     }
+// }
+
+impl ToolbarItemView for Breadcrumbs {
+    fn set_active_pane_item(
+        &mut self,
+        active_pane_item: Option<&dyn ItemHandle>,
+        cx: &mut ViewContext<Self>,
+    ) -> ToolbarItemLocation {
+        cx.notify();
+        self.active_item = None;
+        if let Some(item) = active_pane_item {
+            let this = cx.view().downgrade();
+            self.subscription = Some(item.subscribe_to_item_events(
+                cx,
+                Box::new(move |event, cx| {
+                    if let ItemEvent::UpdateBreadcrumbs = event {
+                        this.update(cx, |_, cx| {
+                            cx.emit(Event::UpdateLocation);
+                            cx.notify();
+                        })
+                        .ok();
+                    }
+                }),
+            ));
+            self.active_item = Some(item.boxed_clone());
+            item.breadcrumb_location(cx)
+        } else {
+            ToolbarItemLocation::Hidden
+        }
+    }
+
+    // fn location_for_event(
+    //     &self,
+    //     _: &Event,
+    //     current_location: ToolbarItemLocation,
+    //     cx: &AppContext,
+    // ) -> ToolbarItemLocation {
+    //     if let Some(active_item) = self.active_item.as_ref() {
+    //         active_item.breadcrumb_location(cx)
+    //     } else {
+    //         current_location
+    //     }
+    // }
+
+    fn pane_focus_update(&mut self, pane_focused: bool, _: &mut ViewContext<Self>) {
+        self.pane_focused = pane_focused;
+    }
+}

crates/client/src/client.rs 🔗

@@ -346,7 +346,7 @@ impl<T: Entity> Drop for PendingEntitySubscription<T> {
     }
 }
 
-#[derive(Copy, Clone)]
+#[derive(Debug, Copy, Clone)]
 pub struct TelemetrySettings {
     pub diagnostics: bool,
     pub metrics: bool,

crates/collab/Cargo.toml 🔗

@@ -3,7 +3,7 @@ authors = ["Nathan Sobo <nathan@zed.dev>"]
 default-run = "collab"
 edition = "2021"
 name = "collab"
-version = "0.29.0"
+version = "0.29.1"
 publish = false
 
 [[bin]]

crates/collab/src/db/queries/channels.rs 🔗

@@ -1220,6 +1220,13 @@ impl Database {
                 self.check_user_is_channel_admin(&new_parent, admin_id, &*tx)
                     .await?;
 
+                if new_parent
+                    .ancestors_including_self()
+                    .any(|id| id == channel.id)
+                {
+                    Err(anyhow!("cannot move a channel into one of its descendants"))?;
+                }
+
                 new_parent_path = new_parent.path();
                 new_parent_channel = Some(new_parent);
             } else {

crates/collab/src/db/tests/channel_tests.rs 🔗

@@ -450,6 +450,20 @@ async fn test_db_channel_moving_bugs(db: &Arc<Database>) {
             (livestreaming_id, &[projects_id]),
         ],
     );
+
+    // Can't move a channel into its ancestor
+    db.move_channel(projects_id, Some(livestreaming_id), user_id)
+        .await
+        .unwrap_err();
+    let result = db.get_channels_for_user(user_id).await.unwrap();
+    assert_channel_tree(
+        result.channels,
+        &[
+            (zed_id, &[]),
+            (projects_id, &[]),
+            (livestreaming_id, &[projects_id]),
+        ],
+    );
 }
 
 test_both_dbs!(

crates/collab2/src/db/queries/channels.rs 🔗

@@ -1220,6 +1220,13 @@ impl Database {
                 self.check_user_is_channel_admin(&new_parent, admin_id, &*tx)
                     .await?;
 
+                if new_parent
+                    .ancestors_including_self()
+                    .any(|id| id == channel.id)
+                {
+                    Err(anyhow!("cannot move a channel into one of its descendants"))?;
+                }
+
                 new_parent_path = new_parent.path();
                 new_parent_channel = Some(new_parent);
             } else {

crates/collab2/src/db/tests/channel_tests.rs 🔗

@@ -420,8 +420,6 @@ async fn test_db_channel_moving_bugs(db: &Arc<Database>) {
         .await
         .unwrap();
 
-    // Dag is: zed - projects - livestreaming
-
     // Move to same parent should be a no-op
     assert!(db
         .move_channel(projects_id, Some(zed_id), user_id)
@@ -450,6 +448,20 @@ async fn test_db_channel_moving_bugs(db: &Arc<Database>) {
             (livestreaming_id, &[projects_id]),
         ],
     );
+
+    // Can't move a channel into its ancestor
+    db.move_channel(projects_id, Some(livestreaming_id), user_id)
+        .await
+        .unwrap_err();
+    let result = db.get_channels_for_user(user_id).await.unwrap();
+    assert_channel_tree(
+        result.channels,
+        &[
+            (zed_id, &[]),
+            (projects_id, &[]),
+            (livestreaming_id, &[projects_id]),
+        ],
+    );
 }
 
 test_both_dbs!(

crates/collab_ui2/src/collab_panel.rs 🔗

@@ -1,5 +1,5 @@
 #![allow(unused)]
-// mod channel_modal;
+mod channel_modal;
 mod contact_finder;
 
 // use crate::{
@@ -192,6 +192,8 @@ use workspace::{
 
 use crate::{face_pile::FacePile, CollaborationPanelSettings};
 
+use self::channel_modal::ChannelModal;
+
 pub fn init(cx: &mut AppContext) {
     cx.observe_new_views(|workspace: &mut Workspace, _| {
         workspace.register_action(|workspace, _: &ToggleFocus, cx| {
@@ -2058,13 +2060,11 @@ impl CollabPanel {
     }
 
     fn invite_members(&mut self, channel_id: ChannelId, cx: &mut ViewContext<Self>) {
-        todo!();
-        // self.show_channel_modal(channel_id, channel_modal::Mode::InviteMembers, cx);
+        self.show_channel_modal(channel_id, channel_modal::Mode::InviteMembers, cx);
     }
 
     fn manage_members(&mut self, channel_id: ChannelId, cx: &mut ViewContext<Self>) {
-        todo!();
-        // self.show_channel_modal(channel_id, channel_modal::Mode::ManageMembers, cx);
+        self.show_channel_modal(channel_id, channel_modal::Mode::ManageMembers, cx);
     }
 
     fn remove_selected_channel(&mut self, _: &Remove, cx: &mut ViewContext<Self>) {
@@ -2156,38 +2156,36 @@ impl CollabPanel {
             })
     }
 
-    //     fn show_channel_modal(
-    //         &mut self,
-    //         channel_id: ChannelId,
-    //         mode: channel_modal::Mode,
-    //         cx: &mut ViewContext<Self>,
-    //     ) {
-    //         let workspace = self.workspace.clone();
-    //         let user_store = self.user_store.clone();
-    //         let channel_store = self.channel_store.clone();
-    //         let members = self.channel_store.update(cx, |channel_store, cx| {
-    //             channel_store.get_channel_member_details(channel_id, cx)
-    //         });
-
-    //         cx.spawn(|_, mut cx| async move {
-    //             let members = members.await?;
-    //             workspace.update(&mut cx, |workspace, cx| {
-    //                 workspace.toggle_modal(cx, |_, cx| {
-    //                     cx.add_view(|cx| {
-    //                         ChannelModal::new(
-    //                             user_store.clone(),
-    //                             channel_store.clone(),
-    //                             channel_id,
-    //                             mode,
-    //                             members,
-    //                             cx,
-    //                         )
-    //                     })
-    //                 });
-    //             })
-    //         })
-    //         .detach();
-    //     }
+    fn show_channel_modal(
+        &mut self,
+        channel_id: ChannelId,
+        mode: channel_modal::Mode,
+        cx: &mut ViewContext<Self>,
+    ) {
+        let workspace = self.workspace.clone();
+        let user_store = self.user_store.clone();
+        let channel_store = self.channel_store.clone();
+        let members = self.channel_store.update(cx, |channel_store, cx| {
+            channel_store.get_channel_member_details(channel_id, cx)
+        });
+
+        cx.spawn(|_, mut cx| async move {
+            let members = members.await?;
+            workspace.update(&mut cx, |workspace, cx| {
+                workspace.toggle_modal(cx, |cx| {
+                    ChannelModal::new(
+                        user_store.clone(),
+                        channel_store.clone(),
+                        channel_id,
+                        mode,
+                        members,
+                        cx,
+                    )
+                });
+            })
+        })
+        .detach();
+    }
 
     //     fn remove_selected_channel(&mut self, action: &RemoveChannel, cx: &mut ViewContext<Self>) {
     //         self.remove_channel(action.channel_id, cx)

crates/collab_ui2/src/collab_panel/channel_modal.rs 🔗

@@ -3,58 +3,54 @@ use client::{
     proto::{self, ChannelRole, ChannelVisibility},
     User, UserId, UserStore,
 };
-use context_menu::{ContextMenu, ContextMenuItem};
 use fuzzy::{match_strings, StringMatchCandidate};
 use gpui::{
-    actions,
-    elements::*,
-    platform::{CursorStyle, MouseButton},
-    AppContext, ClipboardItem, Entity, ModelHandle, MouseState, Task, View, ViewContext,
-    ViewHandle,
+    actions, div, AppContext, ClipboardItem, DismissEvent, Div, Entity, EventEmitter,
+    FocusableView, Model, ParentElement, Render, Styled, Task, View, ViewContext, VisualContext,
+    WeakView,
 };
-use picker::{Picker, PickerDelegate, PickerEvent};
+use picker::{Picker, PickerDelegate};
 use std::sync::Arc;
+use ui::v_stack;
 use util::TryFutureExt;
-use workspace::Modal;
 
 actions!(
-    channel_modal,
-    [
-        SelectNextControl,
-        ToggleMode,
-        ToggleMemberAdmin,
-        RemoveMember
-    ]
+    SelectNextControl,
+    ToggleMode,
+    ToggleMemberAdmin,
+    RemoveMember
 );
 
-pub fn init(cx: &mut AppContext) {
-    Picker::<ChannelModalDelegate>::init(cx);
-    cx.add_action(ChannelModal::toggle_mode);
-    cx.add_action(ChannelModal::toggle_member_admin);
-    cx.add_action(ChannelModal::remove_member);
-    cx.add_action(ChannelModal::dismiss);
-}
+// pub fn init(cx: &mut AppContext) {
+//     Picker::<ChannelModalDelegate>::init(cx);
+//     cx.add_action(ChannelModal::toggle_mode);
+//     cx.add_action(ChannelModal::toggle_member_admin);
+//     cx.add_action(ChannelModal::remove_member);
+//     cx.add_action(ChannelModal::dismiss);
+// }
 
 pub struct ChannelModal {
-    picker: ViewHandle<Picker<ChannelModalDelegate>>,
-    channel_store: ModelHandle<ChannelStore>,
+    picker: View<Picker<ChannelModalDelegate>>,
+    channel_store: Model<ChannelStore>,
     channel_id: ChannelId,
     has_focus: bool,
 }
 
 impl ChannelModal {
     pub fn new(
-        user_store: ModelHandle<UserStore>,
-        channel_store: ModelHandle<ChannelStore>,
+        user_store: Model<UserStore>,
+        channel_store: Model<ChannelStore>,
         channel_id: ChannelId,
         mode: Mode,
         members: Vec<ChannelMembership>,
         cx: &mut ViewContext<Self>,
     ) -> Self {
         cx.observe(&channel_store, |_, _, cx| cx.notify()).detach();
-        let picker = cx.add_view(|cx| {
+        let channel_modal = cx.view().downgrade();
+        let picker = cx.build_view(|cx| {
             Picker::new(
                 ChannelModalDelegate {
+                    channel_modal,
                     matching_users: Vec::new(),
                     matching_member_indices: Vec::new(),
                     selected_index: 0,
@@ -64,20 +60,17 @@ impl ChannelModal {
                     match_candidates: Vec::new(),
                     members,
                     mode,
-                    context_menu: cx.add_view(|cx| {
-                        let mut menu = ContextMenu::new(cx.view_id(), cx);
-                        menu.set_position_mode(OverlayPositionMode::Local);
-                        menu
-                    }),
+                    // context_menu: cx.add_view(|cx| {
+                    //     let mut menu = ContextMenu::new(cx.view_id(), cx);
+                    //     menu.set_position_mode(OverlayPositionMode::Local);
+                    //     menu
+                    // }),
                 },
                 cx,
             )
-            .with_theme(|theme| theme.collab_panel.tabbed_modal.picker.clone())
         });
 
-        cx.subscribe(&picker, |_, _, e, cx| cx.emit(*e)).detach();
-
-        let has_focus = picker.read(cx).has_focus();
+        let has_focus = picker.focus_handle(cx).contains_focused(cx);
 
         Self {
             picker,
@@ -88,7 +81,7 @@ impl ChannelModal {
     }
 
     fn toggle_mode(&mut self, _: &ToggleMode, cx: &mut ViewContext<Self>) {
-        let mode = match self.picker.read(cx).delegate().mode {
+        let mode = match self.picker.read(cx).delegate.mode {
             Mode::ManageMembers => Mode::InviteMembers,
             Mode::InviteMembers => Mode::ManageMembers,
         };
@@ -103,20 +96,20 @@ impl ChannelModal {
                 let mut members = channel_store
                     .update(&mut cx, |channel_store, cx| {
                         channel_store.get_channel_member_details(channel_id, cx)
-                    })
+                    })?
                     .await?;
 
                 members.sort_by(|a, b| a.sort_key().cmp(&b.sort_key()));
 
                 this.update(&mut cx, |this, cx| {
                     this.picker
-                        .update(cx, |picker, _| picker.delegate_mut().members = members);
+                        .update(cx, |picker, _| picker.delegate.members = members);
                 })?;
             }
 
             this.update(&mut cx, |this, cx| {
                 this.picker.update(cx, |picker, cx| {
-                    let delegate = picker.delegate_mut();
+                    let delegate = &mut picker.delegate;
                     delegate.mode = mode;
                     delegate.selected_index = 0;
                     picker.set_query("", cx);
@@ -131,203 +124,194 @@ impl ChannelModal {
 
     fn toggle_member_admin(&mut self, _: &ToggleMemberAdmin, cx: &mut ViewContext<Self>) {
         self.picker.update(cx, |picker, cx| {
-            picker.delegate_mut().toggle_selected_member_admin(cx);
+            picker.delegate.toggle_selected_member_admin(cx);
         })
     }
 
     fn remove_member(&mut self, _: &RemoveMember, cx: &mut ViewContext<Self>) {
         self.picker.update(cx, |picker, cx| {
-            picker.delegate_mut().remove_selected_member(cx);
+            picker.delegate.remove_selected_member(cx);
         });
     }
 
     fn dismiss(&mut self, _: &menu::Cancel, cx: &mut ViewContext<Self>) {
-        cx.emit(PickerEvent::Dismiss);
+        cx.emit(DismissEvent);
     }
 }
 
-impl Entity for ChannelModal {
-    type Event = PickerEvent;
-}
-
-impl View for ChannelModal {
-    fn ui_name() -> &'static str {
-        "ChannelModal"
-    }
-
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
-        let theme = &theme::current(cx).collab_panel.tabbed_modal;
-
-        let mode = self.picker.read(cx).delegate().mode;
-        let Some(channel) = self.channel_store.read(cx).channel_for_id(self.channel_id) else {
-            return Empty::new().into_any();
-        };
-
-        enum InviteMembers {}
-        enum ManageMembers {}
-
-        fn render_mode_button<T: 'static>(
-            mode: Mode,
-            text: &'static str,
-            current_mode: Mode,
-            theme: &theme::TabbedModal,
-            cx: &mut ViewContext<ChannelModal>,
-        ) -> AnyElement<ChannelModal> {
-            let active = mode == current_mode;
-            MouseEventHandler::new::<T, _>(0, cx, move |state, _| {
-                let contained_text = theme.tab_button.style_for(active, state);
-                Label::new(text, contained_text.text.clone())
-                    .contained()
-                    .with_style(contained_text.container.clone())
-            })
-            .on_click(MouseButton::Left, move |_, this, cx| {
-                if !active {
-                    this.set_mode(mode, cx);
-                }
-            })
-            .with_cursor_style(CursorStyle::PointingHand)
-            .into_any()
-        }
-
-        fn render_visibility(
-            channel_id: ChannelId,
-            visibility: ChannelVisibility,
-            theme: &theme::TabbedModal,
-            cx: &mut ViewContext<ChannelModal>,
-        ) -> AnyElement<ChannelModal> {
-            enum TogglePublic {}
-
-            if visibility == ChannelVisibility::Members {
-                return Flex::row()
-                    .with_child(
-                        MouseEventHandler::new::<TogglePublic, _>(0, cx, move |state, _| {
-                            let style = theme.visibility_toggle.style_for(state);
-                            Label::new(format!("{}", "Public access: OFF"), style.text.clone())
-                                .contained()
-                                .with_style(style.container.clone())
-                        })
-                        .on_click(MouseButton::Left, move |_, this, cx| {
-                            this.channel_store
-                                .update(cx, |channel_store, cx| {
-                                    channel_store.set_channel_visibility(
-                                        channel_id,
-                                        ChannelVisibility::Public,
-                                        cx,
-                                    )
-                                })
-                                .detach_and_log_err(cx);
-                        })
-                        .with_cursor_style(CursorStyle::PointingHand),
-                    )
-                    .into_any();
-            }
-
-            Flex::row()
-                .with_child(
-                    MouseEventHandler::new::<TogglePublic, _>(0, cx, move |state, _| {
-                        let style = theme.visibility_toggle.style_for(state);
-                        Label::new(format!("{}", "Public access: ON"), style.text.clone())
-                            .contained()
-                            .with_style(style.container.clone())
-                    })
-                    .on_click(MouseButton::Left, move |_, this, cx| {
-                        this.channel_store
-                            .update(cx, |channel_store, cx| {
-                                channel_store.set_channel_visibility(
-                                    channel_id,
-                                    ChannelVisibility::Members,
-                                    cx,
-                                )
-                            })
-                            .detach_and_log_err(cx);
-                    })
-                    .with_cursor_style(CursorStyle::PointingHand),
-                )
-                .with_spacing(14.0)
-                .with_child(
-                    MouseEventHandler::new::<TogglePublic, _>(1, cx, move |state, _| {
-                        let style = theme.channel_link.style_for(state);
-                        Label::new(format!("{}", "copy link"), style.text.clone())
-                            .contained()
-                            .with_style(style.container.clone())
-                    })
-                    .on_click(MouseButton::Left, move |_, this, cx| {
-                        if let Some(channel) =
-                            this.channel_store.read(cx).channel_for_id(channel_id)
-                        {
-                            let item = ClipboardItem::new(channel.link());
-                            cx.write_to_clipboard(item);
-                        }
-                    })
-                    .with_cursor_style(CursorStyle::PointingHand),
-                )
-                .into_any()
-        }
-
-        Flex::column()
-            .with_child(
-                Flex::column()
-                    .with_child(
-                        Label::new(format!("#{}", channel.name), theme.title.text.clone())
-                            .contained()
-                            .with_style(theme.title.container.clone()),
-                    )
-                    .with_child(render_visibility(channel.id, channel.visibility, theme, cx))
-                    .with_child(Flex::row().with_children([
-                        render_mode_button::<InviteMembers>(
-                            Mode::InviteMembers,
-                            "Invite members",
-                            mode,
-                            theme,
-                            cx,
-                        ),
-                        render_mode_button::<ManageMembers>(
-                            Mode::ManageMembers,
-                            "Manage members",
-                            mode,
-                            theme,
-                            cx,
-                        ),
-                    ]))
-                    .expanded()
-                    .contained()
-                    .with_style(theme.header),
-            )
-            .with_child(
-                ChildView::new(&self.picker, cx)
-                    .contained()
-                    .with_style(theme.body),
-            )
-            .constrained()
-            .with_max_height(theme.max_height)
-            .with_max_width(theme.max_width)
-            .contained()
-            .with_style(theme.modal)
-            .into_any()
-    }
-
-    fn focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext<Self>) {
-        self.has_focus = true;
-        if cx.is_self_focused() {
-            cx.focus(&self.picker)
-        }
-    }
+impl EventEmitter<DismissEvent> for ChannelModal {}
 
-    fn focus_out(&mut self, _: gpui::AnyViewHandle, _: &mut ViewContext<Self>) {
-        self.has_focus = false;
+impl FocusableView for ChannelModal {
+    fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle {
+        self.picker.focus_handle(cx)
     }
 }
 
-impl Modal for ChannelModal {
-    fn has_focus(&self) -> bool {
-        self.has_focus
+impl Render for ChannelModal {
+    type Element = Div;
+
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+        v_stack().min_w_96().child(self.picker.clone())
+        // let theme = &theme::current(cx).collab_panel.tabbed_modal;
+
+        // let mode = self.picker.read(cx).delegate().mode;
+        // let Some(channel) = self.channel_store.read(cx).channel_for_id(self.channel_id) else {
+        //     return Empty::new().into_any();
+        // };
+
+        // enum InviteMembers {}
+        // enum ManageMembers {}
+
+        // fn render_mode_button<T: 'static>(
+        //     mode: Mode,
+        //     text: &'static str,
+        //     current_mode: Mode,
+        //     theme: &theme::TabbedModal,
+        //     cx: &mut ViewContext<ChannelModal>,
+        // ) -> AnyElement<ChannelModal> {
+        //     let active = mode == current_mode;
+        //     MouseEventHandler::new::<T, _>(0, cx, move |state, _| {
+        //         let contained_text = theme.tab_button.style_for(active, state);
+        //         Label::new(text, contained_text.text.clone())
+        //             .contained()
+        //             .with_style(contained_text.container.clone())
+        //     })
+        //     .on_click(MouseButton::Left, move |_, this, cx| {
+        //         if !active {
+        //             this.set_mode(mode, cx);
+        //         }
+        //     })
+        //     .with_cursor_style(CursorStyle::PointingHand)
+        //     .into_any()
+        // }
+
+        // fn render_visibility(
+        //     channel_id: ChannelId,
+        //     visibility: ChannelVisibility,
+        //     theme: &theme::TabbedModal,
+        //     cx: &mut ViewContext<ChannelModal>,
+        // ) -> AnyElement<ChannelModal> {
+        //     enum TogglePublic {}
+
+        //     if visibility == ChannelVisibility::Members {
+        //         return Flex::row()
+        //             .with_child(
+        //                 MouseEventHandler::new::<TogglePublic, _>(0, cx, move |state, _| {
+        //                     let style = theme.visibility_toggle.style_for(state);
+        //                     Label::new(format!("{}", "Public access: OFF"), style.text.clone())
+        //                         .contained()
+        //                         .with_style(style.container.clone())
+        //                 })
+        //                 .on_click(MouseButton::Left, move |_, this, cx| {
+        //                     this.channel_store
+        //                         .update(cx, |channel_store, cx| {
+        //                             channel_store.set_channel_visibility(
+        //                                 channel_id,
+        //                                 ChannelVisibility::Public,
+        //                                 cx,
+        //                             )
+        //                         })
+        //                         .detach_and_log_err(cx);
+        //                 })
+        //                 .with_cursor_style(CursorStyle::PointingHand),
+        //             )
+        //             .into_any();
+        //     }
+
+        //     Flex::row()
+        //         .with_child(
+        //             MouseEventHandler::new::<TogglePublic, _>(0, cx, move |state, _| {
+        //                 let style = theme.visibility_toggle.style_for(state);
+        //                 Label::new(format!("{}", "Public access: ON"), style.text.clone())
+        //                     .contained()
+        //                     .with_style(style.container.clone())
+        //             })
+        //             .on_click(MouseButton::Left, move |_, this, cx| {
+        //                 this.channel_store
+        //                     .update(cx, |channel_store, cx| {
+        //                         channel_store.set_channel_visibility(
+        //                             channel_id,
+        //                             ChannelVisibility::Members,
+        //                             cx,
+        //                         )
+        //                     })
+        //                     .detach_and_log_err(cx);
+        //             })
+        //             .with_cursor_style(CursorStyle::PointingHand),
+        //         )
+        //         .with_spacing(14.0)
+        //         .with_child(
+        //             MouseEventHandler::new::<TogglePublic, _>(1, cx, move |state, _| {
+        //                 let style = theme.channel_link.style_for(state);
+        //                 Label::new(format!("{}", "copy link"), style.text.clone())
+        //                     .contained()
+        //                     .with_style(style.container.clone())
+        //             })
+        //             .on_click(MouseButton::Left, move |_, this, cx| {
+        //                 if let Some(channel) =
+        //                     this.channel_store.read(cx).channel_for_id(channel_id)
+        //                 {
+        //                     let item = ClipboardItem::new(channel.link());
+        //                     cx.write_to_clipboard(item);
+        //                 }
+        //             })
+        //             .with_cursor_style(CursorStyle::PointingHand),
+        //         )
+        //         .into_any()
+        // }
+
+        // Flex::column()
+        //     .with_child(
+        //         Flex::column()
+        //             .with_child(
+        //                 Label::new(format!("#{}", channel.name), theme.title.text.clone())
+        //                     .contained()
+        //                     .with_style(theme.title.container.clone()),
+        //             )
+        //             .with_child(render_visibility(channel.id, channel.visibility, theme, cx))
+        //             .with_child(Flex::row().with_children([
+        //                 render_mode_button::<InviteMembers>(
+        //                     Mode::InviteMembers,
+        //                     "Invite members",
+        //                     mode,
+        //                     theme,
+        //                     cx,
+        //                 ),
+        //                 render_mode_button::<ManageMembers>(
+        //                     Mode::ManageMembers,
+        //                     "Manage members",
+        //                     mode,
+        //                     theme,
+        //                     cx,
+        //                 ),
+        //             ]))
+        //             .expanded()
+        //             .contained()
+        //             .with_style(theme.header),
+        //     )
+        //     .with_child(
+        //         ChildView::new(&self.picker, cx)
+        //             .contained()
+        //             .with_style(theme.body),
+        //     )
+        //     .constrained()
+        //     .with_max_height(theme.max_height)
+        //     .with_max_width(theme.max_width)
+        //     .contained()
+        //     .with_style(theme.modal)
+        //     .into_any()
     }
 
-    fn dismiss_on_event(event: &Self::Event) -> bool {
-        match event {
-            PickerEvent::Dismiss => true,
-        }
-    }
+    // fn focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut ViewContext<Self>) {
+    //     self.has_focus = true;
+    //     if cx.is_self_focused() {
+    //         cx.focus(&self.picker)
+    //     }
+    // }
+
+    // fn focus_out(&mut self, _: gpui::AnyViewHandle, _: &mut ViewContext<Self>) {
+    //     self.has_focus = false;
+    // }
 }
 
 #[derive(Copy, Clone, PartialEq)]
@@ -337,19 +321,22 @@ pub enum Mode {
 }
 
 pub struct ChannelModalDelegate {
+    channel_modal: WeakView<ChannelModal>,
     matching_users: Vec<Arc<User>>,
     matching_member_indices: Vec<usize>,
-    user_store: ModelHandle<UserStore>,
-    channel_store: ModelHandle<ChannelStore>,
+    user_store: Model<UserStore>,
+    channel_store: Model<ChannelStore>,
     channel_id: ChannelId,
     selected_index: usize,
     mode: Mode,
     match_candidates: Vec<StringMatchCandidate>,
     members: Vec<ChannelMembership>,
-    context_menu: ViewHandle<ContextMenu>,
+    // context_menu: ViewHandle<ContextMenu>,
 }
 
 impl PickerDelegate for ChannelModalDelegate {
+    type ListItem = Div;
+
     fn placeholder_text(&self) -> Arc<str> {
         "Search collaborator by username...".into()
     }
@@ -382,19 +369,19 @@ impl PickerDelegate for ChannelModalDelegate {
                         }
                     }));
 
-                let matches = cx.background().block(match_strings(
+                let matches = cx.background_executor().block(match_strings(
                     &self.match_candidates,
                     &query,
                     true,
                     usize::MAX,
                     &Default::default(),
-                    cx.background().clone(),
+                    cx.background_executor().clone(),
                 ));
 
                 cx.spawn(|picker, mut cx| async move {
                     picker
                         .update(&mut cx, |picker, cx| {
-                            let delegate = picker.delegate_mut();
+                            let delegate = &mut picker.delegate;
                             delegate.matching_member_indices.clear();
                             delegate
                                 .matching_member_indices
@@ -412,8 +399,7 @@ impl PickerDelegate for ChannelModalDelegate {
                     async {
                         let users = search_users.await?;
                         picker.update(&mut cx, |picker, cx| {
-                            let delegate = picker.delegate_mut();
-                            delegate.matching_users = users;
+                            picker.delegate.matching_users = users;
                             cx.notify();
                         })?;
                         anyhow::Ok(())
@@ -445,138 +431,142 @@ impl PickerDelegate for ChannelModalDelegate {
     }
 
     fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>) {
-        cx.emit(PickerEvent::Dismiss);
+        self.channel_modal
+            .update(cx, |_, cx| {
+                cx.emit(DismissEvent);
+            })
+            .ok();
     }
 
     fn render_match(
         &self,
         ix: usize,
-        mouse_state: &mut MouseState,
         selected: bool,
-        cx: &gpui::AppContext,
-    ) -> AnyElement<Picker<Self>> {
-        let full_theme = &theme::current(cx);
-        let theme = &full_theme.collab_panel.channel_modal;
-        let tabbed_modal = &full_theme.collab_panel.tabbed_modal;
-        let (user, role) = self.user_at_index(ix).unwrap();
-        let request_status = self.member_status(user.id, cx);
-
-        let style = tabbed_modal
-            .picker
-            .item
-            .in_state(selected)
-            .style_for(mouse_state);
-
-        let in_manage = matches!(self.mode, Mode::ManageMembers);
-
-        let mut result = Flex::row()
-            .with_children(user.avatar.clone().map(|avatar| {
-                Image::from_data(avatar)
-                    .with_style(theme.contact_avatar)
-                    .aligned()
-                    .left()
-            }))
-            .with_child(
-                Label::new(user.github_login.clone(), style.label.clone())
-                    .contained()
-                    .with_style(theme.contact_username)
-                    .aligned()
-                    .left(),
-            )
-            .with_children({
-                (in_manage && request_status == Some(proto::channel_member::Kind::Invitee)).then(
-                    || {
-                        Label::new("Invited", theme.member_tag.text.clone())
-                            .contained()
-                            .with_style(theme.member_tag.container)
-                            .aligned()
-                            .left()
-                    },
-                )
-            })
-            .with_children(if in_manage && role == Some(ChannelRole::Admin) {
-                Some(
-                    Label::new("Admin", theme.member_tag.text.clone())
-                        .contained()
-                        .with_style(theme.member_tag.container)
-                        .aligned()
-                        .left(),
-                )
-            } else if in_manage && role == Some(ChannelRole::Guest) {
-                Some(
-                    Label::new("Guest", theme.member_tag.text.clone())
-                        .contained()
-                        .with_style(theme.member_tag.container)
-                        .aligned()
-                        .left(),
-                )
-            } else {
-                None
-            })
-            .with_children({
-                let svg = match self.mode {
-                    Mode::ManageMembers => Some(
-                        Svg::new("icons/ellipsis.svg")
-                            .with_color(theme.member_icon.color)
-                            .constrained()
-                            .with_width(theme.member_icon.icon_width)
-                            .aligned()
-                            .constrained()
-                            .with_width(theme.member_icon.button_width)
-                            .with_height(theme.member_icon.button_width)
-                            .contained()
-                            .with_style(theme.member_icon.container),
-                    ),
-                    Mode::InviteMembers => match request_status {
-                        Some(proto::channel_member::Kind::Member) => Some(
-                            Svg::new("icons/check.svg")
-                                .with_color(theme.member_icon.color)
-                                .constrained()
-                                .with_width(theme.member_icon.icon_width)
-                                .aligned()
-                                .constrained()
-                                .with_width(theme.member_icon.button_width)
-                                .with_height(theme.member_icon.button_width)
-                                .contained()
-                                .with_style(theme.member_icon.container),
-                        ),
-                        Some(proto::channel_member::Kind::Invitee) => Some(
-                            Svg::new("icons/check.svg")
-                                .with_color(theme.invitee_icon.color)
-                                .constrained()
-                                .with_width(theme.invitee_icon.icon_width)
-                                .aligned()
-                                .constrained()
-                                .with_width(theme.invitee_icon.button_width)
-                                .with_height(theme.invitee_icon.button_width)
-                                .contained()
-                                .with_style(theme.invitee_icon.container),
-                        ),
-                        Some(proto::channel_member::Kind::AncestorMember) | None => None,
-                    },
-                };
-
-                svg.map(|svg| svg.aligned().flex_float().into_any())
-            })
-            .contained()
-            .with_style(style.container)
-            .constrained()
-            .with_height(tabbed_modal.row_height)
-            .into_any();
-
-        if selected {
-            result = Stack::new()
-                .with_child(result)
-                .with_child(
-                    ChildView::new(&self.context_menu, cx)
-                        .aligned()
-                        .top()
-                        .right(),
-                )
-                .into_any();
-        }
-
-        result
+        cx: &mut ViewContext<Picker<Self>>,
+    ) -> Option<Self::ListItem> {
+        None
+        //     let full_theme = &theme::current(cx);
+        //     let theme = &full_theme.collab_panel.channel_modal;
+        //     let tabbed_modal = &full_theme.collab_panel.tabbed_modal;
+        //     let (user, role) = self.user_at_index(ix).unwrap();
+        //     let request_status = self.member_status(user.id, cx);
+
+        //     let style = tabbed_modal
+        //         .picker
+        //         .item
+        //         .in_state(selected)
+        //         .style_for(mouse_state);
+
+        //     let in_manage = matches!(self.mode, Mode::ManageMembers);
+
+        //     let mut result = Flex::row()
+        //         .with_children(user.avatar.clone().map(|avatar| {
+        //             Image::from_data(avatar)
+        //                 .with_style(theme.contact_avatar)
+        //                 .aligned()
+        //                 .left()
+        //         }))
+        //         .with_child(
+        //             Label::new(user.github_login.clone(), style.label.clone())
+        //                 .contained()
+        //                 .with_style(theme.contact_username)
+        //                 .aligned()
+        //                 .left(),
+        //         )
+        //         .with_children({
+        //             (in_manage && request_status == Some(proto::channel_member::Kind::Invitee)).then(
+        //                 || {
+        //                     Label::new("Invited", theme.member_tag.text.clone())
+        //                         .contained()
+        //                         .with_style(theme.member_tag.container)
+        //                         .aligned()
+        //                         .left()
+        //                 },
+        //             )
+        //         })
+        //         .with_children(if in_manage && role == Some(ChannelRole::Admin) {
+        //             Some(
+        //                 Label::new("Admin", theme.member_tag.text.clone())
+        //                     .contained()
+        //                     .with_style(theme.member_tag.container)
+        //                     .aligned()
+        //                     .left(),
+        //             )
+        //         } else if in_manage && role == Some(ChannelRole::Guest) {
+        //             Some(
+        //                 Label::new("Guest", theme.member_tag.text.clone())
+        //                     .contained()
+        //                     .with_style(theme.member_tag.container)
+        //                     .aligned()
+        //                     .left(),
+        //             )
+        //         } else {
+        //             None
+        //         })
+        //         .with_children({
+        //             let svg = match self.mode {
+        //                 Mode::ManageMembers => Some(
+        //                     Svg::new("icons/ellipsis.svg")
+        //                         .with_color(theme.member_icon.color)
+        //                         .constrained()
+        //                         .with_width(theme.member_icon.icon_width)
+        //                         .aligned()
+        //                         .constrained()
+        //                         .with_width(theme.member_icon.button_width)
+        //                         .with_height(theme.member_icon.button_width)
+        //                         .contained()
+        //                         .with_style(theme.member_icon.container),
+        //                 ),
+        //                 Mode::InviteMembers => match request_status {
+        //                     Some(proto::channel_member::Kind::Member) => Some(
+        //                         Svg::new("icons/check.svg")
+        //                             .with_color(theme.member_icon.color)
+        //                             .constrained()
+        //                             .with_width(theme.member_icon.icon_width)
+        //                             .aligned()
+        //                             .constrained()
+        //                             .with_width(theme.member_icon.button_width)
+        //                             .with_height(theme.member_icon.button_width)
+        //                             .contained()
+        //                             .with_style(theme.member_icon.container),
+        //                     ),
+        //                     Some(proto::channel_member::Kind::Invitee) => Some(
+        //                         Svg::new("icons/check.svg")
+        //                             .with_color(theme.invitee_icon.color)
+        //                             .constrained()
+        //                             .with_width(theme.invitee_icon.icon_width)
+        //                             .aligned()
+        //                             .constrained()
+        //                             .with_width(theme.invitee_icon.button_width)
+        //                             .with_height(theme.invitee_icon.button_width)
+        //                             .contained()
+        //                             .with_style(theme.invitee_icon.container),
+        //                     ),
+        //                     Some(proto::channel_member::Kind::AncestorMember) | None => None,
+        //                 },
+        //             };
+
+        //             svg.map(|svg| svg.aligned().flex_float().into_any())
+        //         })
+        //         .contained()
+        //         .with_style(style.container)
+        //         .constrained()
+        //         .with_height(tabbed_modal.row_height)
+        //         .into_any();
+
+        //     if selected {
+        //         result = Stack::new()
+        //             .with_child(result)
+        //             .with_child(
+        //                 ChildView::new(&self.context_menu, cx)
+        //                     .aligned()
+        //                     .top()
+        //                     .right(),
+        //             )
+        //             .into_any();
+        //     }
+
+        //     result
     }
 }
 
@@ -623,7 +613,7 @@ impl ChannelModalDelegate {
         cx.spawn(|picker, mut cx| async move {
             update.await?;
             picker.update(&mut cx, |picker, cx| {
-                let this = picker.delegate_mut();
+                let this = &mut picker.delegate;
                 if let Some(member) = this.members.iter_mut().find(|m| m.user.id == user.id) {
                     member.role = new_role;
                 }
@@ -644,7 +634,7 @@ impl ChannelModalDelegate {
         cx.spawn(|picker, mut cx| async move {
             update.await?;
             picker.update(&mut cx, |picker, cx| {
-                let this = picker.delegate_mut();
+                let this = &mut picker.delegate;
                 if let Some(ix) = this.members.iter_mut().position(|m| m.user.id == user_id) {
                     this.members.remove(ix);
                     this.matching_member_indices.retain_mut(|member_ix| {
@@ -683,7 +673,7 @@ impl ChannelModalDelegate {
                     kind: proto::channel_member::Kind::Invitee,
                     role: ChannelRole::Member,
                 };
-                let members = &mut this.delegate_mut().members;
+                let members = &mut this.delegate.members;
                 match members.binary_search_by_key(&new_member.sort_key(), |k| k.sort_key()) {
                     Ok(ix) | Err(ix) => members.insert(ix, new_member),
                 }
@@ -695,23 +685,23 @@ impl ChannelModalDelegate {
     }
 
     fn show_context_menu(&mut self, role: ChannelRole, cx: &mut ViewContext<Picker<Self>>) {
-        self.context_menu.update(cx, |context_menu, cx| {
-            context_menu.show(
-                Default::default(),
-                AnchorCorner::TopRight,
-                vec![
-                    ContextMenuItem::action("Remove", RemoveMember),
-                    ContextMenuItem::action(
-                        if role == ChannelRole::Admin {
-                            "Make non-admin"
-                        } else {
-                            "Make admin"
-                        },
-                        ToggleMemberAdmin,
-                    ),
-                ],
-                cx,
-            )
-        })
+        // self.context_menu.update(cx, |context_menu, cx| {
+        //     context_menu.show(
+        //         Default::default(),
+        //         AnchorCorner::TopRight,
+        //         vec![
+        //             ContextMenuItem::action("Remove", RemoveMember),
+        //             ContextMenuItem::action(
+        //                 if role == ChannelRole::Admin {
+        //                     "Make non-admin"
+        //                 } else {
+        //                     "Make admin"
+        //                 },
+        //                 ToggleMemberAdmin,
+        //             ),
+        //         ],
+        //         cx,
+        //     )
+        // })
     }
 }

crates/collab_ui2/src/collab_titlebar_item.rs 🔗

@@ -35,16 +35,19 @@ use gpui::{
     ParentElement, Render, RenderOnce, Stateful, StatefulInteractiveElement, Styled, Subscription,
     ViewContext, VisualContext, WeakView, WindowBounds,
 };
-use project::Project;
+use project::{Project, RepositoryEntry};
 use theme::ActiveTheme;
-use ui::{h_stack, prelude::*, Avatar, Button, ButtonStyle, IconButton, KeyBinding, Tooltip};
+use ui::{
+    h_stack, popover_menu, prelude::*, Avatar, Button, ButtonLike, ButtonStyle, ContextMenu, Icon,
+    IconButton, IconElement, KeyBinding, Tooltip,
+};
 use util::ResultExt;
 use workspace::{notifications::NotifyResultExt, Workspace};
 
 use crate::face_pile::FacePile;
 
-// const MAX_PROJECT_NAME_LENGTH: usize = 40;
-// const MAX_BRANCH_NAME_LENGTH: usize = 40;
+const MAX_PROJECT_NAME_LENGTH: usize = 40;
+const MAX_BRANCH_NAME_LENGTH: usize = 40;
 
 // actions!(
 //     collab,
@@ -100,17 +103,18 @@ impl Render for CollabTitlebarItem {
             .update(cx, |this, cx| this.call_state().remote_participants(cx))
             .log_err()
             .flatten();
-        let mic_icon = if self
+        let is_muted = self
             .workspace
             .update(cx, |this, cx| this.call_state().is_muted(cx))
             .log_err()
             .flatten()
-            .unwrap_or_default()
-        {
-            ui::Icon::MicMute
-        } else {
-            ui::Icon::Mic
-        };
+            .unwrap_or_default();
+        let is_deafened = self
+            .workspace
+            .update(cx, |this, cx| this.call_state().is_deafened(cx))
+            .log_err()
+            .flatten()
+            .unwrap_or_default();
         let speakers_icon = if self
             .workspace
             .update(cx, |this, cx| this.call_state().is_deafened(cx))
@@ -146,56 +150,11 @@ impl Render for CollabTitlebarItem {
             .child(
                 h_stack()
                     .gap_1()
-                    // TODO - Add player menu
-                    .child(
-                        div()
-                            .border()
-                            .border_color(gpui::red())
-                            .id("project_owner_indicator")
-                            .child(
-                                Button::new("player", "player")
-                                    .style(ButtonStyle::Subtle)
-                                    .color(Some(Color::Player(0))),
-                            )
-                            .tooltip(move |cx| Tooltip::text("Toggle following", cx)),
-                    )
-                    // TODO - Add project menu
-                    .child(
-                        div()
-                            .border()
-                            .border_color(gpui::red())
-                            .id("titlebar_project_menu_button")
-                            .child(
-                                Button::new("project_name", "project_name")
-                                    .style(ButtonStyle::Subtle),
-                            )
-                            .tooltip(move |cx| Tooltip::text("Recent Projects", cx)),
-                    )
-                    // TODO - Add git menu
-                    .child(
-                        div()
-                            .border()
-                            .border_color(gpui::red())
-                            .id("titlebar_git_menu_button")
-                            .child(
-                                Button::new("branch_name", "branch_name")
-                                    .style(ButtonStyle::Subtle)
-                                    .color(Some(Color::Muted)),
-                            )
-                            .tooltip(move |cx| {
-                                cx.build_view(|_| {
-                                    Tooltip::new("Recent Branches")
-                                        .key_binding(KeyBinding::new(gpui::KeyBinding::new(
-                                            "cmd-b",
-                                            // todo!() Replace with real action.
-                                            gpui::NoAction,
-                                            None,
-                                        )))
-                                        .meta("Only local branches shown")
-                                })
-                                .into()
-                            }),
-                    ),
+                    .when(is_in_room, |this| {
+                        this.children(self.render_project_owner(cx))
+                    })
+                    .child(self.render_project_name(cx))
+                    .children(self.render_project_branch(cx)),
             )
             .when_some(
                 users.zip(current_user.clone()),
@@ -236,62 +195,126 @@ impl Render for CollabTitlebarItem {
             .when(is_in_room, |this| {
                 this.child(
                     h_stack()
+                        .gap_1()
                         .child(
                             h_stack()
-                                .child(Button::new(
-                                    "toggle_sharing",
-                                    if is_shared { "Unshare" } else { "Share" },
-                                ))
-                                .child(IconButton::new("leave-call", ui::Icon::Exit).on_click({
-                                    let workspace = workspace.clone();
-                                    move |_, cx| {
-                                        workspace
-                                            .update(cx, |this, cx| {
-                                                this.call_state().hang_up(cx).detach();
-                                            })
-                                            .log_err();
-                                    }
-                                })),
+                                .gap_1()
+                                .child(
+                                    Button::new(
+                                        "toggle_sharing",
+                                        if is_shared { "Unshare" } else { "Share" },
+                                    )
+                                    .style(ButtonStyle::Subtle),
+                                )
+                                .child(
+                                    IconButton::new("leave-call", ui::Icon::Exit)
+                                        .style(ButtonStyle::Subtle)
+                                        .on_click({
+                                            let workspace = workspace.clone();
+                                            move |_, cx| {
+                                                workspace
+                                                    .update(cx, |this, cx| {
+                                                        this.call_state().hang_up(cx).detach();
+                                                    })
+                                                    .log_err();
+                                            }
+                                        }),
+                                ),
                         )
                         .child(
                             h_stack()
-                                .child(IconButton::new("mute-microphone", mic_icon).on_click({
-                                    let workspace = workspace.clone();
-                                    move |_, cx| {
-                                        workspace
-                                            .update(cx, |this, cx| {
-                                                this.call_state().toggle_mute(cx);
-                                            })
-                                            .log_err();
-                                    }
-                                }))
-                                .child(IconButton::new("mute-sound", speakers_icon).on_click({
-                                    let workspace = workspace.clone();
-                                    move |_, cx| {
-                                        workspace
-                                            .update(cx, |this, cx| {
-                                                this.call_state().toggle_deafen(cx);
-                                            })
-                                            .log_err();
-                                    }
-                                }))
-                                .child(IconButton::new("screen-share", ui::Icon::Screen).on_click(
-                                    move |_, cx| {
-                                        workspace
-                                            .update(cx, |this, cx| {
-                                                this.call_state().toggle_screen_share(cx);
-                                            })
-                                            .log_err();
-                                    },
-                                ))
+                                .gap_1()
+                                .child(
+                                    IconButton::new(
+                                        "mute-microphone",
+                                        if is_muted {
+                                            ui::Icon::MicMute
+                                        } else {
+                                            ui::Icon::Mic
+                                        },
+                                    )
+                                    .style(ButtonStyle::Subtle)
+                                    .selected(is_muted)
+                                    .on_click({
+                                        let workspace = workspace.clone();
+                                        move |_, cx| {
+                                            workspace
+                                                .update(cx, |this, cx| {
+                                                    this.call_state().toggle_mute(cx);
+                                                })
+                                                .log_err();
+                                        }
+                                    }),
+                                )
+                                .child(
+                                    IconButton::new("mute-sound", speakers_icon)
+                                        .style(ButtonStyle::Subtle)
+                                        .selected(is_deafened.clone())
+                                        .tooltip(move |cx| {
+                                            Tooltip::with_meta(
+                                                "Deafen Audio",
+                                                None,
+                                                "Mic will be muted",
+                                                cx,
+                                            )
+                                        })
+                                        .on_click({
+                                            let workspace = workspace.clone();
+                                            move |_, cx| {
+                                                workspace
+                                                    .update(cx, |this, cx| {
+                                                        this.call_state().toggle_deafen(cx);
+                                                    })
+                                                    .log_err();
+                                            }
+                                        }),
+                                )
+                                .child(
+                                    IconButton::new("screen-share", ui::Icon::Screen)
+                                        .style(ButtonStyle::Subtle)
+                                        .on_click(move |_, cx| {
+                                            workspace
+                                                .update(cx, |this, cx| {
+                                                    this.call_state().toggle_screen_share(cx);
+                                                })
+                                                .log_err();
+                                        }),
+                                )
                                 .pl_2(),
                         ),
                 )
             })
-            .map(|this| {
+            .child(h_stack().px_1p5().map(|this| {
                 if let Some(user) = current_user {
                     this.when_some(user.avatar.clone(), |this, avatar| {
-                        this.child(ui::Avatar::data(avatar))
+                        // TODO: Finish implementing user menu popover
+                        //
+                        this.child(
+                            popover_menu("user-menu")
+                                .menu(|cx| ContextMenu::build(cx, |menu, _| menu.header("ADADA")))
+                                .trigger(
+                                    ButtonLike::new("user-menu")
+                                        .child(
+                                            h_stack().gap_0p5().child(Avatar::data(avatar)).child(
+                                                IconElement::new(Icon::ChevronDown)
+                                                    .color(Color::Muted),
+                                            ),
+                                        )
+                                        .style(ButtonStyle::Subtle)
+                                        .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)),
+                                )
+                                .anchor(gpui::AnchorCorner::TopRight),
+                        )
+                        // this.child(
+                        //     ButtonLike::new("user-menu")
+                        //         .child(
+                        //             h_stack().gap_0p5().child(Avatar::data(avatar)).child(
+                        //                 IconElement::new(Icon::ChevronDown).color(Color::Muted),
+                        //             ),
+                        //         )
+                        //         .style(ButtonStyle::Subtle)
+                        //         .tooltip(move |cx| Tooltip::text("Toggle User Menu", cx)),
+                        // )
                     })
                 } else {
                     this.child(Button::new("sign_in", "Sign in").on_click(move |_, cx| {
@@ -305,7 +328,7 @@ impl Render for CollabTitlebarItem {
                         .detach();
                     }))
                 }
-            })
+            }))
     }
 }
 
@@ -424,6 +447,110 @@ impl CollabTitlebarItem {
         }
     }
 
+    // resolve if you are in a room -> render_project_owner
+    // render_project_owner -> resolve if you are in a room -> Option<foo>
+
+    pub fn render_project_owner(&self, cx: &mut ViewContext<Self>) -> Option<impl Element> {
+        // TODO: We can't finish implementing this until project sharing works
+        // - [ ] Show the project owner when the project is remote (maybe done)
+        // - [x] Show the project owner when the project is local
+        // - [ ] Show the project owner with a lock icon when the project is local and unshared
+
+        let remote_id = self.project.read(cx).remote_id();
+        let is_local = remote_id.is_none();
+        let is_shared = self.project.read(cx).is_shared();
+        let (user_name, participant_index) = {
+            if let Some(host) = self.project.read(cx).host() {
+                debug_assert!(!is_local);
+                let (Some(host_user), Some(participant_index)) = (
+                    self.user_store.read(cx).get_cached_user(host.user_id),
+                    self.user_store
+                        .read(cx)
+                        .participant_indices()
+                        .get(&host.user_id),
+                ) else {
+                    return None;
+                };
+                (host_user.github_login.clone(), participant_index.0)
+            } else {
+                debug_assert!(is_local);
+                let name = self
+                    .user_store
+                    .read(cx)
+                    .current_user()
+                    .map(|user| user.github_login.clone())?;
+                (name, 0)
+            }
+        };
+        Some(
+            div().border().border_color(gpui::red()).child(
+                Button::new(
+                    "project_owner_trigger",
+                    format!("{user_name} ({})", !is_shared),
+                )
+                .color(Color::Player(participant_index))
+                .style(ButtonStyle::Subtle)
+                .tooltip(move |cx| Tooltip::text("Toggle following", cx)),
+            ),
+        )
+    }
+
+    pub fn render_project_name(&self, cx: &mut ViewContext<Self>) -> impl Element {
+        let name = {
+            let mut names = self.project.read(cx).visible_worktrees(cx).map(|worktree| {
+                let worktree = worktree.read(cx);
+                worktree.root_name()
+            });
+
+            names.next().unwrap_or("")
+        };
+
+        let name = util::truncate_and_trailoff(name, MAX_PROJECT_NAME_LENGTH);
+
+        div().border().border_color(gpui::red()).child(
+            Button::new("project_name_trigger", name)
+                .style(ButtonStyle::Subtle)
+                .tooltip(move |cx| Tooltip::text("Recent Projects", cx)),
+        )
+    }
+
+    pub fn render_project_branch(&self, cx: &mut ViewContext<Self>) -> Option<impl Element> {
+        let entry = {
+            let mut names_and_branches =
+                self.project.read(cx).visible_worktrees(cx).map(|worktree| {
+                    let worktree = worktree.read(cx);
+                    worktree.root_git_entry()
+                });
+
+            names_and_branches.next().flatten()
+        };
+
+        let branch_name = entry
+            .as_ref()
+            .and_then(RepositoryEntry::branch)
+            .map(|branch| util::truncate_and_trailoff(&branch, MAX_BRANCH_NAME_LENGTH))?;
+
+        Some(
+            div().border().border_color(gpui::red()).child(
+                Button::new("project_branch_trigger", branch_name)
+                    .style(ButtonStyle::Subtle)
+                    .tooltip(move |cx| {
+                        cx.build_view(|_| {
+                            Tooltip::new("Recent Branches")
+                                .key_binding(KeyBinding::new(gpui::KeyBinding::new(
+                                    "cmd-b",
+                                    // todo!() Replace with real action.
+                                    gpui::NoAction,
+                                    None,
+                                )))
+                                .meta("Local branches only")
+                        })
+                        .into()
+                    }),
+            ),
+        )
+    }
+
     // fn collect_title_root_names(
     //     &self,
     //     theme: Arc<Theme>,

crates/copilot_button2/Cargo.toml 🔗

@@ -0,0 +1,27 @@
+[package]
+name = "copilot_button2"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[lib]
+path = "src/copilot_button.rs"
+doctest = false
+
+[dependencies]
+copilot = { package = "copilot2", path = "../copilot2" }
+editor = { package = "editor2", path = "../editor2" }
+fs = { package = "fs2", path = "../fs2" }
+zed-actions = { package="zed_actions2", path = "../zed_actions2"}
+gpui = { package = "gpui2", path = "../gpui2" }
+language = { package = "language2", path = "../language2" }
+settings = { package = "settings2", path = "../settings2" }
+theme = { package = "theme2", path = "../theme2" }
+util = { path = "../util" }
+workspace = { package = "workspace2", path = "../workspace2" }
+anyhow.workspace = true
+smol.workspace = true
+futures.workspace = true
+
+[dev-dependencies]
+editor = { package = "editor2", path = "../editor2", features = ["test-support"] }

crates/copilot_button2/src/copilot_button.rs 🔗

@@ -0,0 +1,371 @@
+#![allow(unused)]
+use anyhow::Result;
+use copilot::{Copilot, SignOut, Status};
+use editor::{scroll::autoscroll::Autoscroll, Editor};
+use fs::Fs;
+use gpui::{
+    div, Action, AnchorCorner, AppContext, AsyncAppContext, AsyncWindowContext, Div, Entity,
+    ParentElement, Render, Subscription, View, ViewContext, WeakView, WindowContext,
+};
+use language::{
+    language_settings::{self, all_language_settings, AllLanguageSettings},
+    File, Language,
+};
+use settings::{update_settings_file, Settings, SettingsStore};
+use std::{path::Path, sync::Arc};
+use util::{paths, ResultExt};
+use workspace::{
+    create_and_open_local_file,
+    item::ItemHandle,
+    ui::{
+        popover_menu, ButtonCommon, Clickable, ContextMenu, Icon, IconButton, PopoverMenu, Tooltip,
+    },
+    StatusItemView, Toast, Workspace,
+};
+use zed_actions::OpenBrowser;
+
+const COPILOT_SETTINGS_URL: &str = "https://github.com/settings/copilot";
+const COPILOT_STARTING_TOAST_ID: usize = 1337;
+const COPILOT_ERROR_TOAST_ID: usize = 1338;
+
+pub struct CopilotButton {
+    editor_subscription: Option<(Subscription, usize)>,
+    editor_enabled: Option<bool>,
+    language: Option<Arc<Language>>,
+    file: Option<Arc<dyn File>>,
+    fs: Arc<dyn Fs>,
+}
+
+impl Render for CopilotButton {
+    type Element = Div;
+
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+        let all_language_settings = all_language_settings(None, cx);
+        if !all_language_settings.copilot.feature_enabled {
+            return div();
+        }
+
+        let Some(copilot) = Copilot::global(cx) else {
+            return div();
+        };
+        let status = copilot.read(cx).status();
+
+        let enabled = self
+            .editor_enabled
+            .unwrap_or_else(|| all_language_settings.copilot_enabled(None, None));
+
+        let icon = match status {
+            Status::Error(_) => Icon::CopilotError,
+            Status::Authorized => {
+                if enabled {
+                    Icon::Copilot
+                } else {
+                    Icon::CopilotDisabled
+                }
+            }
+            _ => Icon::CopilotInit,
+        };
+
+        if let Status::Error(e) = status {
+            return div().child(
+                IconButton::new("copilot-error", icon)
+                    .on_click(cx.listener(move |this, _, cx| {
+                        if let Some(workspace) = cx.window_handle().downcast::<Workspace>() {
+                            workspace.update(cx, |workspace, cx| {
+                                workspace.show_toast(
+                                    Toast::new(
+                                        COPILOT_ERROR_TOAST_ID,
+                                        format!("Copilot can't be started: {}", e),
+                                    )
+                                    .on_click(
+                                        "Reinstall Copilot",
+                                        |cx| {
+                                            if let Some(copilot) = Copilot::global(cx) {
+                                                copilot
+                                                    .update(cx, |copilot, cx| copilot.reinstall(cx))
+                                                    .detach();
+                                            }
+                                        },
+                                    ),
+                                    cx,
+                                );
+                            });
+                        }
+                    }))
+                    .tooltip(|cx| Tooltip::text("GitHub Copilot", cx)),
+            );
+        }
+        let this = cx.view().clone();
+
+        div().child(
+            popover_menu("copilot")
+                .menu(move |cx| match status {
+                    Status::Authorized => this.update(cx, |this, cx| this.build_copilot_menu(cx)),
+                    _ => this.update(cx, |this, cx| this.build_copilot_start_menu(cx)),
+                })
+                .anchor(AnchorCorner::BottomRight)
+                .trigger(
+                    IconButton::new("copilot-icon", icon)
+                        .tooltip(|cx| Tooltip::text("GitHub Copilot", cx)),
+                ),
+        )
+    }
+}
+
+impl CopilotButton {
+    pub fn new(fs: Arc<dyn Fs>, cx: &mut ViewContext<Self>) -> Self {
+        Copilot::global(cx).map(|copilot| cx.observe(&copilot, |_, _, cx| cx.notify()).detach());
+
+        cx.observe_global::<SettingsStore>(move |_, cx| cx.notify())
+            .detach();
+
+        Self {
+            editor_subscription: None,
+            editor_enabled: None,
+            language: None,
+            file: None,
+            fs,
+        }
+    }
+
+    pub fn build_copilot_start_menu(&mut self, cx: &mut ViewContext<Self>) -> View<ContextMenu> {
+        let fs = self.fs.clone();
+        ContextMenu::build(cx, |menu, cx| {
+            menu.entry("Sign In", initiate_sign_in)
+                .entry("Disable Copilot", move |cx| hide_copilot(fs.clone(), cx))
+        })
+    }
+
+    pub fn build_copilot_menu(&mut self, cx: &mut ViewContext<Self>) -> View<ContextMenu> {
+        let fs = self.fs.clone();
+
+        return ContextMenu::build(cx, move |mut menu, cx| {
+            if let Some(language) = self.language.clone() {
+                let fs = fs.clone();
+                let language_enabled =
+                    language_settings::language_settings(Some(&language), None, cx)
+                        .show_copilot_suggestions;
+
+                menu = menu.entry(
+                    format!(
+                        "{} Suggestions for {}",
+                        if language_enabled { "Hide" } else { "Show" },
+                        language.name()
+                    ),
+                    move |cx| toggle_copilot_for_language(language.clone(), fs.clone(), cx),
+                );
+            }
+
+            let settings = AllLanguageSettings::get_global(cx);
+
+            if let Some(file) = &self.file {
+                let path = file.path().clone();
+                let path_enabled = settings.copilot_enabled_for_path(&path);
+
+                menu = menu.entry(
+                    format!(
+                        "{} Suggestions for This Path",
+                        if path_enabled { "Hide" } else { "Show" }
+                    ),
+                    move |cx| {
+                        if let Some(workspace) = cx.window_handle().downcast::<Workspace>() {
+                            if let Ok(workspace) = workspace.root_view(cx) {
+                                let workspace = workspace.downgrade();
+                                cx.spawn(|cx| {
+                                    configure_disabled_globs(
+                                        workspace,
+                                        path_enabled.then_some(path.clone()),
+                                        cx,
+                                    )
+                                })
+                                .detach_and_log_err(cx);
+                            }
+                        }
+                    },
+                );
+            }
+
+            let globally_enabled = settings.copilot_enabled(None, None);
+            menu.entry(
+                if globally_enabled {
+                    "Hide Suggestions for All Files"
+                } else {
+                    "Show Suggestions for All Files"
+                },
+                move |cx| toggle_copilot_globally(fs.clone(), cx),
+            )
+            .separator()
+            .link(
+                "Copilot Settings",
+                OpenBrowser {
+                    url: COPILOT_SETTINGS_URL.to_string(),
+                }
+                .boxed_clone(),
+                cx,
+            )
+            .action("Sign Out", SignOut.boxed_clone(), cx)
+        });
+    }
+
+    pub fn update_enabled(&mut self, editor: View<Editor>, cx: &mut ViewContext<Self>) {
+        let editor = editor.read(cx);
+        let snapshot = editor.buffer().read(cx).snapshot(cx);
+        let suggestion_anchor = editor.selections.newest_anchor().start;
+        let language = snapshot.language_at(suggestion_anchor);
+        let file = snapshot.file_at(suggestion_anchor).cloned();
+
+        self.editor_enabled = Some(
+            all_language_settings(self.file.as_ref(), cx)
+                .copilot_enabled(language, file.as_ref().map(|file| file.path().as_ref())),
+        );
+        self.language = language.cloned();
+        self.file = file;
+
+        cx.notify()
+    }
+}
+
+impl StatusItemView for CopilotButton {
+    fn set_active_pane_item(&mut self, item: Option<&dyn ItemHandle>, cx: &mut ViewContext<Self>) {
+        if let Some(editor) = item.map(|item| item.act_as::<Editor>(cx)).flatten() {
+            self.editor_subscription = Some((
+                cx.observe(&editor, Self::update_enabled),
+                editor.entity_id().as_u64() as usize,
+            ));
+            self.update_enabled(editor, cx);
+        } else {
+            self.language = None;
+            self.editor_subscription = None;
+            self.editor_enabled = None;
+        }
+        cx.notify();
+    }
+}
+
+async fn configure_disabled_globs(
+    workspace: WeakView<Workspace>,
+    path_to_disable: Option<Arc<Path>>,
+    mut cx: AsyncWindowContext,
+) -> Result<()> {
+    let settings_editor = workspace
+        .update(&mut cx, |_, cx| {
+            create_and_open_local_file(&paths::SETTINGS, cx, || {
+                settings::initial_user_settings_content().as_ref().into()
+            })
+        })?
+        .await?
+        .downcast::<Editor>()
+        .unwrap();
+
+    settings_editor.downgrade().update(&mut cx, |item, cx| {
+        let text = item.buffer().read(cx).snapshot(cx).text();
+
+        let settings = cx.global::<SettingsStore>();
+        let edits = settings.edits_for_update::<AllLanguageSettings>(&text, |file| {
+            let copilot = file.copilot.get_or_insert_with(Default::default);
+            let globs = copilot.disabled_globs.get_or_insert_with(|| {
+                settings
+                    .get::<AllLanguageSettings>(None)
+                    .copilot
+                    .disabled_globs
+                    .iter()
+                    .map(|glob| glob.glob().to_string())
+                    .collect()
+            });
+
+            if let Some(path_to_disable) = &path_to_disable {
+                globs.push(path_to_disable.to_string_lossy().into_owned());
+            } else {
+                globs.clear();
+            }
+        });
+
+        if !edits.is_empty() {
+            item.change_selections(Some(Autoscroll::newest()), cx, |selections| {
+                selections.select_ranges(edits.iter().map(|e| e.0.clone()));
+            });
+
+            // When *enabling* a path, don't actually perform an edit, just select the range.
+            if path_to_disable.is_some() {
+                item.edit(edits.iter().cloned(), cx);
+            }
+        }
+    })?;
+
+    anyhow::Ok(())
+}
+
+fn toggle_copilot_globally(fs: Arc<dyn Fs>, cx: &mut AppContext) {
+    let show_copilot_suggestions = all_language_settings(None, cx).copilot_enabled(None, None);
+    update_settings_file::<AllLanguageSettings>(fs, cx, move |file| {
+        file.defaults.show_copilot_suggestions = Some((!show_copilot_suggestions).into())
+    });
+}
+
+fn toggle_copilot_for_language(language: Arc<Language>, fs: Arc<dyn Fs>, cx: &mut AppContext) {
+    let show_copilot_suggestions =
+        all_language_settings(None, cx).copilot_enabled(Some(&language), None);
+    update_settings_file::<AllLanguageSettings>(fs, cx, move |file| {
+        file.languages
+            .entry(language.name())
+            .or_default()
+            .show_copilot_suggestions = Some(!show_copilot_suggestions);
+    });
+}
+
+fn hide_copilot(fs: Arc<dyn Fs>, cx: &mut AppContext) {
+    update_settings_file::<AllLanguageSettings>(fs, cx, move |file| {
+        file.features.get_or_insert(Default::default()).copilot = Some(false);
+    });
+}
+
+fn initiate_sign_in(cx: &mut WindowContext) {
+    let Some(copilot) = Copilot::global(cx) else {
+        return;
+    };
+    let status = copilot.read(cx).status();
+
+    match status {
+        Status::Starting { task } => {
+            let Some(workspace) = cx.window_handle().downcast::<Workspace>() else {
+                return;
+            };
+
+            let Ok(workspace) = workspace.update(cx, |workspace, cx| {
+                workspace.show_toast(
+                    Toast::new(COPILOT_STARTING_TOAST_ID, "Copilot is starting..."),
+                    cx,
+                );
+                workspace.weak_handle()
+            }) else {
+                return;
+            };
+
+            cx.spawn(|mut cx| async move {
+                task.await;
+                if let Some(copilot) = cx.update(|_, cx| Copilot::global(cx)).ok().flatten() {
+                    workspace
+                        .update(&mut cx, |workspace, cx| match copilot.read(cx).status() {
+                            Status::Authorized => workspace.show_toast(
+                                Toast::new(COPILOT_STARTING_TOAST_ID, "Copilot has started!"),
+                                cx,
+                            ),
+                            _ => {
+                                workspace.dismiss_toast(COPILOT_STARTING_TOAST_ID, cx);
+                                copilot
+                                    .update(cx, |copilot, cx| copilot.sign_in(cx))
+                                    .detach_and_log_err(cx);
+                            }
+                        })
+                        .log_err();
+                }
+            })
+            .detach();
+        }
+        _ => {
+            copilot
+                .update(cx, |copilot, cx| copilot.sign_in(cx))
+                .detach_and_log_err(cx);
+        }
+    }
+}

crates/diagnostics2/src/diagnostics.rs 🔗

@@ -774,24 +774,39 @@ fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock {
     Arc::new(move |_| {
         h_stack()
             .id("diagnostic header")
-            .gap_3()
-            .bg(gpui::red())
-            .map(|stack| {
-                let icon = if diagnostic.severity == DiagnosticSeverity::ERROR {
-                    IconElement::new(Icon::XCircle).color(Color::Error)
-                } else {
-                    IconElement::new(Icon::ExclamationTriangle).color(Color::Warning)
-                };
-
-                stack.child(div().pl_8().child(icon))
-            })
-            .when_some(diagnostic.source.as_ref(), |stack, source| {
-                stack.child(Label::new(format!("{source}:")).color(Color::Accent))
-            })
-            .child(HighlightedLabel::new(message.clone(), highlights.clone()))
-            .when_some(diagnostic.code.as_ref(), |stack, code| {
-                stack.child(Label::new(code.clone()))
-            })
+            .py_2()
+            .pl_10()
+            .pr_5()
+            .w_full()
+            .justify_between()
+            .gap_2()
+            .child(
+                h_stack()
+                    .gap_3()
+                    .map(|stack| {
+                        let icon = if diagnostic.severity == DiagnosticSeverity::ERROR {
+                            IconElement::new(Icon::XCircle).color(Color::Error)
+                        } else {
+                            IconElement::new(Icon::ExclamationTriangle).color(Color::Warning)
+                        };
+                        stack.child(icon)
+                    })
+                    .child(
+                        h_stack()
+                            .gap_1()
+                            .child(HighlightedLabel::new(message.clone(), highlights.clone()))
+                            .when_some(diagnostic.code.as_ref(), |stack, code| {
+                                stack.child(Label::new(format!("({code})")).color(Color::Muted))
+                            }),
+                    ),
+            )
+            .child(
+                h_stack()
+                    .gap_1()
+                    .when_some(diagnostic.source.as_ref(), |stack, source| {
+                        stack.child(Label::new(format!("{source}")).color(Color::Muted))
+                    }),
+            )
             .into_any_element()
     })
 }
@@ -802,11 +817,22 @@ pub(crate) fn render_summary(summary: &DiagnosticSummary) -> AnyElement {
         label.into_any_element()
     } else {
         h_stack()
-            .bg(gpui::red())
-            .child(IconElement::new(Icon::XCircle))
-            .child(Label::new(summary.error_count.to_string()))
-            .child(IconElement::new(Icon::ExclamationTriangle))
-            .child(Label::new(summary.warning_count.to_string()))
+            .gap_1()
+            .when(summary.error_count > 0, |then| {
+                then.child(
+                    h_stack()
+                        .gap_1()
+                        .child(IconElement::new(Icon::XCircle).color(Color::Error))
+                        .child(Label::new(summary.error_count.to_string())),
+                )
+            })
+            .when(summary.warning_count > 0, |then| {
+                then.child(
+                    h_stack()
+                        .child(IconElement::new(Icon::ExclamationTriangle).color(Color::Warning))
+                        .child(Label::new(summary.warning_count.to_string())),
+                )
+            })
             .into_any_element()
     }
 }

crates/editor2/src/editor.rs 🔗

@@ -100,8 +100,10 @@ use text::{OffsetUtf16, Rope};
 use theme::{
     ActiveTheme, DiagnosticStyle, PlayerColor, SyntaxTheme, Theme, ThemeColors, ThemeSettings,
 };
-use ui::prelude::*;
-use ui::{h_stack, v_stack, HighlightedLabel, IconButton, Popover, Tooltip};
+use ui::{
+    h_stack, v_stack, ButtonSize, ButtonStyle, HighlightedLabel, Icon, IconButton, Popover, Tooltip,
+};
+use ui::{prelude::*, IconSize};
 use util::{post_inc, RangeExt, ResultExt, TryFutureExt};
 use workspace::{
     item::{ItemEvent, ItemHandle},
@@ -154,7 +156,6 @@ pub fn render_parsed_markdown(
                 }
             }),
     );
-    let runs = text_runs_for_highlights(&parsed.text, &editor_style.text, highlights);
 
     let mut links = Vec::new();
     let mut link_ranges = Vec::new();
@@ -167,7 +168,7 @@ pub fn render_parsed_markdown(
 
     InteractiveText::new(
         element_id,
-        StyledText::new(parsed.text.clone()).with_runs(runs),
+        StyledText::new(parsed.text.clone()).with_highlights(&editor_style.text, highlights),
     )
     .on_click(link_ranges, move |clicked_range_ix, cx| {
         match &links[clicked_range_ix] {
@@ -1199,11 +1200,7 @@ impl CompletionsMenu {
                             ),
                         );
                         let completion_label = StyledText::new(completion.label.text.clone())
-                            .with_runs(text_runs_for_highlights(
-                                &completion.label.text,
-                                &style.text,
-                                highlights,
-                            ));
+                            .with_highlights(&style.text, highlights);
                         let documentation_label =
                             if let Some(Documentation::SingleLine(text)) = documentation {
                                 Some(SharedString::from(text.clone()))
@@ -1925,14 +1922,14 @@ impl Editor {
     //         self.buffer.read(cx).read(cx).file_at(point).cloned()
     //     }
 
-    //     pub fn active_excerpt(
-    //         &self,
-    //         cx: &AppContext,
-    //     ) -> Option<(ExcerptId, Model<Buffer>, Range<text::Anchor>)> {
-    //         self.buffer
-    //             .read(cx)
-    //             .excerpt_containing(self.selections.newest_anchor().head(), cx)
-    //     }
+    pub fn active_excerpt(
+        &self,
+        cx: &AppContext,
+    ) -> Option<(ExcerptId, Model<Buffer>, Range<text::Anchor>)> {
+        self.buffer
+            .read(cx)
+            .excerpt_containing(self.selections.newest_anchor().head(), cx)
+    }
 
     //     pub fn style(&self, cx: &AppContext) -> EditorStyle {
     //         build_style(
@@ -9699,20 +9696,42 @@ pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> Rend
     let message = diagnostic.message;
     Arc::new(move |cx: &mut BlockContext| {
         let message = message.clone();
+        let copy_id: SharedString = format!("copy-{}", cx.block_id.clone()).to_string().into();
+        let write_to_clipboard = cx.write_to_clipboard(ClipboardItem::new(message.clone()));
+
+        // TODO: Nate: We should tint the background of the block with the severity color
+        // We need to extend the theme before we can do this
         v_stack()
             .id(cx.block_id)
+            .relative()
             .size_full()
             .bg(gpui::red())
             .children(highlighted_lines.iter().map(|(line, highlights)| {
-                div()
+                let group_id = cx.block_id.to_string();
+
+                h_stack()
+                    .group(group_id.clone())
+                    .gap_2()
+                    .absolute()
+                    .left(cx.anchor_x)
+                    .px_1p5()
                     .child(HighlightedLabel::new(line.clone(), highlights.clone()))
-                    .ml(cx.anchor_x)
-            }))
-            .cursor_pointer()
-            .on_click(cx.listener(move |_, _, cx| {
-                cx.write_to_clipboard(ClipboardItem::new(message.clone()));
+                    .child(
+                        div()
+                            .border()
+                            .border_color(gpui::red())
+                            .invisible()
+                            .group_hover(group_id, |style| style.visible())
+                            .child(
+                                IconButton::new(copy_id.clone(), Icon::Copy)
+                                    .icon_color(Color::Muted)
+                                    .size(ButtonSize::Compact)
+                                    .style(ButtonStyle::Transparent)
+                                    .on_click(cx.listener(move |_, _, cx| write_to_clipboard))
+                                    .tooltip(|cx| Tooltip::text("Copy diagnostic message", cx)),
+                            ),
+                    )
             }))
-            .tooltip(|cx| Tooltip::text("Copy diagnostic message", cx))
             .into_any_element()
     })
 }
@@ -9760,31 +9779,6 @@ pub fn diagnostic_style(
     }
 }
 
-pub fn text_runs_for_highlights(
-    text: &str,
-    default_style: &TextStyle,
-    highlights: impl IntoIterator<Item = (Range<usize>, HighlightStyle)>,
-) -> Vec<TextRun> {
-    let mut runs = Vec::new();
-    let mut ix = 0;
-    for (range, highlight) in highlights {
-        if ix < range.start {
-            runs.push(default_style.clone().to_run(range.start - ix));
-        }
-        runs.push(
-            default_style
-                .clone()
-                .highlight(highlight)
-                .to_run(range.len()),
-        );
-        ix = range.end;
-    }
-    if ix < text.len() {
-        runs.push(default_style.to_run(text.len() - ix));
-    }
-    runs
-}
-
 pub fn styled_runs_for_code_label<'a>(
     label: &'a CodeLabel,
     syntax_theme: &'a theme::SyntaxTheme,

crates/editor2/src/element.rs 🔗

@@ -51,8 +51,10 @@ use std::{
 };
 use sum_tree::Bias;
 use theme::{ActiveTheme, PlayerColor};
-use ui::prelude::*;
-use ui::{h_stack, IconButton, Tooltip};
+use ui::{
+    h_stack, ButtonLike, ButtonStyle, Disclosure, IconButton, IconElement, IconSize, Label, Tooltip,
+};
+use ui::{prelude::*, Icon};
 use util::ResultExt;
 use workspace::item::Item;
 
@@ -2223,7 +2225,8 @@ impl EditorElement {
                         .as_ref()
                         .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
                         .unwrap_or_default();
-                    let jump_icon = project::File::from_dyn(buffer.file()).map(|file| {
+
+                    let jump_handler = project::File::from_dyn(buffer.file()).map(|file| {
                         let jump_path = ProjectPath {
                             worktree_id: file.worktree_id(cx),
                             path: file.path.clone(),
@@ -2234,11 +2237,11 @@ impl EditorElement {
                             .map_or(range.context.start, |primary| primary.start);
                         let jump_position = language::ToPoint::to_point(&jump_anchor, buffer);
 
-                        IconButton::new(block_id, ui::Icon::ArrowUpRight)
-                            .on_click(cx.listener_for(&self.editor, move |editor, e, cx| {
-                                editor.jump(jump_path.clone(), jump_position, jump_anchor, cx);
-                            }))
-                            .tooltip(|cx| Tooltip::for_action("Jump to Buffer", &OpenExcerpts, cx))
+                        let jump_handler = cx.listener_for(&self.editor, move |editor, e, cx| {
+                            editor.jump(jump_path.clone(), jump_position, jump_anchor, cx);
+                        });
+
+                        jump_handler
                     });
 
                     let element = if *starts_new_buffer {
@@ -2253,25 +2256,108 @@ impl EditorElement {
                                 .map(|p| SharedString::from(p.to_string_lossy().to_string() + "/"));
                         }
 
-                        h_stack()
-                            .id("path header block")
-                            .size_full()
-                            .bg(gpui::red())
-                            .child(
-                                filename
-                                    .map(SharedString::from)
-                                    .unwrap_or_else(|| "untitled".into()),
-                            )
-                            .children(parent_path)
-                            .children(jump_icon) // .p_x(gutter_padding)
+                        let is_open = true;
+
+                        div().id("path header container").size_full().p_1p5().child(
+                            h_stack()
+                                .id("path header block")
+                                .py_1p5()
+                                .pl_3()
+                                .pr_2()
+                                .rounded_lg()
+                                .shadow_md()
+                                .border()
+                                .border_color(cx.theme().colors().border)
+                                .bg(cx.theme().colors().editor_subheader_background)
+                                .justify_between()
+                                .cursor_pointer()
+                                .hover(|style| style.bg(cx.theme().colors().element_hover))
+                                .on_click(cx.listener(|_editor, _event, _cx| {
+                                    // TODO: Implement collapsing path headers
+                                    todo!("Clicking path header")
+                                }))
+                                .child(
+                                    h_stack()
+                                        .gap_3()
+                                        // TODO: Add open/close state and toggle action
+                                        .child(
+                                            div().border().border_color(gpui::red()).child(
+                                                ButtonLike::new("path-header-disclosure-control")
+                                                    .style(ButtonStyle::Subtle)
+                                                    .child(IconElement::new(match is_open {
+                                                        true => Icon::ChevronDown,
+                                                        false => Icon::ChevronRight,
+                                                    })),
+                                            ),
+                                        )
+                                        .child(
+                                            h_stack()
+                                                .gap_2()
+                                                .child(Label::new(
+                                                    filename
+                                                        .map(SharedString::from)
+                                                        .unwrap_or_else(|| "untitled".into()),
+                                                ))
+                                                .when_some(parent_path, |then, path| {
+                                                    then.child(Label::new(path).color(Color::Muted))
+                                                }),
+                                        ),
+                                )
+                                .children(jump_handler.map(|jump_handler| {
+                                    IconButton::new(block_id, Icon::ArrowUpRight)
+                                        .style(ButtonStyle::Subtle)
+                                        .on_click(jump_handler)
+                                        .tooltip(|cx| {
+                                            Tooltip::for_action("Jump to Buffer", &OpenExcerpts, cx)
+                                        })
+                                })), // .p_x(gutter_padding)
+                        )
                     } else {
                         let text_style = style.text.clone();
                         h_stack()
                             .id("collapsed context")
                             .size_full()
-                            .bg(gpui::red())
-                            .child("⋯")
-                            .children(jump_icon) // .p_x(gutter_padding)
+                            .gap(gutter_padding)
+                            .child(
+                                h_stack()
+                                    .justify_end()
+                                    .flex_none()
+                                    .w(gutter_width - gutter_padding)
+                                    .h_full()
+                                    .text_buffer(cx)
+                                    .text_color(cx.theme().colors().editor_line_number)
+                                    .child("..."),
+                            )
+                            .map(|this| {
+                                if let Some(jump_handler) = jump_handler {
+                                    this.child(
+                                        ButtonLike::new("jump to collapsed context")
+                                            .style(ButtonStyle::Transparent)
+                                            .full_width()
+                                            .on_click(jump_handler)
+                                            .tooltip(|cx| {
+                                                Tooltip::for_action(
+                                                    "Jump to Buffer",
+                                                    &OpenExcerpts,
+                                                    cx,
+                                                )
+                                            })
+                                            .child(
+                                                div()
+                                                    .h_px()
+                                                    .w_full()
+                                                    .bg(cx.theme().colors().border_variant)
+                                                    .group_hover("", |style| {
+                                                        style.bg(cx.theme().colors().border)
+                                                    }),
+                                            ),
+                                    )
+                                } else {
+                                    this.child(div().size_full().bg(gpui::green()))
+                                }
+                            })
+                        // .child("⋯")
+                        // .children(jump_icon) // .p_x(gutter_padding)
                     };
                     element.into_any()
                 }

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

@@ -992,10 +992,6 @@ impl Interactivity {
             let interactive_bounds = interactive_bounds.clone();
 
             cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
-                if phase != DispatchPhase::Bubble {
-                    return;
-                }
-
                 let is_hovered = interactive_bounds.visibly_contains(&event.position, cx)
                     && pending_mouse_down.borrow().is_none();
                 if !is_hovered {
@@ -1003,6 +999,10 @@ impl Interactivity {
                     return;
                 }
 
+                if phase != DispatchPhase::Bubble {
+                    return;
+                }
+
                 if active_tooltip.borrow().is_none() {
                     let task = cx.spawn({
                         let active_tooltip = active_tooltip.clone();

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

@@ -1,6 +1,7 @@
 use crate::{
-    Bounds, DispatchPhase, Element, ElementId, IntoElement, LayoutId, MouseDownEvent, MouseUpEvent,
-    Pixels, Point, SharedString, Size, TextRun, WhiteSpace, WindowContext, WrappedLine,
+    Bounds, DispatchPhase, Element, ElementId, HighlightStyle, IntoElement, LayoutId,
+    MouseDownEvent, MouseUpEvent, Pixels, Point, SharedString, Size, TextRun, TextStyle,
+    WhiteSpace, WindowContext, WrappedLine,
 };
 use anyhow::anyhow;
 use parking_lot::{Mutex, MutexGuard};
@@ -87,7 +88,28 @@ impl StyledText {
         }
     }
 
-    pub fn with_runs(mut self, runs: Vec<TextRun>) -> Self {
+    pub fn with_highlights(
+        mut self,
+        default_style: &TextStyle,
+        highlights: impl IntoIterator<Item = (Range<usize>, HighlightStyle)>,
+    ) -> Self {
+        let mut runs = Vec::new();
+        let mut ix = 0;
+        for (range, highlight) in highlights {
+            if ix < range.start {
+                runs.push(default_style.clone().to_run(range.start - ix));
+            }
+            runs.push(
+                default_style
+                    .clone()
+                    .highlight(highlight)
+                    .to_run(range.len()),
+            );
+            ix = range.end;
+        }
+        if ix < self.text.len() {
+            runs.push(default_style.to_run(self.text.len() - ix));
+        }
         self.runs = Some(runs);
         self
     }

crates/gpui2/src/platform.rs 🔗

@@ -472,13 +472,27 @@ pub enum PromptLevel {
     Critical,
 }
 
+/// The style of the cursor (pointer)
 #[derive(Copy, Clone, Debug)]
 pub enum CursorStyle {
     Arrow,
+    IBeam,
+    Crosshair,
+    ClosedHand,
+    OpenHand,
+    PointingHand,
+    ResizeLeft,
+    ResizeRight,
     ResizeLeftRight,
+    ResizeUp,
+    ResizeDown,
     ResizeUpDown,
-    PointingHand,
-    IBeam,
+    DisappearingItem,
+    IBeamCursorForVerticalLayout,
+    OperationNotAllowed,
+    DragLink,
+    DragCopy,
+    ContextualMenu,
 }
 
 impl Default for CursorStyle {

crates/gpui2/src/platform/mac/platform.rs 🔗

@@ -724,16 +724,35 @@ impl Platform for MacPlatform {
         }
     }
 
+    /// Match cursor style to one of the styles available
+    /// in macOS's [NSCursor](https://developer.apple.com/documentation/appkit/nscursor).
     fn set_cursor_style(&self, style: CursorStyle) {
         unsafe {
             let new_cursor: id = match style {
                 CursorStyle::Arrow => msg_send![class!(NSCursor), arrowCursor],
-                CursorStyle::ResizeLeftRight => {
-                    msg_send![class!(NSCursor), resizeLeftRightCursor]
-                }
-                CursorStyle::ResizeUpDown => msg_send![class!(NSCursor), resizeUpDownCursor],
-                CursorStyle::PointingHand => msg_send![class!(NSCursor), pointingHandCursor],
                 CursorStyle::IBeam => msg_send![class!(NSCursor), IBeamCursor],
+                CursorStyle::Crosshair => msg_send![class!(NSCursor), crosshairCursor],
+                CursorStyle::ClosedHand => msg_send![class!(NSCursor), closedHandCursor],
+                CursorStyle::OpenHand => msg_send![class!(NSCursor), openHandCursor],
+                CursorStyle::PointingHand => msg_send![class!(NSCursor), pointingHandCursor],
+                CursorStyle::ResizeLeft => msg_send![class!(NSCursor), resizeLeftCursor],
+                CursorStyle::ResizeRight => msg_send![class!(NSCursor), resizeRightCursor],
+                CursorStyle::ResizeLeftRight => msg_send![class!(NSCursor), resizeLeftRightCursor],
+                CursorStyle::ResizeUp => msg_send![class!(NSCursor), resizeUpCursor],
+                CursorStyle::ResizeDown => msg_send![class!(NSCursor), resizeDownCursor],
+                CursorStyle::ResizeUpDown => msg_send![class!(NSCursor), resizeUpDownCursor],
+                CursorStyle::DisappearingItem => {
+                    msg_send![class!(NSCursor), disappearingItemCursor]
+                }
+                CursorStyle::IBeamCursorForVerticalLayout => {
+                    msg_send![class!(NSCursor), IBeamCursorForVerticalLayout]
+                }
+                CursorStyle::OperationNotAllowed => {
+                    msg_send![class!(NSCursor), operationNotAllowedCursor]
+                }
+                CursorStyle::DragLink => msg_send![class!(NSCursor), dragLinkCursor],
+                CursorStyle::DragCopy => msg_send![class!(NSCursor), dragCopyCursor],
+                CursorStyle::ContextualMenu => msg_send![class!(NSCursor), contextualMenuCursor],
             };
 
             let old_cursor: id = msg_send![class!(NSCursor), currentCursor];

crates/gpui2/src/platform/test/platform.rs 🔗

@@ -238,11 +238,11 @@ impl Platform for TestPlatform {
         true
     }
 
-    fn write_to_clipboard(&self, item: crate::ClipboardItem) {
+    fn write_to_clipboard(&self, item: ClipboardItem) {
         *self.current_clipboard_item.lock() = Some(item);
     }
 
-    fn read_from_clipboard(&self) -> Option<crate::ClipboardItem> {
+    fn read_from_clipboard(&self) -> Option<ClipboardItem> {
         self.current_clipboard_item.lock().clone()
     }
 

crates/gpui2/src/styled.rs 🔗

@@ -101,6 +101,125 @@ pub trait Styled: Sized {
         self
     }
 
+    /// Sets cursor style when hovering over an element to `text`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_text(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::IBeam);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `move`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_move(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::ClosedHand);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `not-allowed`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_not_allowed(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::OperationNotAllowed);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `context-menu`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_context_menu(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::ContextualMenu);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `crosshair`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_crosshair(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::Crosshair);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `vertical-text`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_vertical_text(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::IBeamCursorForVerticalLayout);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `alias`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_alias(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::DragLink);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `copy`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_copy(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::DragCopy);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `no-drop`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_no_drop(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::OperationNotAllowed);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `grab`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_grab(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::OpenHand);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `grabbing`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_grabbing(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::ClosedHand);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `col-resize`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_col_resize(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::ResizeLeftRight);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `row-resize`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_row_resize(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::ResizeUpDown);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `n-resize`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_n_resize(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::ResizeUp);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `e-resize`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_e_resize(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::ResizeRight);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `s-resize`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_s_resize(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::ResizeDown);
+        self
+    }
+
+    /// Sets cursor style when hovering over an element to `w-resize`.
+    /// [Docs](https://tailwindcss.com/docs/cursor)
+    fn cursor_w_resize(mut self) -> Self {
+        self.style().mouse_cursor = Some(CursorStyle::ResizeLeft);
+        self
+    }
+
     /// Sets the whitespace of the element to `normal`.
     /// [Docs](https://tailwindcss.com/docs/whitespace#normal)
     fn whitespace_normal(mut self) -> Self {

crates/language_selector2/Cargo.toml 🔗

@@ -0,0 +1,26 @@
+[package]
+name = "language_selector2"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[lib]
+path = "src/language_selector.rs"
+doctest = false
+
+[dependencies]
+editor = { package = "editor2", path = "../editor2" }
+fuzzy = { package = "fuzzy2", path = "../fuzzy2" }
+language = { package = "language2", path = "../language2" }
+gpui = { package = "gpui2", path = "../gpui2" }
+picker = { package = "picker2", path = "../picker2" }
+project = { package = "project2", path = "../project2" }
+theme = { package = "theme2", path = "../theme2" }
+ui = { package = "ui2", path = "../ui2" }
+settings = { package = "settings2", path = "../settings2" }
+util = { path = "../util" }
+workspace = { package = "workspace2", path = "../workspace2" }
+anyhow.workspace = true
+
+[dev-dependencies]
+editor = { package = "editor2", path = "../editor2", features = ["test-support"] }

crates/language_selector2/src/active_buffer_language.rs 🔗

@@ -0,0 +1,82 @@
+use editor::Editor;
+use gpui::{
+    div, Div, IntoElement, ParentElement, Render, Subscription, View, ViewContext, WeakView,
+};
+use std::sync::Arc;
+use ui::{Button, ButtonCommon, Clickable, Tooltip};
+use workspace::{item::ItemHandle, StatusItemView, Workspace};
+
+use crate::LanguageSelector;
+
+pub struct ActiveBufferLanguage {
+    active_language: Option<Option<Arc<str>>>,
+    workspace: WeakView<Workspace>,
+    _observe_active_editor: Option<Subscription>,
+}
+
+impl ActiveBufferLanguage {
+    pub fn new(workspace: &Workspace) -> Self {
+        Self {
+            active_language: None,
+            workspace: workspace.weak_handle(),
+            _observe_active_editor: None,
+        }
+    }
+
+    fn update_language(&mut self, editor: View<Editor>, cx: &mut ViewContext<Self>) {
+        self.active_language = Some(None);
+
+        let editor = editor.read(cx);
+        if let Some((_, buffer, _)) = editor.active_excerpt(cx) {
+            if let Some(language) = buffer.read(cx).language() {
+                self.active_language = Some(Some(language.name()));
+            }
+        }
+
+        cx.notify();
+    }
+}
+
+impl Render for ActiveBufferLanguage {
+    type Element = Div;
+
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> Div {
+        div().when_some(self.active_language.as_ref(), |el, active_language| {
+            let active_language_text = if let Some(active_language_text) = active_language {
+                active_language_text.to_string()
+            } else {
+                "Unknown".to_string()
+            };
+
+            el.child(
+                Button::new("change-language", active_language_text)
+                    .on_click(cx.listener(|this, _, cx| {
+                        if let Some(workspace) = this.workspace.upgrade() {
+                            workspace.update(cx, |workspace, cx| {
+                                LanguageSelector::toggle(workspace, cx)
+                            });
+                        }
+                    }))
+                    .tooltip(|cx| Tooltip::text("Select Language", cx)),
+            )
+        })
+    }
+}
+
+impl StatusItemView for ActiveBufferLanguage {
+    fn set_active_pane_item(
+        &mut self,
+        active_pane_item: Option<&dyn ItemHandle>,
+        cx: &mut ViewContext<Self>,
+    ) {
+        if let Some(editor) = active_pane_item.and_then(|item| item.act_as::<Editor>(cx)) {
+            self._observe_active_editor = Some(cx.observe(&editor, Self::update_language));
+            self.update_language(editor, cx);
+        } else {
+            self.active_language = None;
+            self._observe_active_editor = None;
+        }
+
+        cx.notify();
+    }
+}

crates/language_selector2/src/language_selector.rs 🔗

@@ -0,0 +1,231 @@
+mod active_buffer_language;
+
+pub use active_buffer_language::ActiveBufferLanguage;
+use anyhow::anyhow;
+use editor::Editor;
+use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
+use gpui::{
+    actions, AppContext, DismissEvent, Div, EventEmitter, FocusHandle, FocusableView, Model,
+    ParentElement, Render, Styled, View, ViewContext, VisualContext, WeakView,
+};
+use language::{Buffer, LanguageRegistry};
+use picker::{Picker, PickerDelegate};
+use project::Project;
+use std::sync::Arc;
+use ui::{v_stack, HighlightedLabel, ListItem, Selectable};
+use util::ResultExt;
+use workspace::Workspace;
+
+actions!(Toggle);
+
+pub fn init(cx: &mut AppContext) {
+    cx.observe_new_views(LanguageSelector::register).detach();
+}
+
+pub struct LanguageSelector {
+    picker: View<Picker<LanguageSelectorDelegate>>,
+}
+
+impl LanguageSelector {
+    fn register(workspace: &mut Workspace, _: &mut ViewContext<Workspace>) {
+        workspace.register_action(move |workspace, _: &Toggle, cx| {
+            Self::toggle(workspace, cx);
+        });
+    }
+
+    fn toggle(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) -> Option<()> {
+        let registry = workspace.app_state().languages.clone();
+        let (_, buffer, _) = workspace
+            .active_item(cx)?
+            .act_as::<Editor>(cx)?
+            .read(cx)
+            .active_excerpt(cx)?;
+        let project = workspace.project().clone();
+
+        workspace.toggle_modal(cx, move |cx| {
+            LanguageSelector::new(buffer, project, registry, cx)
+        });
+        Some(())
+    }
+
+    fn new(
+        buffer: Model<Buffer>,
+        project: Model<Project>,
+        language_registry: Arc<LanguageRegistry>,
+        cx: &mut ViewContext<Self>,
+    ) -> Self {
+        let delegate = LanguageSelectorDelegate::new(
+            cx.view().downgrade(),
+            buffer,
+            project,
+            language_registry,
+        );
+
+        let picker = cx.build_view(|cx| Picker::new(delegate, cx));
+        Self { picker }
+    }
+}
+
+impl Render for LanguageSelector {
+    type Element = Div;
+
+    fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
+        v_stack().min_w_96().child(self.picker.clone())
+    }
+}
+
+impl FocusableView for LanguageSelector {
+    fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
+        self.picker.focus_handle(cx)
+    }
+}
+impl EventEmitter<DismissEvent> for LanguageSelector {}
+
+pub struct LanguageSelectorDelegate {
+    language_selector: WeakView<LanguageSelector>,
+    buffer: Model<Buffer>,
+    project: Model<Project>,
+    language_registry: Arc<LanguageRegistry>,
+    candidates: Vec<StringMatchCandidate>,
+    matches: Vec<StringMatch>,
+    selected_index: usize,
+}
+
+impl LanguageSelectorDelegate {
+    fn new(
+        language_selector: WeakView<LanguageSelector>,
+        buffer: Model<Buffer>,
+        project: Model<Project>,
+        language_registry: Arc<LanguageRegistry>,
+    ) -> Self {
+        let candidates = language_registry
+            .language_names()
+            .into_iter()
+            .enumerate()
+            .map(|(candidate_id, name)| StringMatchCandidate::new(candidate_id, name))
+            .collect::<Vec<_>>();
+
+        Self {
+            language_selector,
+            buffer,
+            project,
+            language_registry,
+            candidates,
+            matches: vec![],
+            selected_index: 0,
+        }
+    }
+}
+
+impl PickerDelegate for LanguageSelectorDelegate {
+    type ListItem = ListItem;
+
+    fn placeholder_text(&self) -> Arc<str> {
+        "Select a language...".into()
+    }
+
+    fn match_count(&self) -> usize {
+        self.matches.len()
+    }
+
+    fn confirm(&mut self, _: bool, cx: &mut ViewContext<Picker<Self>>) {
+        if let Some(mat) = self.matches.get(self.selected_index) {
+            let language_name = &self.candidates[mat.candidate_id].string;
+            let language = self.language_registry.language_for_name(language_name);
+            let project = self.project.downgrade();
+            let buffer = self.buffer.downgrade();
+            cx.spawn(|_, mut cx| async move {
+                let language = language.await?;
+                let project = project
+                    .upgrade()
+                    .ok_or_else(|| anyhow!("project was dropped"))?;
+                let buffer = buffer
+                    .upgrade()
+                    .ok_or_else(|| anyhow!("buffer was dropped"))?;
+                project.update(&mut cx, |project, cx| {
+                    project.set_language_for_buffer(&buffer, language, cx);
+                })
+            })
+            .detach_and_log_err(cx);
+        }
+        self.dismissed(cx);
+    }
+
+    fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>) {
+        self.language_selector
+            .update(cx, |_, cx| cx.emit(DismissEvent))
+            .log_err();
+    }
+
+    fn selected_index(&self) -> usize {
+        self.selected_index
+    }
+
+    fn set_selected_index(&mut self, ix: usize, _: &mut ViewContext<Picker<Self>>) {
+        self.selected_index = ix;
+    }
+
+    fn update_matches(
+        &mut self,
+        query: String,
+        cx: &mut ViewContext<Picker<Self>>,
+    ) -> gpui::Task<()> {
+        let background = cx.background_executor().clone();
+        let candidates = self.candidates.clone();
+        cx.spawn(|this, mut cx| async move {
+            let matches = if query.is_empty() {
+                candidates
+                    .into_iter()
+                    .enumerate()
+                    .map(|(index, candidate)| StringMatch {
+                        candidate_id: index,
+                        string: candidate.string,
+                        positions: Vec::new(),
+                        score: 0.0,
+                    })
+                    .collect()
+            } else {
+                match_strings(
+                    &candidates,
+                    &query,
+                    false,
+                    100,
+                    &Default::default(),
+                    background,
+                )
+                .await
+            };
+
+            this.update(&mut cx, |this, cx| {
+                let delegate = &mut this.delegate;
+                delegate.matches = matches;
+                delegate.selected_index = delegate
+                    .selected_index
+                    .min(delegate.matches.len().saturating_sub(1));
+                cx.notify();
+            })
+            .log_err();
+        })
+    }
+
+    fn render_match(
+        &self,
+        ix: usize,
+        selected: bool,
+        cx: &mut ViewContext<Picker<Self>>,
+    ) -> Option<Self::ListItem> {
+        let mat = &self.matches[ix];
+        let buffer_language_name = self.buffer.read(cx).language().map(|l| l.name());
+        let mut label = mat.string.clone();
+        if buffer_language_name.as_deref() == Some(mat.string.as_str()) {
+            label.push_str(" (current)");
+        }
+
+        Some(
+            ListItem::new(ix)
+                .inset(true)
+                .selected(selected)
+                .child(HighlightedLabel::new(label, mat.positions.clone())),
+        )
+    }
+}

crates/picker2/src/picker2.rs 🔗

@@ -178,6 +178,15 @@ impl<D: PickerDelegate> Picker<D> {
         }
         cx.notify();
     }
+
+    pub fn query(&self, cx: &AppContext) -> String {
+        self.editor.read(cx).text(cx)
+    }
+
+    pub fn set_query(&self, query: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
+        self.editor
+            .update(cx, |editor, cx| editor.set_text(query, cx));
+    }
 }
 
 impl<D: PickerDelegate> Render for Picker<D> {

crates/project/src/project.rs 🔗

@@ -1661,14 +1661,15 @@ impl Project {
         path: impl Into<ProjectPath>,
         cx: &mut ModelContext<Self>,
     ) -> Task<Result<(ProjectEntryId, AnyModelHandle)>> {
-        let task = self.open_buffer(path, cx);
+        let project_path = path.into();
+        let task = self.open_buffer(project_path.clone(), cx);
         cx.spawn_weak(|_, cx| async move {
             let buffer = task.await?;
             let project_entry_id = buffer
                 .read_with(&cx, |buffer, cx| {
                     File::from_dyn(buffer.file()).and_then(|file| file.project_entry_id(cx))
                 })
-                .ok_or_else(|| anyhow!("no project entry"))?;
+                .with_context(|| format!("no project entry for {project_path:?}"))?;
 
             let buffer: &AnyModelHandle = &buffer;
             Ok((project_entry_id, buffer.clone()))

crates/project2/src/project2.rs 🔗

@@ -1691,14 +1691,15 @@ impl Project {
         path: impl Into<ProjectPath>,
         cx: &mut ModelContext<Self>,
     ) -> Task<Result<(ProjectEntryId, AnyModel)>> {
-        let task = self.open_buffer(path, cx);
+        let project_path = path.into();
+        let task = self.open_buffer(project_path.clone(), cx);
         cx.spawn(move |_, mut cx| async move {
             let buffer = task.await?;
             let project_entry_id = buffer
                 .update(&mut cx, |buffer, cx| {
                     File::from_dyn(buffer.file()).and_then(|file| file.project_entry_id(cx))
                 })?
-                .ok_or_else(|| anyhow!("no project entry"))?;
+                .with_context(|| format!("no project entry for {project_path:?}"))?;
 
             let buffer: &AnyModel = &buffer;
             Ok((project_entry_id, buffer.clone()))

crates/rpc2/src/rpc.rs 🔗

@@ -9,4 +9,4 @@ pub use notification::*;
 pub use peer::*;
 mod macros;
 
-pub const PROTOCOL_VERSION: u32 = 64;
+pub const PROTOCOL_VERSION: u32 = 66;

crates/storybook2/src/stories.rs 🔗

@@ -1,4 +1,5 @@
 mod auto_height_editor;
+mod cursor;
 mod focus;
 mod kitchen_sink;
 mod picker;
@@ -7,6 +8,7 @@ mod text;
 mod z_index;
 
 pub use auto_height_editor::*;
+pub use cursor::*;
 pub use focus::*;
 pub use kitchen_sink::*;
 pub use picker::*;

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

@@ -0,0 +1,112 @@
+use gpui::{Div, Render, Stateful};
+use story::Story;
+use ui::prelude::*;
+
+pub struct CursorStory;
+
+impl Render for CursorStory {
+    type Element = Div;
+
+    fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
+        let all_cursors: [(&str, Box<dyn Fn(Stateful<Div>) -> Stateful<Div>>); 19] = [
+            (
+                "cursor_default",
+                Box::new(|el: Stateful<Div>| el.cursor_default()),
+            ),
+            (
+                "cursor_pointer",
+                Box::new(|el: Stateful<Div>| el.cursor_pointer()),
+            ),
+            (
+                "cursor_text",
+                Box::new(|el: Stateful<Div>| el.cursor_text()),
+            ),
+            (
+                "cursor_move",
+                Box::new(|el: Stateful<Div>| el.cursor_move()),
+            ),
+            (
+                "cursor_not_allowed",
+                Box::new(|el: Stateful<Div>| el.cursor_not_allowed()),
+            ),
+            (
+                "cursor_context_menu",
+                Box::new(|el: Stateful<Div>| el.cursor_context_menu()),
+            ),
+            (
+                "cursor_crosshair",
+                Box::new(|el: Stateful<Div>| el.cursor_crosshair()),
+            ),
+            (
+                "cursor_vertical_text",
+                Box::new(|el: Stateful<Div>| el.cursor_vertical_text()),
+            ),
+            (
+                "cursor_alias",
+                Box::new(|el: Stateful<Div>| el.cursor_alias()),
+            ),
+            (
+                "cursor_copy",
+                Box::new(|el: Stateful<Div>| el.cursor_copy()),
+            ),
+            (
+                "cursor_no_drop",
+                Box::new(|el: Stateful<Div>| el.cursor_no_drop()),
+            ),
+            (
+                "cursor_grab",
+                Box::new(|el: Stateful<Div>| el.cursor_grab()),
+            ),
+            (
+                "cursor_grabbing",
+                Box::new(|el: Stateful<Div>| el.cursor_grabbing()),
+            ),
+            (
+                "cursor_col_resize",
+                Box::new(|el: Stateful<Div>| el.cursor_col_resize()),
+            ),
+            (
+                "cursor_row_resize",
+                Box::new(|el: Stateful<Div>| el.cursor_row_resize()),
+            ),
+            (
+                "cursor_n_resize",
+                Box::new(|el: Stateful<Div>| el.cursor_n_resize()),
+            ),
+            (
+                "cursor_e_resize",
+                Box::new(|el: Stateful<Div>| el.cursor_e_resize()),
+            ),
+            (
+                "cursor_s_resize",
+                Box::new(|el: Stateful<Div>| el.cursor_s_resize()),
+            ),
+            (
+                "cursor_w_resize",
+                Box::new(|el: Stateful<Div>| el.cursor_w_resize()),
+            ),
+        ];
+
+        Story::container()
+            .flex()
+            .gap_1()
+            .child(Story::title("cursor"))
+            .children(all_cursors.map(|(name, apply_cursor)| {
+                div().gap_1().flex().text_color(gpui::white()).child(
+                    div()
+                        .flex()
+                        .items_center()
+                        .justify_center()
+                        .id(name)
+                        .map(apply_cursor)
+                        .w_64()
+                        .h_8()
+                        .bg(gpui::red())
+                        .hover(|style| style.bg(gpui::blue()))
+                        .active(|style| style.bg(gpui::green()))
+                        .text_sm()
+                        .child(Story::label(name)),
+                )
+            }))
+    }
+}

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

@@ -1,6 +1,6 @@
 use gpui::{
-    blue, div, green, red, white, Div, InteractiveText, ParentElement, Render, Styled, StyledText,
-    TextRun, View, VisualContext, WindowContext,
+    blue, div, green, red, white, Div, HighlightStyle, InteractiveText, ParentElement, Render,
+    Styled, StyledText, View, VisualContext, WindowContext,
 };
 use ui::v_stack;
 
@@ -59,13 +59,11 @@ impl Render for TextStory {
             ))).child(
                 InteractiveText::new(
                     "interactive",
-                    StyledText::new("Hello world, how is it going?").with_runs(vec![
-                        cx.text_style().to_run(6),
-                        TextRun {
+                    StyledText::new("Hello world, how is it going?").with_highlights(&cx.text_style(), [
+                        (6..11, HighlightStyle {
                             background_color: Some(green()),
-                            ..cx.text_style().to_run(5)
-                        },
-                        cx.text_style().to_run(18),
+                            ..Default::default()
+                        }),
                     ]),
                 )
                 .on_click(vec![2..4, 1..3, 7..9], |range_ix, _cx| {

crates/storybook2/src/story_selector.rs 🔗

@@ -17,6 +17,7 @@ pub enum ComponentStory {
     Button,
     Checkbox,
     ContextMenu,
+    Cursor,
     Disclosure,
     Focus,
     Icon,
@@ -40,6 +41,7 @@ impl ComponentStory {
             Self::Button => cx.build_view(|_| ui::ButtonStory).into(),
             Self::Checkbox => cx.build_view(|_| ui::CheckboxStory).into(),
             Self::ContextMenu => cx.build_view(|_| ui::ContextMenuStory).into(),
+            Self::Cursor => cx.build_view(|_| crate::stories::CursorStory).into(),
             Self::Disclosure => cx.build_view(|_| ui::DisclosureStory).into(),
             Self::Focus => FocusStory::view(cx).into(),
             Self::Icon => cx.build_view(|_| ui::IconStory).into(),

crates/theme2/src/one_themes.rs 🔗

@@ -52,13 +52,13 @@ pub(crate) fn one_dark() -> Theme {
                 element_hover: hsla(225.0 / 360., 11.8 / 100., 26.7 / 100., 1.0),
                 element_active: hsla(220.0 / 360., 11.8 / 100., 20.0 / 100., 1.0),
                 element_selected: hsla(224.0 / 360., 11.3 / 100., 26.1 / 100., 1.0),
-                element_disabled: hsla(224.0 / 360., 11.3 / 100., 26.1 / 100., 1.0),
+                element_disabled: SystemColors::default().transparent,
                 drop_target_background: hsla(220.0 / 360., 8.3 / 100., 21.4 / 100., 1.0),
                 ghost_element_background: SystemColors::default().transparent,
                 ghost_element_hover: hsla(225.0 / 360., 11.8 / 100., 26.7 / 100., 1.0),
                 ghost_element_active: hsla(220.0 / 360., 11.8 / 100., 20.0 / 100., 1.0),
                 ghost_element_selected: hsla(224.0 / 360., 11.3 / 100., 26.1 / 100., 1.0),
-                ghost_element_disabled: hsla(224.0 / 360., 11.3 / 100., 26.1 / 100., 1.0),
+                ghost_element_disabled: SystemColors::default().transparent,
                 text: hsla(221. / 360., 11. / 100., 86. / 100., 1.0),
                 text_muted: hsla(218.0 / 360., 7. / 100., 46. / 100., 1.0),
                 text_placeholder: hsla(220.0 / 360., 6.6 / 100., 44.5 / 100., 1.0),

crates/ui2/src/components.rs 🔗

@@ -9,6 +9,8 @@ mod keybinding;
 mod label;
 mod list;
 mod popover;
+mod popover_menu;
+mod right_click_menu;
 mod stack;
 mod tooltip;
 
@@ -26,6 +28,8 @@ pub use keybinding::*;
 pub use label::*;
 pub use list::*;
 pub use popover::*;
+pub use popover_menu::*;
+pub use right_click_menu::*;
 pub use stack::*;
 pub use tooltip::*;
 

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

@@ -1,13 +1,22 @@
-use gpui::AnyView;
+use gpui::{AnyView, DefiniteLength};
 
 use crate::prelude::*;
-use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, Label, LineHeightStyle};
+use crate::{
+    ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, Icon, IconSize, Label, LineHeightStyle,
+};
+
+use super::button_icon::ButtonIcon;
 
 #[derive(IntoElement)]
 pub struct Button {
     base: ButtonLike,
     label: SharedString,
     label_color: Option<Color>,
+    selected_label: Option<SharedString>,
+    icon: Option<Icon>,
+    icon_size: Option<IconSize>,
+    icon_color: Option<Color>,
+    selected_icon: Option<Icon>,
 }
 
 impl Button {
@@ -16,6 +25,11 @@ impl Button {
             base: ButtonLike::new(id),
             label: label.into(),
             label_color: None,
+            selected_label: None,
+            icon: None,
+            icon_size: None,
+            icon_color: None,
+            selected_icon: None,
         }
     }
 
@@ -23,6 +37,31 @@ impl Button {
         self.label_color = label_color.into();
         self
     }
+
+    pub fn selected_label<L: Into<SharedString>>(mut self, label: impl Into<Option<L>>) -> Self {
+        self.selected_label = label.into().map(Into::into);
+        self
+    }
+
+    pub fn icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
+        self.icon = icon.into();
+        self
+    }
+
+    pub fn icon_size(mut self, icon_size: impl Into<Option<IconSize>>) -> Self {
+        self.icon_size = icon_size.into();
+        self
+    }
+
+    pub fn icon_color(mut self, icon_color: impl Into<Option<Color>>) -> Self {
+        self.icon_color = icon_color.into();
+        self
+    }
+
+    pub fn selected_icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
+        self.selected_icon = icon.into();
+        self
+    }
 }
 
 impl Selectable for Button {
@@ -49,6 +88,18 @@ impl Clickable for Button {
     }
 }
 
+impl FixedWidth for Button {
+    fn width(mut self, width: DefiniteLength) -> Self {
+        self.base = self.base.width(width);
+        self
+    }
+
+    fn full_width(mut self) -> Self {
+        self.base = self.base.full_width();
+        self
+    }
+}
+
 impl ButtonCommon for Button {
     fn id(&self) -> &ElementId {
         self.base.id()
@@ -74,18 +125,35 @@ impl RenderOnce for Button {
     type Rendered = ButtonLike;
 
     fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
-        let label_color = if self.base.disabled {
+        let is_disabled = self.base.disabled;
+        let is_selected = self.base.selected;
+
+        let label = self
+            .selected_label
+            .filter(|_| is_selected)
+            .unwrap_or(self.label);
+
+        let label_color = if is_disabled {
             Color::Disabled
-        } else if self.base.selected {
+        } else if is_selected {
             Color::Selected
         } else {
             self.label_color.unwrap_or_default()
         };
 
-        self.base.child(
-            Label::new(self.label)
-                .color(label_color)
-                .line_height_style(LineHeightStyle::UILabel),
-        )
+        self.base
+            .children(self.icon.map(|icon| {
+                ButtonIcon::new(icon)
+                    .disabled(is_disabled)
+                    .selected(is_selected)
+                    .selected_icon(self.selected_icon)
+                    .size(self.icon_size)
+                    .color(self.icon_color)
+            }))
+            .child(
+                Label::new(label)
+                    .color(label_color)
+                    .line_height_style(LineHeightStyle::UILabel),
+            )
     }
 }

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

@@ -0,0 +1,84 @@
+use crate::{prelude::*, Icon, IconElement, IconSize};
+
+/// An icon that appears within a button.
+///
+/// Can be used as either an icon alongside a label, like in [`Button`](crate::Button),
+/// or as a standalone icon, like in [`IconButton`](crate::IconButton).
+#[derive(IntoElement)]
+pub(super) struct ButtonIcon {
+    icon: Icon,
+    size: IconSize,
+    color: Color,
+    disabled: bool,
+    selected: bool,
+    selected_icon: Option<Icon>,
+}
+
+impl ButtonIcon {
+    pub fn new(icon: Icon) -> Self {
+        Self {
+            icon,
+            size: IconSize::default(),
+            color: Color::default(),
+            disabled: false,
+            selected: false,
+            selected_icon: None,
+        }
+    }
+
+    pub fn size(mut self, size: impl Into<Option<IconSize>>) -> Self {
+        if let Some(size) = size.into() {
+            self.size = size;
+        }
+
+        self
+    }
+
+    pub fn color(mut self, color: impl Into<Option<Color>>) -> Self {
+        if let Some(color) = color.into() {
+            self.color = color;
+        }
+
+        self
+    }
+
+    pub fn selected_icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
+        self.selected_icon = icon.into();
+        self
+    }
+}
+
+impl Disableable for ButtonIcon {
+    fn disabled(mut self, disabled: bool) -> Self {
+        self.disabled = disabled;
+        self
+    }
+}
+
+impl Selectable for ButtonIcon {
+    fn selected(mut self, selected: bool) -> Self {
+        self.selected = selected;
+        self
+    }
+}
+
+impl RenderOnce for ButtonIcon {
+    type Rendered = IconElement;
+
+    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
+        let icon = self
+            .selected_icon
+            .filter(|_| self.selected)
+            .unwrap_or(self.icon);
+
+        let icon_color = if self.disabled {
+            Color::Disabled
+        } else if self.selected {
+            Color::Selected
+        } else {
+            self.color
+        };
+
+        IconElement::new(icon).size(self.size).color(icon_color)
+    }
+}

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

@@ -1,3 +1,4 @@
+use gpui::{relative, DefiniteLength};
 use gpui::{rems, transparent_black, AnyElement, AnyView, ClickEvent, Div, Hsla, Rems, Stateful};
 use smallvec::SmallVec;
 
@@ -5,18 +6,50 @@ use crate::h_stack;
 use crate::prelude::*;
 
 pub trait ButtonCommon: Clickable + Disableable {
+    /// A unique element ID to identify the button.
     fn id(&self) -> &ElementId;
+
+    /// The visual style of the button.
+    ///
+    /// Mosty commonly will be [`ButtonStyle::Subtle`], or [`ButtonStyle::Filled`]
+    /// for an emphasized button.
     fn style(self, style: ButtonStyle) -> Self;
+
+    /// The size of the button.
+    ///
+    /// Most buttons will use the default size.
+    ///
+    /// [`ButtonSize`] can also be used to help build non-button elements
+    /// that are consistently sized with buttons.
     fn size(self, size: ButtonSize) -> Self;
+
+    /// The tooltip that shows when a user hovers over the button.
+    ///
+    /// Nearly all interactable elements should have a tooltip. Some example
+    /// exceptions might a scroll bar, or a slider.
     fn tooltip(self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self;
 }
 
 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
 pub enum ButtonStyle {
-    #[default]
+    /// A filled button with a solid background color. Provides emphasis versus
+    /// the more common subtle button.
     Filled,
-    // Tinted,
+
+    /// 🚧 Under construction 🚧
+    ///
+    /// Used to emphasize a button in some way, like a selected state, or a semantic
+    /// coloring like an error or success button.
+    Tinted,
+
+    /// The default button style, used for most buttons. Has a transparent background,
+    /// but has a background color to indicate states like hover and active.
+    #[default]
     Subtle,
+
+    /// Used for buttons that only change forground color on hover and active states.
+    ///
+    /// TODO: Better docs for this.
     Transparent,
 }
 
@@ -40,6 +73,12 @@ impl ButtonStyle {
                 label_color: Color::Default.color(cx),
                 icon_color: Color::Default.color(cx),
             },
+            ButtonStyle::Tinted => ButtonLikeStyles {
+                background: gpui::red(),
+                border_color: gpui::red(),
+                label_color: gpui::red(),
+                icon_color: gpui::red(),
+            },
             ButtonStyle::Subtle => ButtonLikeStyles {
                 background: cx.theme().colors().ghost_element_background,
                 border_color: transparent_black(),
@@ -63,6 +102,12 @@ impl ButtonStyle {
                 label_color: Color::Default.color(cx),
                 icon_color: Color::Default.color(cx),
             },
+            ButtonStyle::Tinted => ButtonLikeStyles {
+                background: gpui::red(),
+                border_color: gpui::red(),
+                label_color: gpui::red(),
+                icon_color: gpui::red(),
+            },
             ButtonStyle::Subtle => ButtonLikeStyles {
                 background: cx.theme().colors().ghost_element_hover,
                 border_color: transparent_black(),
@@ -88,6 +133,12 @@ impl ButtonStyle {
                 label_color: Color::Default.color(cx),
                 icon_color: Color::Default.color(cx),
             },
+            ButtonStyle::Tinted => ButtonLikeStyles {
+                background: gpui::red(),
+                border_color: gpui::red(),
+                label_color: gpui::red(),
+                icon_color: gpui::red(),
+            },
             ButtonStyle::Subtle => ButtonLikeStyles {
                 background: cx.theme().colors().ghost_element_active,
                 border_color: transparent_black(),
@@ -114,6 +165,12 @@ impl ButtonStyle {
                 label_color: Color::Default.color(cx),
                 icon_color: Color::Default.color(cx),
             },
+            ButtonStyle::Tinted => ButtonLikeStyles {
+                background: gpui::red(),
+                border_color: gpui::red(),
+                label_color: gpui::red(),
+                icon_color: gpui::red(),
+            },
             ButtonStyle::Subtle => ButtonLikeStyles {
                 background: cx.theme().colors().ghost_element_background,
                 border_color: cx.theme().colors().border_focused,
@@ -137,6 +194,12 @@ impl ButtonStyle {
                 label_color: Color::Disabled.color(cx),
                 icon_color: Color::Disabled.color(cx),
             },
+            ButtonStyle::Tinted => ButtonLikeStyles {
+                background: gpui::red(),
+                border_color: gpui::red(),
+                label_color: gpui::red(),
+                icon_color: gpui::red(),
+            },
             ButtonStyle::Subtle => ButtonLikeStyles {
                 background: cx.theme().colors().ghost_element_disabled,
                 border_color: cx.theme().colors().border_disabled,
@@ -153,6 +216,8 @@ impl ButtonStyle {
     }
 }
 
+/// ButtonSize can also be used to help build  non-button elements
+/// that are consistently sized with buttons.
 #[derive(Default, PartialEq, Clone, Copy)]
 pub enum ButtonSize {
     #[default]
@@ -171,12 +236,18 @@ impl ButtonSize {
     }
 }
 
+/// A button-like element that can be used to create a custom button when
+/// prebuilt buttons are not sufficient. Use this sparingly, as it is
+/// unconstrained and may make the UI feel less consistent.
+///
+/// This is also used to build the prebuilt buttons.
 #[derive(IntoElement)]
 pub struct ButtonLike {
     id: ElementId,
     pub(super) style: ButtonStyle,
     pub(super) disabled: bool,
     pub(super) selected: bool,
+    pub(super) width: Option<DefiniteLength>,
     size: ButtonSize,
     tooltip: Option<Box<dyn Fn(&mut WindowContext) -> AnyView>>,
     on_click: Option<Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
@@ -190,6 +261,7 @@ impl ButtonLike {
             style: ButtonStyle::default(),
             disabled: false,
             selected: false,
+            width: None,
             size: ButtonSize::Default,
             tooltip: None,
             children: SmallVec::new(),
@@ -219,6 +291,18 @@ impl Clickable for ButtonLike {
     }
 }
 
+impl FixedWidth for ButtonLike {
+    fn width(mut self, width: DefiniteLength) -> Self {
+        self.width = Some(width);
+        self
+    }
+
+    fn full_width(mut self) -> Self {
+        self.width = Some(relative(1.));
+        self
+    }
+}
+
 impl ButtonCommon for ButtonLike {
     fn id(&self) -> &ElementId {
         &self.id
@@ -252,14 +336,19 @@ impl RenderOnce for ButtonLike {
     fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         h_stack()
             .id(self.id.clone())
+            .group("")
+            .flex_none()
             .h(self.size.height())
+            .when_some(self.width, |this, width| this.w(width))
             .rounded_md()
-            .cursor_pointer()
             .gap_1()
             .px_1()
             .bg(self.style.enabled(cx).background)
-            .hover(|hover| hover.bg(self.style.hovered(cx).background))
-            .active(|active| active.bg(self.style.active(cx).background))
+            .when(!self.disabled, |this| {
+                this.cursor_pointer()
+                    .hover(|hover| hover.bg(self.style.hovered(cx).background))
+                    .active(|active| active.bg(self.style.active(cx).background))
+            })
             .when_some(
                 self.on_click.filter(|_| !self.disabled),
                 |this, on_click| {
@@ -270,7 +359,11 @@ impl RenderOnce for ButtonLike {
                 },
             )
             .when_some(self.tooltip, |this, tooltip| {
-                this.tooltip(move |cx| tooltip(cx))
+                if !self.selected {
+                    this.tooltip(move |cx| tooltip(cx))
+                } else {
+                    this
+                }
             })
             .children(self.children)
     }

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

@@ -1,7 +1,9 @@
-use gpui::{Action, AnyView};
+use gpui::{Action, AnyView, DefiniteLength};
 
 use crate::prelude::*;
-use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, Icon, IconElement, IconSize};
+use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, Icon, IconSize};
+
+use super::button_icon::ButtonIcon;
 
 #[derive(IntoElement)]
 pub struct IconButton {
@@ -9,6 +11,7 @@ pub struct IconButton {
     icon: Icon,
     icon_size: IconSize,
     icon_color: Color,
+    selected_icon: Option<Icon>,
 }
 
 impl IconButton {
@@ -18,6 +21,7 @@ impl IconButton {
             icon,
             icon_size: IconSize::default(),
             icon_color: Color::Default,
+            selected_icon: None,
         }
     }
 
@@ -31,6 +35,11 @@ impl IconButton {
         self
     }
 
+    pub fn selected_icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
+        self.selected_icon = icon.into();
+        self
+    }
+
     pub fn action(self, action: Box<dyn Action>) -> Self {
         self.on_click(move |_event, cx| cx.dispatch_action(action.boxed_clone()))
     }
@@ -60,6 +69,18 @@ impl Clickable for IconButton {
     }
 }
 
+impl FixedWidth for IconButton {
+    fn width(mut self, width: DefiniteLength) -> Self {
+        self.base = self.base.width(width);
+        self
+    }
+
+    fn full_width(mut self) -> Self {
+        self.base = self.base.full_width();
+        self
+    }
+}
+
 impl ButtonCommon for IconButton {
     fn id(&self) -> &ElementId {
         self.base.id()
@@ -85,18 +106,16 @@ impl RenderOnce for IconButton {
     type Rendered = ButtonLike;
 
     fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
-        let icon_color = if self.base.disabled {
-            Color::Disabled
-        } else if self.base.selected {
-            Color::Selected
-        } else {
-            self.icon_color
-        };
+        let is_disabled = self.base.disabled;
+        let is_selected = self.base.selected;
 
         self.base.child(
-            IconElement::new(self.icon)
+            ButtonIcon::new(self.icon)
+                .disabled(is_disabled)
+                .selected(is_selected)
+                .selected_icon(self.selected_icon)
                 .size(self.icon_size)
-                .color(icon_color),
+                .color(self.icon_color),
         )
     }
 }

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

@@ -1,19 +1,20 @@
 use crate::{
-    h_stack, prelude::*, v_stack, KeyBinding, Label, List, ListItem, ListSeparator, ListSubHeader,
+    h_stack, prelude::*, v_stack, Icon, IconElement, KeyBinding, Label, List, ListItem,
+    ListSeparator, ListSubHeader,
 };
 use gpui::{
-    overlay, px, Action, AnchorCorner, AnyElement, AppContext, Bounds, DismissEvent, DispatchPhase,
-    Div, EventEmitter, FocusHandle, FocusableView, IntoElement, LayoutId, ManagedView, MouseButton,
-    MouseDownEvent, Pixels, Point, Render, View, VisualContext,
+    px, Action, AppContext, DismissEvent, Div, EventEmitter, FocusHandle, FocusableView,
+    IntoElement, Render, View, VisualContext,
 };
 use menu::{SelectFirst, SelectLast, SelectNext, SelectPrev};
-use std::{cell::RefCell, rc::Rc};
+use std::rc::Rc;
 
 pub enum ContextMenuItem {
     Separator,
     Header(SharedString),
     Entry {
         label: SharedString,
+        icon: Option<Icon>,
         handler: Rc<dyn Fn(&mut WindowContext)>,
         key_binding: Option<KeyBinding>,
     },
@@ -70,6 +71,7 @@ impl ContextMenu {
             label: label.into(),
             handler: Rc::new(on_click),
             key_binding: None,
+            icon: None,
         });
         self
     }
@@ -84,6 +86,22 @@ impl ContextMenu {
             label: label.into(),
             key_binding: KeyBinding::for_action(&*action, cx),
             handler: Rc::new(move |cx| cx.dispatch_action(action.boxed_clone())),
+            icon: None,
+        });
+        self
+    }
+
+    pub fn link(
+        mut self,
+        label: impl Into<SharedString>,
+        action: Box<dyn Action>,
+        cx: &mut WindowContext,
+    ) -> Self {
+        self.items.push(ContextMenuItem::Entry {
+            label: label.into(),
+            key_binding: KeyBinding::for_action(&*action, cx),
+            handler: Rc::new(move |cx| cx.dispatch_action(action.boxed_clone())),
+            icon: Some(Icon::Link),
         });
         self
     }
@@ -176,19 +194,30 @@ impl Render for ContextMenu {
                                 ListSubHeader::new(header.clone()).into_any_element()
                             }
                             ContextMenuItem::Entry {
-                                label: entry,
-                                handler: callback,
+                                label,
+                                handler,
                                 key_binding,
+                                icon,
                             } => {
-                                let callback = callback.clone();
+                                let handler = handler.clone();
                                 let dismiss = cx.listener(|_, _, cx| cx.emit(DismissEvent));
 
-                                ListItem::new(entry.clone())
+                                let label_element = if let Some(icon) = icon {
+                                    h_stack()
+                                        .gap_1()
+                                        .child(Label::new(label.clone()))
+                                        .child(IconElement::new(*icon))
+                                        .into_any_element()
+                                } else {
+                                    Label::new(label.clone()).into_any_element()
+                                };
+
+                                ListItem::new(label.clone())
                                     .child(
                                         h_stack()
                                             .w_full()
                                             .justify_between()
-                                            .child(Label::new(entry.clone()))
+                                            .child(label_element)
                                             .children(
                                                 key_binding
                                                     .clone()
@@ -197,7 +226,7 @@ impl Render for ContextMenu {
                                     )
                                     .selected(Some(ix) == self.selected_index)
                                     .on_click(move |event, cx| {
-                                        callback(cx);
+                                        handler(cx);
                                         dismiss(event, cx)
                                     })
                                     .into_any_element()
@@ -208,174 +237,3 @@ impl Render for ContextMenu {
         )
     }
 }
-
-pub struct MenuHandle<M: ManagedView> {
-    id: ElementId,
-    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<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: IntoElement>(mut self, f: impl FnOnce(bool) -> R + 'static) -> Self {
-        self.child_builder = Some(Box::new(|b| f(b).into_element().into_any()));
-        self
-    }
-
-    /// anchor defines which corner of the menu to anchor to the attachment point
-    /// (by default the cursor position, but see attach)
-    pub fn anchor(mut self, anchor: AnchorCorner) -> Self {
-        self.anchor = Some(anchor);
-        self
-    }
-
-    /// attach defines which corner of the handle to attach the menu's anchor to
-    pub fn attach(mut self, attach: AnchorCorner) -> Self {
-        self.attach = Some(attach);
-        self
-    }
-}
-
-pub fn menu_handle<M: ManagedView>(id: impl Into<ElementId>) -> MenuHandle<M> {
-    MenuHandle {
-        id: id.into(),
-        child_builder: None,
-        menu_builder: None,
-        anchor: None,
-        attach: None,
-    }
-}
-
-pub struct MenuHandleState<M> {
-    menu: Rc<RefCell<Option<View<M>>>>,
-    position: Rc<RefCell<Point<Pixels>>>,
-    child_layout_id: Option<LayoutId>,
-    child_element: Option<AnyElement>,
-    menu_element: Option<AnyElement>,
-}
-
-impl<M: ManagedView> Element for MenuHandle<M> {
-    type State = MenuHandleState<M>;
-
-    fn layout(
-        &mut self,
-        element_state: Option<Self::State>,
-        cx: &mut WindowContext,
-    ) -> (gpui::LayoutId, Self::State) {
-        let (menu, position) = if let Some(element_state) = element_state {
-            (element_state.menu, element_state.position)
-        } else {
-            (Rc::default(), Rc::default())
-        };
-
-        let mut menu_layout_id = None;
-
-        let menu_element = menu.borrow_mut().as_mut().map(|menu| {
-            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(cx));
-            element
-        });
-
-        let mut child_element = self
-            .child_builder
-            .take()
-            .map(|child_builder| (child_builder)(menu.borrow().is_some()));
-
-        let child_layout_id = child_element
-            .as_mut()
-            .map(|child_element| child_element.layout(cx));
-
-        let layout_id = cx.request_layout(
-            &gpui::Style::default(),
-            menu_layout_id.into_iter().chain(child_layout_id),
-        );
-
-        (
-            layout_id,
-            MenuHandleState {
-                menu,
-                position,
-                child_element,
-                child_layout_id,
-                menu_element,
-            },
-        )
-    }
-
-    fn paint(
-        self,
-        bounds: Bounds<gpui::Pixels>,
-        element_state: &mut Self::State,
-        cx: &mut WindowContext,
-    ) {
-        if let Some(child) = element_state.child_element.take() {
-            child.paint(cx);
-        }
-
-        if let Some(menu) = element_state.menu_element.take() {
-            menu.paint(cx);
-            return;
-        }
-
-        let Some(builder) = self.menu_builder else {
-            return;
-        };
-        let menu = element_state.menu.clone();
-        let position = element_state.position.clone();
-        let attach = self.attach.clone();
-        let child_layout_id = element_state.child_layout_id.clone();
-
-        cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
-            if phase == DispatchPhase::Bubble
-                && event.button == MouseButton::Right
-                && bounds.contains_point(&event.position)
-            {
-                cx.stop_propagation();
-                cx.prevent_default();
-
-                let new_menu = (builder)(cx);
-                let menu2 = menu.clone();
-                cx.subscribe(&new_menu, move |_modal, _: &DismissEvent, cx| {
-                    *menu2.borrow_mut() = None;
-                    cx.notify();
-                })
-                .detach();
-                cx.focus_view(&new_menu);
-                *menu.borrow_mut() = Some(new_menu);
-
-                *position.borrow_mut() = if attach.is_some() && child_layout_id.is_some() {
-                    attach
-                        .unwrap()
-                        .corner(cx.layout_bounds(child_layout_id.unwrap()))
-                } else {
-                    cx.mouse_position()
-                };
-                cx.notify();
-            }
-        });
-    }
-}
-
-impl<M: ManagedView> IntoElement for MenuHandle<M> {
-    type Element = Self;
-
-    fn element_id(&self) -> Option<gpui::ElementId> {
-        Some(self.id.clone())
-    }
-
-    fn into_element(self) -> Self::Element {
-        self
-    }
-}

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

@@ -27,6 +27,7 @@ pub enum Icon {
     Bolt,
     CaseSensitive,
     Check,
+    Copy,
     ChevronDown,
     ChevronLeft,
     ChevronRight,
@@ -54,6 +55,7 @@ pub enum Icon {
     FolderX,
     Hash,
     InlayHint,
+    Link,
     MagicWand,
     MagnifyingGlass,
     MailOpen,
@@ -99,6 +101,7 @@ impl Icon {
             Icon::Bolt => "icons/bolt.svg",
             Icon::CaseSensitive => "icons/case_insensitive.svg",
             Icon::Check => "icons/check.svg",
+            Icon::Copy => "icons/copy.svg",
             Icon::ChevronDown => "icons/chevron_down.svg",
             Icon::ChevronLeft => "icons/chevron_left.svg",
             Icon::ChevronRight => "icons/chevron_right.svg",
@@ -126,6 +129,7 @@ impl Icon {
             Icon::FolderX => "icons/stop_sharing.svg",
             Icon::Hash => "icons/hash.svg",
             Icon::InlayHint => "icons/inlay_hint.svg",
+            Icon::Link => "icons/link.svg",
             Icon::MagicWand => "icons/magic-wand.svg",
             Icon::MagnifyingGlass => "icons/magnifying_glass.svg",
             Icon::MailOpen => "icons/mail-open.svg",

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

@@ -1,6 +1,8 @@
+use std::ops::Range;
+
 use crate::prelude::*;
 use crate::styled_ext::StyledExt;
-use gpui::{relative, Div, IntoElement, StyledText, TextRun, WindowContext};
+use gpui::{relative, Div, HighlightStyle, IntoElement, StyledText, WindowContext};
 
 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
 pub enum LabelSize {
@@ -99,38 +101,32 @@ impl RenderOnce for HighlightedLabel {
 
     fn render(self, cx: &mut WindowContext) -> Self::Rendered {
         let highlight_color = cx.theme().colors().text_accent;
-        let mut text_style = cx.text_style().clone();
 
         let mut highlight_indices = self.highlight_indices.iter().copied().peekable();
-
-        let mut runs: Vec<TextRun> = Vec::new();
-
-        for (char_ix, char) in self.label.char_indices() {
-            let mut color = self.color.color(cx);
-
-            if let Some(highlight_ix) = highlight_indices.peek() {
-                if char_ix == *highlight_ix {
-                    color = highlight_color;
-                    highlight_indices.next();
+        let mut highlights: Vec<(Range<usize>, HighlightStyle)> = Vec::new();
+
+        while let Some(start_ix) = highlight_indices.next() {
+            let mut end_ix = start_ix;
+
+            loop {
+                end_ix = end_ix + self.label[end_ix..].chars().next().unwrap().len_utf8();
+                if let Some(&next_ix) = highlight_indices.peek() {
+                    if next_ix == end_ix {
+                        end_ix = next_ix;
+                        highlight_indices.next();
+                        continue;
+                    }
                 }
+                break;
             }
 
-            let last_run = runs.last_mut();
-            let start_new_run = if let Some(last_run) = last_run {
-                if color == last_run.color {
-                    last_run.len += char.len_utf8();
-                    false
-                } else {
-                    true
-                }
-            } else {
-                true
-            };
-
-            if start_new_run {
-                text_style.color = color;
-                runs.push(text_style.to_run(char.len_utf8()))
-            }
+            highlights.push((
+                start_ix..end_ix,
+                HighlightStyle {
+                    color: Some(highlight_color),
+                    ..Default::default()
+                },
+            ));
         }
 
         div()
@@ -150,7 +146,7 @@ impl RenderOnce for HighlightedLabel {
                 LabelSize::Default => this.text_ui(),
                 LabelSize::Small => this.text_ui_sm(),
             })
-            .child(StyledText::new(self.label).with_runs(runs))
+            .child(StyledText::new(self.label).with_highlights(&cx.text_style(), highlights))
     }
 }
 

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

@@ -0,0 +1,231 @@
+use std::{cell::RefCell, rc::Rc};
+
+use gpui::{
+    overlay, point, px, rems, AnchorCorner, AnyElement, Bounds, DismissEvent, DispatchPhase,
+    Element, ElementId, InteractiveBounds, IntoElement, LayoutId, ManagedView, MouseDownEvent,
+    ParentElement, Pixels, Point, View, VisualContext, WindowContext,
+};
+
+use crate::{Clickable, Selectable};
+
+pub trait PopoverTrigger: IntoElement + Clickable + Selectable + 'static {}
+
+impl<T: IntoElement + Clickable + Selectable + 'static> PopoverTrigger for T {}
+
+pub struct PopoverMenu<M: ManagedView> {
+    id: ElementId,
+    child_builder: Option<
+        Box<
+            dyn FnOnce(
+                    Rc<RefCell<Option<View<M>>>>,
+                    Option<Rc<dyn Fn(&mut WindowContext) -> View<M> + 'static>>,
+                ) -> AnyElement
+                + 'static,
+        >,
+    >,
+    menu_builder: Option<Rc<dyn Fn(&mut WindowContext) -> View<M> + 'static>>,
+    anchor: AnchorCorner,
+    attach: Option<AnchorCorner>,
+    offset: Option<Point<Pixels>>,
+}
+
+impl<M: ManagedView> PopoverMenu<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 trigger<T: PopoverTrigger>(mut self, t: T) -> Self {
+        self.child_builder = Some(Box::new(|menu, builder| {
+            let open = menu.borrow().is_some();
+            t.selected(open)
+                .when_some(builder, |el, builder| {
+                    el.on_click({
+                        move |_, cx| {
+                            let new_menu = (builder)(cx);
+                            let menu2 = menu.clone();
+                            let previous_focus_handle = cx.focused();
+
+                            cx.subscribe(&new_menu, move |modal, _: &DismissEvent, cx| {
+                                if modal.focus_handle(cx).contains_focused(cx) {
+                                    if previous_focus_handle.is_some() {
+                                        cx.focus(&previous_focus_handle.as_ref().unwrap())
+                                    }
+                                }
+                                *menu2.borrow_mut() = None;
+                                cx.notify();
+                            })
+                            .detach();
+                            cx.focus_view(&new_menu);
+                            *menu.borrow_mut() = Some(new_menu);
+                        }
+                    })
+                })
+                .into_any_element()
+        }));
+        self
+    }
+
+    /// anchor defines which corner of the menu to anchor to the attachment point
+    /// (by default the cursor position, but see attach)
+    pub fn anchor(mut self, anchor: AnchorCorner) -> Self {
+        self.anchor = anchor;
+        self
+    }
+
+    /// attach defines which corner of the handle to attach the menu's anchor to
+    pub fn attach(mut self, attach: AnchorCorner) -> Self {
+        self.attach = Some(attach);
+        self
+    }
+
+    /// offset offsets the position of the content by that many pixels.
+    pub fn offset(mut self, offset: Point<Pixels>) -> Self {
+        self.offset = Some(offset);
+        self
+    }
+
+    fn resolved_attach(&self) -> AnchorCorner {
+        self.attach.unwrap_or_else(|| match self.anchor {
+            AnchorCorner::TopLeft => AnchorCorner::BottomLeft,
+            AnchorCorner::TopRight => AnchorCorner::BottomRight,
+            AnchorCorner::BottomLeft => AnchorCorner::TopLeft,
+            AnchorCorner::BottomRight => AnchorCorner::TopRight,
+        })
+    }
+
+    fn resolved_offset(&self, cx: &WindowContext) -> Point<Pixels> {
+        self.offset.unwrap_or_else(|| {
+            // Default offset = 4px padding + 1px border
+            let offset = rems(5. / 16.) * cx.rem_size();
+            match self.anchor {
+                AnchorCorner::TopRight | AnchorCorner::BottomRight => point(offset, px(0.)),
+                AnchorCorner::TopLeft | AnchorCorner::BottomLeft => point(-offset, px(0.)),
+            }
+        })
+    }
+}
+
+pub fn popover_menu<M: ManagedView>(id: impl Into<ElementId>) -> PopoverMenu<M> {
+    PopoverMenu {
+        id: id.into(),
+        child_builder: None,
+        menu_builder: None,
+        anchor: AnchorCorner::TopLeft,
+        attach: None,
+        offset: None,
+    }
+}
+
+pub struct PopoverMenuState<M> {
+    child_layout_id: Option<LayoutId>,
+    child_element: Option<AnyElement>,
+    child_bounds: Option<Bounds<Pixels>>,
+    menu_element: Option<AnyElement>,
+    menu: Rc<RefCell<Option<View<M>>>>,
+}
+
+impl<M: ManagedView> Element for PopoverMenu<M> {
+    type State = PopoverMenuState<M>;
+
+    fn layout(
+        &mut self,
+        element_state: Option<Self::State>,
+        cx: &mut WindowContext,
+    ) -> (gpui::LayoutId, Self::State) {
+        let mut menu_layout_id = None;
+
+        let (menu, child_bounds) = if let Some(element_state) = element_state {
+            (element_state.menu, element_state.child_bounds)
+        } else {
+            (Rc::default(), None)
+        };
+
+        let menu_element = menu.borrow_mut().as_mut().map(|menu| {
+            let mut overlay = overlay().snap_to_window().anchor(self.anchor);
+
+            if let Some(child_bounds) = child_bounds {
+                overlay = overlay.position(
+                    self.resolved_attach().corner(child_bounds) + self.resolved_offset(cx),
+                );
+            }
+
+            let mut element = overlay.child(menu.clone()).into_any();
+            menu_layout_id = Some(element.layout(cx));
+            element
+        });
+
+        let mut child_element = self
+            .child_builder
+            .take()
+            .map(|child_builder| (child_builder)(menu.clone(), self.menu_builder.clone()));
+
+        let child_layout_id = child_element
+            .as_mut()
+            .map(|child_element| child_element.layout(cx));
+
+        let layout_id = cx.request_layout(
+            &gpui::Style::default(),
+            menu_layout_id.into_iter().chain(child_layout_id),
+        );
+
+        (
+            layout_id,
+            PopoverMenuState {
+                menu,
+                child_element,
+                child_layout_id,
+                menu_element,
+                child_bounds,
+            },
+        )
+    }
+
+    fn paint(
+        self,
+        _: Bounds<gpui::Pixels>,
+        element_state: &mut Self::State,
+        cx: &mut WindowContext,
+    ) {
+        if let Some(child) = element_state.child_element.take() {
+            child.paint(cx);
+        }
+
+        if let Some(child_layout_id) = element_state.child_layout_id.take() {
+            element_state.child_bounds = Some(cx.layout_bounds(child_layout_id));
+        }
+
+        if let Some(menu) = element_state.menu_element.take() {
+            menu.paint(cx);
+
+            if let Some(child_bounds) = element_state.child_bounds {
+                let interactive_bounds = InteractiveBounds {
+                    bounds: child_bounds,
+                    stacking_order: cx.stacking_order().clone(),
+                };
+
+                // Mouse-downing outside the menu dismisses it, so we don't
+                // want a click on the toggle to re-open it.
+                cx.on_mouse_event(move |e: &MouseDownEvent, phase, cx| {
+                    if phase == DispatchPhase::Bubble
+                        && interactive_bounds.visibly_contains(&e.position, cx)
+                    {
+                        cx.stop_propagation()
+                    }
+                })
+            }
+        }
+    }
+}
+
+impl<M: ManagedView> IntoElement for PopoverMenu<M> {
+    type Element = Self;
+
+    fn element_id(&self) -> Option<gpui::ElementId> {
+        Some(self.id.clone())
+    }
+
+    fn into_element(self) -> Self::Element {
+        self
+    }
+}

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

@@ -0,0 +1,185 @@
+use std::{cell::RefCell, rc::Rc};
+
+use gpui::{
+    overlay, AnchorCorner, AnyElement, Bounds, DismissEvent, DispatchPhase, Element, ElementId,
+    IntoElement, LayoutId, ManagedView, MouseButton, MouseDownEvent, ParentElement, Pixels, Point,
+    View, VisualContext, WindowContext,
+};
+
+pub struct RightClickMenu<M: ManagedView> {
+    id: ElementId,
+    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<M: ManagedView> RightClickMenu<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 trigger<E: IntoElement + 'static>(mut self, e: E) -> Self {
+        self.child_builder = Some(Box::new(move |_| e.into_any_element()));
+        self
+    }
+
+    /// anchor defines which corner of the menu to anchor to the attachment point
+    /// (by default the cursor position, but see attach)
+    pub fn anchor(mut self, anchor: AnchorCorner) -> Self {
+        self.anchor = Some(anchor);
+        self
+    }
+
+    /// attach defines which corner of the handle to attach the menu's anchor to
+    pub fn attach(mut self, attach: AnchorCorner) -> Self {
+        self.attach = Some(attach);
+        self
+    }
+}
+
+pub fn right_click_menu<M: ManagedView>(id: impl Into<ElementId>) -> RightClickMenu<M> {
+    RightClickMenu {
+        id: id.into(),
+        child_builder: None,
+        menu_builder: None,
+        anchor: None,
+        attach: None,
+    }
+}
+
+pub struct MenuHandleState<M> {
+    menu: Rc<RefCell<Option<View<M>>>>,
+    position: Rc<RefCell<Point<Pixels>>>,
+    child_layout_id: Option<LayoutId>,
+    child_element: Option<AnyElement>,
+    menu_element: Option<AnyElement>,
+}
+
+impl<M: ManagedView> Element for RightClickMenu<M> {
+    type State = MenuHandleState<M>;
+
+    fn layout(
+        &mut self,
+        element_state: Option<Self::State>,
+        cx: &mut WindowContext,
+    ) -> (gpui::LayoutId, Self::State) {
+        let (menu, position) = if let Some(element_state) = element_state {
+            (element_state.menu, element_state.position)
+        } else {
+            (Rc::default(), Rc::default())
+        };
+
+        let mut menu_layout_id = None;
+
+        let menu_element = menu.borrow_mut().as_mut().map(|menu| {
+            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(cx));
+            element
+        });
+
+        let mut child_element = self
+            .child_builder
+            .take()
+            .map(|child_builder| (child_builder)(menu.borrow().is_some()));
+
+        let child_layout_id = child_element
+            .as_mut()
+            .map(|child_element| child_element.layout(cx));
+
+        let layout_id = cx.request_layout(
+            &gpui::Style::default(),
+            menu_layout_id.into_iter().chain(child_layout_id),
+        );
+
+        (
+            layout_id,
+            MenuHandleState {
+                menu,
+                position,
+                child_element,
+                child_layout_id,
+                menu_element,
+            },
+        )
+    }
+
+    fn paint(
+        self,
+        bounds: Bounds<gpui::Pixels>,
+        element_state: &mut Self::State,
+        cx: &mut WindowContext,
+    ) {
+        if let Some(child) = element_state.child_element.take() {
+            child.paint(cx);
+        }
+
+        if let Some(menu) = element_state.menu_element.take() {
+            menu.paint(cx);
+            return;
+        }
+
+        let Some(builder) = self.menu_builder else {
+            return;
+        };
+        let menu = element_state.menu.clone();
+        let position = element_state.position.clone();
+        let attach = self.attach.clone();
+        let child_layout_id = element_state.child_layout_id.clone();
+
+        cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
+            if phase == DispatchPhase::Bubble
+                && event.button == MouseButton::Right
+                && bounds.contains_point(&event.position)
+            {
+                cx.stop_propagation();
+                cx.prevent_default();
+
+                let new_menu = (builder)(cx);
+                let menu2 = menu.clone();
+                let previous_focus_handle = cx.focused();
+
+                cx.subscribe(&new_menu, move |modal, _: &DismissEvent, cx| {
+                    if modal.focus_handle(cx).contains_focused(cx) {
+                        if previous_focus_handle.is_some() {
+                            cx.focus(&previous_focus_handle.as_ref().unwrap())
+                        }
+                    }
+                    *menu2.borrow_mut() = None;
+                    cx.notify();
+                })
+                .detach();
+                cx.focus_view(&new_menu);
+                *menu.borrow_mut() = Some(new_menu);
+
+                *position.borrow_mut() = if attach.is_some() && child_layout_id.is_some() {
+                    attach
+                        .unwrap()
+                        .corner(cx.layout_bounds(child_layout_id.unwrap()))
+                } else {
+                    cx.mouse_position()
+                };
+                cx.notify();
+            }
+        });
+    }
+}
+
+impl<M: ManagedView> IntoElement for RightClickMenu<M> {
+    type Element = Self;
+
+    fn element_id(&self) -> Option<gpui::ElementId> {
+        Some(self.id.clone())
+    }
+
+    fn into_element(self) -> Self::Element {
+        self
+    }
+}

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

@@ -1,7 +1,7 @@
 use gpui::{Div, Render};
 use story::Story;
 
-use crate::prelude::*;
+use crate::{prelude::*, Icon};
 use crate::{Button, ButtonStyle};
 
 pub struct ButtonStory;
@@ -16,8 +16,22 @@ impl Render for ButtonStory {
             .child(Button::new("default_filled", "Click me"))
             .child(Story::label("Selected"))
             .child(Button::new("selected_filled", "Click me").selected(true))
+            .child(Story::label("Selected with `selected_label`"))
+            .child(
+                Button::new("selected_label_filled", "Click me")
+                    .selected(true)
+                    .selected_label("I have been selected"),
+            )
             .child(Story::label("With `label_color`"))
             .child(Button::new("filled_with_label_color", "Click me").color(Color::Created))
+            .child(Story::label("With `icon`"))
+            .child(Button::new("filled_with_icon", "Click me").icon(Icon::FileGit))
+            .child(Story::label("Selected with `icon`"))
+            .child(
+                Button::new("filled_and_selected_with_icon", "Click me")
+                    .selected(true)
+                    .icon(Icon::FileGit),
+            )
             .child(Story::label("Default (Subtle)"))
             .child(Button::new("default_subtle", "Click me").style(ButtonStyle::Subtle))
             .child(Story::label("Default (Transparent)"))

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

@@ -2,7 +2,7 @@ use gpui::{actions, Action, AnchorCorner, Div, Render, View};
 use story::Story;
 
 use crate::prelude::*;
-use crate::{menu_handle, ContextMenu, Label};
+use crate::{right_click_menu, ContextMenu, Label};
 
 actions!(PrintCurrentDate, PrintBestFood);
 
@@ -45,25 +45,13 @@ impl Render for ContextMenuStory {
                     .flex_col()
                     .justify_between()
                     .child(
-                        menu_handle("test2")
-                            .child(|is_open| {
-                                Label::new(if is_open {
-                                    "TOP LEFT"
-                                } else {
-                                    "RIGHT CLICK ME"
-                                })
-                            })
+                        right_click_menu("test2")
+                            .trigger(Label::new("TOP LEFT"))
                             .menu(move |cx| build_menu(cx, "top left")),
                     )
                     .child(
-                        menu_handle("test1")
-                            .child(|is_open| {
-                                Label::new(if is_open {
-                                    "BOTTOM LEFT"
-                                } else {
-                                    "RIGHT CLICK ME"
-                                })
-                            })
+                        right_click_menu("test1")
+                            .trigger(Label::new("BOTTOM LEFT"))
                             .anchor(AnchorCorner::BottomLeft)
                             .attach(AnchorCorner::TopLeft)
                             .menu(move |cx| build_menu(cx, "bottom left")),
@@ -75,26 +63,14 @@ impl Render for ContextMenuStory {
                     .flex_col()
                     .justify_between()
                     .child(
-                        menu_handle("test3")
-                            .child(|is_open| {
-                                Label::new(if is_open {
-                                    "TOP RIGHT"
-                                } else {
-                                    "RIGHT CLICK ME"
-                                })
-                            })
+                        right_click_menu("test3")
+                            .trigger(Label::new("TOP RIGHT"))
                             .anchor(AnchorCorner::TopRight)
                             .menu(move |cx| build_menu(cx, "top right")),
                     )
                     .child(
-                        menu_handle("test4")
-                            .child(|is_open| {
-                                Label::new(if is_open {
-                                    "BOTTOM RIGHT"
-                                } else {
-                                    "RIGHT CLICK ME"
-                                })
-                            })
+                        right_click_menu("test4")
+                            .trigger(Label::new("BOTTOM RIGHT"))
                             .anchor(AnchorCorner::BottomRight)
                             .attach(AnchorCorner::TopRight)
                             .menu(move |cx| build_menu(cx, "bottom right")),

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

@@ -20,6 +20,14 @@ impl Render for IconButtonStory {
                     .w_8()
                     .child(IconButton::new("icon_a", Icon::Hash).selected(true)),
             )
+            .child(Story::label("Selected with `selected_icon`"))
+            .child(
+                div().w_8().child(
+                    IconButton::new("icon_a", Icon::AudioOn)
+                        .selected(true)
+                        .selected_icon(Icon::AudioOff),
+                ),
+            )
             .child(Story::label("Disabled"))
             .child(
                 div()

crates/ui2/src/styled_ext.rs 🔗

@@ -1,4 +1,6 @@
 use gpui::{px, Styled, WindowContext};
+use settings::Settings;
+use theme::ThemeSettings;
 
 use crate::prelude::*;
 use crate::{ElevationIndex, UITextSize};
@@ -60,6 +62,18 @@ pub trait StyledExt: Styled + Sized {
         self.text_size(size)
     }
 
+    /// The font size for buffer text.
+    ///
+    /// Retrieves the default font size, or the user's custom font size if set.
+    ///
+    /// This should only be used for text that is displayed in a buffer,
+    /// or other places that text needs to match the user's buffer font size.
+    fn text_buffer(self, cx: &mut WindowContext) -> Self {
+        let settings = ThemeSettings::get_global(cx);
+
+        self.text_size(settings.buffer_font_size)
+    }
+
     /// The [`Surface`](ui2::ElevationIndex::Surface) elevation level, located above the app background, is the standard level for all elements
     ///
     /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`

crates/workspace2/src/dock.rs 🔗

@@ -7,8 +7,8 @@ use gpui::{
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
 use std::sync::Arc;
-use ui::prelude::*;
-use ui::{h_stack, menu_handle, ContextMenu, IconButton, Tooltip};
+use ui::{h_stack, ContextMenu, IconButton, Tooltip};
+use ui::{prelude::*, right_click_menu};
 
 pub enum PanelEvent {
     ChangePosition,
@@ -702,7 +702,7 @@ impl Render for PanelButtons {
                 };
 
                 Some(
-                    menu_handle(name)
+                    right_click_menu(name)
                         .menu(move |cx| {
                             const POSITIONS: [DockPosition; 3] = [
                                 DockPosition::Left,
@@ -726,14 +726,14 @@ impl Render for PanelButtons {
                         })
                         .anchor(menu_anchor)
                         .attach(menu_attach)
-                        .child(move |_is_open| {
+                        .trigger(
                             IconButton::new(name, icon)
                                 .selected(is_active_button)
                                 .action(action.boxed_clone())
                                 .tooltip(move |cx| {
                                     Tooltip::for_action(tooltip.clone(), &*action, cx)
-                                })
-                        }),
+                                }),
+                        ),
                 )
             });
 

crates/workspace2/src/notifications.rs 🔗

@@ -135,24 +135,22 @@ impl Workspace {
     }
 
     pub fn show_toast(&mut self, toast: Toast, cx: &mut ViewContext<Self>) {
-        todo!()
-        // self.dismiss_notification::<simple_message_notification::MessageNotification>(toast.id, cx);
-        // self.show_notification(toast.id, cx, |cx| {
-        //     cx.add_view(|_cx| match toast.on_click.as_ref() {
-        //         Some((click_msg, on_click)) => {
-        //             let on_click = on_click.clone();
-        //             simple_message_notification::MessageNotification::new(toast.msg.clone())
-        //                 .with_click_message(click_msg.clone())
-        //                 .on_click(move |cx| on_click(cx))
-        //         }
-        //         None => simple_message_notification::MessageNotification::new(toast.msg.clone()),
-        //     })
-        // })
+        self.dismiss_notification::<simple_message_notification::MessageNotification>(toast.id, cx);
+        self.show_notification(toast.id, cx, |cx| {
+            cx.build_view(|_cx| match toast.on_click.as_ref() {
+                Some((click_msg, on_click)) => {
+                    let on_click = on_click.clone();
+                    simple_message_notification::MessageNotification::new(toast.msg.clone())
+                        .with_click_message(click_msg.clone())
+                        .on_click(move |cx| on_click(cx))
+                }
+                None => simple_message_notification::MessageNotification::new(toast.msg.clone()),
+            })
+        })
     }
 
     pub fn dismiss_toast(&mut self, id: usize, cx: &mut ViewContext<Self>) {
-        todo!()
-        // self.dismiss_notification::<simple_message_notification::MessageNotification>(id, cx);
+        self.dismiss_notification::<simple_message_notification::MessageNotification>(id, cx);
     }
 
     fn dismiss_notification_internal(
@@ -179,33 +177,10 @@ pub mod simple_message_notification {
         ParentElement, Render, SharedString, StatefulInteractiveElement, Styled, TextStyle,
         ViewContext,
     };
-    use serde::Deserialize;
-    use std::{borrow::Cow, sync::Arc};
+    use std::sync::Arc;
     use ui::prelude::*;
     use ui::{h_stack, v_stack, Button, Icon, IconElement, Label, StyledExt};
 
-    #[derive(Clone, Default, Deserialize, PartialEq)]
-    pub struct OsOpen(pub Cow<'static, str>);
-
-    impl OsOpen {
-        pub fn new<I: Into<Cow<'static, str>>>(url: I) -> Self {
-            OsOpen(url.into())
-        }
-    }
-
-    // todo!()
-    //     impl_actions!(message_notifications, [OsOpen]);
-    //
-    // todo!()
-    //     pub fn init(cx: &mut AppContext) {
-    //         cx.add_action(MessageNotification::dismiss);
-    //         cx.add_action(
-    //             |_workspace: &mut Workspace, open_action: &OsOpen, cx: &mut ViewContext<Workspace>| {
-    //                 cx.platform().open_url(open_action.0.as_ref());
-    //             },
-    //         )
-    //     }
-
     enum NotificationMessage {
         Text(SharedString),
         Element(fn(TextStyle, &AppContext) -> AnyElement),
@@ -213,7 +188,7 @@ pub mod simple_message_notification {
 
     pub struct MessageNotification {
         message: NotificationMessage,
-        on_click: Option<Arc<dyn Fn(&mut ViewContext<Self>) + Send + Sync>>,
+        on_click: Option<Arc<dyn Fn(&mut ViewContext<Self>)>>,
         click_message: Option<SharedString>,
     }
 
@@ -252,7 +227,7 @@ pub mod simple_message_notification {
 
         pub fn on_click<F>(mut self, on_click: F) -> Self
         where
-            F: 'static + Send + Sync + Fn(&mut ViewContext<Self>),
+            F: 'static + Fn(&mut ViewContext<Self>),
         {
             self.on_click = Some(Arc::new(on_click));
             self

crates/workspace2/src/pane.rs 🔗

@@ -2,14 +2,15 @@ use crate::{
     item::{Item, ItemHandle, ItemSettings, WeakItemHandle},
     toolbar::Toolbar,
     workspace_settings::{AutosaveSetting, WorkspaceSettings},
-    SplitDirection, Workspace,
+    NewCenterTerminal, NewFile, NewSearch, SplitDirection, ToggleZoom, Workspace,
 };
 use anyhow::Result;
 use collections::{HashMap, HashSet, VecDeque};
 use gpui::{
-    actions, prelude::*, Action, AppContext, AsyncWindowContext, Div, EntityId, EventEmitter,
-    FocusHandle, Focusable, FocusableView, Model, Pixels, Point, PromptLevel, Render, Task, View,
-    ViewContext, VisualContext, WeakView, WindowContext,
+    actions, overlay, prelude::*, rems, Action, AnchorCorner, AnyWeakView, AppContext,
+    AsyncWindowContext, DismissEvent, Div, EntityId, EventEmitter, FocusHandle, Focusable,
+    FocusableView, Model, Pixels, Point, PromptLevel, Render, Task, View, ViewContext,
+    VisualContext, WeakView, WindowContext,
 };
 use parking_lot::Mutex;
 use project::{Project, ProjectEntryId, ProjectPath};
@@ -25,8 +26,10 @@ use std::{
     },
 };
 
-use ui::v_stack;
-use ui::{prelude::*, Color, Icon, IconButton, IconElement, Tooltip};
+use ui::{
+    h_stack, prelude::*, right_click_menu, Color, Icon, IconButton, IconElement, Label, Tooltip,
+};
+use ui::{v_stack, ContextMenu};
 use util::truncate_and_remove_front;
 
 #[derive(PartialEq, Clone, Copy, Deserialize, Debug)]
@@ -50,7 +53,7 @@ pub enum SaveIntent {
 
 //todo!("Do we need the default bound on actions? Decide soon")
 // #[register_action]
-#[derive(Clone, Deserialize, PartialEq, Debug)]
+#[derive(Action, Clone, Deserialize, PartialEq, Debug)]
 pub struct ActivateItem(pub usize);
 
 // #[derive(Clone, PartialEq)]
@@ -143,17 +146,24 @@ impl fmt::Debug for Event {
     }
 }
 
+struct FocusedView {
+    view: AnyWeakView,
+    focus_handle: FocusHandle,
+}
+
 pub struct Pane {
     focus_handle: FocusHandle,
     items: Vec<Box<dyn ItemHandle>>,
     activation_history: Vec<EntityId>,
     zoomed: bool,
     active_item_index: usize,
-    //     last_focused_view_by_item: HashMap<usize, AnyWeakViewHandle>,
+    last_focused_view_by_item: HashMap<EntityId, FocusHandle>,
     autoscroll: bool,
     nav_history: NavHistory,
     toolbar: View<Toolbar>,
-    //     tab_bar_context_menu: TabBarContextMenu,
+    tab_bar_focus_handle: FocusHandle,
+    new_item_menu: Option<View<ContextMenu>>,
+    split_item_menu: Option<View<ContextMenu>>,
     //     tab_context_menu: ViewHandle<ContextMenu>,
     workspace: WeakView<Workspace>,
     project: Model<Project>,
@@ -306,7 +316,7 @@ impl Pane {
             activation_history: Vec::new(),
             zoomed: false,
             active_item_index: 0,
-            // last_focused_view_by_item: Default::default(),
+            last_focused_view_by_item: Default::default(),
             autoscroll: false,
             nav_history: NavHistory(Arc::new(Mutex::new(NavHistoryState {
                 mode: NavigationMode::Normal,
@@ -318,6 +328,9 @@ impl Pane {
                 next_timestamp,
             }))),
             toolbar: cx.build_view(|_| Toolbar::new()),
+            tab_bar_focus_handle: cx.focus_handle(),
+            new_item_menu: None,
+            split_item_menu: None,
             // tab_bar_context_menu: TabBarContextMenu {
             //     kind: TabBarContextMenuKind::New,
             //     handle: context_menu,
@@ -392,9 +405,48 @@ impl Pane {
     }
 
     pub fn has_focus(&self, cx: &WindowContext) -> bool {
+        // todo!(); // inline this manually
         self.focus_handle.contains_focused(cx)
     }
 
+    fn focus_in(&mut self, cx: &mut ViewContext<Self>) {
+        if !self.has_focus(cx) {
+            cx.emit(Event::Focus);
+            cx.notify();
+        }
+
+        self.toolbar.update(cx, |toolbar, cx| {
+            toolbar.focus_changed(true, cx);
+        });
+
+        if let Some(active_item) = self.active_item() {
+            if self.focus_handle.is_focused(cx) {
+                // Pane was focused directly. We need to either focus a view inside the active item,
+                // or focus the active item itself
+                if let Some(weak_last_focused_view) =
+                    self.last_focused_view_by_item.get(&active_item.item_id())
+                {
+                    weak_last_focused_view.focus(cx);
+                    return;
+                }
+
+                active_item.focus_handle(cx).focus(cx);
+            } else if !self.tab_bar_focus_handle.contains_focused(cx) {
+                if let Some(focused) = cx.focused() {
+                    self.last_focused_view_by_item
+                        .insert(active_item.item_id(), focused);
+                }
+            }
+        }
+    }
+
+    fn focus_out(&mut self, cx: &mut ViewContext<Self>) {
+        self.toolbar.update(cx, |toolbar, cx| {
+            toolbar.focus_changed(false, cx);
+        });
+        cx.notify();
+    }
+
     pub fn active_item_index(&self) -> usize {
         self.active_item_index
     }
@@ -652,21 +704,16 @@ impl Pane {
             .position(|i| i.item_id() == item.item_id())
     }
 
-    // pub fn toggle_zoom(&mut self, _: &ToggleZoom, cx: &mut ViewContext<Self>) {
-    //     // Potentially warn the user of the new keybinding
-    //     let workspace_handle = self.workspace().clone();
-    //     cx.spawn(|_, mut cx| async move { notify_of_new_dock(&workspace_handle, &mut cx) })
-    //         .detach();
-
-    //     if self.zoomed {
-    //         cx.emit(Event::ZoomOut);
-    //     } else if !self.items.is_empty() {
-    //         if !self.has_focus {
-    //             cx.focus_self();
-    //         }
-    //         cx.emit(Event::ZoomIn);
-    //     }
-    // }
+    pub fn toggle_zoom(&mut self, _: &ToggleZoom, cx: &mut ViewContext<Self>) {
+        if self.zoomed {
+            cx.emit(Event::ZoomOut);
+        } else if !self.items.is_empty() {
+            if !self.focus_handle.contains_focused(cx) {
+                cx.focus_self();
+            }
+            cx.emit(Event::ZoomIn);
+        }
+    }
 
     pub fn activate_item(
         &mut self,
@@ -1403,7 +1450,7 @@ impl Pane {
         let close_right = ItemSettings::get_global(cx).close_position.right();
         let is_active = ix == self.active_item_index;
 
-        div()
+        let tab = div()
             .group("")
             .id(ix)
             .cursor_pointer()
@@ -1477,51 +1524,75 @@ impl Pane {
                     .children((!close_right).then(|| close_icon()))
                     .child(label)
                     .children(close_right.then(|| close_icon())),
-            )
+            );
+
+        right_click_menu(ix).trigger(tab).menu(|cx| {
+            ContextMenu::build(cx, |menu, cx| {
+                menu.action(
+                    "Close Active Item",
+                    CloseActiveItem { save_intent: None }.boxed_clone(),
+                    cx,
+                )
+                .action("Close Inactive Items", CloseInactiveItems.boxed_clone(), cx)
+                .action("Close Clean Items", CloseCleanItems.boxed_clone(), cx)
+                .action(
+                    "Close Items To The Left",
+                    CloseItemsToTheLeft.boxed_clone(),
+                    cx,
+                )
+                .action(
+                    "Close Items To The Right",
+                    CloseItemsToTheRight.boxed_clone(),
+                    cx,
+                )
+                .action(
+                    "Close All Items",
+                    CloseAllItems { save_intent: None }.boxed_clone(),
+                    cx,
+                )
+            })
+        })
     }
 
     fn render_tab_bar(&mut self, cx: &mut ViewContext<'_, Pane>) -> impl IntoElement {
         div()
-            .group("tab_bar")
             .id("tab_bar")
+            .group("tab_bar")
+            .track_focus(&self.tab_bar_focus_handle)
             .w_full()
+            // 30px @ 16px/rem
+            .h(rems(1.875))
+            .overflow_hidden()
             .flex()
+            .flex_none()
             .bg(cx.theme().colors().tab_bar_background)
             // Left Side
             .child(
-                div()
-                    .relative()
-                    .px_1()
+                h_stack()
+                    .px_2()
                     .flex()
                     .flex_none()
-                    .gap_2()
+                    .gap_1()
                     // Nav Buttons
                     .child(
-                        div()
-                            .right_0()
-                            .flex()
-                            .items_center()
-                            .gap_px()
-                            .child(
-                                div().border().border_color(gpui::red()).child(
-                                    IconButton::new("navigate_backward", Icon::ArrowLeft)
-                                        .on_click({
-                                            let view = cx.view().clone();
-                                            move |_, cx| view.update(cx, Self::navigate_backward)
-                                        })
-                                        .disabled(!self.can_navigate_backward()),
-                                ),
-                            )
-                            .child(
-                                div().border().border_color(gpui::red()).child(
-                                    IconButton::new("navigate_forward", Icon::ArrowRight)
-                                        .on_click({
-                                            let view = cx.view().clone();
-                                            move |_, cx| view.update(cx, Self::navigate_backward)
-                                        })
-                                        .disabled(!self.can_navigate_forward()),
-                                ),
-                            ),
+                        div().border().border_color(gpui::red()).child(
+                            IconButton::new("navigate_backward", Icon::ArrowLeft)
+                                .on_click({
+                                    let view = cx.view().clone();
+                                    move |_, cx| view.update(cx, Self::navigate_backward)
+                                })
+                                .disabled(!self.can_navigate_backward()),
+                        ),
+                    )
+                    .child(
+                        div().border().border_color(gpui::red()).child(
+                            IconButton::new("navigate_forward", Icon::ArrowRight)
+                                .on_click({
+                                    let view = cx.view().clone();
+                                    move |_, cx| view.update(cx, Self::navigate_backward)
+                                })
+                                .disabled(!self.can_navigate_forward()),
+                        ),
                     ),
             )
             .child(
@@ -1550,20 +1621,87 @@ impl Pane {
                             .gap_px()
                             .child(
                                 div()
+                                    .bg(gpui::blue())
                                     .border()
                                     .border_color(gpui::red())
-                                    .child(IconButton::new("plus", Icon::Plus)),
+                                    .child(IconButton::new("plus", Icon::Plus).on_click(
+                                        cx.listener(|this, _, cx| {
+                                            let menu = ContextMenu::build(cx, |menu, cx| {
+                                                menu.action("New File", NewFile.boxed_clone(), cx)
+                                                    .action(
+                                                        "New Terminal",
+                                                        NewCenterTerminal.boxed_clone(),
+                                                        cx,
+                                                    )
+                                                    .action(
+                                                        "New Search",
+                                                        NewSearch.boxed_clone(),
+                                                        cx,
+                                                    )
+                                            });
+                                            cx.subscribe(
+                                                &menu,
+                                                |this, _, event: &DismissEvent, cx| {
+                                                    this.focus(cx);
+                                                    this.new_item_menu = None;
+                                                },
+                                            )
+                                            .detach();
+                                            this.new_item_menu = Some(menu);
+                                        }),
+                                    ))
+                                    .when_some(self.new_item_menu.as_ref(), |el, new_item_menu| {
+                                        el.child(Self::render_menu_overlay(new_item_menu))
+                                    }),
                             )
                             .child(
                                 div()
                                     .border()
                                     .border_color(gpui::red())
-                                    .child(IconButton::new("split", Icon::Split)),
+                                    .child(IconButton::new("split", Icon::Split).on_click(
+                                        cx.listener(|this, _, cx| {
+                                            let menu = ContextMenu::build(cx, |menu, cx| {
+                                                menu.action(
+                                                    "Split Right",
+                                                    SplitRight.boxed_clone(),
+                                                    cx,
+                                                )
+                                                .action("Split Left", SplitLeft.boxed_clone(), cx)
+                                                .action("Split Up", SplitUp.boxed_clone(), cx)
+                                                .action("Split Down", SplitDown.boxed_clone(), cx)
+                                            });
+                                            cx.subscribe(
+                                                &menu,
+                                                |this, _, event: &DismissEvent, cx| {
+                                                    this.focus(cx);
+                                                    this.split_item_menu = None;
+                                                },
+                                            )
+                                            .detach();
+                                            this.split_item_menu = Some(menu);
+                                        }),
+                                    ))
+                                    .when_some(
+                                        self.split_item_menu.as_ref(),
+                                        |el, split_item_menu| {
+                                            el.child(Self::render_menu_overlay(split_item_menu))
+                                        },
+                                    ),
                             ),
                     ),
             )
     }
 
+    fn render_menu_overlay(menu: &View<ContextMenu>) -> Div {
+        div()
+            .absolute()
+            .z_index(1)
+            .bottom_0()
+            .right_0()
+            .size_0()
+            .child(overlay().anchor(AnchorCorner::TopRight).child(menu.clone()))
+    }
+
     //     fn render_tabs(&mut self, cx: &mut ViewContext<Self>) -> impl Element<Self> {
     //         let theme = theme::current(cx).clone();
 
@@ -1962,9 +2100,23 @@ impl Render for Pane {
     type Element = Focusable<Div>;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+        let this = cx.view().downgrade();
+
         v_stack()
             .key_context("Pane")
             .track_focus(&self.focus_handle)
+            .on_focus_in({
+                let this = this.clone();
+                move |event, cx| {
+                    this.update(cx, |this, cx| this.focus_in(cx)).ok();
+                }
+            })
+            .on_focus_out({
+                let this = this.clone();
+                move |event, cx| {
+                    this.update(cx, |this, cx| this.focus_out(cx)).ok();
+                }
+            })
             .on_action(cx.listener(|pane, _: &SplitLeft, cx| pane.split(SplitDirection::Left, cx)))
             .on_action(cx.listener(|pane, _: &SplitUp, cx| pane.split(SplitDirection::Up, cx)))
             .on_action(
@@ -1973,25 +2125,53 @@ impl Render for Pane {
             .on_action(cx.listener(|pane, _: &SplitDown, cx| pane.split(SplitDirection::Down, cx)))
             .on_action(cx.listener(|pane, _: &GoBack, cx| pane.navigate_backward(cx)))
             .on_action(cx.listener(|pane, _: &GoForward, cx| pane.navigate_forward(cx)))
-            //     cx.add_action(Pane::toggle_zoom);
-            //     cx.add_action(|pane: &mut Pane, action: &ActivateItem, cx| {
-            //         pane.activate_item(action.0, true, true, cx);
-            //     });
-            //     cx.add_action(|pane: &mut Pane, _: &ActivateLastItem, cx| {
-            //         pane.activate_item(pane.items.len() - 1, true, true, cx);
-            //     });
-            //     cx.add_action(|pane: &mut Pane, _: &ActivatePrevItem, cx| {
-            //         pane.activate_prev_item(true, cx);
-            //     });
-            //     cx.add_action(|pane: &mut Pane, _: &ActivateNextItem, cx| {
-            //         pane.activate_next_item(true, cx);
-            //     });
-            //     cx.add_async_action(Pane::close_active_item);
-            //     cx.add_async_action(Pane::close_inactive_items);
-            //     cx.add_async_action(Pane::close_clean_items);
-            //     cx.add_async_action(Pane::close_items_to_the_left);
-            //     cx.add_async_action(Pane::close_items_to_the_right);
-            //     cx.add_async_action(Pane::close_all_items);
+            .on_action(cx.listener(Pane::toggle_zoom))
+            .on_action(cx.listener(|pane: &mut Pane, action: &ActivateItem, cx| {
+                pane.activate_item(action.0, true, true, cx);
+            }))
+            .on_action(cx.listener(|pane: &mut Pane, _: &ActivateLastItem, cx| {
+                pane.activate_item(pane.items.len() - 1, true, true, cx);
+            }))
+            .on_action(cx.listener(|pane: &mut Pane, _: &ActivatePrevItem, cx| {
+                pane.activate_prev_item(true, cx);
+            }))
+            .on_action(cx.listener(|pane: &mut Pane, _: &ActivateNextItem, cx| {
+                pane.activate_next_item(true, 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));
+                }),
+            )
+            .on_action(
+                cx.listener(|pane: &mut Self, action: &CloseInactiveItems, cx| {
+                    pane.close_inactive_items(action, cx)
+                        .map(|task| task.detach_and_log_err(cx));
+                }),
+            )
+            .on_action(
+                cx.listener(|pane: &mut Self, action: &CloseCleanItems, cx| {
+                    pane.close_clean_items(action, cx)
+                        .map(|task| task.detach_and_log_err(cx));
+                }),
+            )
+            .on_action(
+                cx.listener(|pane: &mut Self, action: &CloseItemsToTheLeft, cx| {
+                    pane.close_items_to_the_left(action, cx)
+                        .map(|task| task.detach_and_log_err(cx));
+                }),
+            )
+            .on_action(
+                cx.listener(|pane: &mut Self, action: &CloseItemsToTheRight, cx| {
+                    pane.close_items_to_the_right(action, cx)
+                        .map(|task| task.detach_and_log_err(cx));
+                }),
+            )
+            .on_action(cx.listener(|pane: &mut Self, action: &CloseAllItems, cx| {
+                pane.close_all_items(action, cx)
+                    .map(|task| task.detach_and_log_err(cx));
+            }))
             .size_full()
             .on_action(
                 cx.listener(|pane: &mut Self, action: &CloseActiveItem, cx| {
@@ -2004,8 +2184,11 @@ impl Render for Pane {
             .child(if let Some(item) = self.active_item() {
                 div().flex().flex_1().child(item.to_any())
             } else {
-                // todo!()
-                div().child("Empty Pane")
+                h_stack()
+                    .items_center()
+                    .size_full()
+                    .justify_center()
+                    .child(Label::new("Open a file or project to get started.").color(Color::Muted))
             })
 
         // enum MouseNavigationHandler {}

crates/workspace2/src/status_bar.rs 🔗

@@ -6,7 +6,7 @@ use gpui::{
     WindowContext,
 };
 use ui::prelude::*;
-use ui::{h_stack, Button, Icon, IconButton};
+use ui::{h_stack, Icon, IconButton};
 use util::ResultExt;
 
 pub trait StatusItemView: Render {
@@ -53,39 +53,11 @@ impl Render for StatusBar {
                     .gap_4()
                     .child(
                         h_stack().gap_1().child(
-                            // TODO: Language picker
+                            // Feedback Tool
                             div()
                                 .border()
                                 .border_color(gpui::red())
-                                .child(Button::new("status_buffer_language", "Rust")),
-                        ),
-                    )
-                    .child(
-                        h_stack()
-                            .gap_1()
-                            .child(
-                                // Github tool
-                                div()
-                                    .border()
-                                    .border_color(gpui::red())
-                                    .child(IconButton::new("status-copilot", Icon::Copilot)),
-                            )
-                            .child(
-                                // Feedback Tool
-                                div()
-                                    .border()
-                                    .border_color(gpui::red())
-                                    .child(IconButton::new("status-feedback", Icon::Envelope)),
-                            ),
-                    )
-                    .child(
-                        // Bottom Dock
-                        h_stack().gap_1().child(
-                            // Terminal
-                            div()
-                                .border()
-                                .border_color(gpui::red())
-                                .child(IconButton::new("status-terminal", Icon::Terminal)),
+                                .child(IconButton::new("status-feedback", Icon::Envelope)),
                         ),
                     )
                     .child(

crates/workspace2/src/toolbar.rs 🔗

@@ -4,7 +4,7 @@ use gpui::{
     ViewContext, WindowContext,
 };
 use ui::prelude::*;
-use ui::{h_stack, v_stack, ButtonLike, Color, Icon, IconButton, Label};
+use ui::{h_stack, v_stack, Icon, IconButton};
 
 pub enum ToolbarItemEvent {
     ChangeLocation(ToolbarItemLocation),
@@ -87,17 +87,8 @@ impl Render for Toolbar {
             .child(
                 h_stack()
                     .justify_between()
-                    .child(
-                        // Toolbar left side
-                        h_stack().border().border_color(gpui::red()).p_1().child(
-                            ButtonLike::new("breadcrumb")
-                                .child(Label::new("crates/workspace2/src/toolbar.rs"))
-                                .child(Label::new("›").color(Color::Muted))
-                                .child(Label::new("impl Render for Toolbar"))
-                                .child(Label::new("›").color(Color::Muted))
-                                .child(Label::new("fn render")),
-                        ),
-                    )
+                    // Toolbar left side
+                    .children(self.items.iter().map(|(child, _)| child.to_any()))
                     // Toolbar right side
                     .child(
                         h_stack()
@@ -116,7 +107,6 @@ impl Render for Toolbar {
                             ),
                     ),
             )
-            .children(self.items.iter().map(|(child, _)| child.to_any()))
     }
 }
 

crates/workspace2/src/workspace2.rs 🔗

@@ -3585,87 +3585,6 @@ fn open_items(
     })
 }
 
-// todo!()
-// fn notify_of_new_dock(workspace: &WeakView<Workspace>, cx: &mut AsyncAppContext) {
-//     const NEW_PANEL_BLOG_POST: &str = "https://zed.dev/blog/new-panel-system";
-//     const NEW_DOCK_HINT_KEY: &str = "show_new_dock_key";
-//     const MESSAGE_ID: usize = 2;
-
-//     if workspace
-//         .read_with(cx, |workspace, cx| {
-//             workspace.has_shown_notification_once::<MessageNotification>(MESSAGE_ID, cx)
-//         })
-//         .unwrap_or(false)
-//     {
-//         return;
-//     }
-
-//     if db::kvp::KEY_VALUE_STORE
-//         .read_kvp(NEW_DOCK_HINT_KEY)
-//         .ok()
-//         .flatten()
-//         .is_some()
-//     {
-//         if !workspace
-//             .read_with(cx, |workspace, cx| {
-//                 workspace.has_shown_notification_once::<MessageNotification>(MESSAGE_ID, cx)
-//             })
-//             .unwrap_or(false)
-//         {
-//             cx.update(|cx| {
-//                 cx.update_global::<NotificationTracker, _, _>(|tracker, _| {
-//                     let entry = tracker
-//                         .entry(TypeId::of::<MessageNotification>())
-//                         .or_default();
-//                     if !entry.contains(&MESSAGE_ID) {
-//                         entry.push(MESSAGE_ID);
-//                     }
-//                 });
-//             });
-//         }
-
-//         return;
-//     }
-
-//     cx.spawn(|_| async move {
-//         db::kvp::KEY_VALUE_STORE
-//             .write_kvp(NEW_DOCK_HINT_KEY.to_string(), "seen".to_string())
-//             .await
-//             .ok();
-//     })
-//     .detach();
-
-//     workspace
-//         .update(cx, |workspace, cx| {
-//             workspace.show_notification_once(2, cx, |cx| {
-//                 cx.build_view(|_| {
-//                     MessageNotification::new_element(|text, _| {
-//                         Text::new(
-//                             "Looking for the dock? Try ctrl-`!\nshift-escape now zooms your pane.",
-//                             text,
-//                         )
-//                         .with_custom_runs(vec![26..32, 34..46], |_, bounds, cx| {
-//                             let code_span_background_color = settings::get::<ThemeSettings>(cx)
-//                                 .theme
-//                                 .editor
-//                                 .document_highlight_read_background;
-
-//                             cx.scene().push_quad(gpui::Quad {
-//                                 bounds,
-//                                 background: Some(code_span_background_color),
-//                                 border: Default::default(),
-//                                 corner_radii: (2.0).into(),
-//                             })
-//                         })
-//                         .into_any()
-//                     })
-//                     .with_click_message("Read more about the new panel system")
-//                     .on_click(|cx| cx.platform().open_url(NEW_PANEL_BLOG_POST))
-//                 })
-//             })
-//         })
-//         .ok();
-
 fn notify_if_database_failed(workspace: WindowHandle<Workspace>, cx: &mut AsyncAppContext) {
     const REPORT_ISSUE_URL: &str ="https://github.com/zed-industries/community/issues/new?assignees=&labels=defect%2Ctriage&template=2_bug_report.yml";
 
@@ -3719,6 +3638,8 @@ impl Render for Workspace {
             .items_start()
             .text_color(cx.theme().colors().text)
             .bg(cx.theme().colors().background)
+            .border()
+            .border_color(cx.theme().colors().border)
             .children(self.titlebar_item.clone())
             .child(
                 div()

crates/zed/Cargo.toml 🔗

@@ -172,7 +172,7 @@ osx_info_plist_exts = ["resources/info/*"]
 osx_url_schemes = ["zed-dev"]
 
 [package.metadata.bundle-nightly]
-icon = ["resources/app-icon-preview@2x.png", "resources/app-icon-preview.png"]
+icon = ["resources/app-icon-nightly@2x.png", "resources/app-icon-nightly.png"]
 identifier = "dev.zed.Zed-Nightly"
 name = "Zed Nightly"
 osx_minimum_system_version = "10.15.7"

crates/zed/src/only_instance.rs 🔗

@@ -39,7 +39,7 @@ pub enum IsOnlyInstance {
 }
 
 pub fn ensure_only_instance() -> IsOnlyInstance {
-    if *db::ZED_STATELESS {
+    if *db::ZED_STATELESS || *util::channel::RELEASE_CHANNEL == ReleaseChannel::Dev {
         return IsOnlyInstance::Yes;
     }
 

crates/zed2/Cargo.toml 🔗

@@ -19,7 +19,7 @@ ai = { package = "ai2", path = "../ai2"}
 audio = { package = "audio2", path = "../audio2" }
 activity_indicator = { package = "activity_indicator2", path = "../activity_indicator2"}
 auto_update = { package = "auto_update2", path = "../auto_update2" }
-# breadcrumbs = { path = "../breadcrumbs" }
+breadcrumbs = { package = "breadcrumbs2", path = "../breadcrumbs2" }
 call = { package = "call2", path = "../call2" }
 channel = { package = "channel2", path = "../channel2" }
 cli = { path = "../cli" }
@@ -30,7 +30,7 @@ command_palette = { package="command_palette2", path = "../command_palette2" }
 client = { package = "client2", path = "../client2" }
 # clock = { path = "../clock" }
 copilot = { package = "copilot2", path = "../copilot2" }
-# copilot_button = { path = "../copilot_button" }
+copilot_button = { package = "copilot_button2", path = "../copilot_button2" }
 diagnostics = { package = "diagnostics2", path = "../diagnostics2" }
 db = { package = "db2", path = "../db2" }
 editor = { package="editor2", path = "../editor2" }
@@ -44,7 +44,7 @@ gpui = { package = "gpui2", path = "../gpui2" }
 install_cli = { package = "install_cli2", path = "../install_cli2" }
 journal = { package = "journal2", path = "../journal2" }
 language = { package = "language2", path = "../language2" }
-# language_selector = { path = "../language_selector" }
+language_selector = { package = "language_selector2", path = "../language_selector2" }
 lsp = { package = "lsp2", path = "../lsp2" }
 menu = { package = "menu2", path = "../menu2" }
 # language_tools = { path = "../language_tools" }
@@ -167,7 +167,7 @@ osx_info_plist_exts = ["resources/info/*"]
 osx_url_schemes = ["zed-dev"]
 
 [package.metadata.bundle-nightly]
-icon = ["resources/app-icon-preview@2x.png", "resources/app-icon-preview.png"]
+icon = ["resources/app-icon-nightly@2x.png", "resources/app-icon-nightly.png"]
 identifier = "dev.zed.Zed-Dev"
 name = "Zed Nightly"
 osx_minimum_system_version = "10.15.7"

crates/zed2/src/main.rs 🔗

@@ -216,7 +216,7 @@ fn main() {
         terminal_view::init(cx);
 
         // journal2::init(app_state.clone(), cx);
-        // language_selector::init(cx);
+        language_selector::init(cx);
         theme_selector::init(cx);
         // activity_indicator::init(cx);
         // language_tools::init(cx);

crates/zed2/src/only_instance.rs 🔗

@@ -39,7 +39,7 @@ pub enum IsOnlyInstance {
 }
 
 pub fn ensure_only_instance() -> IsOnlyInstance {
-    if *db::ZED_STATELESS {
+    if *db::ZED_STATELESS || *util::channel::RELEASE_CHANNEL == ReleaseChannel::Dev {
         return IsOnlyInstance::Yes;
     }
 

crates/zed2/src/zed2.rs 🔗

@@ -7,6 +7,7 @@ mod only_instance;
 mod open_listener;
 
 pub use assets::*;
+use breadcrumbs::Breadcrumbs;
 use collections::VecDeque;
 use editor::{Editor, MultiBuffer};
 use gpui::{
@@ -95,11 +96,11 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
                 if let workspace::Event::PaneAdded(pane) = event {
                     pane.update(cx, |pane, cx| {
                         pane.toolbar().update(cx, |toolbar, cx| {
-                            // todo!()
-                            //     let breadcrumbs = cx.add_view(|_| Breadcrumbs::new(workspace));
-                            //     toolbar.add_item(breadcrumbs, cx);
+                            let breadcrumbs = cx.build_view(|_| Breadcrumbs::new(workspace));
+                            toolbar.add_item(breadcrumbs, cx);
                             let buffer_search_bar = cx.build_view(search::BufferSearchBar::new);
                             toolbar.add_item(buffer_search_bar.clone(), cx);
+                            // todo!()
                             //     let quick_action_bar = cx.add_view(|_| {
                             //         QuickActionBar::new(buffer_search_bar, workspace)
                             //     });
@@ -135,14 +136,14 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
         //         cx.add_view(|cx| CollabTitlebarItem::new(workspace, &workspace_handle, cx));
         //     workspace.set_titlebar_item(collab_titlebar_item.into_any(), cx);
 
-        //     let copilot =
-        //         cx.add_view(|cx| copilot_button::CopilotButton::new(app_state.fs.clone(), cx));
+        let copilot =
+            cx.build_view(|cx| copilot_button::CopilotButton::new(app_state.fs.clone(), cx));
         let diagnostic_summary =
             cx.build_view(|cx| diagnostics::items::DiagnosticIndicator::new(workspace, cx));
         let activity_indicator =
             activity_indicator::ActivityIndicator::new(workspace, app_state.languages.clone(), cx);
-        //     let active_buffer_language =
-        //         cx.add_view(|_| language_selector::ActiveBufferLanguage::new(workspace));
+        let active_buffer_language =
+            cx.build_view(|_| language_selector::ActiveBufferLanguage::new(workspace));
         //     let vim_mode_indicator = cx.add_view(|cx| vim::ModeIndicator::new(cx));
         //     let feedback_button = cx.add_view(|_| {
         //         feedback::deploy_feedback_button::DeployFeedbackButton::new(workspace)
@@ -153,8 +154,8 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
             status_bar.add_left_item(activity_indicator, cx);
 
             // status_bar.add_right_item(feedback_button, cx);
-            // status_bar.add_right_item(copilot, cx);
-            // status_bar.add_right_item(active_buffer_language, cx);
+            status_bar.add_right_item(copilot, cx);
+            status_bar.add_right_item(active_buffer_language, cx);
             // status_bar.add_right_item(vim_mode_indicator, cx);
             status_bar.add_right_item(cursor_position, cx);
         });

test.rs 🔗

@@ -1,5618 +0,0 @@
-#![feature(prelude_import)]
-#![allow(dead_code, unused_variables)]
-#[prelude_import]
-use std::prelude::rust_2021::*;
-#[macro_use]
-extern crate std;
-use color::black;
-use components::button;
-use element::Element;
-use frame::frame;
-use gpui::{
-    geometry::{rect::RectF, vector::vec2f},
-    platform::WindowOptions,aa
-};
-use log::LevelFilter;a
-use simplelog::SimpleLogger;
-use themes::{rose_pine, ThemeColors};
-use view::view;a
-mod adapter {
-    use crate::element::AnyElement;
-    use crate::element::{LayoutContext, PaintContext};
-    use gpui::{geometry::rect::RectF, LayoutEngine};aaaa
-    use util::ResultExt;
-    pub struct Adapter<V>(pub(crate) AnyElement<V>);
-    impl<V: 'static> gpui::Element<V> for Adapter<V> {aa
-        type LayoutState = Option<LayaoutEngine>;
-        type PaintState = ();
-        fn layout(
-            &mut self,
-            constraint: gpui::SizeConstraint,
-            view: &mut V,
-            cx: &mut LayoutContext<V>,aa
-        ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) {
-            cx.push_layout_engine(LayoutEngine::new());
-            let node = self.0.layout(view, cx).log_err();a
-            if let Some(node) = node {
-                let layout_engine = cx.layout_engine().unwrap();
-                layout_engine.compute_layout(node, constraint.max).log_err();
-            }
-            let layout_engine = cx.pop_layout_engine();
-            if true {a
-                if !layout_engine.is_some() {
-                    ::core::panicking::panic("assertion failed: layout_engine.is_some()")
-                }
-            }
-            (constraint.max, layout_engine)a
-        }
-        fn paint(a
-            &mut self,
-            scene: &mut gpui::SceneBuilder,
-            bounds: RectF,
-            visible_bounds: RectF,
-            layout_engine: &mut Option<LayoutEngine>,
-            view: &mut V,
-            legacy_cx: &mut gpui::PaintContext<V>,aaa
-        ) -> Self::PaintState {
-            legacy_cx.push_layout_engine(layout_engine.take().unwrap());
-            let mut cx = PaintContext::new(legacy_cx, scene);
-            self.0.paint(view, &mut cx).log_err();
-            *layout_engine = legacy_cx.pop_layout_engine();
-            if true {
-                if !layout_engine.is_some() {
-                    ::core::panicking::panic("assertion failed: layout_engine.is_some()")
-                }
-            }
-        }
-        fn rect_for_text_range(
-            &self,
-            range_utf16: std::ops::Range<usize>,
-            bounds: RectF,
-            visible_bounds: RectF,
-            layout: &Self::LayoutState,
-            paint: &Self::PaintState,
-            view: &V,
-            cx: &gpui::ViewContext<V>,
-        ) -> Option<RectF> {
-            ::core::panicking::panic("not yet implemented")
-        }
-        fn debug(
-            &self,
-            bounds: RectF,
-            layout: &Self::LayoutState,
-            paint: &Self::PaintState,
-            view: &V,
-            cx: &gpui::ViewContext<V>,
-        ) -> gpui::serde_json::Value {
-            ::core::panicking::panic("not yet implemented")
-        }
-    }
-}
-mod color {
-    #![allow(dead_code)]
-    use smallvec::SmallVec;
-    use std::{num::ParseIntError, ops::Range};
-    pub fn rgb<C: From<Rgba>>(hex: u32) -> C {
-        let r = ((hex >> 16) & 0xFF) as f32 / 255.0;
-        let g = ((hex >> 8) & 0xFF) as f32 / 255.0;
-        let b = (hex & 0xFF) as f32 / 255.0;
-        Rgba { r, g, b, a: 1.0 }.into()
-    }
-    pub struct Rgba {
-        pub r: f32,
-        pub g: f32,
-        pub b: f32,
-        pub a: f32,
-    }
-    #[automatically_derived]
-    impl ::core::clone::Clone for Rgba {
-        #[inline]
-        fn clone(&self) -> Rgba {
-            let _: ::core::clone::AssertParamIsClone<f32>;
-            *self
-        }
-    }
-    #[automatically_derived]
-    impl ::core::marker::Copy for Rgba {}
-    #[automatically_derived]
-    impl ::core::default::Default for Rgba {
-        #[inline]
-        fn default() -> Rgba {
-            Rgba {
-                r: ::core::default::Default::default(),
-                g: ::core::default::Default::default(),
-                b: ::core::default::Default::default(),
-                a: ::core::default::Default::default(),
-            }
-        }
-    }
-    #[automatically_derived]
-    impl ::core::fmt::Debug for Rgba {
-        fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-            ::core::fmt::Formatter::debug_struct_field4_finish(
-                f, "Rgba", "r", &self.r, "g", &self.g, "b", &self.b, "a", &&self.a,
-            )
-        }
-    }
-    pub trait Lerp {
-        fn lerp(&self, level: f32) -> Hsla;
-    }
-    impl Lerp for Range<Hsla> {
-        fn lerp(&self, level: f32) -> Hsla {
-            let level = level.clamp(0., 1.);
-            Hsla {
-                h: self.start.h + (level * (self.end.h - self.start.h)),
-                s: self.start.s + (level * (self.end.s - self.start.s)),
-                l: self.start.l + (level * (self.end.l - self.start.l)),
-                a: self.start.a + (level * (self.end.a - self.start.a)),
-            }
-        }
-    }
-    impl From<gpui::color::Color> for Rgba {
-        fn from(value: gpui::color::Color) -> Self {
-            Self {
-                r: value.0.r as f32 / 255.0,
-                g: value.0.g as f32 / 255.0,
-                b: value.0.b as f32 / 255.0,
-                a: value.0.a as f32 / 255.0,
-            }
-        }
-    }
-    impl From<Hsla> for Rgba {
-        fn from(color: Hsla) -> Self {
-            let h = color.h;
-            let s = color.s;
-            let l = color.l;
-            let c = (1.0 - (2.0 * l - 1.0).abs()) * s;
-            let x = c * (1.0 - ((h * 6.0) % 2.0 - 1.0).abs());
-            let m = l - c / 2.0;
-            let cm = c + m;
-            let xm = x + m;
-            let (r, g, b) = match (h * 6.0).floor() as i32 {
-                0 | 6 => (cm, xm, m),
-                1 => (xm, cm, m),
-                2 => (m, cm, xm),
-                3 => (m, xm, cm),
-                4 => (xm, m, cm),
-                _ => (cm, m, xm),
-            };
-            Rgba {
-                r,
-                g,
-                b,
-                a: color.a,
-            }
-        }
-    }
-    impl TryFrom<&'_ str> for Rgba {
-        type Error = ParseIntError;
-        fn try_from(value: &'_ str) -> Result<Self, Self::Error> {
-            let r = u8::from_str_radix(&value[1..3], 16)? as f32 / 255.0;
-            let g = u8::from_str_radix(&value[3..5], 16)? as f32 / 255.0;
-            let b = u8::from_str_radix(&value[5..7], 16)? as f32 / 255.0;
-            let a = if value.len() > 7 {
-                u8::from_str_radix(&value[7..9], 16)? as f32 / 255.0
-            } else {
-                1.0
-            };
-            Ok(Rgba { r, g, b, a })
-        }
-    }
-    impl Into<gpui::color::Color> for Rgba {
-        fn into(self) -> gpui::color::Color {
-            gpui::color::rgba(self.r, self.g, self.b, self.a)
-        }
-    }
-    pub struct Hsla {
-        pub h: f32,
-        pub s: f32,
-        pub l: f32,
-        pub a: f32,
-    }
-    #[automatically_derived]
-    impl ::core::default::Default for Hsla {
-        #[inline]
-        fn default() -> Hsla {
-            Hsla {
-                h: ::core::default::Default::default(),
-                s: ::core::default::Default::default(),
-                l: ::core::default::Default::default(),
-                a: ::core::default::Default::default(),
-            }
-        }
-    }
-    #[automatically_derived]
-    impl ::core::marker::Copy for Hsla {}
-    #[automatically_derived]
-    impl ::core::clone::Clone for Hsla {
-        #[inline]
-        fn clone(&self) -> Hsla {
-            let _: ::core::clone::AssertParamIsClone<f32>;
-            *self
-        }
-    }
-    #[automatically_derived]
-    impl ::core::fmt::Debug for Hsla {
-        fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-            ::core::fmt::Formatter::debug_struct_field4_finish(
-                f, "Hsla", "h", &self.h, "s", &self.s, "l", &self.l, "a", &&self.a,
-            )
-        }
-    }
-    #[automatically_derived]
-    impl ::core::marker::StructuralPartialEq for Hsla {}
-    #[automatically_derived]
-    impl ::core::cmp::PartialEq for Hsla {
-        #[inline]
-        fn eq(&self, other: &Hsla) -> bool {
-            self.h == other.h && self.s == other.s && self.l == other.l && self.a == other.a
-        }
-    }
-    pub fn hsla(h: f32, s: f32, l: f32, a: f32) -> Hsla {
-        Hsla {
-            h: h.clamp(0., 1.),
-            s: s.clamp(0., 1.),
-            l: l.clamp(0., 1.),
-            a: a.clamp(0., 1.),
-        }
-    }
-    pub fn black() -> Hsla {
-        Hsla {
-            h: 0.,
-            s: 0.,
-            l: 0.,
-            a: 1.,
-        }
-    }
-    impl From<Rgba> for Hsla {
-        fn from(color: Rgba) -> Self {
-            let r = color.r;
-            let g = color.g;
-            let b = color.b;
-            let max = r.max(g.max(b));
-            let min = r.min(g.min(b));
-            let delta = max - min;
-            let l = (max + min) / 2.0;
-            let s = if l == 0.0 || l == 1.0 {
-                0.0
-            } else if l < 0.5 {
-                delta / (2.0 * l)
-            } else {
-                delta / (2.0 - 2.0 * l)
-            };
-            let h = if delta == 0.0 {
-                0.0
-            } else if max == r {
-                ((g - b) / delta).rem_euclid(6.0) / 6.0
-            } else if max == g {
-                ((b - r) / delta + 2.0) / 6.0
-            } else {
-                ((r - g) / delta + 4.0) / 6.0
-            };
-            Hsla {
-                h,
-                s,
-                l,
-                a: color.a,
-            }
-        }
-    }
-    impl Hsla {
-        /// Scales the saturation and lightness by the given values, clamping at 1.0.
-        pub fn scale_sl(mut self, s: f32, l: f32) -> Self {
-            self.s = (self.s * s).clamp(0., 1.);
-            self.l = (self.l * l).clamp(0., 1.);
-            self
-        }
-        /// Increases the saturation of the color by a certain amount, with a max
-        /// value of 1.0.
-        pub fn saturate(mut self, amount: f32) -> Self {
-            self.s += amount;
-            self.s = self.s.clamp(0.0, 1.0);
-            self
-        }
-        /// Decreases the saturation of the color by a certain amount, with a min
-        /// value of 0.0.
-        pub fn desaturate(mut self, amount: f32) -> Self {
-            self.s -= amount;
-            self.s = self.s.max(0.0);
-            if self.s < 0.0 {
-                self.s = 0.0;
-            }
-            self
-        }
-        /// Brightens the color by increasing the lightness by a certain amount,
-        /// with a max value of 1.0.
-        pub fn brighten(mut self, amount: f32) -> Self {
-            self.l += amount;
-            self.l = self.l.clamp(0.0, 1.0);
-            self
-        }
-        /// Darkens the color by decreasing the lightness by a certain amount,
-        /// with a max value of 0.0.
-        pub fn darken(mut self, amount: f32) -> Self {
-            self.l -= amount;
-            self.l = self.l.clamp(0.0, 1.0);
-            self
-        }
-    }
-    impl From<gpui::color::Color> for Hsla {
-        fn from(value: gpui::color::Color) -> Self {
-            Rgba::from(value).into()
-        }
-    }
-    impl Into<gpui::color::Color> for Hsla {
-        fn into(self) -> gpui::color::Color {
-            Rgba::from(self).into()
-        }
-    }
-    pub struct ColorScale {
-        colors: SmallVec<[Hsla; 2]>,
-        positions: SmallVec<[f32; 2]>,
-    }
-    pub fn scale<I, C>(colors: I) -> ColorScale
-    where
-        I: IntoIterator<Item = C>,
-        C: Into<Hsla>,
-    {
-        let mut scale = ColorScale {
-            colors: colors.into_iter().map(Into::into).collect(),
-            positions: SmallVec::new(),
-        };
-        let num_colors: f32 = scale.colors.len() as f32 - 1.0;
-        scale.positions = (0..scale.colors.len())
-            .map(|i| i as f32 / num_colors)
-            .collect();
-        scale
-    }
-    impl ColorScale {
-        fn at(&self, t: f32) -> Hsla {
-            if true {
-                if !(0.0 <= t && t <= 1.0) {
-                    {
-                        ::core::panicking::panic_fmt(format_args!(
-                            "t value {0} is out of range. Expected value in range 0.0 to 1.0",
-                            t,
-                        ));
-                    }
-                }
-            }
-            let position = match self
-                .positions
-                .binary_search_by(|a| a.partial_cmp(&t).unwrap())
-            {
-                Ok(index) | Err(index) => index,
-            };
-            let lower_bound = position.saturating_sub(1);
-            let upper_bound = position.min(self.colors.len() - 1);
-            let lower_color = &self.colors[lower_bound];
-            let upper_color = &self.colors[upper_bound];
-            match upper_bound.checked_sub(lower_bound) {
-                Some(0) | None => *lower_color,
-                Some(_) => {
-                    let interval_t = (t - self.positions[lower_bound])
-                        / (self.positions[upper_bound] - self.positions[lower_bound]);
-                    let h = lower_color.h + interval_t * (upper_color.h - lower_color.h);
-                    let s = lower_color.s + interval_t * (upper_color.s - lower_color.s);
-                    let l = lower_color.l + interval_t * (upper_color.l - lower_color.l);
-                    let a = lower_color.a + interval_t * (upper_color.a - lower_color.a);
-                    Hsla { h, s, l, a }
-                }
-            }
-        }
-    }
-}
-mod components {
-    use crate::{
-        element::{Element, ElementMetadata},
-        frame,
-        text::ArcCow,
-        themes::rose_pine,
-    };
-    use gpui::{platform::MouseButton, ViewContext};
-    use gpui_macros::Element;
-    use std::{marker::PhantomData, rc::Rc};
-    struct ButtonHandlers<V, D> {
-        click: Option<Rc<dyn Fn(&mut V, &D, &mut ViewContext<V>)>>,
-    }
-    impl<V, D> Default for ButtonHandlers<V, D> {
-        fn default() -> Self {
-            Self { click: None }
-        }
-    }
-    #[element_crate = "crate"]
-    pub struct Button<V: 'static, D: 'static> {
-        metadata: ElementMetadata<V>,
-        handlers: ButtonHandlers<V, D>,
-        label: Option<ArcCow<'static, str>>,
-        icon: Option<ArcCow<'static, str>>,
-        data: Rc<D>,
-        view_type: PhantomData<V>,
-    }
-    impl<V: 'static, D: 'static> crate::element::Element<V> for Button<V, D> {
-        type Layout = crate::element::AnyElement<V>;
-        fn declared_style(&mut self) -> &mut crate::style::OptionalStyle {
-            &mut self.metadata.style
-        }
-        fn handlers_mut(&mut self) -> &mut Vec<crate::element::EventHandler<V>> {
-            &mut self.metadata.handlers
-        }
-        fn layout(
-            &mut self,
-            view: &mut V,
-            cx: &mut crate::element::LayoutContext<V>,
-        ) -> anyhow::Result<(taffy::tree::NodeId, Self::Layout)> {
-            let mut element = self.render(view, cx).into_any();
-            let node_id = element.layout(view, cx)?;
-            Ok((node_id, element))
-        }
-        fn paint<'a>(
-            &mut self,
-            layout: crate::element::Layout<'a, Self::Layout>,
-            view: &mut V,
-            cx: &mut crate::element::PaintContext<V>,
-        ) -> anyhow::Result<()> {
-            layout.from_element.paint(view, cx)?;
-            Ok(())
-        }
-    }
-    impl<V: 'static, D: 'static> crate::element::IntoElement<V> for Button<V, D> {
-        type Element = Self;
-        fn into_element(self) -> Self {
-            self
-        }
-    }
-    impl<V: 'static> Button<V, ()> {
-        fn new() -> Self {
-            Self {
-                metadata: Default::default(),
-                handlers: ButtonHandlers::default(),
-                label: None,
-                icon: None,
-                data: Rc::new(()),
-                view_type: PhantomData,
-            }
-        }
-        pub fn data<D: 'static>(self, data: D) -> Button<V, D> {
-            Button {
-                metadata: Default::default(),
-                handlers: ButtonHandlers::default(),
-                label: self.label,
-                icon: self.icon,
-                data: Rc::new(data),
-                view_type: PhantomData,
-            }
-        }
-    }
-    impl<V: 'static, D: 'static> Button<V, D> {
-        pub fn label(mut self, label: impl Into<ArcCow<'static, str>>) -> Self {
-            self.label = Some(label.into());
-            self
-        }
-        pub fn icon(mut self, icon: impl Into<ArcCow<'static, str>>) -> Self {
-            self.icon = Some(icon.into());
-            self
-        }
-        pub fn click(self, handler: impl Fn(&mut V, &D, &mut ViewContext<V>) + 'static) -> Self {
-            let data = self.data.clone();
-            Element::click(self, MouseButton::Left, move |view, _, cx| {
-                handler(view, data.as_ref(), cx);
-            })
-        }
-    }
-    pub fn button<V>() -> Button<V, ()> {
-        Button::new()
-    }
-    impl<V: 'static, D: 'static> Button<V, D> {
-        fn render(&mut self, view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
-            let button = frame()
-                .fill(rose_pine::dawn().error(0.5))
-                .h_4()
-                .children(self.label.clone());
-            if let Some(handler) = self.handlers.click.clone() {
-                let data = self.data.clone();
-                button.mouse_down(MouseButton::Left, move |view, event, cx| {
-                    handler(view, data.as_ref(), cx)
-                })
-            } else {
-                button
-            }
-        }
-    }
-}
-mod element {
-    pub use crate::paint_context::PaintContext;
-    use crate::{
-        adapter::Adapter,
-        color::Hsla,
-        hoverable::Hoverable,
-        style::{Display, Fill, OptionalStyle, Overflow, Position},
-    };
-    use anyhow::Result;
-    pub use gpui::LayoutContext;
-    use gpui::{
-        geometry::{DefinedLength, Length, OptionalPoint},
-        platform::{MouseButton, MouseButtonEvent},
-        EngineLayout, EventContext, RenderContext, ViewContext,
-    };
-    use gpui_macros::tailwind_lengths;
-    use std::{
-        any::{Any, TypeId},
-        cell::Cell,
-        rc::Rc,
-    };
-    pub use taffy::tree::NodeId;
-    pub struct Layout<'a, E: ?Sized> {
-        pub from_engine: EngineLayout,
-        pub from_element: &'a mut E,
-    }
-    pub struct ElementMetadata<V> {
-        pub style: OptionalStyle,
-        pub handlers: Vec<EventHandler<V>>,
-    }
-    pub struct EventHandler<V> {
-        handler: Rc<dyn Fn(&mut V, &dyn Any, &mut EventContext<V>)>,
-        event_type: TypeId,
-        outside_bounds: bool,
-    }
-    impl<V> Clone for EventHandler<V> {
-        fn clone(&self) -> Self {
-            Self {
-                handler: self.handler.clone(),
-                event_type: self.event_type,
-                outside_bounds: self.outside_bounds,
-            }
-        }
-    }
-    impl<V> Default for ElementMetadata<V> {
-        fn default() -> Self {
-            Self {
-                style: OptionalStyle::default(),
-                handlers: Vec::new(),
-            }
-        }
-    }
-    pub trait Element<V: 'static>: 'static {
-        type Layout: 'static;
-        fn declared_style(&mut self) -> &mut OptionalStyle;
-        fn computed_style(&mut self) -> &OptionalStyle {
-            self.declared_style()
-        }
-        fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>>;
-        fn layout(
-            &mut self,
-            view: &mut V,
-            cx: &mut LayoutContext<V>,
-        ) -> Result<(NodeId, Self::Layout)>;
-        fn paint<'a>(
-            &mut self,
-            layout: Layout<Self::Layout>,
-            view: &mut V,
-            cx: &mut PaintContext<V>,
-        ) -> Result<()>;
-        /// Convert to a dynamically-typed element suitable for layout and paint.
-        fn into_any(self) -> AnyElement<V>
-        where
-            Self: 'static + Sized,
-        {
-            AnyElement {
-                element: Box::new(self) as Box<dyn ElementObject<V>>,
-                layout: None,
-            }
-        }
-        fn adapt(self) -> Adapter<V>
-        where
-            Self: Sized,
-            Self: Element<V>,
-        {
-            Adapter(self.into_any())
-        }
-        fn click(
-            self,
-            button: MouseButton,
-            handler: impl Fn(&mut V, &MouseButtonEvent, &mut ViewContext<V>) + 'static,
-        ) -> Self
-        where
-            Self: Sized,
-        {
-            let pressed: Rc<Cell<bool>> = Default::default();
-            self.mouse_down(button, {
-                let pressed = pressed.clone();
-                move |_, _, _| {
-                    pressed.set(true);
-                }
-            })
-            .mouse_up_outside(button, {
-                let pressed = pressed.clone();
-                move |_, _, _| {
-                    pressed.set(false);
-                }
-            })
-            .mouse_up(button, move |view, event, event_cx| {
-                if pressed.get() {
-                    pressed.set(false);
-                    handler(view, event, event_cx);
-                }
-            })
-        }
-        fn mouse_down(
-            mut self,
-            button: MouseButton,
-            handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
-        ) -> Self
-        where
-            Self: Sized,
-        {
-            self.handlers_mut().push(EventHandler {
-                handler: Rc::new(move |view, event, event_cx| {
-                    let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
-                    if event.button == button && event.is_down {
-                        handler(view, event, event_cx);
-                    }
-                }),
-                event_type: TypeId::of::<MouseButtonEvent>(),
-                outside_bounds: false,
-            });
-            self
-        }
-        fn mouse_down_outside(
-            mut self,
-            button: MouseButton,
-            handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
-        ) -> Self
-        where
-            Self: Sized,
-        {
-            self.handlers_mut().push(EventHandler {
-                handler: Rc::new(move |view, event, event_cx| {
-                    let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
-                    if event.button == button && event.is_down {
-                        handler(view, event, event_cx);
-                    }
-                }),
-                event_type: TypeId::of::<MouseButtonEvent>(),
-                outside_bounds: true,
-            });
-            self
-        }
-        fn mouse_up(
-            mut self,
-            button: MouseButton,
-            handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
-        ) -> Self
-        where
-            Self: Sized,
-        {
-            self.handlers_mut().push(EventHandler {
-                handler: Rc::new(move |view, event, event_cx| {
-                    let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
-                    if event.button == button && !event.is_down {
-                        handler(view, event, event_cx);
-                    }
-                }),
-                event_type: TypeId::of::<MouseButtonEvent>(),
-                outside_bounds: false,
-            });
-            self
-        }
-        fn mouse_up_outside(
-            mut self,
-            button: MouseButton,
-            handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
-        ) -> Self
-        where
-            Self: Sized,
-        {
-            self.handlers_mut().push(EventHandler {
-                handler: Rc::new(move |view, event, event_cx| {
-                    let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
-                    if event.button == button && !event.is_down {
-                        handler(view, event, event_cx);
-                    }
-                }),
-                event_type: TypeId::of::<MouseButtonEvent>(),
-                outside_bounds: true,
-            });
-            self
-        }
-        fn block(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().display = Some(Display::Block);
-            self
-        }
-        fn flex(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().display = Some(Display::Flex);
-            self
-        }
-        fn grid(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().display = Some(Display::Grid);
-            self
-        }
-        fn overflow_visible(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().overflow = OptionalPoint {
-                x: Some(Overflow::Visible),
-                y: Some(Overflow::Visible),
-            };
-            self
-        }
-        fn overflow_hidden(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().overflow = OptionalPoint {
-                x: Some(Overflow::Hidden),
-                y: Some(Overflow::Hidden),
-            };
-            self
-        }
-        fn overflow_scroll(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().overflow = OptionalPoint {
-                x: Some(Overflow::Scroll),
-                y: Some(Overflow::Scroll),
-            };
-            self
-        }
-        fn overflow_x_visible(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().overflow.x = Some(Overflow::Visible);
-            self
-        }
-        fn overflow_x_hidden(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().overflow.x = Some(Overflow::Hidden);
-            self
-        }
-        fn overflow_x_scroll(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().overflow.x = Some(Overflow::Scroll);
-            self
-        }
-        fn overflow_y_visible(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().overflow.y = Some(Overflow::Visible);
-            self
-        }
-        fn overflow_y_hidden(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().overflow.y = Some(Overflow::Hidden);
-            self
-        }
-        fn overflow_y_scroll(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().overflow.y = Some(Overflow::Scroll);
-            self
-        }
-        fn relative(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().position = Some(Position::Relative);
-            self
-        }
-        fn absolute(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().position = Some(Position::Absolute);
-            self
-        }
-        fn inset_0(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Pixels(0.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_px(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Pixels(1.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_0_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.125).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_1(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.25).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_1_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.375).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_2(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.5).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_2_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.625).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_3(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.75).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_3_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.875).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_4(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.25).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_6(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.5).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_7(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.75).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_8(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_9(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.25).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_10(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.5).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_11(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.75).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_12(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(3.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_14(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(3.5).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_16(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(4.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_20(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(5.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_24(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(6.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_28(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(7.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_32(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(8.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_36(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(9.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_40(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(10.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_44(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(11.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_48(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(12.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_52(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(13.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_56(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(14.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_60(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(15.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_64(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(16.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_72(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(18.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_80(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(20.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_96(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(24.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_half(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_1_3rd(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(33.333333).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_2_3rd(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(66.666667).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_1_4th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(25.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_2_4th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_3_4th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(75.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_1_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(20.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_2_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(40.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_3_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(60.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_4_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(80.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_1_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(16.666667).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_2_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(33.333333).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_3_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_4_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(66.666667).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_5_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(83.333333).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_1_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(8.333333).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_2_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(16.666667).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_3_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(25.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_4_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(33.333333).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_5_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(41.666667).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_6_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_7_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(58.333333).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_8_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(66.666667).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_9_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(75.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_10_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(83.333333).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_11_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(91.666667).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn inset_full(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(100.).into();
-            {
-                let inset = self
-                    .computed_style()
-                    .inset
-                    .get_or_insert_with(Default::default);
-                inset.top = length;
-                inset.right = length;
-                inset.bottom = length;
-                inset.left = length;
-                self
-            }
-        }
-        fn w(mut self, width: impl Into<Length>) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().size.width = Some(width.into());
-            self
-        }
-        fn w_auto(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().size.width = Some(Length::Auto);
-            self
-        }
-        fn w_0(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Pixels(0.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_px(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Pixels(1.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_0_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.125).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_1(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.25).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_1_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.375).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_2(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.5).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_2_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.625).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_3(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.75).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_3_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.875).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_4(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.25).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_6(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.5).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_7(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.75).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_8(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_9(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.25).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_10(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.5).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_11(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.75).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_12(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(3.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_14(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(3.5).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_16(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(4.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_20(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(5.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_24(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(6.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_28(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(7.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_32(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(8.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_36(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(9.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_40(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(10.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_44(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(11.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_48(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(12.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_52(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(13.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_56(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(14.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_60(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(15.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_64(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(16.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_72(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(18.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_80(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(20.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_96(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(24.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_half(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_1_3rd(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(33.333333).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_2_3rd(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(66.666667).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_1_4th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(25.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_2_4th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_3_4th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(75.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_1_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(20.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_2_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(40.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_3_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(60.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_4_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(80.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_1_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(16.666667).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_2_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(33.333333).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_3_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_4_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(66.666667).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_5_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(83.333333).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_1_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(8.333333).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_2_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(16.666667).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_3_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(25.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_4_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(33.333333).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_5_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(41.666667).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_6_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_7_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(58.333333).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_8_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(66.666667).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_9_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(75.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_10_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(83.333333).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_11_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(91.666667).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn w_full(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(100.).into();
-            {
-                self.declared_style().size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_0(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Pixels(0.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_px(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Pixels(1.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_0_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.125).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_1(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.25).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_1_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.375).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_2(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.5).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_2_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.625).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_3(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.75).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_3_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.875).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_4(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.25).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_6(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.5).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_7(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.75).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_8(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_9(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.25).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_10(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.5).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_11(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.75).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_12(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(3.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_14(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(3.5).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_16(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(4.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_20(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(5.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_24(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(6.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_28(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(7.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_32(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(8.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_36(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(9.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_40(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(10.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_44(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(11.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_48(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(12.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_52(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(13.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_56(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(14.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_60(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(15.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_64(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(16.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_72(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(18.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_80(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(20.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_96(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(24.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_half(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_1_3rd(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(33.333333).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_2_3rd(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(66.666667).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_1_4th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(25.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_2_4th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_3_4th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(75.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_1_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(20.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_2_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(40.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_3_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(60.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_4_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(80.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_1_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(16.666667).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_2_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(33.333333).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_3_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_4_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(66.666667).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_5_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(83.333333).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_1_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(8.333333).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_2_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(16.666667).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_3_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(25.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_4_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(33.333333).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_5_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(41.666667).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_6_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_7_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(58.333333).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_8_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(66.666667).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_9_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(75.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_10_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(83.333333).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_11_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(91.666667).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn min_w_full(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(100.).into();
-            {
-                self.declared_style().min_size.width = Some(length);
-                self
-            }
-        }
-        fn h(mut self, height: impl Into<Length>) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().size.height = Some(height.into());
-            self
-        }
-        fn h_auto(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().size.height = Some(Length::Auto);
-            self
-        }
-        fn h_0(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Pixels(0.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_px(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Pixels(1.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_0_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(0.125).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_1(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(0.25).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_1_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(0.375).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_2(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(0.5).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_2_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(0.625).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_3(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(0.75).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_3_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(0.875).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_4(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(1.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(1.25).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_6(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(1.5).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_7(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(1.75).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_8(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(2.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_9(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(2.25).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_10(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(2.5).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_11(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(2.75).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_12(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(3.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_14(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(3.5).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_16(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(4.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_20(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(5.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_24(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(6.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_28(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(7.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_32(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(8.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_36(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(9.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_40(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(10.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_44(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(11.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_48(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(12.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_52(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(13.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_56(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(14.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_60(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(15.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_64(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(16.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_72(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(18.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_80(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(20.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_96(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Rems(24.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_half(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_1_3rd(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(33.333333).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_2_3rd(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(66.666667).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_1_4th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(25.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_2_4th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_3_4th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(75.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_1_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(20.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_2_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(40.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_3_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(60.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_4_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(80.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_1_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(16.666667).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_2_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(33.333333).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_3_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_4_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(66.666667).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_5_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(83.333333).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_1_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(8.333333).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_2_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(16.666667).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_3_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(25.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_4_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(33.333333).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_5_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(41.666667).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_6_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_7_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(58.333333).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_8_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(66.666667).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_9_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(75.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_10_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(83.333333).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_11_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(91.666667).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn h_full(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let height = DefinedLength::Percent(100.).into();
-            {
-                self.declared_style().size.height = Some(height);
-                self
-            }
-        }
-        fn min_h_0(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Pixels(0.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_px(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Pixels(1.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_0_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.125).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_1(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.25).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_1_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.375).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_2(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.5).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_2_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.625).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_3(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.75).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_3_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(0.875).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_4(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_5(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.25).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_6(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.5).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_7(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(1.75).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_8(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_9(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.25).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_10(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.5).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_11(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(2.75).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_12(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(3.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_14(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(3.5).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_16(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(4.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_20(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(5.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_24(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(6.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_28(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(7.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_32(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(8.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_36(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(9.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_40(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(10.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_44(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(11.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_48(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(12.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_52(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(13.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_56(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(14.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_60(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(15.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_64(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(16.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_72(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(18.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_80(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(20.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_96(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Rems(24.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_half(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_1_3rd(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(33.333333).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_2_3rd(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(66.666667).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_1_4th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(25.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_2_4th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_3_4th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(75.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_1_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(20.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_2_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(40.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_3_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(60.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_4_5th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(80.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_1_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(16.666667).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_2_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(33.333333).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_3_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_4_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(66.666667).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_5_6th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(83.333333).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_1_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(8.333333).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_2_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(16.666667).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_3_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(25.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_4_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(33.333333).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_5_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(41.666667).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_6_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(50.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_7_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(58.333333).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_8_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(66.666667).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_9_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(75.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_10_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(83.333333).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_11_12th(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(91.666667).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn min_h_full(mut self) -> Self
-        where
-            Self: Sized,
-        {
-            let length = DefinedLength::Percent(100.).into();
-            {
-                self.declared_style().min_size.height = Some(length);
-                self
-            }
-        }
-        fn hoverable(self) -> Hoverable<V, Self>
-        where
-            Self: Sized,
-        {
-            Hoverable::new(self)
-        }
-        fn fill(mut self, fill: impl Into<Fill>) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().fill = Some(Some(fill.into()));
-            self
-        }
-        fn text_color(mut self, color: impl Into<Hsla>) -> Self
-        where
-            Self: Sized,
-        {
-            self.declared_style().text_color = Some(Some(color.into()));
-            self
-        }
-    }
-    trait ElementObject<V> {
-        fn style(&mut self) -> &mut OptionalStyle;
-        fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>>;
-        fn layout(
-            &mut self,
-            view: &mut V,
-            cx: &mut LayoutContext<V>,
-        ) -> Result<(NodeId, Box<dyn Any>)>;
-        fn paint(
-            &mut self,
-            layout: Layout<dyn Any>,
-            view: &mut V,
-            cx: &mut PaintContext<V>,
-        ) -> Result<()>;
-    }
-    impl<V: 'static, E: Element<V>> ElementObject<V> for E {
-        fn style(&mut self) -> &mut OptionalStyle {
-            Element::declared_style(self)
-        }
-        fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
-            Element::handlers_mut(self)
-        }
-        fn layout(
-            &mut self,
-            view: &mut V,
-            cx: &mut LayoutContext<V>,
-        ) -> Result<(NodeId, Box<dyn Any>)> {
-            let (node_id, layout) = self.layout(view, cx)?;
-            let layout = Box::new(layout) as Box<dyn Any>;
-            Ok((node_id, layout))
-        }
-        fn paint(
-            &mut self,
-            layout: Layout<dyn Any>,
-            view: &mut V,
-            cx: &mut PaintContext<V>,
-        ) -> Result<()> {
-            let layout = Layout {
-                from_engine: layout.from_engine,
-                from_element: layout.from_element.downcast_mut::<E::Layout>().unwrap(),
-            };
-            self.paint(layout, view, cx)
-        }
-    }
-    /// A dynamically typed element.
-    pub struct AnyElement<V> {
-        element: Box<dyn ElementObject<V>>,
-        layout: Option<(NodeId, Box<dyn Any>)>,
-    }
-    impl<V: 'static> AnyElement<V> {
-        pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<NodeId> {
-            let pushed_text_style = self.push_text_style(cx);
-            let (node_id, layout) = self.element.layout(view, cx)?;
-            self.layout = Some((node_id, layout));
-            if pushed_text_style {
-                cx.pop_text_style();
-            }
-            Ok(node_id)
-        }
-        pub fn push_text_style(&mut self, cx: &mut impl RenderContext) -> bool {
-            let text_style = self.element.style().text_style();
-            if let Some(text_style) = text_style {
-                let mut current_text_style = cx.text_style();
-                text_style.apply(&mut current_text_style);
-                cx.push_text_style(current_text_style);
-                true
-            } else {
-                false
-            }
-        }
-        pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
-            let pushed_text_style = self.push_text_style(cx);
-            let (layout_node_id, element_layout) =
-                self.layout.as_mut().expect("paint called before layout");
-            let layout = Layout {
-                from_engine: cx
-                    .layout_engine()
-                    .unwrap()
-                    .computed_layout(*layout_node_id)
-                    .expect("make sure you're using this within a gpui2 adapter element"),
-                from_element: element_layout.as_mut(),
-            };
-            let style = self.element.style();
-            let fill_color = style.fill.flatten().and_then(|fill| fill.color());
-            if let Some(fill_color) = fill_color {
-                cx.scene.push_quad(gpui::scene::Quad {
-                    bounds: layout.from_engine.bounds,
-                    background: Some(fill_color.into()),
-                    border: Default::default(),
-                    corner_radii: Default::default(),
-                });
-            }
-            for event_handler in self.element.handlers_mut().iter().cloned() {
-                let EngineLayout { order, bounds } = layout.from_engine;
-                let view_id = cx.view_id();
-                let view_event_handler = event_handler.handler.clone();
-                cx.scene
-                    .interactive_regions
-                    .push(gpui::scene::InteractiveRegion {
-                        order,
-                        bounds,
-                        outside_bounds: event_handler.outside_bounds,
-                        event_handler: Rc::new(move |view, event, window_cx, view_id| {
-                            let mut view_context = ViewContext::mutable(window_cx, view_id);
-                            let mut event_context = EventContext::new(&mut view_context);
-                            view_event_handler(
-                                view.downcast_mut().unwrap(),
-                                event,
-                                &mut event_context,
-                            );
-                        }),
-                        event_type: event_handler.event_type,
-                        view_id,
-                    });
-            }
-            self.element.paint(layout, view, cx)?;
-            if pushed_text_style {
-                cx.pop_text_style();
-            }
-            Ok(())
-        }
-    }
-    impl<V: 'static> Element<V> for AnyElement<V> {
-        type Layout = ();
-        fn declared_style(&mut self) -> &mut OptionalStyle {
-            self.element.style()
-        }
-        fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
-            self.element.handlers_mut()
-        }
-        fn layout(
-            &mut self,
-            view: &mut V,
-            cx: &mut LayoutContext<V>,
-        ) -> Result<(NodeId, Self::Layout)> {
-            Ok((self.layout(view, cx)?, ()))
-        }
-        fn paint(
-            &mut self,
-            layout: Layout<()>,
-            view: &mut V,
-            cx: &mut PaintContext<V>,
-        ) -> Result<()> {
-            self.paint(view, cx)
-        }
-    }
-    pub trait IntoElement<V: 'static> {
-        type Element: Element<V>;
-        fn into_element(self) -> Self::Element;
-        fn into_any_element(self) -> AnyElement<V>
-        where
-            Self: Sized,
-        {
-            self.into_element().into_any()
-        }
-    }
-}
-mod frame {
-    use crate::{
-        element::{
-            AnyElement, Element, EventHandler, IntoElement, Layout, LayoutContext, NodeId,
-            PaintContext,
-        },
-        style::{OptionalStyle, Style},
-    };
-    use anyhow::{anyhow, Result};
-    use gpui::LayoutNodeId;
-    use gpui_macros::IntoElement;
-    #[element_crate = "crate"]
-    pub struct Frame<V: 'static> {
-        style: OptionalStyle,
-        handlers: Vec<EventHandler<V>>,
-        children: Vec<AnyElement<V>>,
-    }
-    impl<V: 'static> crate::element::IntoElement<V> for Frame<V> {
-        type Element = Self;
-        fn into_element(self) -> Self {
-            self
-        }
-    }
-    pub fn frame<V>() -> Frame<V> {
-        Frame {
-            style: OptionalStyle::default(),
-            handlers: Vec::new(),
-            children: Vec::new(),
-        }
-    }
-    impl<V: 'static> Element<V> for Frame<V> {
-        type Layout = ();
-        fn declared_style(&mut self) -> &mut OptionalStyle {
-            &mut self.style
-        }
-        fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
-            &mut self.handlers
-        }
-        fn layout(
-            &mut self,
-            view: &mut V,
-            cx: &mut LayoutContext<V>,
-        ) -> Result<(NodeId, Self::Layout)> {
-            let child_layout_node_ids = self
-                .children
-                .iter_mut()
-                .map(|child| child.layout(view, cx))
-                .collect::<Result<Vec<LayoutNodeId>>>()?;
-            let rem_size = cx.rem_pixels();
-            let style: Style = self.style.into();
-            let node_id = cx
-                .layout_engine()
-                .ok_or_else(|| {
-                    ::anyhow::__private::must_use({
-                        let error =
-                            ::anyhow::__private::format_err(format_args!("no layout engine"));
-                        error
-                    })
-                })?
-                .add_node(style.to_taffy(rem_size), child_layout_node_ids)?;
-            Ok((node_id, ()))
-        }
-        fn paint(
-            &mut self,
-            layout: Layout<()>,
-            view: &mut V,
-            cx: &mut PaintContext<V>,
-        ) -> Result<()> {
-            for child in &mut self.children {
-                child.paint(view, cx)?;
-            }
-            Ok(())
-        }
-    }
-    impl<V: 'static> Frame<V> {
-        pub fn child(mut self, child: impl IntoElement<V>) -> Self {
-            self.children.push(child.into_any_element());
-            self
-        }
-        pub fn children<I, E>(mut self, children: I) -> Self
-        where
-            I: IntoIterator<Item = E>,
-            E: IntoElement<V>,
-        {
-            self.children
-                .extend(children.into_iter().map(|e| e.into_any_element()));
-            self
-        }
-    }
-}
-mod hoverable {
-    use crate::{
-        element::Element,
-        style::{OptionalStyle, Style},
-    };
-    use gpui::{
-        geometry::{rect::RectF, vector::Vector2F},
-        scene::MouseMove,
-        EngineLayout,
-    };
-    use std::{cell::Cell, marker::PhantomData, rc::Rc};
-    pub struct Hoverable<V, E> {
-        hover_style: OptionalStyle,
-        computed_style: Option<Style>,
-        view_type: PhantomData<V>,
-        child: E,
-    }
-    impl<V, E> Hoverable<V, E> {
-        pub fn new(child: E) -> Self {
-            Self {
-                hover_style: OptionalStyle::default(),
-                computed_style: None,
-                view_type: PhantomData,
-                child,
-            }
-        }
-    }
-    impl<V: 'static, E: Element<V>> Element<V> for Hoverable<V, E> {
-        type Layout = E::Layout;
-        fn declared_style(&mut self) -> &mut OptionalStyle {
-            &mut self.hover_style
-        }
-        fn computed_style(&mut self) -> &OptionalStyle {
-            ::core::panicking::panic("not yet implemented")
-        }
-        fn handlers_mut(&mut self) -> &mut Vec<crate::element::EventHandler<V>> {
-            self.child.handlers_mut()
-        }
-        fn layout(
-            &mut self,
-            view: &mut V,
-            cx: &mut gpui::LayoutContext<V>,
-        ) -> anyhow::Result<(taffy::tree::NodeId, Self::Layout)> {
-            self.child.layout(view, cx)
-        }
-        fn paint<'a>(
-            &mut self,
-            layout: crate::element::Layout<Self::Layout>,
-            view: &mut V,
-            cx: &mut crate::element::PaintContext<V>,
-        ) -> anyhow::Result<()> {
-            let EngineLayout { bounds, order } = layout.from_engine;
-            let window_bounds = RectF::new(Vector2F::zero(), cx.window_size());
-            let was_hovered = Rc::new(Cell::new(false));
-            self.child.paint(layout, view, cx)?;
-            cx.draw_interactive_region(
-                order,
-                window_bounds,
-                false,
-                move |view, event: &MouseMove, cx| {
-                    let is_hovered = bounds.contains_point(cx.mouse_position());
-                    if is_hovered != was_hovered.get() {
-                        was_hovered.set(is_hovered);
-                        cx.repaint();
-                    }
-                },
-            );
-            Ok(())
-        }
-    }
-}
-mod paint_context {
-    use derive_more::{Deref, DerefMut};
-    use gpui::{geometry::rect::RectF, EventContext, RenderContext, ViewContext};
-    pub use gpui::{LayoutContext, PaintContext as LegacyPaintContext};
-    use std::{any::TypeId, rc::Rc};
-    pub use taffy::tree::NodeId;
-    pub struct PaintContext<'a, 'b, 'c, 'd, V> {
-        #[deref]
-        #[deref_mut]
-        pub(crate) legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>,
-        pub(crate) scene: &'d mut gpui::SceneBuilder,
-    }
-    impl<'a, 'b, 'c, 'd, V> ::core::ops::Deref for PaintContext<'a, 'b, 'c, 'd, V> {
-        type Target = &'d mut LegacyPaintContext<'a, 'b, 'c, V>;
-        #[inline]
-        fn deref(&self) -> &Self::Target {
-            &self.legacy_cx
-        }
-    }
-    impl<'a, 'b, 'c, 'd, V> ::core::ops::DerefMut for PaintContext<'a, 'b, 'c, 'd, V> {
-        #[inline]
-        fn deref_mut(&mut self) -> &mut Self::Target {
-            &mut self.legacy_cx
-        }
-    }
-    impl<V> RenderContext for PaintContext<'_, '_, '_, '_, V> {
-        fn text_style(&self) -> gpui::fonts::TextStyle {
-            self.legacy_cx.text_style()
-        }
-        fn push_text_style(&mut self, style: gpui::fonts::TextStyle) {
-            self.legacy_cx.push_text_style(style)
-        }
-        fn pop_text_style(&mut self) {
-            self.legacy_cx.pop_text_style()
-        }
-    }
-    impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> {
-        pub fn new(
-            legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>,
-            scene: &'d mut gpui::SceneBuilder,
-        ) -> Self {
-            Self { legacy_cx, scene }
-        }
-        pub fn draw_interactive_region<E: 'static>(
-            &mut self,
-            order: u32,
-            bounds: RectF,
-            outside_bounds: bool,
-            event_handler: impl Fn(&mut V, &E, &mut EventContext<V>) + 'static,
-        ) {
-            self.scene
-                .interactive_regions
-                .push(gpui::scene::InteractiveRegion {
-                    order,
-                    bounds,
-                    outside_bounds,
-                    event_handler: Rc::new(move |view, event, window_cx, view_id| {
-                        let mut view_context = ViewContext::mutable(window_cx, view_id);
-                        let mut event_context = EventContext::new(&mut view_context);
-                        event_handler(
-                            view.downcast_mut().unwrap(),
-                            event.downcast_ref().unwrap(),
-                            &mut event_context,
-                        );
-                    }),
-                    event_type: TypeId::of::<E>(),
-                    view_id: self.view_id(),
-                });
-        }
-    }
-}
-mod style {
-    use crate::color::Hsla;
-    use gpui::geometry::{
-        DefinedLength, Edges, Length, OptionalEdges, OptionalPoint, OptionalSize, Point, Size,
-    };
-    use optional::Optional;
-    pub use taffy::style::{
-        AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent,
-        Overflow, Position,
-    };
-    pub struct Style {
-        /// What layout strategy should be used?
-        pub display: Display,
-        /// How children overflowing their container should affect layout
-        #[optional]
-        pub overflow: Point<Overflow>,
-        /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes.
-        pub scrollbar_width: f32,
-        /// What should the `position` value of this struct use as a base offset?
-        pub position: Position,
-        /// How should the position of this element be tweaked relative to the layout defined?
-        pub inset: Edges<Length>,
-        /// Sets the initial size of the item
-        #[optional]
-        pub size: Size<Length>,
-        /// Controls the minimum size of the item
-        #[optional]
-        pub min_size: Size<Length>,
-        /// Controls the maximum size of the item
-        #[optional]
-        pub max_size: Size<Length>,
-        /// Sets the preferred aspect ratio for the item. The ratio is calculated as width divided by height.
-        pub aspect_ratio: Option<f32>,
-        /// How large should the margin be on each side?
-        #[optional]
-        pub margin: Edges<Length>,
-        /// How large should the padding be on each side?
-        pub padding: Edges<DefinedLength>,
-        /// How large should the border be on each side?
-        pub border: Edges<DefinedLength>,
-        /// How this node's children aligned in the cross/block axis?
-        pub align_items: Option<AlignItems>,
-        /// How this node should be aligned in the cross/block axis. Falls back to the parents [`AlignItems`] if not set
-        pub align_self: Option<AlignSelf>,
-        /// How should content contained within this item be aligned in the cross/block axis
-        pub align_content: Option<AlignContent>,
-        /// How should contained within this item be aligned in the main/inline axis
-        pub justify_content: Option<JustifyContent>,
-        /// How large should the gaps between items in a flex container be?
-        pub gap: Size<DefinedLength>,
-        /// Which direction does the main axis flow in?
-        pub flex_direction: FlexDirection,
-        /// Should elements wrap, or stay in a single line?
-        pub flex_wrap: FlexWrap,
-        /// Sets the initial main axis size of the item
-        pub flex_basis: Length,
-        /// The relative rate at which this item grows when it is expanding to fill space, 0.0 is the default value, and this value must be positive.
-        pub flex_grow: f32,
-        /// The relative rate at which this item shrinks when it is contracting to fit into space, 1.0 is the default value, and this value must be positive.
-        pub flex_shrink: f32,
-        /// The fill color of this element
-        pub fill: Option<Fill>,
-        /// The color of text within this element. Cascades to children unless overridden.
-        pub text_color: Option<Hsla>,
-    }
-    #[automatically_derived]
-    impl ::core::clone::Clone for Style {
-        #[inline]
-        fn clone(&self) -> Style {
-            Style {
-                display: ::core::clone::Clone::clone(&self.display),
-                overflow: ::core::clone::Clone::clone(&self.overflow),
-                scrollbar_width: ::core::clone::Clone::clone(&self.scrollbar_width),
-                position: ::core::clone::Clone::clone(&self.position),
-                inset: ::core::clone::Clone::clone(&self.inset),
-                size: ::core::clone::Clone::clone(&self.size),
-                min_size: ::core::clone::Clone::clone(&self.min_size),
-                max_size: ::core::clone::Clone::clone(&self.max_size),
-                aspect_ratio: ::core::clone::Clone::clone(&self.aspect_ratio),
-                margin: ::core::clone::Clone::clone(&self.margin),
-                padding: ::core::clone::Clone::clone(&self.padding),
-                border: ::core::clone::Clone::clone(&self.border),
-                align_items: ::core::clone::Clone::clone(&self.align_items),
-                align_self: ::core::clone::Clone::clone(&self.align_self),
-                align_content: ::core::clone::Clone::clone(&self.align_content),
-                justify_content: ::core::clone::Clone::clone(&self.justify_content),
-                gap: ::core::clone::Clone::clone(&self.gap),
-                flex_direction: ::core::clone::Clone::clone(&self.flex_direction),
-                flex_wrap: ::core::clone::Clone::clone(&self.flex_wrap),
-                flex_basis: ::core::clone::Clone::clone(&self.flex_basis),
-                flex_grow: ::core::clone::Clone::clone(&self.flex_grow),
-                flex_shrink: ::core::clone::Clone::clone(&self.flex_shrink),
-                fill: ::core::clone::Clone::clone(&self.fill),
-                text_color: ::core::clone::Clone::clone(&self.text_color),
-            }
-        }
-    }
-    pub struct OptionalStyle {
-        pub display: Option<Display>,
-        pub overflow: OptionalPoint<Overflow>,
-        pub scrollbar_width: Option<f32>,
-        pub position: Option<Position>,
-        pub inset: Option<Edges<Length>>,
-        pub size: OptionalSize<Length>,
-        pub min_size: OptionalSize<Length>,
-        pub max_size: OptionalSize<Length>,
-        pub aspect_ratio: Option<Option<f32>>,
-        pub margin: OptionalEdges<Length>,
-        pub padding: Option<Edges<DefinedLength>>,
-        pub border: Option<Edges<DefinedLength>>,
-        pub align_items: Option<Option<AlignItems>>,
-        pub align_self: Option<Option<AlignSelf>>,
-        pub align_content: Option<Option<AlignContent>>,
-        pub justify_content: Option<Option<JustifyContent>>,
-        pub gap: Option<Size<DefinedLength>>,
-        pub flex_direction: Option<FlexDirection>,
-        pub flex_wrap: Option<FlexWrap>,
-        pub flex_basis: Option<Length>,
-        pub flex_grow: Option<f32>,
-        pub flex_shrink: Option<f32>,
-        pub fill: Option<Option<Fill>>,
-        pub text_color: Option<Option<Hsla>>,
-    }
-    #[automatically_derived]
-    impl ::core::default::Default for OptionalStyle {
-        #[inline]
-        fn default() -> OptionalStyle {
-            OptionalStyle {
-                display: ::core::default::Default::default(),
-                overflow: ::core::default::Default::default(),
-                scrollbar_width: ::core::default::Default::default(),
-                position: ::core::default::Default::default(),
-                inset: ::core::default::Default::default(),
-                size: ::core::default::Default::default(),
-                min_size: ::core::default::Default::default(),
-                max_size: ::core::default::Default::default(),
-                aspect_ratio: ::core::default::Default::default(),
-                margin: ::core::default::Default::default(),
-                padding: ::core::default::Default::default(),
-                border: ::core::default::Default::default(),
-                align_items: ::core::default::Default::default(),
-                align_self: ::core::default::Default::default(),
-                align_content: ::core::default::Default::default(),
-                justify_content: ::core::default::Default::default(),
-                gap: ::core::default::Default::default(),
-                flex_direction: ::core::default::Default::default(),
-                flex_wrap: ::core::default::Default::default(),
-                flex_basis: ::core::default::Default::default(),
-                flex_grow: ::core::default::Default::default(),
-                flex_shrink: ::core::default::Default::default(),
-                fill: ::core::default::Default::default(),
-                text_color: ::core::default::Default::default(),
-            }
-        }
-    }
-    #[automatically_derived]
-    impl ::core::clone::Clone for OptionalStyle {
-        #[inline]
-        fn clone(&self) -> OptionalStyle {
-            OptionalStyle {
-                display: ::core::clone::Clone::clone(&self.display),
-                overflow: ::core::clone::Clone::clone(&self.overflow),
-                scrollbar_width: ::core::clone::Clone::clone(&self.scrollbar_width),
-                position: ::core::clone::Clone::clone(&self.position),
-                inset: ::core::clone::Clone::clone(&self.inset),
-                size: ::core::clone::Clone::clone(&self.size),
-                min_size: ::core::clone::Clone::clone(&self.min_size),
-                max_size: ::core::clone::Clone::clone(&self.max_size),
-                aspect_ratio: ::core::clone::Clone::clone(&self.aspect_ratio),
-                margin: ::core::clone::Clone::clone(&self.margin),
-                padding: ::core::clone::Clone::clone(&self.padding),
-                border: ::core::clone::Clone::clone(&self.border),
-                align_items: ::core::clone::Clone::clone(&self.align_items),
-                align_self: ::core::clone::Clone::clone(&self.align_self),
-                align_content: ::core::clone::Clone::clone(&self.align_content),
-                justify_content: ::core::clone::Clone::clone(&self.justify_content),
-                gap: ::core::clone::Clone::clone(&self.gap),
-                flex_direction: ::core::clone::Clone::clone(&self.flex_direction),
-                flex_wrap: ::core::clone::Clone::clone(&self.flex_wrap),
-                flex_basis: ::core::clone::Clone::clone(&self.flex_basis),
-                flex_grow: ::core::clone::Clone::clone(&self.flex_grow),
-                flex_shrink: ::core::clone::Clone::clone(&self.flex_shrink),
-                fill: ::core::clone::Clone::clone(&self.fill),
-                text_color: ::core::clone::Clone::clone(&self.text_color),
-            }
-        }
-    }
-    impl Optional for OptionalStyle {
-        type Base = Style;
-        fn assign(&self, base: &mut Self::Base) {
-            if let Some(value) = self.display.clone() {
-                base.display = value;
-            }
-            if let Some(value) = self.overflow.clone() {
-                base.overflow = value;
-            }
-            if let Some(value) = self.scrollbar_width.clone() {
-                base.scrollbar_width = value;
-            }
-            if let Some(value) = self.position.clone() {
-                base.position = value;
-            }
-            if let Some(value) = self.inset.clone() {
-                base.inset = value;
-            }
-            if let Some(value) = self.size.clone() {
-                base.size = value;
-            }
-            if let Some(value) = self.min_size.clone() {
-                base.min_size = value;
-            }
-            if let Some(value) = self.max_size.clone() {
-                base.max_size = value;
-            }
-            if let Some(value) = self.aspect_ratio.clone() {
-                base.aspect_ratio = value;
-            }
-            if let Some(value) = self.margin.clone() {
-                base.margin = value;
-            }
-            if let Some(value) = self.padding.clone() {
-                base.padding = value;
-            }
-            if let Some(value) = self.border.clone() {
-                base.border = value;
-            }
-            if let Some(value) = self.align_items.clone() {
-                base.align_items = value;
-            }
-            if let Some(value) = self.align_self.clone() {
-                base.align_self = value;
-            }
-            if let Some(value) = self.align_content.clone() {
-                base.align_content = value;
-            }
-            if let Some(value) = self.justify_content.clone() {
-                base.justify_content = value;
-            }
-            if let Some(value) = self.gap.clone() {
-                base.gap = value;
-            }
-            if let Some(value) = self.flex_direction.clone() {
-                base.flex_direction = value;
-            }
-            if let Some(value) = self.flex_wrap.clone() {
-                base.flex_wrap = value;
-            }
-            if let Some(value) = self.flex_basis.clone() {
-                base.flex_basis = value;
-            }
-            if let Some(value) = self.flex_grow.clone() {
-                base.flex_grow = value;
-            }
-            if let Some(value) = self.flex_shrink.clone() {
-                base.flex_shrink = value;
-            }
-            if let Some(value) = self.fill.clone() {
-                base.fill = value;
-            }
-            if let Some(value) = self.text_color.clone() {
-                base.text_color = value;
-            }
-        }
-    }
-    impl From<OptionalStyle> for Style
-    where
-        Style: Default,
-    {
-        fn from(wrapper: OptionalStyle) -> Self {
-            let mut base = Self::default();
-            wrapper.assign(&mut base);
-            base
-        }
-    }
-    impl Style {
-        pub const DEFAULT: Style = Style {
-            display: Display::DEFAULT,
-            overflow: Point {
-                x: Overflow::Visible,
-                y: Overflow::Visible,
-            },
-            scrollbar_width: 0.0,
-            position: Position::Relative,
-            inset: Edges::auto(),
-            margin: Edges::<Length>::zero(),
-            padding: Edges::<DefinedLength>::zero(),
-            border: Edges::<DefinedLength>::zero(),
-            size: Size::auto(),
-            min_size: Size::auto(),
-            max_size: Size::auto(),
-            aspect_ratio: None,
-            gap: Size::zero(),
-            align_items: None,
-            align_self: None,
-            align_content: None,
-            justify_content: None,
-            flex_direction: FlexDirection::Row,
-            flex_wrap: FlexWrap::NoWrap,
-            flex_grow: 0.0,
-            flex_shrink: 1.0,
-            flex_basis: Length::Auto,
-            fill: None,
-            text_color: None,
-        };
-        pub fn new() -> Self {
-            Self::DEFAULT.clone()
-        }
-        pub fn to_taffy(&self, rem_size: f32) -> taffy::style::Style {
-            taffy::style::Style {
-                display: self.display,
-                overflow: self.overflow.clone().into(),
-                scrollbar_width: self.scrollbar_width,
-                position: self.position,
-                inset: self.inset.to_taffy(rem_size),
-                size: self.size.to_taffy(rem_size),
-                min_size: self.min_size.to_taffy(rem_size),
-                max_size: self.max_size.to_taffy(rem_size),
-                aspect_ratio: self.aspect_ratio,
-                margin: self.margin.to_taffy(rem_size),
-                padding: self.padding.to_taffy(rem_size),
-                border: self.border.to_taffy(rem_size),
-                align_items: self.align_items,
-                align_self: self.align_self,
-                align_content: self.align_content,
-                justify_content: self.justify_content,
-                gap: self.gap.to_taffy(rem_size),
-                flex_direction: self.flex_direction,
-                flex_wrap: self.flex_wrap,
-                flex_basis: self.flex_basis.to_taffy(rem_size).into(),
-                flex_grow: self.flex_grow,
-                flex_shrink: self.flex_shrink,
-                ..Default::default()
-            }
-        }
-    }
-    impl Default for Style {
-        fn default() -> Self {
-            Self::DEFAULT.clone()
-        }
-    }
-    impl OptionalStyle {
-        pub fn text_style(&self) -> Option<OptionalTextStyle> {
-            self.text_color.map(|color| OptionalTextStyle { color })
-        }
-    }
-    pub struct OptionalTextStyle {
-        color: Option<Hsla>,
-    }
-    impl OptionalTextStyle {
-        pub fn apply(&self, style: &mut gpui::fonts::TextStyle) {
-            if let Some(color) = self.color {
-                style.color = color.into();
-            }
-        }
-    }
-    pub enum Fill {
-        Color(Hsla),
-    }
-    #[automatically_derived]
-    impl ::core::clone::Clone for Fill {
-        #[inline]
-        fn clone(&self) -> Fill {
-            match self {
-                Fill::Color(__self_0) => Fill::Color(::core::clone::Clone::clone(__self_0)),
-            }
-        }
-    }
-    impl Fill {
-        pub fn color(&self) -> Option<Hsla> {
-            match self {
-                Fill::Color(color) => Some(*color),
-            }
-        }
-    }
-    impl Default for Fill {
-        fn default() -> Self {
-            Self::Color(Hsla::default())
-        }
-    }
-    impl From<Hsla> for Fill {
-        fn from(color: Hsla) -> Self {
-            Self::Color(color)
-        }
-    }
-}
-mod text {
-    use crate::{
-        element::{Element, ElementMetadata, EventHandler, IntoElement},
-        style::Style,
-    };
-    use gpui::{geometry::Size, text_layout::LineLayout, RenderContext};
-    use parking_lot::Mutex;
-    use std::sync::Arc;
-    impl<V: 'static, S: Into<ArcCow<'static, str>>> IntoElement<V> for S {
-        type Element = Text<V>;
-        fn into_element(self) -> Self::Element {
-            Text {
-                text: self.into(),
-                metadata: Default::default(),
-            }
-        }
-    }
-    pub struct Text<V> {
-        text: ArcCow<'static, str>,
-        metadata: ElementMetadata<V>,
-    }
-    impl<V: 'static> Element<V> for Text<V> {
-        type Layout = Arc<Mutex<Option<TextLayout>>>;
-        fn declared_style(&mut self) -> &mut crate::style::OptionalStyle {
-            &mut self.metadata.style
-        }
-        fn layout(
-            &mut self,
-            view: &mut V,
-            cx: &mut gpui::LayoutContext<V>,
-        ) -> anyhow::Result<(taffy::tree::NodeId, Self::Layout)> {
-            let rem_size = cx.rem_pixels();
-            let fonts = cx.platform().fonts();
-            let text_style = cx.text_style();
-            let line_height = cx.font_cache().line_height(text_style.font_size);
-            let layout_engine = cx.layout_engine().expect("no layout engine present");
-            let text = self.text.clone();
-            let layout = Arc::new(Mutex::new(None));
-            let style: Style = self.metadata.style.into();
-            let node_id = layout_engine.add_measured_node(style.to_taffy(rem_size), {
-                let layout = layout.clone();
-                move |params| {
-                    let line_layout = fonts.layout_line(
-                        text.as_ref(),
-                        text_style.font_size,
-                        &[(text.len(), text_style.to_run())],
-                    );
-                    let size = Size {
-                        width: line_layout.width,
-                        height: line_height,
-                    };
-                    layout.lock().replace(TextLayout {
-                        line_layout: Arc::new(line_layout),
-                        line_height,
-                    });
-                    size
-                }
-            })?;
-            Ok((node_id, layout))
-        }
-        fn paint<'a>(
-            &mut self,
-            layout: crate::element::Layout<Arc<Mutex<Option<TextLayout>>>>,
-            view: &mut V,
-            cx: &mut crate::element::PaintContext<V>,
-        ) -> anyhow::Result<()> {
-            let element_layout_lock = layout.from_element.lock();
-            let element_layout = element_layout_lock
-                .as_ref()
-                .expect("layout has not been performed");
-            let line_layout = element_layout.line_layout.clone();
-            let line_height = element_layout.line_height;
-            drop(element_layout_lock);
-            let text_style = cx.text_style();
-            let line = gpui::text_layout::Line::new(
-                line_layout,
-                &[(self.text.len(), text_style.to_run())],
-            );
-            line.paint(
-                cx.scene,
-                layout.from_engine.bounds.origin(),
-                layout.from_engine.bounds,
-                line_height,
-                cx.legacy_cx,
-            );
-            Ok(())
-        }
-        fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
-            &mut self.metadata.handlers
-        }
-    }
-    pub struct TextLayout {
-        line_layout: Arc<LineLayout>,
-        line_height: f32,
-    }
-    pub enum ArcCow<'a, T: ?Sized> {
-        Borrowed(&'a T),
-        Owned(Arc<T>),
-    }
-    impl<'a, T: ?Sized> Clone for ArcCow<'a, T> {
-        fn clone(&self) -> Self {
-            match self {
-                Self::Borrowed(borrowed) => Self::Borrowed(borrowed),
-                Self::Owned(owned) => Self::Owned(owned.clone()),
-            }
-        }
-    }
-    impl<'a, T: ?Sized> From<&'a T> for ArcCow<'a, T> {
-        fn from(s: &'a T) -> Self {
-            Self::Borrowed(s)
-        }
-    }
-    impl<T> From<Arc<T>> for ArcCow<'_, T> {
-        fn from(s: Arc<T>) -> Self {
-            Self::Owned(s)
-        }
-    }
-    impl From<String> for ArcCow<'_, str> {
-        fn from(value: String) -> Self {
-            Self::Owned(value.into())
-        }
-    }
-    impl<T: ?Sized> std::ops::Deref for ArcCow<'_, T> {
-        type Target = T;
-        fn deref(&self) -> &Self::Target {
-            match self {
-                ArcCow::Borrowed(s) => s,
-                ArcCow::Owned(s) => s.as_ref(),
-            }
-        }
-    }
-    impl<T: ?Sized> AsRef<T> for ArcCow<'_, T> {
-        fn as_ref(&self) -> &T {
-            match self {
-                ArcCow::Borrowed(borrowed) => borrowed,
-                ArcCow::Owned(owned) => owned.as_ref(),
-            }
-        }
-    }
-}
-mod themes {
-    use crate::color::{Hsla, Lerp};
-    use std::ops::Range;
-    pub mod rose_pine {
-        use crate::{
-            color::{hsla, rgb, Hsla},
-            ThemeColors,
-        };
-        use std::ops::Range;
-        pub struct RosePineThemes {
-            pub default: RosePinePalette,
-            pub dawn: RosePinePalette,
-            pub moon: RosePinePalette,
-        }
-        pub struct RosePinePalette {
-            pub base: Hsla,
-            pub surface: Hsla,
-            pub overlay: Hsla,
-            pub muted: Hsla,
-            pub subtle: Hsla,
-            pub text: Hsla,
-            pub love: Hsla,
-            pub gold: Hsla,
-            pub rose: Hsla,
-            pub pine: Hsla,
-            pub foam: Hsla,
-            pub iris: Hsla,
-            pub highlight_low: Hsla,
-            pub highlight_med: Hsla,
-            pub highlight_high: Hsla,
-        }
-        #[automatically_derived]
-        impl ::core::clone::Clone for RosePinePalette {
-            #[inline]
-            fn clone(&self) -> RosePinePalette {
-                let _: ::core::clone::AssertParamIsClone<Hsla>;
-                *self
-            }
-        }
-        #[automatically_derived]
-        impl ::core::marker::Copy for RosePinePalette {}
-        #[automatically_derived]
-        impl ::core::fmt::Debug for RosePinePalette {
-            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-                let names: &'static _ = &[
-                    "base",
-                    "surface",
-                    "overlay",
-                    "muted",
-                    "subtle",
-                    "text",
-                    "love",
-                    "gold",
-                    "rose",
-                    "pine",
-                    "foam",
-                    "iris",
-                    "highlight_low",
-                    "highlight_med",
-                    "highlight_high",
-                ];
-                let values: &[&dyn::core::fmt::Debug] = &[
-                    &self.base,
-                    &self.surface,
-                    &self.overlay,
-                    &self.muted,
-                    &self.subtle,
-                    &self.text,
-                    &self.love,
-                    &self.gold,
-                    &self.rose,
-                    &self.pine,
-                    &self.foam,
-                    &self.iris,
-                    &self.highlight_low,
-                    &self.highlight_med,
-                    &&self.highlight_high,
-                ];
-                ::core::fmt::Formatter::debug_struct_fields_finish(
-                    f,
-                    "RosePinePalette",
-                    names,
-                    values,
-                )
-            }
-        }
-        impl RosePinePalette {
-            pub fn default() -> RosePinePalette {
-                RosePinePalette {
-                    base: rgb(0x191724),
-                    surface: rgb(0x1f1d2e),
-                    overlay: rgb(0x26233a),
-                    muted: rgb(0x6e6a86),
-                    subtle: rgb(0x908caa),
-                    text: rgb(0xe0def4),
-                    love: rgb(0xeb6f92),
-                    gold: rgb(0xf6c177),
-                    rose: rgb(0xebbcba),
-                    pine: rgb(0x31748f),
-                    foam: rgb(0x9ccfd8),
-                    iris: rgb(0xc4a7e7),
-                    highlight_low: rgb(0x21202e),
-                    highlight_med: rgb(0x403d52),
-                    highlight_high: rgb(0x524f67),
-                }
-            }
-            pub fn moon() -> RosePinePalette {
-                RosePinePalette {
-                    base: rgb(0x232136),
-                    surface: rgb(0x2a273f),
-                    overlay: rgb(0x393552),
-                    muted: rgb(0x6e6a86),
-                    subtle: rgb(0x908caa),
-                    text: rgb(0xe0def4),
-                    love: rgb(0xeb6f92),
-                    gold: rgb(0xf6c177),
-                    rose: rgb(0xea9a97),
-                    pine: rgb(0x3e8fb0),
-                    foam: rgb(0x9ccfd8),
-                    iris: rgb(0xc4a7e7),
-                    highlight_low: rgb(0x2a283e),
-                    highlight_med: rgb(0x44415a),
-                    highlight_high: rgb(0x56526e),
-                }
-            }
-            pub fn dawn() -> RosePinePalette {
-                RosePinePalette {
-                    base: rgb(0xfaf4ed),
-                    surface: rgb(0xfffaf3),
-                    overlay: rgb(0xf2e9e1),
-                    muted: rgb(0x9893a5),
-                    subtle: rgb(0x797593),
-                    text: rgb(0x575279),
-                    love: rgb(0xb4637a),
-                    gold: rgb(0xea9d34),
-                    rose: rgb(0xd7827e),
-                    pine: rgb(0x286983),
-                    foam: rgb(0x56949f),
-                    iris: rgb(0x907aa9),
-                    highlight_low: rgb(0xf4ede8),
-                    highlight_med: rgb(0xdfdad9),
-                    highlight_high: rgb(0xcecacd),
-                }
-            }
-        }
-        pub fn default() -> ThemeColors {
-            theme_colors(&RosePinePalette::default())
-        }
-        pub fn moon() -> ThemeColors {
-            theme_colors(&RosePinePalette::moon())
-        }
-        pub fn dawn() -> ThemeColors {
-            theme_colors(&RosePinePalette::dawn())
-        }
-        fn theme_colors(p: &RosePinePalette) -> ThemeColors {
-            ThemeColors {
-                base: scale_sl(p.base, (0.8, 0.8), (1.2, 1.2)),
-                surface: scale_sl(p.surface, (0.8, 0.8), (1.2, 1.2)),
-                overlay: scale_sl(p.overlay, (0.8, 0.8), (1.2, 1.2)),
-                muted: scale_sl(p.muted, (0.8, 0.8), (1.2, 1.2)),
-                subtle: scale_sl(p.subtle, (0.8, 0.8), (1.2, 1.2)),
-                text: scale_sl(p.text, (0.8, 0.8), (1.2, 1.2)),
-                highlight_low: scale_sl(p.highlight_low, (0.8, 0.8), (1.2, 1.2)),
-                highlight_med: scale_sl(p.highlight_med, (0.8, 0.8), (1.2, 1.2)),
-                highlight_high: scale_sl(p.highlight_high, (0.8, 0.8), (1.2, 1.2)),
-                success: scale_sl(p.foam, (0.8, 0.8), (1.2, 1.2)),
-                warning: scale_sl(p.gold, (0.8, 0.8), (1.2, 1.2)),
-                error: scale_sl(p.love, (0.8, 0.8), (1.2, 1.2)),
-                inserted: scale_sl(p.foam, (0.8, 0.8), (1.2, 1.2)),
-                deleted: scale_sl(p.love, (0.8, 0.8), (1.2, 1.2)),
-                modified: scale_sl(p.rose, (0.8, 0.8), (1.2, 1.2)),
-            }
-        }
-        /// Produces a range by multiplying the saturation and lightness of the base color by the given
-        /// start and end factors.
-        fn scale_sl(
-            base: Hsla,
-            (start_s, start_l): (f32, f32),
-            (end_s, end_l): (f32, f32),
-        ) -> Range<Hsla> {
-            let start = hsla(base.h, base.s * start_s, base.l * start_l, base.a);
-            let end = hsla(base.h, base.s * end_s, base.l * end_l, base.a);
-            Range { start, end }
-        }
-    }
-    pub struct ThemeColors {
-        pub base: Range<Hsla>,
-        pub surface: Range<Hsla>,
-        pub overlay: Range<Hsla>,
-        pub muted: Range<Hsla>,
-        pub subtle: Range<Hsla>,
-        pub text: Range<Hsla>,
-        pub highlight_low: Range<Hsla>,
-        pub highlight_med: Range<Hsla>,
-        pub highlight_high: Range<Hsla>,
-        pub success: Range<Hsla>,
-        pub warning: Range<Hsla>,
-        pub error: Range<Hsla>,
-        pub inserted: Range<Hsla>,
-        pub deleted: Range<Hsla>,
-        pub modified: Range<Hsla>,
-    }
-    impl ThemeColors {
-        pub fn base(&self, level: f32) -> Hsla {
-            self.base.lerp(level)
-        }
-        pub fn surface(&self, level: f32) -> Hsla {
-            self.surface.lerp(level)
-        }
-        pub fn overlay(&self, level: f32) -> Hsla {
-            self.overlay.lerp(level)
-        }
-        pub fn muted(&self, level: f32) -> Hsla {
-            self.muted.lerp(level)
-        }
-        pub fn subtle(&self, level: f32) -> Hsla {
-            self.subtle.lerp(level)
-        }
-        pub fn text(&self, level: f32) -> Hsla {
-            self.text.lerp(level)
-        }
-        pub fn highlight_low(&self, level: f32) -> Hsla {
-            self.highlight_low.lerp(level)
-        }
-        pub fn highlight_med(&self, level: f32) -> Hsla {
-            self.highlight_med.lerp(level)
-        }
-        pub fn highlight_high(&self, level: f32) -> Hsla {
-            self.highlight_high.lerp(level)
-        }
-        pub fn success(&self, level: f32) -> Hsla {
-            self.success.lerp(level)
-        }
-        pub fn warning(&self, level: f32) -> Hsla {
-            self.warning.lerp(level)
-        }
-        pub fn error(&self, level: f32) -> Hsla {
-            self.error.lerp(level)
-        }
-        pub fn inserted(&self, level: f32) -> Hsla {
-            self.inserted.lerp(level)
-        }
-        pub fn deleted(&self, level: f32) -> Hsla {
-            self.deleted.lerp(level)
-        }
-        pub fn modified(&self, level: f32) -> Hsla {
-            self.modified.lerp(level)
-        }
-    }
-}
-mod view {
-    use crate::element::{AnyElement, Element};
-    use gpui::{Element as _, ViewContext};
-    pub fn view<F, E>(mut render: F) -> ViewFn
-    where
-        F: 'static + FnMut(&mut ViewContext<ViewFn>) -> E,
-        E: Element<ViewFn>,
-    {
-        ViewFn(Box::new(move |cx| (render)(cx).into_any()))
-    }
-    pub struct ViewFn(Box<dyn FnMut(&mut ViewContext<ViewFn>) -> AnyElement<ViewFn>>);
-    impl gpui::Entity for ViewFn {
-        type Event = ();
-    }
-    impl gpui::View for ViewFn {
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> gpui::AnyElement<Self> {
-            (self.0)(cx).adapt().into_any()
-        }
-    }
-}
-fn main() {
-    SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
-    gpui::App::new(()).unwrap().run(|cx| {
-        cx.add_window(
-            WindowOptions {
-                bounds: gpui::platform::WindowBounds::Fixed(RectF::new(
-                    vec2f(0., 0.),
-                    vec2f(400., 300.),
-                )),
-                center: true,
-                ..Default::default()
-            },
-            |_| view(|_| storybook(&rose_pine::moon())),
-        );
-        cx.platform().activate(true);
-    });
-}
-fn storybook<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
-    frame()
-        .text_color(black())
-        .h_full()
-        .w_half()
-        .fill(theme.success(0.5))
-        .child(button().label("Hello").click(|_, _, _| {
-            ::std::io::_print(format_args!("click!\n"));
-        }))
-}