From c6d479715dce283ce61a33361a445d6dc1530131 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Fri, 22 Mar 2024 11:55:29 -0400 Subject: [PATCH] Add setting to allow disabling the Assistant (#9706) This PR adds a new `assistant.enabled` setting that controls whether the Zed Assistant is enabled. Some users have requested the ability to disable the AI-related features in Zed if they don't use them. Changing `assistant.enabled` to `false` will hide the Assistant icon in the status bar (taking priority over the `assistant.button` setting) as well as filter out the `assistant:` actions. The Assistant is enabled by default. Release Notes: - Added an `assistant.enabled` setting to control whether the Assistant is enabled. --- Cargo.lock | 1 + assets/settings/default.json | 2 + crates/assistant/Cargo.toml | 1 + crates/assistant/src/assistant.rs | 56 +++++++++++++++++++- crates/assistant/src/assistant_panel.rs | 17 ++++++- crates/assistant/src/assistant_settings.rs | 59 +++++++++------------- crates/zed/src/zed.rs | 1 + 7 files changed, 100 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 57a19d8a9d79952432759e414701e15b8a072bcd..bd1666f16b0e47f4b52840825b41618fbebc8eae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -318,6 +318,7 @@ dependencies = [ "chrono", "client", "collections", + "command_palette_hooks", "ctor", "editor", "env_logger", diff --git a/assets/settings/default.json b/assets/settings/default.json index 39c62b4ea2f32fa7ee98a1fe87b443819f9a0bbf..94d4854ff443ee41238ec308b5e0234ca366f7eb 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -245,6 +245,8 @@ "assistant": { // Version of this setting. "version": "1", + // Whether the assistant is enabled. + "enabled": true, // Whether to show the assistant panel button in the status bar. "button": true, // Where to dock the assistant panel. Can be 'left', 'right' or 'bottom'. diff --git a/crates/assistant/Cargo.toml b/crates/assistant/Cargo.toml index 45b2f530a53d477ce84f6c8ba264fac4b070568c..a1e0f98a0037f68ae2931a4c75af86f14f87811b 100644 --- a/crates/assistant/Cargo.toml +++ b/crates/assistant/Cargo.toml @@ -14,6 +14,7 @@ anyhow.workspace = true chrono.workspace = true client.workspace = true collections.workspace = true +command_palette_hooks.workspace = true editor.workspace = true fs.workspace = true futures.workspace = true diff --git a/crates/assistant/src/assistant.rs b/crates/assistant/src/assistant.rs index de810e0fc505aa33a5c6280d1ba413efec5ee7ed..cb2ad19ccbc5fee11f8e24e9b68be163f445baff 100644 --- a/crates/assistant/src/assistant.rs +++ b/crates/assistant/src/assistant.rs @@ -10,11 +10,12 @@ pub use assistant_panel::AssistantPanel; use assistant_settings::{AssistantSettings, OpenAiModel, ZedDotDevModel}; use chrono::{DateTime, Local}; use client::{proto, Client}; +use command_palette_hooks::CommandPaletteFilter; pub(crate) use completion_provider::*; -use gpui::{actions, AppContext, SharedString}; +use gpui::{actions, AppContext, Global, SharedString}; pub(crate) use saved_conversation::*; use serde::{Deserialize, Serialize}; -use settings::Settings; +use settings::{Settings, SettingsStore}; use std::{ fmt::{self, Display}, sync::Arc, @@ -182,10 +183,61 @@ enum MessageStatus { Error(SharedString), } +/// The state pertaining to the Assistant. +#[derive(Default)] +struct Assistant { + /// Whether the Assistant is enabled. + enabled: bool, +} + +impl Global for Assistant {} + +impl Assistant { + const NAMESPACE: &'static str = "assistant"; + + fn set_enabled(&mut self, enabled: bool, cx: &mut AppContext) { + if self.enabled == enabled { + return; + } + + self.enabled = enabled; + + if !enabled { + CommandPaletteFilter::update_global(cx, |filter, _cx| { + filter.hide_namespace(Self::NAMESPACE); + }); + + return; + } + + CommandPaletteFilter::update_global(cx, |filter, _cx| { + filter.show_namespace(Self::NAMESPACE); + }); + } +} + pub fn init(client: Arc, cx: &mut AppContext) { + cx.set_global(Assistant::default()); AssistantSettings::register(cx); completion_provider::init(client, cx); assistant_panel::init(cx); + + CommandPaletteFilter::update_global(cx, |filter, _cx| { + filter.hide_namespace(Assistant::NAMESPACE); + }); + cx.update_global(|assistant: &mut Assistant, cx: &mut AppContext| { + let settings = AssistantSettings::get_global(cx); + + assistant.set_enabled(settings.enabled, cx); + }); + cx.observe_global::(|cx| { + cx.update_global(|assistant: &mut Assistant, cx: &mut AppContext| { + let settings = AssistantSettings::get_global(cx); + + assistant.set_enabled(settings.enabled, cx); + }); + }) + .detach(); } #[cfg(test)] diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index 419bd10f4e96fc3504968d615743d2ae3c01a265..b721521372efaaea0c2ceb9a8501beba5c29d5bf 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -55,6 +55,11 @@ pub fn init(cx: &mut AppContext) { |workspace: &mut Workspace, _cx: &mut ViewContext| { workspace .register_action(|workspace, _: &ToggleFocus, cx| { + let settings = AssistantSettings::get_global(cx); + if !settings.enabled { + return; + } + workspace.toggle_panel_focus::(cx); }) .register_action(AssistantPanel::inline_assist) @@ -229,6 +234,11 @@ impl AssistantPanel { _: &InlineAssist, cx: &mut ViewContext, ) { + let settings = AssistantSettings::get_global(cx); + if !settings.enabled { + return; + } + let Some(assistant) = workspace.panel::(cx) else { return; }; @@ -1217,7 +1227,12 @@ impl Panel for AssistantPanel { } fn icon(&self, cx: &WindowContext) -> Option { - Some(IconName::Ai).filter(|_| AssistantSettings::get_global(cx).button) + let settings = AssistantSettings::get_global(cx); + if !settings.enabled || !settings.button { + return None; + } + + Some(IconName::Ai) } fn icon_tooltip(&self, _cx: &WindowContext) -> Option<&'static str> { diff --git a/crates/assistant/src/assistant_settings.rs b/crates/assistant/src/assistant_settings.rs index f4e70f254877af474643f2caecbc2c6b9013f65f..9a7572f55b3cdc659f10740622ca5c1b7d265b55 100644 --- a/crates/assistant/src/assistant_settings.rs +++ b/crates/assistant/src/assistant_settings.rs @@ -160,6 +160,7 @@ fn open_ai_url() -> String { #[derive(Default, Debug, Deserialize, Serialize)] pub struct AssistantSettings { + pub enabled: bool, pub button: bool, pub dock: AssistantDockPosition, pub default_width: Pixels, @@ -201,42 +202,26 @@ impl AssistantSettingsContent { AssistantSettingsContent::Versioned(settings) => match settings { VersionedAssistantSettingsContent::V1(settings) => settings.clone(), }, - AssistantSettingsContent::Legacy(settings) => { - if let Some(open_ai_api_url) = settings.openai_api_url.as_ref() { - AssistantSettingsContentV1 { - button: settings.button, - dock: settings.dock, - default_width: settings.default_width, - default_height: settings.default_height, - provider: Some(AssistantProvider::OpenAi { - default_model: settings - .default_open_ai_model - .clone() - .unwrap_or_default(), - api_url: open_ai_api_url.clone(), - }), - } - } else if let Some(open_ai_model) = settings.default_open_ai_model.clone() { - AssistantSettingsContentV1 { - button: settings.button, - dock: settings.dock, - default_width: settings.default_width, - default_height: settings.default_height, - provider: Some(AssistantProvider::OpenAi { + AssistantSettingsContent::Legacy(settings) => AssistantSettingsContentV1 { + enabled: None, + button: settings.button, + dock: settings.dock, + default_width: settings.default_width, + default_height: settings.default_height, + provider: if let Some(open_ai_api_url) = settings.openai_api_url.as_ref() { + Some(AssistantProvider::OpenAi { + default_model: settings.default_open_ai_model.clone().unwrap_or_default(), + api_url: open_ai_api_url.clone(), + }) + } else { + settings.default_open_ai_model.clone().map(|open_ai_model| { + AssistantProvider::OpenAi { default_model: open_ai_model, api_url: open_ai_url(), - }), - } - } else { - AssistantSettingsContentV1 { - button: settings.button, - dock: settings.dock, - default_width: settings.default_width, - default_height: settings.default_height, - provider: None, - } - } - } + } + }) + }, + }, } } @@ -264,6 +249,7 @@ pub enum VersionedAssistantSettingsContent { impl Default for VersionedAssistantSettingsContent { fn default() -> Self { Self::V1(AssistantSettingsContentV1 { + enabled: None, button: None, dock: None, default_width: None, @@ -275,6 +261,10 @@ impl Default for VersionedAssistantSettingsContent { #[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)] pub struct AssistantSettingsContentV1 { + /// Whether the Assistant is enabled. + /// + /// Default: true + enabled: Option, /// Whether to show the assistant panel button in the status bar. /// /// Default: true @@ -340,6 +330,7 @@ impl Settings for AssistantSettings { for value in [default_value].iter().chain(user_values) { let value = value.upgrade(); + merge(&mut settings.enabled, value.enabled); merge(&mut settings.button, value.button); merge(&mut settings.dock, value.dock); merge( diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 10440242c0de67db792bc765ab30f335ace22818..8983be0c214ba4bbca32648656e6455e34001151 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -3073,6 +3073,7 @@ mod tests { notifications::init(app_state.client.clone(), app_state.user_store.clone(), cx); workspace::init(app_state.clone(), cx); Project::init_settings(cx); + command_palette::init(cx); language::init(cx); editor::init(cx); project_panel::init_settings(cx);