copilot: Decouple copilot sign in from edit prediction settings (#26689)
Closes #25883 This PR allows you to use copilot chat for assistant without setting copilot as the edit prediction provider. [copilot.webm](https://github.com/user-attachments/assets/fecfbde1-d72c-4c0c-b080-a07671fb846e) Todos: - [x] Remove redudant "copilot" key from settings - [x] Do not disable copilot LSP when `edit_prediction_provider` is not set to `copilot` - [x] Start copilot LSP when: - [x] `edit_prediction_provider` is set to `copilot` - [x] Copilot sign in clicked from assistant settings - [x] Handle flicker for frame after starting LSP, but before signing in caused due to signed out status - [x] Fixed this by adding intermediate state for awaiting signing in in sign out enum - [x] Handle cancel button should sign out from `copilot` (existing bug) - [x] Handle modal dismissal should sign out if not in signed in state (existing bug) Release Notes: - You can now sign into Copilot from assistant settings without making it your edit prediction provider. This is useful if you want to use Copilot chat while keeping a different provider, like Zed, for predictions. - Removed the `copilot` key from `features` in settings. Use `edit_prediction_provider` instead.
This commit is contained in:
parent
8d7b021f92
commit
6a95ec6a64
4 changed files with 114 additions and 61 deletions
|
@ -1,9 +1,10 @@
|
|||
use crate::{request::PromptUserDeviceFlow, Copilot, Status};
|
||||
use gpui::{
|
||||
div, App, ClipboardItem, Context, DismissEvent, Element, Entity, EventEmitter, FocusHandle,
|
||||
Focusable, InteractiveElement, IntoElement, MouseDownEvent, ParentElement, Render, Styled,
|
||||
Subscription, Window,
|
||||
div, percentage, svg, Animation, AnimationExt, App, ClipboardItem, Context, DismissEvent,
|
||||
Element, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement, IntoElement,
|
||||
MouseDownEvent, ParentElement, Render, Styled, Subscription, Transformation, Window,
|
||||
};
|
||||
use std::time::Duration;
|
||||
use ui::{prelude::*, Button, Label, Vector, VectorName};
|
||||
use util::ResultExt as _;
|
||||
use workspace::notifications::NotificationId;
|
||||
|
@ -17,11 +18,13 @@ pub fn initiate_sign_in(window: &mut Window, cx: &mut App) {
|
|||
let Some(copilot) = Copilot::global(cx) else {
|
||||
return;
|
||||
};
|
||||
let status = copilot.read(cx).status();
|
||||
let Some(workspace) = window.root::<Workspace>().flatten() else {
|
||||
return;
|
||||
};
|
||||
match status {
|
||||
if matches!(copilot.read(cx).status(), Status::Disabled) {
|
||||
copilot.update(cx, |this, cx| this.start_copilot(false, true, cx));
|
||||
}
|
||||
match copilot.read(cx).status() {
|
||||
Status::Starting { task } => {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace.show_toast(
|
||||
|
@ -54,6 +57,15 @@ pub fn initiate_sign_in(window: &mut Window, cx: &mut App) {
|
|||
copilot
|
||||
.update(cx, |copilot, cx| copilot.sign_in(cx))
|
||||
.detach_and_log_err(cx);
|
||||
if let Some(window_handle) = cx.active_window() {
|
||||
window_handle
|
||||
.update(cx, |_, window, cx| {
|
||||
workspace.toggle_modal(window, cx, |_, cx| {
|
||||
CopilotCodeVerification::new(&copilot, cx)
|
||||
});
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
}
|
||||
})
|
||||
.log_err();
|
||||
|
@ -76,6 +88,7 @@ pub struct CopilotCodeVerification {
|
|||
status: Status,
|
||||
connect_clicked: bool,
|
||||
focus_handle: FocusHandle,
|
||||
copilot: Entity<Copilot>,
|
||||
_subscription: Subscription,
|
||||
}
|
||||
|
||||
|
@ -86,7 +99,20 @@ impl Focusable for CopilotCodeVerification {
|
|||
}
|
||||
|
||||
impl EventEmitter<DismissEvent> for CopilotCodeVerification {}
|
||||
impl ModalView for CopilotCodeVerification {}
|
||||
impl ModalView for CopilotCodeVerification {
|
||||
fn on_before_dismiss(
|
||||
&mut self,
|
||||
_: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> workspace::DismissDecision {
|
||||
self.copilot.update(cx, |copilot, cx| {
|
||||
if matches!(copilot.status(), Status::SigningIn { .. }) {
|
||||
copilot.sign_out(cx).detach_and_log_err(cx);
|
||||
}
|
||||
});
|
||||
workspace::DismissDecision::Dismiss(true)
|
||||
}
|
||||
}
|
||||
|
||||
impl CopilotCodeVerification {
|
||||
pub fn new(copilot: &Entity<Copilot>, cx: &mut Context<Self>) -> Self {
|
||||
|
@ -95,6 +121,7 @@ impl CopilotCodeVerification {
|
|||
status,
|
||||
connect_clicked: false,
|
||||
focus_handle: cx.focus_handle(),
|
||||
copilot: copilot.clone(),
|
||||
_subscription: cx.observe(copilot, |this, copilot, cx| {
|
||||
let status = copilot.read(cx).status();
|
||||
match status {
|
||||
|
@ -180,9 +207,12 @@ impl CopilotCodeVerification {
|
|||
.child(
|
||||
Button::new("copilot-enable-cancel-button", "Cancel")
|
||||
.full_width()
|
||||
.on_click(cx.listener(|_, _, _, cx| cx.emit(DismissEvent))),
|
||||
.on_click(cx.listener(|_, _, _, cx| {
|
||||
cx.emit(DismissEvent);
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
fn render_enabled_modal(cx: &mut Context<Self>) -> impl Element {
|
||||
v_flex()
|
||||
.gap_2()
|
||||
|
@ -216,16 +246,27 @@ impl CopilotCodeVerification {
|
|||
)
|
||||
}
|
||||
|
||||
fn render_disabled_modal() -> impl Element {
|
||||
v_flex()
|
||||
.child(Headline::new("Copilot is disabled").size(HeadlineSize::Large))
|
||||
.child(Label::new("You can enable Copilot in your settings."))
|
||||
fn render_loading(window: &mut Window, _: &mut Context<Self>) -> impl Element {
|
||||
let loading_icon = svg()
|
||||
.size_8()
|
||||
.path(IconName::ArrowCircle.path())
|
||||
.text_color(window.text_style().color)
|
||||
.with_animation(
|
||||
"icon_circle_arrow",
|
||||
Animation::new(Duration::from_secs(2)).repeat(),
|
||||
|svg, delta| svg.with_transformation(Transformation::rotate(percentage(delta))),
|
||||
);
|
||||
|
||||
h_flex().justify_center().child(loading_icon)
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for CopilotCodeVerification {
|
||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let prompt = match &self.status {
|
||||
Status::SigningIn { prompt: None } => {
|
||||
Self::render_loading(window, cx).into_any_element()
|
||||
}
|
||||
Status::SigningIn {
|
||||
prompt: Some(prompt),
|
||||
} => Self::render_prompting_modal(self.connect_clicked, prompt, cx).into_any_element(),
|
||||
|
@ -237,10 +278,6 @@ impl Render for CopilotCodeVerification {
|
|||
self.connect_clicked = false;
|
||||
Self::render_enabled_modal(cx).into_any_element()
|
||||
}
|
||||
Status::Disabled => {
|
||||
self.connect_clicked = false;
|
||||
Self::render_disabled_modal().into_any_element()
|
||||
}
|
||||
_ => div().into_any_element(),
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue