Cherry-picked Make `copilot::SignIn` open sign-in modal when needed (#30239) Also: * Makes sign out show status notifications and errors. * Reinstall now prompts for sign-in after start. Addresses some of #29250, but not all of it. Release Notes: - N/A Co-authored-by: Michael Sloan <michael@zed.dev>
This commit is contained in:
parent
eff23ab177
commit
3c22ad9e93
@ -3,6 +3,7 @@ mod copilot_completion_provider;
|
|||||||
pub mod request;
|
pub mod request;
|
||||||
mod sign_in;
|
mod sign_in;
|
||||||
|
|
||||||
|
use crate::sign_in::initiate_sign_in_within_workspace;
|
||||||
use ::fs::Fs;
|
use ::fs::Fs;
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
@ -24,6 +25,7 @@ use node_runtime::NodeRuntime;
|
|||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use request::StatusNotification;
|
use request::StatusNotification;
|
||||||
use settings::SettingsStore;
|
use settings::SettingsStore;
|
||||||
|
use sign_in::{reinstall_and_sign_in_within_workspace, sign_out_within_workspace};
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
env,
|
env,
|
||||||
@ -34,9 +36,10 @@ use std::{
|
|||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use util::{ResultExt, fs::remove_matching};
|
use util::{ResultExt, fs::remove_matching};
|
||||||
|
use workspace::Workspace;
|
||||||
|
|
||||||
pub use crate::copilot_completion_provider::CopilotCompletionProvider;
|
pub use crate::copilot_completion_provider::CopilotCompletionProvider;
|
||||||
pub use crate::sign_in::{CopilotCodeVerification, initiate_sign_in};
|
pub use crate::sign_in::{CopilotCodeVerification, initiate_sign_in, reinstall_and_sign_in};
|
||||||
|
|
||||||
actions!(
|
actions!(
|
||||||
copilot,
|
copilot,
|
||||||
@ -99,27 +102,25 @@ pub fn init(
|
|||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
cx.on_action(|_: &SignIn, cx| {
|
cx.observe_new(|workspace: &mut Workspace, _window, _cx| {
|
||||||
|
workspace.register_action(|workspace, _: &SignIn, window, cx| {
|
||||||
if let Some(copilot) = Copilot::global(cx) {
|
if let Some(copilot) = Copilot::global(cx) {
|
||||||
copilot
|
let is_reinstall = false;
|
||||||
.update(cx, |copilot, cx| copilot.sign_in(cx))
|
initiate_sign_in_within_workspace(workspace, copilot, is_reinstall, window, cx);
|
||||||
.detach_and_log_err(cx);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
cx.on_action(|_: &SignOut, cx| {
|
workspace.register_action(|workspace, _: &Reinstall, window, cx| {
|
||||||
if let Some(copilot) = Copilot::global(cx) {
|
if let Some(copilot) = Copilot::global(cx) {
|
||||||
copilot
|
reinstall_and_sign_in_within_workspace(workspace, copilot, window, cx);
|
||||||
.update(cx, |copilot, cx| copilot.sign_out(cx))
|
|
||||||
.detach_and_log_err(cx);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
cx.on_action(|_: &Reinstall, cx| {
|
workspace.register_action(|workspace, _: &SignOut, _window, cx| {
|
||||||
if let Some(copilot) = Copilot::global(cx) {
|
if let Some(copilot) = Copilot::global(cx) {
|
||||||
copilot
|
sign_out_within_workspace(workspace, copilot, cx);
|
||||||
.update(cx, |copilot, cx| copilot.reinstall(cx))
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
.detach();
|
.detach();
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CopilotServer {
|
enum CopilotServer {
|
||||||
@ -563,7 +564,7 @@ impl Copilot {
|
|||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign_in(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> {
|
pub(crate) fn sign_in(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> {
|
||||||
if let CopilotServer::Running(server) = &mut self.server {
|
if let CopilotServer::Running(server) = &mut self.server {
|
||||||
let task = match &server.sign_in_status {
|
let task = match &server.sign_in_status {
|
||||||
SignInStatus::Authorized { .. } => Task::ready(Ok(())).shared(),
|
SignInStatus::Authorized { .. } => Task::ready(Ok(())).shared(),
|
||||||
@ -647,7 +648,7 @@ impl Copilot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign_out(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> {
|
pub(crate) fn sign_out(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> {
|
||||||
self.update_sign_in_status(request::SignInStatus::NotSignedIn, cx);
|
self.update_sign_in_status(request::SignInStatus::NotSignedIn, cx);
|
||||||
match &self.server {
|
match &self.server {
|
||||||
CopilotServer::Running(RunningCopilotServer { lsp: server, .. }) => {
|
CopilotServer::Running(RunningCopilotServer { lsp: server, .. }) => {
|
||||||
@ -667,7 +668,7 @@ impl Copilot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reinstall(&mut self, cx: &mut Context<Self>) -> Task<()> {
|
pub(crate) fn reinstall(&mut self, cx: &mut Context<Self>) -> Shared<Task<()>> {
|
||||||
let language_settings = all_language_settings(None, cx);
|
let language_settings = all_language_settings(None, cx);
|
||||||
let env = self.build_env(&language_settings.edit_predictions.copilot);
|
let env = self.build_env(&language_settings.edit_predictions.copilot);
|
||||||
let start_task = cx
|
let start_task = cx
|
||||||
@ -689,7 +690,7 @@ impl Copilot {
|
|||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
|
||||||
cx.background_spawn(start_task)
|
start_task
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn language_server(&self) -> Option<&Arc<LanguageServer>> {
|
pub fn language_server(&self) -> Option<&Arc<LanguageServer>> {
|
||||||
|
@ -12,7 +12,7 @@ use workspace::{ModalView, Toast, Workspace};
|
|||||||
|
|
||||||
const COPILOT_SIGN_UP_URL: &str = "https://github.com/features/copilot";
|
const COPILOT_SIGN_UP_URL: &str = "https://github.com/features/copilot";
|
||||||
|
|
||||||
struct CopilotStartingToast;
|
struct CopilotStatusToast;
|
||||||
|
|
||||||
pub fn initiate_sign_in(window: &mut Window, cx: &mut App) {
|
pub fn initiate_sign_in(window: &mut Window, cx: &mut App) {
|
||||||
let Some(copilot) = Copilot::global(cx) else {
|
let Some(copilot) = Copilot::global(cx) else {
|
||||||
@ -21,50 +21,83 @@ pub fn initiate_sign_in(window: &mut Window, cx: &mut App) {
|
|||||||
let Some(workspace) = window.root::<Workspace>().flatten() else {
|
let Some(workspace) = window.root::<Workspace>().flatten() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
workspace.update(cx, |workspace, cx| {
|
||||||
|
let is_reinstall = false;
|
||||||
|
initiate_sign_in_within_workspace(workspace, copilot, is_reinstall, window, cx)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reinstall_and_sign_in(window: &mut Window, cx: &mut App) {
|
||||||
|
let Some(copilot) = Copilot::global(cx) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(workspace) = window.root::<Workspace>().flatten() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
workspace.update(cx, |workspace, cx| {
|
||||||
|
reinstall_and_sign_in_within_workspace(workspace, copilot, window, cx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reinstall_and_sign_in_within_workspace(
|
||||||
|
workspace: &mut Workspace,
|
||||||
|
copilot: Entity<Copilot>,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Workspace>,
|
||||||
|
) {
|
||||||
|
let _ = copilot.update(cx, |copilot, cx| copilot.reinstall(cx));
|
||||||
|
let is_reinstall = true;
|
||||||
|
initiate_sign_in_within_workspace(workspace, copilot, is_reinstall, window, cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initiate_sign_in_within_workspace(
|
||||||
|
workspace: &mut Workspace,
|
||||||
|
copilot: Entity<Copilot>,
|
||||||
|
is_reinstall: bool,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Workspace>,
|
||||||
|
) {
|
||||||
if matches!(copilot.read(cx).status(), Status::Disabled) {
|
if matches!(copilot.read(cx).status(), Status::Disabled) {
|
||||||
copilot.update(cx, |this, cx| this.start_copilot(false, true, cx));
|
copilot.update(cx, |copilot, cx| copilot.start_copilot(false, true, cx));
|
||||||
}
|
}
|
||||||
match copilot.read(cx).status() {
|
match copilot.read(cx).status() {
|
||||||
Status::Starting { task } => {
|
Status::Starting { task } => {
|
||||||
workspace.update(cx, |workspace, cx| {
|
|
||||||
workspace.show_toast(
|
workspace.show_toast(
|
||||||
Toast::new(
|
Toast::new(
|
||||||
NotificationId::unique::<CopilotStartingToast>(),
|
NotificationId::unique::<CopilotStatusToast>(),
|
||||||
"Copilot is starting...",
|
if is_reinstall {
|
||||||
|
"Copilot is reinstalling..."
|
||||||
|
} else {
|
||||||
|
"Copilot is starting..."
|
||||||
|
},
|
||||||
),
|
),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
let workspace = workspace.downgrade();
|
cx.spawn_in(window, async move |workspace, cx| {
|
||||||
cx.spawn(async move |cx| {
|
|
||||||
task.await;
|
task.await;
|
||||||
if let Some(copilot) = cx.update(|cx| Copilot::global(cx)).ok().flatten() {
|
if let Some(copilot) = cx.update(|_window, cx| Copilot::global(cx)).ok().flatten() {
|
||||||
workspace
|
workspace
|
||||||
.update(cx, |workspace, cx| match copilot.read(cx).status() {
|
.update_in(cx, |workspace, window, cx| {
|
||||||
|
match copilot.read(cx).status() {
|
||||||
Status::Authorized => workspace.show_toast(
|
Status::Authorized => workspace.show_toast(
|
||||||
Toast::new(
|
Toast::new(
|
||||||
NotificationId::unique::<CopilotStartingToast>(),
|
NotificationId::unique::<CopilotStatusToast>(),
|
||||||
"Copilot has started!",
|
"Copilot has started.",
|
||||||
),
|
),
|
||||||
cx,
|
cx,
|
||||||
),
|
),
|
||||||
_ => {
|
_ => {
|
||||||
workspace.dismiss_toast(
|
workspace.dismiss_toast(
|
||||||
&NotificationId::unique::<CopilotStartingToast>(),
|
&NotificationId::unique::<CopilotStatusToast>(),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
copilot
|
copilot
|
||||||
.update(cx, |copilot, cx| copilot.sign_in(cx))
|
.update(cx, |copilot, cx| copilot.sign_in(cx))
|
||||||
.detach_and_log_err(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| {
|
workspace.toggle_modal(window, cx, |_, cx| {
|
||||||
CopilotCodeVerification::new(&copilot, cx)
|
CopilotCodeVerification::new(&copilot, cx)
|
||||||
});
|
});
|
||||||
})
|
|
||||||
.log_err();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -74,16 +107,54 @@ pub fn initiate_sign_in(window: &mut Window, cx: &mut App) {
|
|||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
copilot.update(cx, |this, cx| this.sign_in(cx)).detach();
|
copilot
|
||||||
workspace.update(cx, |this, cx| {
|
.update(cx, |copilot, cx| copilot.sign_in(cx))
|
||||||
this.toggle_modal(window, cx, |_, cx| {
|
.detach();
|
||||||
|
workspace.toggle_modal(window, cx, |_, cx| {
|
||||||
CopilotCodeVerification::new(&copilot, cx)
|
CopilotCodeVerification::new(&copilot, cx)
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sign_out_within_workspace(
|
||||||
|
workspace: &mut Workspace,
|
||||||
|
copilot: Entity<Copilot>,
|
||||||
|
cx: &mut Context<Workspace>,
|
||||||
|
) {
|
||||||
|
workspace.show_toast(
|
||||||
|
Toast::new(
|
||||||
|
NotificationId::unique::<CopilotStatusToast>(),
|
||||||
|
"Signing out of Copilot...",
|
||||||
|
),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
let sign_out_task = copilot.update(cx, |copilot, cx| copilot.sign_out(cx));
|
||||||
|
cx.spawn(async move |workspace, cx| match sign_out_task.await {
|
||||||
|
Ok(()) => {
|
||||||
|
workspace
|
||||||
|
.update(cx, |workspace, cx| {
|
||||||
|
workspace.show_toast(
|
||||||
|
Toast::new(
|
||||||
|
NotificationId::unique::<CopilotStatusToast>(),
|
||||||
|
"Signed out of Copilot.",
|
||||||
|
),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
workspace
|
||||||
|
.update(cx, |workspace, cx| {
|
||||||
|
workspace.show_error(&err, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
|
||||||
pub struct CopilotCodeVerification {
|
pub struct CopilotCodeVerification {
|
||||||
status: Status,
|
status: Status,
|
||||||
connect_clicked: bool,
|
connect_clicked: bool,
|
||||||
|
@ -106,14 +106,8 @@ impl Render for InlineCompletionButton {
|
|||||||
)
|
)
|
||||||
.on_click(
|
.on_click(
|
||||||
"Reinstall Copilot",
|
"Reinstall Copilot",
|
||||||
|_, cx| {
|
|window, cx| {
|
||||||
if let Some(copilot) = Copilot::global(cx) {
|
copilot::reinstall_and_sign_in(window, cx)
|
||||||
copilot
|
|
||||||
.update(cx, |copilot, cx| {
|
|
||||||
copilot.reinstall(cx)
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
cx,
|
cx,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user