Detailed changes
@@ -51,10 +51,10 @@ enum CopilotServer {
#[derive(Clone, Debug)]
enum SignInStatus {
Authorized {
- user: String,
+ _user: String,
},
Unauthorized {
- user: String,
+ _user: String,
},
SigningIn {
prompt: Option<request::PromptUserDeviceFlow>,
@@ -321,10 +321,10 @@ impl Copilot {
if let CopilotServer::Started { status, .. } = &mut self.server {
*status = match lsp_status {
request::SignInStatus::Ok { user } | request::SignInStatus::MaybeOk { user } => {
- SignInStatus::Authorized { user }
+ SignInStatus::Authorized { _user: user }
}
request::SignInStatus::NotAuthorized { user } => {
- SignInStatus::Unauthorized { user }
+ SignInStatus::Unauthorized { _user: user }
}
_ => SignInStatus::SignedOut,
};
@@ -26,13 +26,7 @@ pub fn init(cx: &mut MutableAppContext) {
cx.remove_window(window_id);
}
- let window_size = cx
- .global::<Settings>()
- .theme
- .copilot
- .auth
- .popup_dimensions
- .to_vec();
+ let window_size = cx.global::<Settings>().theme.copilot.modal.dimensions();
let (window_id, _) = cx.add_window(
WindowOptions {
@@ -43,13 +37,15 @@ pub fn init(cx: &mut MutableAppContext) {
titlebar: None,
center: true,
focus: false,
- kind: WindowKind::PopUp,
+ kind: WindowKind::Normal,
is_movable: true,
screen: None,
},
|_| CopilotCodeVerification::new(prompt),
);
code_verification_window_id = Some(window_id);
+
+ cx.activate_window(window_id);
}
_ => {
if let Some(window_id) = code_verification_window_id.take() {
@@ -59,6 +55,26 @@ pub fn init(cx: &mut MutableAppContext) {
}
})
.detach();
+
+ // let window_size = cx.global::<Settings>().theme.copilot.modal.dimensions();
+
+ // let (_window_id, _) = cx.add_window(
+ // WindowOptions {
+ // bounds: gpui::WindowBounds::Fixed(RectF::new(Default::default(), window_size)),
+ // titlebar: None,
+ // center: true,
+ // focus: false,
+ // kind: WindowKind::PopUp,
+ // is_movable: true,
+ // screen: None,
+ // },
+ // |_| {
+ // CopilotCodeVerification::new(PromptUserDeviceFlow {
+ // user_code: "ABCD-1234".to_string(),
+ // verification_uri: "https://github.com/login/device".to_string(),
+ // })
+ // },
+ // );
}
pub struct CopilotCodeVerification {
@@ -74,71 +90,146 @@ impl View for CopilotCodeVerification {
"CopilotCodeVerification"
}
+ fn focus_in(&mut self, _: gpui::AnyViewHandle, cx: &mut gpui::ViewContext<Self>) {
+ cx.notify()
+ }
+
fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox {
let style = cx.global::<Settings>().theme.copilot.clone();
- let instruction_text = style.auth.instruction_text;
- let user_code_text = style.auth.user_code;
- let button = style.auth.button;
- let button_width = style.auth.button_width;
- let height = style.auth.popup_dimensions.height;
-
- let user_code = self.prompt.user_code.replace("-", " - ");
-
- Flex::column()
- .with_child(
- MouseEventHandler::<Self>::new(0, cx, |state, _cx| {
- let style = style.auth.close_icon.style_for(state, false);
- theme::ui::icon(style).boxed()
- })
- .on_click(gpui::MouseButton::Left, move |_, cx| {
- let window_id = cx.window_id();
- cx.remove_window(window_id);
- })
- .with_cursor_style(gpui::CursorStyle::PointingHand)
- .aligned()
- .right()
- .boxed(),
- )
- .with_child(
- Flex::column()
- .align_children_center()
- .with_children([
- theme::ui::svg(&style.auth.copilot_icon).boxed(),
- Label::new(
- "Here is your code to authenticate with github",
- instruction_text.clone(),
- )
+ let copied = cx
+ .read_from_clipboard()
+ .map(|item| item.text() == &self.prompt.user_code)
+ .unwrap_or(false);
+
+ theme::ui::modal("Authenticate Copilot", &style.modal, cx, |cx| {
+ Flex::column()
+ .align_children_center()
+ .with_children([
+ Flex::column()
+ .with_children([
+ Flex::row()
+ .with_children([
+ theme::ui::svg(&style.auth.copilot_icon).boxed(),
+ theme::ui::svg(&style.auth.plus_icon).boxed(),
+ theme::ui::svg(&style.auth.zed_icon).boxed(),
+ ])
+ .boxed(),
+ Label::new("Copilot for Zed", style.auth.header_text.clone()).boxed(),
+ ])
+ .align_children_center()
+ .contained()
+ .with_style(style.auth.header_group)
+ .aligned()
+ .boxed(),
+ Flex::column()
+ .with_children([
+ Label::new(
+ "Here is your code to authenticate with github",
+ style.auth.instruction_text.clone(),
+ )
+ .boxed(),
+ MouseEventHandler::<Self>::new(0, cx, |state, _cx| {
+ Flex::row()
+ .with_children([
+ Label::new(
+ self.prompt.user_code.clone(),
+ style.auth.device_code.clone(),
+ )
+ .aligned()
+ .contained()
+ .with_style(style.auth.device_code_left_container)
+ .constrained()
+ .with_width(style.auth.device_code_left)
+ .boxed(),
+ Empty::new()
+ .constrained()
+ .with_width(1.)
+ .with_height(style.auth.device_code_seperator_height)
+ .contained()
+ .with_background_color(
+ style
+ .auth
+ .cta_button
+ .style_for(state, false)
+ .container
+ .border
+ .color,
+ )
+ .boxed(),
+ Label::new(
+ if copied { "Copied!" } else { "Copy" },
+ style
+ .auth
+ .cta_button
+ .style_for(state, false)
+ .text
+ .clone(),
+ )
+ .aligned()
+ .contained()
+ .with_style(style.auth.device_code_right_container)
+ .constrained()
+ .with_width(style.auth.device_code_right)
+ .boxed(),
+ ])
+ .contained()
+ .with_style(
+ style
+ .auth
+ .device_code_cta
+ .style_for(state, false)
+ .container,
+ )
+ .constrained()
+ .with_width(style.auth.content_width)
+ .boxed()
+ })
+ .on_click(gpui::MouseButton::Left, {
+ let user_code = self.prompt.user_code.clone();
+ move |_, cx| {
+ cx.platform()
+ .write_to_clipboard(ClipboardItem::new(user_code.clone()));
+ cx.notify();
+ }
+ })
+ .with_cursor_style(gpui::CursorStyle::PointingHand)
+ .boxed(),
+ ])
+ .align_children_center()
+ .contained()
+ .with_style(style.auth.device_code_group)
+ .aligned()
.boxed(),
- Label::new(user_code, user_code_text.clone()).boxed(),
- theme::ui::cta_button_with_click("Copy Code", button_width, &button, cx, {
- let user_code = self.prompt.user_code.clone();
- move |_, cx| {
- cx.platform()
- .write_to_clipboard(ClipboardItem::new(user_code.clone()))
- }
- }),
- Label::new("Copy it and enter it on GitHub", instruction_text.clone())
+ Flex::column()
+ .with_children([
+ Label::new(
+ "Copy it and enter it on GitHub",
+ style.auth.instruction_text.clone(),
+ )
.boxed(),
- theme::ui::cta_button_with_click(
- "Go to Github",
- button_width,
- &button,
- cx,
- {
- let verification_uri = self.prompt.verification_uri.clone();
- move |_, cx| cx.platform().open_url(&verification_uri)
- },
- ),
- ])
- .aligned()
- .boxed(),
- )
- .contained()
- .with_style(style.auth.popup_container)
- .constrained()
- .with_height(height)
- .boxed()
+ theme::ui::cta_button_with_click(
+ "Go to Github",
+ style.auth.content_width,
+ &style.auth.cta_button,
+ cx,
+ {
+ let verification_uri = self.prompt.verification_uri.clone();
+ move |_, cx| cx.platform().open_url(&verification_uri)
+ },
+ ),
+ ])
+ .align_children_center()
+ .contained()
+ .with_style(style.auth.github_group)
+ .aligned()
+ .boxed(),
+ ])
+ .constrained()
+ .with_width(style.auth.content_width)
+ .aligned()
+ .boxed()
+ })
}
}
@@ -9,7 +9,7 @@ use gpui::{
use serde::{de::DeserializeOwned, Deserialize};
use serde_json::Value;
use std::{collections::HashMap, sync::Arc};
-use ui::{ButtonStyle, CheckboxStyle, Dimensions, IconStyle, SvgStyle};
+use ui::{ButtonStyle, CheckboxStyle, ModalStyle, SvgStyle};
pub mod ui;
@@ -118,19 +118,29 @@ pub struct AvatarStyle {
#[derive(Deserialize, Default, Clone)]
pub struct Copilot {
+ pub modal: ModalStyle,
pub auth: CopilotAuth,
}
#[derive(Deserialize, Default, Clone)]
pub struct CopilotAuth {
- pub popup_container: ContainerStyle,
- pub popup_dimensions: Dimensions,
pub instruction_text: TextStyle,
- pub user_code: TextStyle,
- pub button: ButtonStyle,
- pub button_width: f32,
+ pub cta_button: ButtonStyle,
+ pub content_width: f32,
pub copilot_icon: SvgStyle,
- pub close_icon: Interactive<IconStyle>,
+ pub plus_icon: SvgStyle,
+ pub zed_icon: SvgStyle,
+ pub header_text: TextStyle,
+ pub device_code_group: ContainerStyle,
+ pub github_group: ContainerStyle,
+ pub header_group: ContainerStyle,
+ pub device_code: TextStyle,
+ pub device_code_cta: ButtonStyle,
+ pub device_code_left: f32,
+ pub device_code_left_container: ContainerStyle,
+ pub device_code_right: f32,
+ pub device_code_right_container: ContainerStyle,
+ pub device_code_seperator_height: f32,
}
#[derive(Deserialize, Default)]
@@ -4,11 +4,12 @@ use gpui::{
color::Color,
elements::{
ConstrainedBox, Container, ContainerStyle, Empty, Flex, KeystrokeLabel, Label,
- MouseEventHandler, ParentElement, Svg,
+ MouseEventHandler, ParentElement, Stack, Svg,
},
+ fonts::TextStyle,
geometry::vector::{vec2f, Vector2F},
scene::MouseClick,
- Action, Element, ElementBox, EventContext, MouseButton, MouseState, RenderContext, View,
+ Action, Element, ElementBox, EventContext, MouseButton, RenderContext, View,
};
use serde::Deserialize;
@@ -213,3 +214,60 @@ where
.with_cursor_style(gpui::CursorStyle::PointingHand)
.boxed()
}
+
+#[derive(Clone, Deserialize, Default)]
+pub struct ModalStyle {
+ close_icon: Interactive<IconStyle>,
+ container: ContainerStyle,
+ titlebar: ContainerStyle,
+ title_text: TextStyle,
+ dimensions: Dimensions,
+}
+
+impl ModalStyle {
+ pub fn dimensions(&self) -> Vector2F {
+ self.dimensions.to_vec()
+ }
+}
+
+pub fn modal<V, I, F>(
+ title: I,
+ style: &ModalStyle,
+ cx: &mut RenderContext<V>,
+ build_modal: F,
+) -> ElementBox
+where
+ V: View,
+ I: Into<Cow<'static, str>>,
+ F: FnOnce(&mut gpui::RenderContext<V>) -> ElementBox,
+{
+ Flex::column()
+ .with_child(
+ Stack::new()
+ .with_children([
+ Label::new(title, style.title_text.clone()).boxed(),
+ // FIXME: Get a better tag type
+ MouseEventHandler::<V>::new(999999, cx, |state, _cx| {
+ let style = style.close_icon.style_for(state, false);
+ icon(style).boxed()
+ })
+ .on_click(gpui::MouseButton::Left, move |_, cx| {
+ let window_id = cx.window_id();
+ cx.remove_window(window_id);
+ })
+ .with_cursor_style(gpui::CursorStyle::PointingHand)
+ .aligned()
+ .right()
+ .boxed(),
+ ])
+ .contained()
+ .with_style(style.titlebar)
+ .boxed(),
+ )
+ .with_child(build_modal(cx))
+ .contained()
+ .with_style(style.container)
+ .constrained()
+ .with_height(style.dimensions().y())
+ .boxed()
+}
@@ -5,41 +5,52 @@ import { background, border, foreground, svg, text } from "./components";
export default function copilot(colorScheme: ColorScheme) {
let layer = colorScheme.highest;
+ let content_width = 304;
+
+ let ctaButton = { // Copied from welcome screen. FIXME: Move this into a ZDS component
+ background: background(layer),
+ border: border(layer, "active"),
+ cornerRadius: 4,
+ margin: {
+ top: 4,
+ bottom: 4,
+ },
+ padding: {
+ top: 3,
+ bottom: 3,
+ left: 7,
+ right: 7,
+ },
+ ...text(layer, "sans", "default", { size: "sm" }),
+ hover: {
+ ...text(layer, "sans", "default", { size: "sm" }),
+ background: background(layer, "hovered"),
+ border: border(layer, "active"),
+ },
+ };
+
return {
- auth: {
- popupContainer: {
- background: background(colorScheme.highest),
- },
- popupDimensions: {
- width: 336,
- height: 256,
- },
- instructionText: text(layer, "sans"),
- userCode:
- text(layer, "sans", { size: "lg" }),
- button: { // Copied from welcome screen. FIXME: Move this into a ZDS component
- background: background(layer),
+ modal: {
+ titleText: text(layer, "sans", { size: "md" }),
+ titlebar: {
border: border(layer, "active"),
- cornerRadius: 4,
- margin: {
+ padding: {
top: 4,
bottom: 4,
+ left: 8,
+ right: 8,
},
- padding: {
- top: 3,
- bottom: 3,
- left: 7,
- right: 7,
- },
- ...text(layer, "sans", "default", { size: "sm" }),
- hover: {
- ...text(layer, "sans", "default", { size: "sm" }),
- background: background(layer, "hovered"),
- border: border(layer, "active"),
- },
+ margin: {
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 8
+ }
+ },
+ container: {
+ background: background(colorScheme.highest),
+
},
- buttonWidth: 320,
- copilotIcon: svg(foreground(layer, "default"), "icons/github-copilot-dummy.svg", 64, 64),
closeIcon: {
icon: svg(background(layer, "on"), "icons/x_mark_16.svg", 16, 16),
container: {
@@ -47,13 +58,86 @@ export default function copilot(colorScheme: ColorScheme) {
top: 3,
bottom: 3,
left: 7,
- right: 7,
+ right: 0,
}
},
hover: {
icon: svg(foreground(layer, "on"), "icons/x_mark_16.svg", 16, 16),
}
},
+ dimensions: {
+ width: 400,
+ height: 500,
+ },
+ },
+ auth: {
+ content_width,
+
+ headerGroup: {
+ margin: {
+ top: 5,
+ bottom: 5,
+ left: 0,
+ right: 0
+ }
+ },
+ headerText: text(layer, "sans", { size: "lg" }),
+ copilotIcon: svg(foreground(layer, "default"), "icons/github-copilot-dummy.svg", 36, 36),
+ plusIcon: svg(foreground(layer, "default"), "icons/plus_16.svg", 36, 36),
+ zedIcon: svg(foreground(layer, "default"), "icons/logo_96.svg", 36, 36),
+
+ instructionText: text(layer, "sans"),
+
+ deviceCodeGroup: {
+ margin: {
+ top: 5,
+ bottom: 5,
+ left: 0,
+ right: 0
+ }
+ },
+ deviceCode:
+ text(layer, "mono", { size: "md" }),
+ deviceCodeCta: {
+ ...ctaButton,
+ padding: {
+ top: 0,
+ bottom: 0,
+ left: 0,
+ right: 0,
+ },
+ },
+ deviceCodeLeft: content_width * 2 / 3,
+ deviceCodeLeftContainer: {
+ padding: {
+ top: 3,
+ bottom: 3,
+ left: 0,
+ right: 0,
+ },
+ },
+ deviceCodeRight: content_width * 1 / 3,
+ deviceCodeRightContainer: {
+ border: border(layer, "active", { bottom: false, right: false, top: false, left: true }),
+ padding: {
+ top: 3,
+ bottom: 5,
+ left: 0,
+ right: 0,
+ },
+ },
+ deviceCodeSeperatorHeight: 0,
+
+ githubGroup: {
+ margin: {
+ top: 3,
+ bottom: 3,
+ left: 0,
+ right: 0
+ }
+ },
+
+ ctaButton
}
}
}