Cargo.lock 🔗
@@ -3743,6 +3743,7 @@ dependencies = [
"log",
"lsp",
"menu",
+ "project",
"serde_json",
"settings",
"ui",
zed-zippy[bot] and Piotr Osiewicz created
Cherry-pick of #48191 to preview
----
Closes #48097
Release Notes:
- Fixed Copilot instances not being cleared up after their window is
closed.
- Copilot edit prediction provider now respects `disable_ai` setting.
Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
Cargo.lock | 1
crates/copilot/src/copilot.rs | 21 ++-
crates/copilot_ui/Cargo.toml | 1
crates/copilot_ui/src/copilot_ui.rs | 6
crates/copilot_ui/src/sign_in.rs | 12 +
crates/edit_prediction/src/edit_prediction.rs | 17 ++
crates/edit_prediction_ui/src/edit_prediction_button.rs | 6
crates/settings_ui/src/pages/edit_prediction_provider_setup.rs | 4
8 files changed, 46 insertions(+), 22 deletions(-)
@@ -3743,6 +3743,7 @@ dependencies = [
"log",
"lsp",
"menu",
+ "project",
"serde_json",
"settings",
"ui",
@@ -281,16 +281,25 @@ impl GlobalCopilotAuth {
cx.try_global()
}
- pub fn get_or_init(app_state: Arc<AppState>, cx: &mut App) -> GlobalCopilotAuth {
- if let Some(copilot) = cx.try_global::<Self>() {
- copilot.clone()
- } else {
- Self::set_global(
+ pub fn try_get_or_init(app_state: Arc<AppState>, cx: &mut App) -> Option<GlobalCopilotAuth> {
+ let ai_enabled = !DisableAiSettings::get(None, cx).disable_ai;
+
+ if let Some(copilot) = cx.try_global::<Self>().cloned() {
+ if ai_enabled {
+ Some(copilot)
+ } else {
+ cx.remove_global::<Self>();
+ None
+ }
+ } else if ai_enabled {
+ Some(Self::set_global(
app_state.languages.next_language_server_id(),
app_state.fs.clone(),
app_state.node_runtime.clone(),
cx,
- )
+ ))
+ } else {
+ None
}
}
}
@@ -27,6 +27,7 @@ language.workspace = true
log.workspace = true
lsp.workspace = true
menu.workspace = true
+project.workspace = true
serde_json.workspace = true
settings.workspace = true
ui.workspace = true
@@ -5,6 +5,7 @@ use std::sync::Arc;
use copilot::GlobalCopilotAuth;
use gpui::AppContext;
use language::language_settings::AllLanguageSettings;
+use project::DisableAiSettings;
use settings::SettingsStore;
pub use sign_in::{
ConfigurationMode, ConfigurationView, CopilotCodeVerification, initiate_sign_in,
@@ -14,13 +15,16 @@ use ui::App;
use workspace::AppState;
pub fn init(app_state: &Arc<AppState>, cx: &mut App) {
+ let disable_ai = cx.read_global(|settings: &SettingsStore, _| {
+ settings.get::<DisableAiSettings>(None).disable_ai
+ });
let provider = cx.read_global(|settings: &SettingsStore, _| {
settings
.get::<AllLanguageSettings>(None)
.edit_predictions
.provider
});
- if provider == settings::EditPredictionProvider::Copilot {
+ if !disable_ai && provider == settings::EditPredictionProvider::Copilot {
GlobalCopilotAuth::set_global(
app_state.languages.next_language_server_id(),
app_state.fs.clone(),
@@ -475,7 +475,7 @@ impl ConfigurationView {
) -> Self {
let copilot = AppState::try_global(cx)
.and_then(|state| state.upgrade())
- .map(|state| GlobalCopilotAuth::get_or_init(state, cx));
+ .and_then(|state| GlobalCopilotAuth::try_get_or_init(state, cx));
Self {
copilot_status: copilot.as_ref().map(|copilot| copilot.0.read(cx).status()),
@@ -569,8 +569,9 @@ impl ConfigurationView {
.icon_position(IconPosition::Start)
.icon_size(IconSize::Small)
.on_click(|_, window, cx| {
- if let Some(app_state) = AppState::global(cx).upgrade() {
- let copilot = GlobalCopilotAuth::get_or_init(app_state, cx);
+ if let Some(app_state) = AppState::global(cx).upgrade()
+ && let Some(copilot) = GlobalCopilotAuth::try_get_or_init(app_state, cx)
+ {
initiate_sign_in(copilot.0, window, cx)
}
})
@@ -597,8 +598,9 @@ impl ConfigurationView {
.icon_position(IconPosition::Start)
.icon_size(IconSize::Small)
.on_click(|_, window, cx| {
- if let Some(app_state) = AppState::global(cx).upgrade() {
- let copilot = GlobalCopilotAuth::get_or_init(app_state, cx);
+ if let Some(app_state) = AppState::global(cx).upgrade()
+ && let Some(copilot) = GlobalCopilotAuth::try_get_or_init(app_state, cx)
+ {
reinstall_and_sign_in(copilot.0, window, cx);
}
})
@@ -30,11 +30,11 @@ use language::language_settings::all_language_settings;
use language::{Anchor, Buffer, File, Point, TextBufferSnapshot, ToOffset, ToPoint};
use language::{BufferSnapshot, OffsetRangeExt};
use language_model::{LlmApiToken, NeedsLlmTokenRefresh, RefreshLlmTokenListener};
-use project::{Project, ProjectPath, WorktreeId};
+use project::{DisableAiSettings, Project, ProjectPath, WorktreeId};
use release_channel::AppVersion;
use semver::Version;
use serde::de::DeserializeOwned;
-use settings::{EditPredictionProvider, update_settings_file};
+use settings::{EditPredictionProvider, Settings as _, update_settings_file};
use std::collections::{VecDeque, hash_map};
use text::Edit;
use workspace::Workspace;
@@ -263,7 +263,7 @@ struct ProjectState {
context: Entity<RelatedExcerptStore>,
license_detection_watchers: HashMap<WorktreeId, Rc<LicenseDetectionWatcher>>,
user_actions: VecDeque<UserActionRecord>,
- _subscription: gpui::Subscription,
+ _subscriptions: [gpui::Subscription; 2],
copilot: Option<Entity<Copilot>>,
}
@@ -725,6 +725,9 @@ impl EditPredictionStore {
project: &Entity<Project>,
cx: &mut Context<Self>,
) -> Option<Entity<Copilot>> {
+ if DisableAiSettings::get(None, cx).disable_ai {
+ return None;
+ }
let state = self.get_or_init_project(project, cx);
if state.copilot.is_some() {
@@ -815,7 +818,13 @@ impl EditPredictionStore {
last_prediction_refresh: None,
license_detection_watchers: HashMap::default(),
user_actions: VecDeque::with_capacity(USER_ACTION_HISTORY_SIZE),
- _subscription: cx.subscribe(&project, Self::handle_project_event),
+ _subscriptions: [
+ cx.subscribe(&project, Self::handle_project_event),
+ cx.observe_release(&project, move |this, _, cx| {
+ this.projects.remove(&entity_id);
+ cx.notify();
+ }),
+ ],
copilot: None,
})
}
@@ -1294,10 +1294,8 @@ pub fn get_available_providers(cx: &mut App) -> Vec<EditPredictionProvider> {
}
if let Some(app_state) = workspace::AppState::global(cx).upgrade()
- && copilot::GlobalCopilotAuth::get_or_init(app_state, cx)
- .0
- .read(cx)
- .is_authenticated()
+ && copilot::GlobalCopilotAuth::try_get_or_init(app_state, cx)
+ .is_some_and(|copilot| copilot.0.read(cx).is_authenticated())
{
providers.push(EditPredictionProvider::Copilot);
};
@@ -391,8 +391,8 @@ fn render_github_copilot_provider(window: &mut Window, cx: &mut App) -> Option<i
copilot_ui::ConfigurationView::new(
move |cx| {
if let Some(app_state) = AppState::global(cx).upgrade() {
- let copilot = copilot::GlobalCopilotAuth::get_or_init(app_state, cx);
- copilot.0.read(cx).is_authenticated()
+ copilot::GlobalCopilotAuth::try_get_or_init(app_state, cx)
+ .is_some_and(|copilot| copilot.0.read(cx).is_authenticated())
} else {
false
}