From bca900a5d36e76c72866525ca2ee44318b028e7c Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Fri, 5 Jan 2024 00:40:08 -0500 Subject: [PATCH 01/10] Add Headline component --- crates/ui/src/components.rs | 2 + crates/ui/src/components/typography.rs | 71 ++++++++++++++++++++++++++ crates/ui/src/prelude.rs | 1 + 3 files changed, 74 insertions(+) create mode 100644 crates/ui/src/components/typography.rs diff --git a/crates/ui/src/components.rs b/crates/ui/src/components.rs index 0848ac74dfd594ab2dbf2a170d927a70b3ae386d..4049815f1b5abdfaf68144456c38f7c6f72b51c7 100644 --- a/crates/ui/src/components.rs +++ b/crates/ui/src/components.rs @@ -16,6 +16,7 @@ mod stack; mod tab; mod tab_bar; mod tooltip; +mod typography; #[cfg(feature = "stories")] mod stories; @@ -38,6 +39,7 @@ pub use stack::*; pub use tab::*; pub use tab_bar::*; pub use tooltip::*; +pub use typography::*; #[cfg(feature = "stories")] pub use stories::*; diff --git a/crates/ui/src/components/typography.rs b/crates/ui/src/components/typography.rs new file mode 100644 index 0000000000000000000000000000000000000000..c613559faf61ed352cb533767fa310c2b94041d8 --- /dev/null +++ b/crates/ui/src/components/typography.rs @@ -0,0 +1,71 @@ +use gpui::{ + div, rems, IntoElement, ParentElement, Rems, RenderOnce, SharedString, Styled, WindowContext, +}; +use settings::Settings; +use theme::{ActiveTheme, ThemeSettings}; + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)] +pub enum HeadlineSize { + XSmall, + Small, + #[default] + Medium, + Large, + XLarge, +} + +impl HeadlineSize { + pub fn size(self) -> Rems { + match self { + // Based on the Major Second scale + Self::XSmall => rems(0.88), + Self::Small => rems(1.0), + Self::Medium => rems(1.125), + Self::Large => rems(1.27), + Self::XLarge => rems(1.43), + } + } + + pub fn line_height(self) -> Rems { + match self { + Self::XSmall => rems(1.6), + Self::Small => rems(1.6), + Self::Medium => rems(1.6), + Self::Large => rems(1.6), + Self::XLarge => rems(1.6), + } + } +} + +#[derive(IntoElement)] +pub struct Headline { + size: HeadlineSize, + text: SharedString, +} + +impl RenderOnce for Headline { + fn render(self, cx: &mut WindowContext) -> impl IntoElement { + let ui_font = ThemeSettings::get_global(cx).ui_font.family.clone(); + + div() + .font(ui_font) + .line_height(self.size.line_height()) + .text_size(self.size.size()) + .text_color(cx.theme().colors().text) + .child(self.text) + } +} + +impl Headline { + pub fn new(text: impl Into) -> Self { + Self { + size: HeadlineSize::default(), + text: text.into(), + } + } + + pub fn size(mut self, size: HeadlineSize) -> Self { + self.size = size; + self + } +} diff --git a/crates/ui/src/prelude.rs b/crates/ui/src/prelude.rs index dbf3c79b7173c1c6d018216cb4e11aab444d2e54..9432e622a66138a7e3bb125b7597761b75fc1b88 100644 --- a/crates/ui/src/prelude.rs +++ b/crates/ui/src/prelude.rs @@ -14,6 +14,7 @@ pub use crate::visible_on_hover::*; pub use crate::{h_stack, v_stack}; pub use crate::{Button, ButtonSize, ButtonStyle, IconButton}; pub use crate::{ButtonCommon, Color, StyledExt}; +pub use crate::{Headline, HeadlineSize}; pub use crate::{Icon, IconElement, IconPosition, IconSize}; pub use crate::{Label, LabelCommon, LabelSize, LineHeightStyle}; pub use theme::ActiveTheme; From f7a036e95213cc4cf95bcfb4ce169ce95f9bacbd Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Fri, 5 Jan 2024 00:51:03 -0500 Subject: [PATCH 02/10] WIP - Start on Copilot Modal --- crates/copilot/src/sign_in.rs | 45 +++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/crates/copilot/src/sign_in.rs b/crates/copilot/src/sign_in.rs index ba5dbe0e315828ac1761cf1d76ac37bb8211ea4c..4c736e930e0cf5f0a325a267af68295b37e68079 100644 --- a/crates/copilot/src/sign_in.rs +++ b/crates/copilot/src/sign_in.rs @@ -1,11 +1,10 @@ use crate::{request::PromptUserDeviceFlow, Copilot, Status}; use gpui::{ - div, size, AppContext, Bounds, ClipboardItem, Element, GlobalPixels, InteractiveElement, + div, size, svg, AppContext, Bounds, ClipboardItem, Element, GlobalPixels, InteractiveElement, IntoElement, ParentElement, Point, Render, Styled, ViewContext, VisualContext, WindowBounds, WindowHandle, WindowKind, WindowOptions, }; -use theme::ActiveTheme; -use ui::{prelude::*, Button, Icon, IconElement, Label}; +use ui::{prelude::*, Button, Icon, Label}; const COPILOT_SIGN_UP_URL: &'static str = "https://github.com/features/copilot"; @@ -59,7 +58,7 @@ fn create_copilot_auth_window( cx: &mut AppContext, status: &Status, ) -> WindowHandle { - let window_size = size(GlobalPixels::from(280.), GlobalPixels::from(280.)); + let window_size = size(GlobalPixels::from(400.), GlobalPixels::from(480.)); let window_options = WindowOptions { bounds: WindowBounds::Fixed(Bounds::new(Point::default(), window_size)), titlebar: None, @@ -129,8 +128,8 @@ impl CopilotCodeVerification { }; v_stack() .flex_1() + .gap_2() .items_center() - .justify_between() .w_full() .child(Label::new( "Enable Copilot by connecting your existing license", @@ -141,13 +140,16 @@ impl CopilotCodeVerification { .size(ui::LabelSize::Small), ) .child( - Button::new("connect-button", connect_button_label).on_click({ - let verification_uri = data.verification_uri.clone(); - cx.listener(move |this, _, cx| { - cx.open_url(&verification_uri); - this.connect_clicked = true; + Button::new("connect-button", connect_button_label) + .on_click({ + let verification_uri = data.verification_uri.clone(); + cx.listener(move |this, _, cx| { + cx.open_url(&verification_uri); + this.connect_clicked = true; + }) }) - }), + .full_width() + .style(ButtonStyle::Filled), ) } fn render_enabled_modal() -> impl Element { @@ -196,16 +198,23 @@ impl Render for CopilotCodeVerification { } _ => div().into_any_element(), }; - div() + + v_stack() .id("copilot code verification") - .flex() - .flex_col() + .elevation_3(cx) .size_full() .items_center() - .p_10() - .bg(cx.theme().colors().element_background) - .child(ui::Label::new("Connect Copilot to Zed")) - .child(IconElement::new(Icon::ZedXCopilot)) + .p_4() + .gap_4() + .child(Headline::new("Connect Copilot to Zed").size(HeadlineSize::Large)) + .child( + svg() + .w_32() + .h_16() + .flex_none() + .path(Icon::ZedXCopilot.path()) + .text_color(cx.theme().colors().icon), + ) .child(prompt) } } From 3e8e1c64045181d958fa4f32f3d89ecffa8dc0a4 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 5 Jan 2024 15:58:45 +0100 Subject: [PATCH 03/10] Move UI for copilot sign in to copilot_button --- Cargo.lock | 2 +- crates/copilot/Cargo.toml | 1 - crates/copilot/src/copilot.rs | 3 --- crates/copilot_button/Cargo.toml | 1 + crates/copilot_button/src/copilot_button.rs | 6 ++++++ crates/{copilot => copilot_button}/src/sign_in.rs | 3 ++- crates/zed/src/main.rs | 1 + 7 files changed, 11 insertions(+), 6 deletions(-) rename crates/{copilot => copilot_button}/src/sign_in.rs (98%) diff --git a/Cargo.lock b/Cargo.lock index 0316c343cb4ea5922897d9fc8ab417793e770ade..e0bfcc79b63f38e03a6984d21d7e8fdba85cb329 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1684,7 +1684,6 @@ dependencies = [ "settings", "smol", "theme", - "ui", "util", ] @@ -1702,6 +1701,7 @@ dependencies = [ "settings", "smol", "theme", + "ui", "util", "workspace", "zed_actions", diff --git a/crates/copilot/Cargo.toml b/crates/copilot/Cargo.toml index 588c747696c3ed58696bd12fbe97f3cbf3f9ef8a..fefd49090fd2020f4dc6da8aa1c2a1c5d119ea96 100644 --- a/crates/copilot/Cargo.toml +++ b/crates/copilot/Cargo.toml @@ -28,7 +28,6 @@ theme = { path = "../theme" } lsp = { path = "../lsp" } node_runtime = { path = "../node_runtime"} util = { path = "../util" } -ui = { path = "../ui" } async-compression.workspace = true async-tar = "0.4.2" anyhow.workspace = true diff --git a/crates/copilot/src/copilot.rs b/crates/copilot/src/copilot.rs index 658eb3451f473d4a9af26053dae20f21479c339e..89d1086c8e4b897c3527964289ff11810078a57c 100644 --- a/crates/copilot/src/copilot.rs +++ b/crates/copilot/src/copilot.rs @@ -1,6 +1,4 @@ pub mod request; -mod sign_in; - use anyhow::{anyhow, Context as _, Result}; use async_compression::futures::bufread::GzipDecoder; use async_tar::Archive; @@ -98,7 +96,6 @@ pub fn init( }) .detach(); - sign_in::init(cx); cx.on_action(|_: &SignIn, cx| { if let Some(copilot) = Copilot::global(cx) { copilot diff --git a/crates/copilot_button/Cargo.toml b/crates/copilot_button/Cargo.toml index 63788f9d28a5097bab1f02ab340c253b704cc599..e166e760c13dc8faddfd45f9712ebfb84c826393 100644 --- a/crates/copilot_button/Cargo.toml +++ b/crates/copilot_button/Cargo.toml @@ -17,6 +17,7 @@ gpui = { path = "../gpui" } language = { path = "../language" } settings = { path = "../settings" } theme = { path = "../theme" } +ui = { path = "../ui" } util = { path = "../util" } workspace = {path = "../workspace" } anyhow.workspace = true diff --git a/crates/copilot_button/src/copilot_button.rs b/crates/copilot_button/src/copilot_button.rs index 60b25fee12ab8c32ca6894fb2363f271f27246a4..3b561da2f142a771157f4ed3c141c41768428cb4 100644 --- a/crates/copilot_button/src/copilot_button.rs +++ b/crates/copilot_button/src/copilot_button.rs @@ -1,3 +1,5 @@ +mod sign_in; + use anyhow::Result; use copilot::{Copilot, SignOut, Status}; use editor::{scroll::autoscroll::Autoscroll, Editor}; @@ -25,6 +27,10 @@ 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 fn init(cx: &mut AppContext) { + sign_in::init(cx); +} + pub struct CopilotButton { editor_subscription: Option<(Subscription, usize)>, editor_enabled: Option, diff --git a/crates/copilot/src/sign_in.rs b/crates/copilot_button/src/sign_in.rs similarity index 98% rename from crates/copilot/src/sign_in.rs rename to crates/copilot_button/src/sign_in.rs index 4c736e930e0cf5f0a325a267af68295b37e68079..a632ce08d050dbc1f10d9a163da23afa0fedc9ff 100644 --- a/crates/copilot/src/sign_in.rs +++ b/crates/copilot_button/src/sign_in.rs @@ -1,4 +1,4 @@ -use crate::{request::PromptUserDeviceFlow, Copilot, Status}; +use copilot::{request::PromptUserDeviceFlow, Copilot, Status}; use gpui::{ div, size, svg, AppContext, Bounds, ClipboardItem, Element, GlobalPixels, InteractiveElement, IntoElement, ParentElement, Point, Render, Styled, ViewContext, VisualContext, WindowBounds, @@ -80,6 +80,7 @@ pub struct CopilotCodeVerification { connect_clicked: bool, } +//impl ModalView for CopilotCodeVerification {} impl CopilotCodeVerification { pub fn new(status: Status) -> Self { Self { diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index e0da81edc4ae17702b55a306bae3ec8b9d7a2bfd..e41baee4aea80c39bf5153f15f6fb1f80db4bb53 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -158,6 +158,7 @@ fn main() { node_runtime.clone(), cx, ); + copilot_button::init(cx); assistant::init(cx); cx.spawn(|_| watch_languages(fs.clone(), languages.clone())) From 0ce94fc791af44e0bce3f2202904f2f6585e6b7f Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 5 Jan 2024 16:27:52 +0100 Subject: [PATCH 04/10] Convert copilot popup to modal --- crates/copilot_button/src/copilot_button.rs | 16 +-- crates/copilot_button/src/sign_in.rs | 109 ++++++-------------- crates/zed/src/main.rs | 1 - 3 files changed, 39 insertions(+), 87 deletions(-) diff --git a/crates/copilot_button/src/copilot_button.rs b/crates/copilot_button/src/copilot_button.rs index 3b561da2f142a771157f4ed3c141c41768428cb4..6bf1d6cfcc9a1a7b614857e04952e6e301a71745 100644 --- a/crates/copilot_button/src/copilot_button.rs +++ b/crates/copilot_button/src/copilot_button.rs @@ -13,6 +13,7 @@ use language::{ File, Language, }; use settings::{update_settings_file, Settings, SettingsStore}; +use sign_in::CopilotCodeVerification; use std::{path::Path, sync::Arc}; use util::{paths, ResultExt}; use workspace::{ @@ -27,10 +28,6 @@ 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 fn init(cx: &mut AppContext) { - sign_in::init(cx); -} - pub struct CopilotButton { editor_subscription: Option<(Subscription, usize)>, editor_enabled: Option, @@ -337,7 +334,9 @@ fn initiate_sign_in(cx: &mut WindowContext) { return; }; let status = copilot.read(cx).status(); - + let Some(workspace) = cx.window_handle().downcast::() else { + return; + }; match status { Status::Starting { task } => { let Some(workspace) = cx.window_handle().downcast::() else { @@ -376,9 +375,10 @@ fn initiate_sign_in(cx: &mut WindowContext) { .detach(); } _ => { - copilot - .update(cx, |copilot, cx| copilot.sign_in(cx)) - .detach_and_log_err(cx); + copilot.update(cx, |this, cx| this.sign_in(cx)).detach(); + workspace.update(cx, |this, cx| { + this.toggle_modal(cx, |cx| CopilotCodeVerification::new(&copilot, cx)); + }); } } } diff --git a/crates/copilot_button/src/sign_in.rs b/crates/copilot_button/src/sign_in.rs index a632ce08d050dbc1f10d9a163da23afa0fedc9ff..15e68f961e9c1f099cd456956b8d3c7552d3d7d4 100644 --- a/crates/copilot_button/src/sign_in.rs +++ b/crates/copilot_button/src/sign_in.rs @@ -1,91 +1,49 @@ use copilot::{request::PromptUserDeviceFlow, Copilot, Status}; use gpui::{ - div, size, svg, AppContext, Bounds, ClipboardItem, Element, GlobalPixels, InteractiveElement, - IntoElement, ParentElement, Point, Render, Styled, ViewContext, VisualContext, WindowBounds, + div, size, svg, AppContext, Bounds, ClipboardItem, DismissEvent, Element, EventEmitter, + FocusHandle, FocusableView, GlobalPixels, InteractiveElement, IntoElement, Model, + ParentElement, Point, Render, Styled, Subscription, ViewContext, VisualContext, WindowBounds, WindowHandle, WindowKind, WindowOptions, }; use ui::{prelude::*, Button, Icon, Label}; +use workspace::ModalView; const COPILOT_SIGN_UP_URL: &'static str = "https://github.com/features/copilot"; -pub fn init(cx: &mut AppContext) { - if let Some(copilot) = Copilot::global(cx) { - let mut verification_window: Option> = None; - cx.observe(&copilot, move |copilot, cx| { - let status = copilot.read(cx).status(); - - match &status { - crate::Status::SigningIn { prompt } => { - if let Some(window) = verification_window.as_mut() { - let updated = window - .update(cx, |verification, cx| { - verification.set_status(status.clone(), cx); - cx.activate_window(); - }) - .is_ok(); - if !updated { - verification_window = Some(create_copilot_auth_window(cx, &status)); - } - } else if let Some(_prompt) = prompt { - verification_window = Some(create_copilot_auth_window(cx, &status)); - } - } - Status::Authorized | Status::Unauthorized => { - if let Some(window) = verification_window.as_ref() { - window - .update(cx, |verification, cx| { - verification.set_status(status, cx); - cx.activate(true); - cx.activate_window(); - }) - .ok(); - } - } - _ => { - if let Some(code_verification) = verification_window.take() { - code_verification - .update(cx, |_, cx| cx.remove_window()) - .ok(); - } - } - } - }) - .detach(); - } -} - -fn create_copilot_auth_window( - cx: &mut AppContext, - status: &Status, -) -> WindowHandle { - let window_size = size(GlobalPixels::from(400.), GlobalPixels::from(480.)); - let window_options = WindowOptions { - bounds: WindowBounds::Fixed(Bounds::new(Point::default(), window_size)), - titlebar: None, - center: true, - focus: true, - show: true, - kind: WindowKind::PopUp, - is_movable: true, - display_id: None, - }; - let window = cx.open_window(window_options, |cx| { - cx.new_view(|_| CopilotCodeVerification::new(status.clone())) - }); - window -} +pub fn init(cx: &mut AppContext) {} pub struct CopilotCodeVerification { status: Status, connect_clicked: bool, + focus_handle: FocusHandle, + _subscription: Subscription, +} + +impl FocusableView for CopilotCodeVerification { + fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle { + self.focus_handle.clone() + } } -//impl ModalView for CopilotCodeVerification {} +impl EventEmitter for CopilotCodeVerification {} +impl ModalView for CopilotCodeVerification {} + impl CopilotCodeVerification { - pub fn new(status: Status) -> Self { + pub(crate) fn new(copilot: &Model, cx: &mut ViewContext) -> Self { + let status = copilot.read(cx).status(); Self { status, connect_clicked: false, + focus_handle: cx.focus_handle(), + _subscription: cx.observe(copilot, |this, copilot, cx| { + let status = copilot.read(cx).status(); + match status { + Status::Authorized | Status::Unauthorized | Status::SigningIn { .. } => { + this.set_status(status, cx) + } + _ => cx.emit(DismissEvent), + } + }), } } @@ -159,10 +117,7 @@ impl CopilotCodeVerification { .child(Label::new( "You can update your settings or sign out from the Copilot menu in the status bar.", )) - .child( - Button::new("copilot-enabled-done-button", "Done") - .on_click(|_, cx| cx.remove_window()), - ) + .child(Button::new("copilot-enabled-done-button", "Done").on_click(|_, cx| {})) } fn render_unauthorized_modal() -> impl Element { @@ -175,10 +130,8 @@ impl CopilotCodeVerification { .color(Color::Warning), ) .child( - Button::new("copilot-subscribe-button", "Subscibe on Github").on_click(|_, cx| { - cx.remove_window(); - cx.open_url(COPILOT_SIGN_UP_URL) - }), + Button::new("copilot-subscribe-button", "Subscibe on Github") + .on_click(|_, cx| cx.open_url(COPILOT_SIGN_UP_URL)), ) } } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index e41baee4aea80c39bf5153f15f6fb1f80db4bb53..e0da81edc4ae17702b55a306bae3ec8b9d7a2bfd 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -158,7 +158,6 @@ fn main() { node_runtime.clone(), cx, ); - copilot_button::init(cx); assistant::init(cx); cx.spawn(|_| watch_languages(fs.clone(), languages.clone())) From 0670a6f838e0d869b8607e5f3dd605373cdd68ff Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 5 Jan 2024 16:32:47 +0100 Subject: [PATCH 05/10] Fix up warnings, bind 'Done' button to DismissEvent --- crates/copilot_button/src/copilot_button.rs | 8 +++++--- crates/copilot_button/src/sign_in.rs | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/crates/copilot_button/src/copilot_button.rs b/crates/copilot_button/src/copilot_button.rs index 6bf1d6cfcc9a1a7b614857e04952e6e301a71745..2a1bde785e0f69c2ddef8041ff0c2177d528ebed 100644 --- a/crates/copilot_button/src/copilot_button.rs +++ b/crates/copilot_button/src/copilot_button.rs @@ -376,9 +376,11 @@ fn initiate_sign_in(cx: &mut WindowContext) { } _ => { copilot.update(cx, |this, cx| this.sign_in(cx)).detach(); - workspace.update(cx, |this, cx| { - this.toggle_modal(cx, |cx| CopilotCodeVerification::new(&copilot, cx)); - }); + workspace + .update(cx, |this, cx| { + this.toggle_modal(cx, |cx| CopilotCodeVerification::new(&copilot, cx)); + }) + .ok(); } } } diff --git a/crates/copilot_button/src/sign_in.rs b/crates/copilot_button/src/sign_in.rs index 15e68f961e9c1f099cd456956b8d3c7552d3d7d4..d3e52c3e19db9c491fcf6091a4db67d6753d270b 100644 --- a/crates/copilot_button/src/sign_in.rs +++ b/crates/copilot_button/src/sign_in.rs @@ -1,17 +1,14 @@ use copilot::{request::PromptUserDeviceFlow, Copilot, Status}; use gpui::{ - div, size, svg, AppContext, Bounds, ClipboardItem, DismissEvent, Element, EventEmitter, - FocusHandle, FocusableView, GlobalPixels, InteractiveElement, IntoElement, Model, - ParentElement, Point, Render, Styled, Subscription, ViewContext, VisualContext, WindowBounds, - WindowHandle, WindowKind, WindowOptions, + div, svg, AppContext, ClipboardItem, DismissEvent, Element, EventEmitter, FocusHandle, + FocusableView, InteractiveElement, IntoElement, Model, ParentElement, Render, Styled, + Subscription, ViewContext, }; use ui::{prelude::*, Button, Icon, Label}; use workspace::ModalView; const COPILOT_SIGN_UP_URL: &'static str = "https://github.com/features/copilot"; -pub fn init(cx: &mut AppContext) {} - pub struct CopilotCodeVerification { status: Status, connect_clicked: bool, @@ -20,7 +17,7 @@ pub struct CopilotCodeVerification { } impl FocusableView for CopilotCodeVerification { - fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle { + fn focus_handle(&self, _: &AppContext) -> gpui::FocusHandle { self.focus_handle.clone() } } @@ -111,13 +108,16 @@ impl CopilotCodeVerification { .style(ButtonStyle::Filled), ) } - fn render_enabled_modal() -> impl Element { + fn render_enabled_modal(cx: &mut ViewContext) -> impl Element { v_stack() .child(Label::new("Copilot Enabled!")) .child(Label::new( "You can update your settings or sign out from the Copilot menu in the status bar.", )) - .child(Button::new("copilot-enabled-done-button", "Done").on_click(|_, cx| {})) + .child( + Button::new("copilot-enabled-done-button", "Done") + .on_click(cx.listener(|_, _, cx| cx.emit(DismissEvent))), + ) } fn render_unauthorized_modal() -> impl Element { @@ -148,7 +148,7 @@ impl Render for CopilotCodeVerification { } Status::Authorized => { self.connect_clicked = false; - Self::render_enabled_modal().into_any_element() + Self::render_enabled_modal(cx).into_any_element() } _ => div().into_any_element(), }; From 0602953af457c24574d654d2137c56822bc7611b Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 5 Jan 2024 16:36:26 +0100 Subject: [PATCH 06/10] Rename copilot_button crate to copilot_ui --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- crates/{copilot_button => copilot_ui}/Cargo.toml | 4 ++-- crates/{copilot_button => copilot_ui}/src/copilot_button.rs | 4 +--- crates/copilot_ui/src/copilot_ui.rs | 5 +++++ crates/{copilot_button => copilot_ui}/src/sign_in.rs | 0 crates/zed/Cargo.toml | 2 +- crates/zed/src/zed.rs | 2 +- 8 files changed, 13 insertions(+), 10 deletions(-) rename crates/{copilot_button => copilot_ui}/Cargo.toml (91%) rename crates/{copilot_button => copilot_ui}/src/copilot_button.rs (99%) create mode 100644 crates/copilot_ui/src/copilot_ui.rs rename crates/{copilot_button => copilot_ui}/src/sign_in.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index e0bfcc79b63f38e03a6984d21d7e8fdba85cb329..ac167dcc7b1778cb955cbe4c8e8ba38dc51cca7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1688,7 +1688,7 @@ dependencies = [ ] [[package]] -name = "copilot_button" +name = "copilot_ui" version = "0.1.0" dependencies = [ "anyhow", @@ -9537,7 +9537,7 @@ dependencies = [ "collections", "command_palette", "copilot", - "copilot_button", + "copilot_ui", "ctor", "db", "diagnostics", diff --git a/Cargo.toml b/Cargo.toml index 9f2bc145901cdcfa4fc7c02649edcdbbbb73dc07..fa21cc5364b34c639e8faa419448943d4ba5cd3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ members = [ "crates/collections", "crates/command_palette", "crates/copilot", - "crates/copilot_button", + "crates/copilot_ui", "crates/db", "crates/refineable", "crates/refineable/derive_refineable", diff --git a/crates/copilot_button/Cargo.toml b/crates/copilot_ui/Cargo.toml similarity index 91% rename from crates/copilot_button/Cargo.toml rename to crates/copilot_ui/Cargo.toml index e166e760c13dc8faddfd45f9712ebfb84c826393..491f4f3cdec3d2ebd20fe1d6a2536471f862b90b 100644 --- a/crates/copilot_button/Cargo.toml +++ b/crates/copilot_ui/Cargo.toml @@ -1,11 +1,11 @@ [package] -name = "copilot_button" +name = "copilot_ui" version = "0.1.0" edition = "2021" publish = false [lib] -path = "src/copilot_button.rs" +path = "src/copilot_ui.rs" doctest = false [dependencies] diff --git a/crates/copilot_button/src/copilot_button.rs b/crates/copilot_ui/src/copilot_button.rs similarity index 99% rename from crates/copilot_button/src/copilot_button.rs rename to crates/copilot_ui/src/copilot_button.rs index 2a1bde785e0f69c2ddef8041ff0c2177d528ebed..e55f45c29333edbecc22742fccf0d4cd10a4a0df 100644 --- a/crates/copilot_button/src/copilot_button.rs +++ b/crates/copilot_ui/src/copilot_button.rs @@ -1,5 +1,4 @@ -mod sign_in; - +use crate::sign_in::CopilotCodeVerification; use anyhow::Result; use copilot::{Copilot, SignOut, Status}; use editor::{scroll::autoscroll::Autoscroll, Editor}; @@ -13,7 +12,6 @@ use language::{ File, Language, }; use settings::{update_settings_file, Settings, SettingsStore}; -use sign_in::CopilotCodeVerification; use std::{path::Path, sync::Arc}; use util::{paths, ResultExt}; use workspace::{ diff --git a/crates/copilot_ui/src/copilot_ui.rs b/crates/copilot_ui/src/copilot_ui.rs new file mode 100644 index 0000000000000000000000000000000000000000..64dd068d5aff5f0910e0ed78ea2746f0f6540189 --- /dev/null +++ b/crates/copilot_ui/src/copilot_ui.rs @@ -0,0 +1,5 @@ +mod copilot_button; +mod sign_in; + +pub use copilot_button::*; +pub use sign_in::*; diff --git a/crates/copilot_button/src/sign_in.rs b/crates/copilot_ui/src/sign_in.rs similarity index 100% rename from crates/copilot_button/src/sign_in.rs rename to crates/copilot_ui/src/sign_in.rs diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 39ab5e285b77672e31d8b33555f83bd768e4be68..2d6ad999a55731fee0eb09a1f64e471a20edd7fd 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -30,7 +30,7 @@ command_palette = { path = "../command_palette" } client = { path = "../client" } # clock = { path = "../clock" } copilot = { path = "../copilot" } -copilot_button = { path = "../copilot_button" } +copilot_ui = { path = "../copilot_ui" } diagnostics = { path = "../diagnostics" } db = { path = "../db" } editor = { path = "../editor" } diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index c7d30230ea035b29121ceb487e4ea3ce483d5d54..f0634081f3491439b8a662422acd9d641966eb4e 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -123,7 +123,7 @@ pub fn initialize_workspace(app_state: Arc, cx: &mut AppContext) { // workspace.set_titlebar_item(collab_titlebar_item.into_any(), cx); let copilot = - cx.new_view(|cx| copilot_button::CopilotButton::new(app_state.fs.clone(), cx)); + cx.new_view(|cx| copilot_ui::CopilotButton::new(app_state.fs.clone(), cx)); let diagnostic_summary = cx.new_view(|cx| diagnostics::items::DiagnosticIndicator::new(workspace, cx)); let activity_indicator = From 61ebb9fb378459807c1906643a77f494b628655c Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 5 Jan 2024 16:43:35 +0100 Subject: [PATCH 07/10] cargo fmt --- crates/zed/src/zed.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index f0634081f3491439b8a662422acd9d641966eb4e..d5efa0f26380ef3d521f705d8acd437e4833426f 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -122,8 +122,7 @@ pub fn initialize_workspace(app_state: Arc, 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.new_view(|cx| copilot_ui::CopilotButton::new(app_state.fs.clone(), cx)); + let copilot = cx.new_view(|cx| copilot_ui::CopilotButton::new(app_state.fs.clone(), cx)); let diagnostic_summary = cx.new_view(|cx| diagnostics::items::DiagnosticIndicator::new(workspace, cx)); let activity_indicator = From d1445431f2deb6fb7225c81d8966b72ba3729f64 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Fri, 5 Jan 2024 15:59:34 -0500 Subject: [PATCH 08/10] Use the already existing styles/typography for Headline --- crates/ui/src/components.rs | 2 - crates/ui/src/components/typography.rs | 71 ------------------------- crates/ui/src/styles/typography.rs | 72 +++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 74 deletions(-) delete mode 100644 crates/ui/src/components/typography.rs diff --git a/crates/ui/src/components.rs b/crates/ui/src/components.rs index 4049815f1b5abdfaf68144456c38f7c6f72b51c7..0848ac74dfd594ab2dbf2a170d927a70b3ae386d 100644 --- a/crates/ui/src/components.rs +++ b/crates/ui/src/components.rs @@ -16,7 +16,6 @@ mod stack; mod tab; mod tab_bar; mod tooltip; -mod typography; #[cfg(feature = "stories")] mod stories; @@ -39,7 +38,6 @@ pub use stack::*; pub use tab::*; pub use tab_bar::*; pub use tooltip::*; -pub use typography::*; #[cfg(feature = "stories")] pub use stories::*; diff --git a/crates/ui/src/components/typography.rs b/crates/ui/src/components/typography.rs deleted file mode 100644 index c613559faf61ed352cb533767fa310c2b94041d8..0000000000000000000000000000000000000000 --- a/crates/ui/src/components/typography.rs +++ /dev/null @@ -1,71 +0,0 @@ -use gpui::{ - div, rems, IntoElement, ParentElement, Rems, RenderOnce, SharedString, Styled, WindowContext, -}; -use settings::Settings; -use theme::{ActiveTheme, ThemeSettings}; - -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)] -pub enum HeadlineSize { - XSmall, - Small, - #[default] - Medium, - Large, - XLarge, -} - -impl HeadlineSize { - pub fn size(self) -> Rems { - match self { - // Based on the Major Second scale - Self::XSmall => rems(0.88), - Self::Small => rems(1.0), - Self::Medium => rems(1.125), - Self::Large => rems(1.27), - Self::XLarge => rems(1.43), - } - } - - pub fn line_height(self) -> Rems { - match self { - Self::XSmall => rems(1.6), - Self::Small => rems(1.6), - Self::Medium => rems(1.6), - Self::Large => rems(1.6), - Self::XLarge => rems(1.6), - } - } -} - -#[derive(IntoElement)] -pub struct Headline { - size: HeadlineSize, - text: SharedString, -} - -impl RenderOnce for Headline { - fn render(self, cx: &mut WindowContext) -> impl IntoElement { - let ui_font = ThemeSettings::get_global(cx).ui_font.family.clone(); - - div() - .font(ui_font) - .line_height(self.size.line_height()) - .text_size(self.size.size()) - .text_color(cx.theme().colors().text) - .child(self.text) - } -} - -impl Headline { - pub fn new(text: impl Into) -> Self { - Self { - size: HeadlineSize::default(), - text: text.into(), - } - } - - pub fn size(mut self, size: HeadlineSize) -> Self { - self.size = size; - self - } -} diff --git a/crates/ui/src/styles/typography.rs b/crates/ui/src/styles/typography.rs index 4819791b02c988bfccc1c59484b373e5d8249bfe..39937ebff1701f2195c4112235c919368b97b364 100644 --- a/crates/ui/src/styles/typography.rs +++ b/crates/ui/src/styles/typography.rs @@ -1,4 +1,8 @@ -use gpui::{rems, Rems}; +use gpui::{ + div, rems, IntoElement, ParentElement, Rems, RenderOnce, SharedString, Styled, WindowContext, +}; +use settings::Settings; +use theme::{ActiveTheme, ThemeSettings}; #[derive(Debug, Default, Clone)] pub enum UiTextSize { @@ -33,3 +37,69 @@ impl UiTextSize { } } } + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)] +pub enum HeadlineSize { + XSmall, + Small, + #[default] + Medium, + Large, + XLarge, +} + +impl HeadlineSize { + pub fn size(self) -> Rems { + match self { + // Based on the Major Second scale + Self::XSmall => rems(0.88), + Self::Small => rems(1.0), + Self::Medium => rems(1.125), + Self::Large => rems(1.27), + Self::XLarge => rems(1.43), + } + } + + pub fn line_height(self) -> Rems { + match self { + Self::XSmall => rems(1.6), + Self::Small => rems(1.6), + Self::Medium => rems(1.6), + Self::Large => rems(1.6), + Self::XLarge => rems(1.6), + } + } +} + +#[derive(IntoElement)] +pub struct Headline { + size: HeadlineSize, + text: SharedString, +} + +impl RenderOnce for Headline { + fn render(self, cx: &mut WindowContext) -> impl IntoElement { + let ui_font = ThemeSettings::get_global(cx).ui_font.family.clone(); + + div() + .font(ui_font) + .line_height(self.size.line_height()) + .text_size(self.size.size()) + .text_color(cx.theme().colors().text) + .child(self.text) + } +} + +impl Headline { + pub fn new(text: impl Into) -> Self { + Self { + size: HeadlineSize::default(), + text: text.into(), + } + } + + pub fn size(mut self, size: HeadlineSize) -> Self { + self.size = size; + self + } +} From 76b1a3ca0ef166d0fad52e0b2d55fab9b32066e3 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Fri, 5 Jan 2024 16:17:06 -0500 Subject: [PATCH 09/10] Refine copilot UI --- crates/copilot_ui/src/sign_in.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/copilot_ui/src/sign_in.rs b/crates/copilot_ui/src/sign_in.rs index d3e52c3e19db9c491fcf6091a4db67d6753d270b..029ad149b8d07df22ea7b4bcf97738e2b4631f84 100644 --- a/crates/copilot_ui/src/sign_in.rs +++ b/crates/copilot_ui/src/sign_in.rs @@ -86,10 +86,11 @@ impl CopilotCodeVerification { .flex_1() .gap_2() .items_center() - .w_full() - .child(Label::new( - "Enable Copilot by connecting your existing license", - )) + .child(Headline::new("Use Github Copilot in Zed.").size(HeadlineSize::Large)) + .child( + Label::new("Using Copilot requres an active subscription on Github.") + .color(Color::Muted), + ) .child(Self::render_device_code(data, cx)) .child( Label::new("Paste this code into GitHub after clicking the button below.") @@ -156,11 +157,10 @@ impl Render for CopilotCodeVerification { v_stack() .id("copilot code verification") .elevation_3(cx) - .size_full() + .w_96() .items_center() .p_4() - .gap_4() - .child(Headline::new("Connect Copilot to Zed").size(HeadlineSize::Large)) + .gap_2() .child( svg() .w_32() From b57a1f90f491cdbc1862a1de891eee8a674dd51d Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Mon, 8 Jan 2024 13:21:45 -0500 Subject: [PATCH 10/10] Update copilot ui --- crates/copilot_ui/src/sign_in.rs | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/crates/copilot_ui/src/sign_in.rs b/crates/copilot_ui/src/sign_in.rs index 029ad149b8d07df22ea7b4bcf97738e2b4631f84..aeaa35784bfabe5ab75fc2b26a59dada83ddb61a 100644 --- a/crates/copilot_ui/src/sign_in.rs +++ b/crates/copilot_ui/src/sign_in.rs @@ -58,6 +58,11 @@ impl CopilotCodeVerification { .map(|item| item.text() == &data.user_code) .unwrap_or(false); h_stack() + .w_full() + .p_1() + .border() + .border_muted(cx) + .rounded_md() .cursor_pointer() .justify_between() .on_mouse_down(gpui::MouseButton::Left, { @@ -67,9 +72,12 @@ impl CopilotCodeVerification { cx.notify(); } }) - .child(Label::new(data.user_code.clone())) - .child(div()) - .child(Label::new(if copied { "Copied!" } else { "Copy" })) + .child(div().flex_1().child(Label::new(data.user_code.clone()))) + .child(div().flex_none().px_1().child(Label::new(if copied { + "Copied!" + } else { + "Copy" + }))) } fn render_prompting_modal( @@ -111,27 +119,28 @@ impl CopilotCodeVerification { } fn render_enabled_modal(cx: &mut ViewContext) -> impl Element { v_stack() - .child(Label::new("Copilot Enabled!")) + .gap_2() + .child(Headline::new("Copilot Enabled!").size(HeadlineSize::Large)) .child(Label::new( "You can update your settings or sign out from the Copilot menu in the status bar.", )) .child( Button::new("copilot-enabled-done-button", "Done") + .full_width() .on_click(cx.listener(|_, _, cx| cx.emit(DismissEvent))), ) } fn render_unauthorized_modal() -> impl Element { v_stack() + .child(Headline::new("You must have an active GitHub Copilot subscription.").size(HeadlineSize::Large)) + .child(Label::new( - "Enable Copilot by connecting your existing license.", - )) - .child( - Label::new("You must have an active Copilot license to use it in Zed.") - .color(Color::Warning), - ) + "You can enable Copilot by connecting your existing license once you have subscribed or renewed your subscription.", + ).color(Color::Warning)) .child( Button::new("copilot-subscribe-button", "Subscibe on Github") + .full_width() .on_click(|_, cx| cx.open_url(COPILOT_SIGN_UP_URL)), ) }