Introduce global ai setting
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -10826,6 +10826,7 @@ dependencies = [
|
||||
"editor",
|
||||
"feature_flags",
|
||||
"gpui",
|
||||
"language",
|
||||
"menu",
|
||||
"project",
|
||||
"serde_json",
|
||||
@@ -19999,6 +20000,7 @@ dependencies = [
|
||||
"collab_ui",
|
||||
"collections",
|
||||
"command_palette",
|
||||
"command_palette_hooks",
|
||||
"component",
|
||||
"copilot",
|
||||
"dap",
|
||||
|
||||
@@ -25,7 +25,11 @@
|
||||
// Features that can be globally enabled or disabled
|
||||
"features": {
|
||||
// Which edit prediction provider to use.
|
||||
"edit_prediction_provider": "zed"
|
||||
"edit_prediction_provider": "zed",
|
||||
// A globally enable or disable AI features.
|
||||
//
|
||||
// This setting supersedes all other settings related to AI features.
|
||||
"ai_assistance": true
|
||||
},
|
||||
// The name of a font to use for rendering text in the editor
|
||||
"buffer_font_family": "Zed Plex Mono",
|
||||
|
||||
@@ -33,6 +33,7 @@ use gpui::{
|
||||
App, Context, Entity, Focusable, Global, HighlightStyle, Subscription, Task, UpdateGlobal,
|
||||
WeakEntity, Window, point,
|
||||
};
|
||||
use language::language_settings;
|
||||
use language::{Buffer, Point, Selection, TransactionId};
|
||||
use language_model::{
|
||||
ConfigurationError, ConfiguredModel, LanguageModelRegistry, report_assistant_event,
|
||||
@@ -1768,7 +1769,7 @@ impl CodeActionProvider for AssistantCodeActionProvider {
|
||||
_: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<Vec<CodeAction>>> {
|
||||
if !AgentSettings::get_global(cx).enabled {
|
||||
if !AgentSettings::get_global(cx).enabled || !language_settings::ai_enabled(cx) {
|
||||
return Task::ready(Ok(Vec::new()));
|
||||
}
|
||||
|
||||
|
||||
@@ -54,11 +54,18 @@ pub fn all_language_settings<'a>(
|
||||
AllLanguageSettings::get(location, cx)
|
||||
}
|
||||
|
||||
/// Returns whether AI assistance is globally enabled or disabled.
|
||||
pub fn ai_enabled(cx: &App) -> bool {
|
||||
all_language_settings(None, cx).ai_assistance
|
||||
}
|
||||
|
||||
/// The settings for all languages.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AllLanguageSettings {
|
||||
/// The edit prediction settings.
|
||||
pub edit_predictions: EditPredictionSettings,
|
||||
/// Whether AI assistance is enabled.
|
||||
pub ai_assistance: bool,
|
||||
pub defaults: LanguageSettings,
|
||||
languages: HashMap<LanguageName, LanguageSettings>,
|
||||
pub(crate) file_types: FxHashMap<Arc<str>, GlobSet>,
|
||||
@@ -646,6 +653,8 @@ pub struct CopilotSettingsContent {
|
||||
pub struct FeaturesContent {
|
||||
/// Determines which edit prediction provider to use.
|
||||
pub edit_prediction_provider: Option<EditPredictionProvider>,
|
||||
/// Whether AI assistance is enabled.
|
||||
pub ai_assistance: Option<bool>,
|
||||
}
|
||||
|
||||
/// Controls the soft-wrapping behavior in the editor.
|
||||
@@ -1122,6 +1131,11 @@ impl AllLanguageSettings {
|
||||
pub fn edit_predictions_mode(&self) -> EditPredictionsMode {
|
||||
self.edit_predictions.mode
|
||||
}
|
||||
|
||||
/// Returns whether AI assistance is enabled.
|
||||
pub fn is_ai_assistance_enabled(&self) -> bool {
|
||||
self.ai_assistance
|
||||
}
|
||||
}
|
||||
|
||||
fn merge_with_editorconfig(settings: &mut LanguageSettings, cfg: &EditorconfigProperties) {
|
||||
@@ -1247,6 +1261,12 @@ impl settings::Settings for AllLanguageSettings {
|
||||
.map(|settings| settings.enabled_in_text_threads)
|
||||
.unwrap_or(true);
|
||||
|
||||
let ai_assistance = default_value
|
||||
.features
|
||||
.as_ref()
|
||||
.and_then(|f| f.ai_assistance)
|
||||
.unwrap_or(true);
|
||||
|
||||
let mut file_types: FxHashMap<Arc<str>, GlobSet> = FxHashMap::default();
|
||||
|
||||
for (language, patterns) in &default_value.file_types {
|
||||
@@ -1359,6 +1379,7 @@ impl settings::Settings for AllLanguageSettings {
|
||||
copilot: copilot_settings,
|
||||
enabled_in_text_threads,
|
||||
},
|
||||
ai_assistance,
|
||||
defaults,
|
||||
languages,
|
||||
file_types,
|
||||
|
||||
@@ -23,6 +23,7 @@ component.workspace = true
|
||||
db.workspace = true
|
||||
feature_flags.workspace = true
|
||||
gpui.workspace = true
|
||||
language.workspace = true
|
||||
menu.workspace = true
|
||||
project.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
@@ -10,20 +10,22 @@ use client::{Client, TelemetrySettings};
|
||||
use command_palette_hooks::CommandPaletteFilter;
|
||||
use feature_flags::FeatureFlagAppExt as _;
|
||||
use gpui::{
|
||||
Action, Entity, EventEmitter, FocusHandle, Focusable, FontWeight, KeyBinding, Task,
|
||||
UpdateGlobal, WeakEntity, actions, prelude::*, svg, transparent_black,
|
||||
Action, Entity, EventEmitter, FocusHandle, Focusable, FontWeight, KeyBinding, Subscription,
|
||||
Task, UpdateGlobal, WeakEntity, actions, prelude::*, svg, transparent_black,
|
||||
};
|
||||
use menu;
|
||||
use persistence::ONBOARDING_DB;
|
||||
|
||||
use language::language_settings::{AllLanguageSettings, ai_enabled, all_language_settings};
|
||||
use project::Project;
|
||||
use serde_json;
|
||||
use settings::{Settings, SettingsStore};
|
||||
use settings::{Settings, SettingsStore, update_settings_file};
|
||||
use settings_ui::SettingsUiFeatureFlag;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
use theme::{Theme, ThemeRegistry, ThemeSettings};
|
||||
use ui::{
|
||||
CheckboxWithLabel, ContentGroup, KeybindingHint, ListItem, Ring, ToggleState, Vector,
|
||||
CheckboxWithLabel, ContentGroup, FocusOutline, KeybindingHint, ListItem, ToggleState, Vector,
|
||||
VectorName, prelude::*,
|
||||
};
|
||||
use util::ResultExt;
|
||||
@@ -87,7 +89,7 @@ fn feature_gate_onboarding_ui_actions(cx: &mut App) {
|
||||
.detach();
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum OnboardingPage {
|
||||
Basics,
|
||||
Editing,
|
||||
@@ -139,7 +141,7 @@ pub struct OnboardingUI {
|
||||
current_page: OnboardingPage,
|
||||
nav_focus: NavigationFocusItem,
|
||||
page_focus: [PageFocusItem; 4],
|
||||
completed_pages: [bool; 4],
|
||||
completed_pages: HashSet<OnboardingPage>,
|
||||
focus_area: FocusArea,
|
||||
|
||||
// Workspace reference for Item trait
|
||||
@@ -147,6 +149,7 @@ pub struct OnboardingUI {
|
||||
workspace_id: Option<WorkspaceId>,
|
||||
client: Arc<Client>,
|
||||
welcome_page: Option<Entity<WelcomePage>>,
|
||||
_settings_subscription: Option<Subscription>,
|
||||
}
|
||||
|
||||
impl OnboardingUI {}
|
||||
@@ -179,6 +182,8 @@ impl Render for OnboardingUI {
|
||||
.on_action(cx.listener(Self::confirm))
|
||||
.on_action(cx.listener(Self::cancel))
|
||||
.on_action(cx.listener(Self::toggle_focus))
|
||||
.on_action(cx.listener(Self::handle_enable_ai_assistance))
|
||||
.on_action(cx.listener(Self::handle_disable_ai_assistance))
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
@@ -218,31 +223,57 @@ impl Render for OnboardingUI {
|
||||
|
||||
impl OnboardingUI {
|
||||
pub fn new(workspace: &Workspace, client: Arc<Client>, cx: &mut Context<Self>) -> Self {
|
||||
let settings_subscription = cx.observe_global::<SettingsStore>(|_, cx| {
|
||||
cx.notify();
|
||||
});
|
||||
|
||||
Self {
|
||||
focus_handle: cx.focus_handle(),
|
||||
current_page: OnboardingPage::Basics,
|
||||
nav_focus: NavigationFocusItem::Basics,
|
||||
page_focus: [PageFocusItem(0); 4],
|
||||
completed_pages: [false; 4],
|
||||
completed_pages: HashSet::new(),
|
||||
focus_area: FocusArea::Navigation,
|
||||
workspace: workspace.weak_handle(),
|
||||
workspace_id: workspace.database_id(),
|
||||
client,
|
||||
welcome_page: None,
|
||||
_settings_subscription: Some(settings_subscription),
|
||||
}
|
||||
}
|
||||
|
||||
fn completed_pages_to_string(&self) -> String {
|
||||
self.completed_pages
|
||||
.iter()
|
||||
.map(|&completed| if completed { '1' } else { '0' })
|
||||
.collect()
|
||||
let mut result = String::new();
|
||||
for i in 0..4 {
|
||||
let page = match i {
|
||||
0 => OnboardingPage::Basics,
|
||||
1 => OnboardingPage::Editing,
|
||||
2 => OnboardingPage::AiSetup,
|
||||
3 => OnboardingPage::Welcome,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
result.push(if self.completed_pages.contains(&page) {
|
||||
'1'
|
||||
} else {
|
||||
'0'
|
||||
});
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn completed_pages_from_string(s: &str) -> [bool; 4] {
|
||||
let mut result = [false; 4];
|
||||
fn completed_pages_from_string(s: &str) -> HashSet<OnboardingPage> {
|
||||
let mut result = HashSet::new();
|
||||
for (i, ch) in s.chars().take(4).enumerate() {
|
||||
result[i] = ch == '1';
|
||||
if ch == '1' {
|
||||
let page = match i {
|
||||
0 => OnboardingPage::Basics,
|
||||
1 => OnboardingPage::Editing,
|
||||
2 => OnboardingPage::AiSetup,
|
||||
3 => OnboardingPage::Welcome,
|
||||
_ => continue,
|
||||
};
|
||||
result.insert(page);
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
@@ -275,7 +306,7 @@ impl OnboardingUI {
|
||||
fn reset(&mut self, _window: &mut gpui::Window, cx: &mut Context<Self>) {
|
||||
self.current_page = OnboardingPage::Basics;
|
||||
self.focus_area = FocusArea::Navigation;
|
||||
self.completed_pages = [false; 4];
|
||||
self.completed_pages = HashSet::new();
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
@@ -460,13 +491,7 @@ impl OnboardingUI {
|
||||
_window: &mut gpui::Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let index = match page {
|
||||
OnboardingPage::Basics => 0,
|
||||
OnboardingPage::Editing => 1,
|
||||
OnboardingPage::AiSetup => 2,
|
||||
OnboardingPage::Welcome => 3,
|
||||
};
|
||||
self.completed_pages[index] = true;
|
||||
self.completed_pages.insert(page);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
@@ -510,6 +535,40 @@ impl OnboardingUI {
|
||||
self.next_page(window, cx);
|
||||
}
|
||||
|
||||
fn handle_enable_ai_assistance(
|
||||
&mut self,
|
||||
_: &zed_actions::EnableAiAssistance,
|
||||
_window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if let Some(workspace) = self.workspace.upgrade() {
|
||||
let fs = workspace.read(cx).app_state().fs.clone();
|
||||
update_settings_file::<AllLanguageSettings>(fs, cx, move |file, _| {
|
||||
file.features
|
||||
.get_or_insert(Default::default())
|
||||
.ai_assistance = Some(true);
|
||||
});
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_disable_ai_assistance(
|
||||
&mut self,
|
||||
_: &zed_actions::DisableAiAssistance,
|
||||
_window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if let Some(workspace) = self.workspace.upgrade() {
|
||||
let fs = workspace.read(cx).app_state().fs.clone();
|
||||
update_settings_file::<AllLanguageSettings>(fs, cx, move |file, _| {
|
||||
file.features
|
||||
.get_or_insert(Default::default())
|
||||
.ai_assistance = Some(false);
|
||||
});
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_previous_page(
|
||||
&mut self,
|
||||
_: &PreviousPage,
|
||||
@@ -626,7 +685,7 @@ impl OnboardingUI {
|
||||
|
||||
let area_focused = self.focus_area == FocusArea::Navigation;
|
||||
|
||||
Ring::new(corner_radius, item_focused)
|
||||
FocusOutline::new(corner_radius, item_focused, px(2.))
|
||||
.active(area_focused && item_focused)
|
||||
.child(
|
||||
h_flex()
|
||||
@@ -1024,6 +1083,10 @@ impl OnboardingUI {
|
||||
let focused_item = self.page_focus[page_index].0;
|
||||
let is_page_focused = self.focus_area == FocusArea::PageContent;
|
||||
|
||||
let ai_enabled = ai_enabled(cx);
|
||||
|
||||
let workspace = self.workspace.clone();
|
||||
|
||||
v_flex()
|
||||
.h_full()
|
||||
.w_full()
|
||||
@@ -1035,8 +1098,22 @@ impl OnboardingUI {
|
||||
CheckboxWithLabel::new(
|
||||
"disable_ai",
|
||||
Label::new("Enable AI Features"),
|
||||
ToggleState::Selected,
|
||||
|_, _, cx| todo!("implement ai toggle"),
|
||||
if ai_enabled {
|
||||
ToggleState::Selected
|
||||
} else {
|
||||
ToggleState::Unselected
|
||||
},
|
||||
move |state, _, cx| {
|
||||
let enabled = state == &ToggleState::Selected;
|
||||
if let Some(workspace) = workspace.upgrade() {
|
||||
let fs = workspace.read(cx).app_state().fs.clone();
|
||||
update_settings_file::<AllLanguageSettings>(fs, cx, move |file, _| {
|
||||
file.features
|
||||
.get_or_insert(Default::default())
|
||||
.ai_assistance = Some(enabled);
|
||||
});
|
||||
}
|
||||
},
|
||||
)))
|
||||
.child(
|
||||
CalloutRow::new("We don't use your code to train AI models")
|
||||
@@ -1148,7 +1225,7 @@ impl SerializableItem for OnboardingUI {
|
||||
let completed = OnboardingUI::completed_pages_from_string(&completed_str);
|
||||
(page, completed)
|
||||
} else {
|
||||
(OnboardingPage::Basics, [false; 4])
|
||||
(OnboardingPage::Basics, HashSet::new())
|
||||
};
|
||||
|
||||
cx.update(|window, cx| {
|
||||
|
||||
@@ -42,6 +42,7 @@ client.workspace = true
|
||||
collab_ui.workspace = true
|
||||
collections.workspace = true
|
||||
command_palette.workspace = true
|
||||
command_palette_hooks.workspace = true
|
||||
component.workspace = true
|
||||
copilot.workspace = true
|
||||
dap_adapters.workspace = true
|
||||
|
||||
@@ -16,6 +16,7 @@ use assets::Assets;
|
||||
use breadcrumbs::Breadcrumbs;
|
||||
use client::zed_urls;
|
||||
use collections::VecDeque;
|
||||
use command_palette_hooks::CommandPaletteFilter;
|
||||
use debugger_ui::debugger_panel::DebugPanel;
|
||||
use editor::ProposedChangesEditorToolbar;
|
||||
use editor::{Editor, MultiBuffer};
|
||||
@@ -52,6 +53,7 @@ use settings::{
|
||||
Settings, SettingsStore, VIM_KEYMAP_PATH, initial_local_debug_tasks_content,
|
||||
initial_project_settings_content, initial_tasks_content, update_settings_file,
|
||||
};
|
||||
use std::any::TypeId;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::{self, AtomicBool};
|
||||
use std::{borrow::Cow, path::Path, sync::Arc};
|
||||
@@ -72,7 +74,8 @@ use workspace::{
|
||||
use workspace::{CloseIntent, CloseWindow, RestoreBanner, with_active_or_new_workspace};
|
||||
use workspace::{Pane, notifications::DetachAndPromptErr};
|
||||
use zed_actions::{
|
||||
OpenAccountSettings, OpenBrowser, OpenDocs, OpenServerSettings, OpenSettings, OpenZedUrl, Quit,
|
||||
DisableAiAssistance, EnableAiAssistance, OpenAccountSettings, OpenBrowser, OpenDocs,
|
||||
OpenServerSettings, OpenSettings, OpenZedUrl, Quit,
|
||||
};
|
||||
|
||||
actions!(
|
||||
@@ -215,6 +218,51 @@ pub fn init(cx: &mut App) {
|
||||
);
|
||||
});
|
||||
});
|
||||
cx.on_action(|_: &EnableAiAssistance, cx| {
|
||||
with_active_or_new_workspace(cx, |workspace, _, cx| {
|
||||
let fs = workspace.app_state().fs.clone();
|
||||
update_settings_file::<language::language_settings::AllLanguageSettings>(
|
||||
fs,
|
||||
cx,
|
||||
move |file, _| {
|
||||
file.features
|
||||
.get_or_insert(Default::default())
|
||||
.ai_assistance = Some(true);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
cx.on_action(|_: &DisableAiAssistance, cx| {
|
||||
with_active_or_new_workspace(cx, |workspace, _, cx| {
|
||||
let fs = workspace.app_state().fs.clone();
|
||||
update_settings_file::<language::language_settings::AllLanguageSettings>(
|
||||
fs,
|
||||
cx,
|
||||
move |file, _| {
|
||||
file.features
|
||||
.get_or_insert(Default::default())
|
||||
.ai_assistance = Some(false);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// Filter AI assistance actions based on current state
|
||||
cx.observe_global::<SettingsStore>(move |cx| {
|
||||
let ai_enabled =
|
||||
language::language_settings::all_language_settings(None, cx).is_ai_assistance_enabled();
|
||||
|
||||
CommandPaletteFilter::update_global(cx, |filter, _cx| {
|
||||
if ai_enabled {
|
||||
filter.hide_action_types(&[TypeId::of::<EnableAiAssistance>()]);
|
||||
filter.show_action_types([TypeId::of::<DisableAiAssistance>()].iter());
|
||||
} else {
|
||||
filter.show_action_types([TypeId::of::<EnableAiAssistance>()].iter());
|
||||
filter.hide_action_types(&[TypeId::of::<DisableAiAssistance>()]);
|
||||
}
|
||||
});
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
fn bind_on_window_closed(cx: &mut App) -> Option<gpui::Subscription> {
|
||||
|
||||
@@ -50,6 +50,10 @@ actions!(
|
||||
OpenLicenses,
|
||||
/// Opens the telemetry log.
|
||||
OpenTelemetryLog,
|
||||
/// Enables AI assistance features.
|
||||
EnableAiAssistance,
|
||||
/// Disables AI assistance features.
|
||||
DisableAiAssistance,
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user