Detailed changes
@@ -8,8 +8,8 @@ use language_model::LanguageModel;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{
- AgentDockPosition, DefaultAgentView, LanguageModelParameters, LanguageModelSelection,
- NotifyWhenAgentWaiting, Settings, SettingsContent,
+ DefaultAgentView, LanguageModelParameters, LanguageModelSelection, NotifyWhenAgentWaiting,
+ Settings, SettingsContent,
};
use util::MergeFrom;
@@ -28,7 +28,7 @@ pub fn init(cx: &mut App) {
pub struct AgentSettings {
pub enabled: bool,
pub button: bool,
- pub dock: AgentDockPosition,
+ pub dock: DockPosition,
pub default_width: Pixels,
pub default_height: Pixels,
pub default_model: Option<LanguageModelSelection>,
@@ -7,7 +7,7 @@ use acp_thread::{AgentConnection, Plan};
use action_log::ActionLog;
use agent_client_protocol::{self as acp, PromptCapabilities};
use agent_servers::{AgentServer, AgentServerDelegate};
-use agent_settings::{AgentProfileId, AgentSettings, CompletionMode, NotifyWhenAgentWaiting};
+use agent_settings::{AgentProfileId, AgentSettings, CompletionMode};
use agent2::{DbThreadMetadata, HistoryEntry, HistoryEntryId, HistoryStore, NativeAgentServer};
use anyhow::{Context as _, Result, anyhow, bail};
use arrayvec::ArrayVec;
@@ -35,7 +35,7 @@ use markdown::{HeadingLevelStyles, Markdown, MarkdownElement, MarkdownStyle};
use project::{Project, ProjectEntryId};
use prompt_store::{PromptId, PromptStore};
use rope::Point;
-use settings::{Settings as _, SettingsStore};
+use settings::{NotifyWhenAgentWaiting, Settings as _, SettingsStore};
use std::cell::RefCell;
use std::path::Path;
use std::sync::Arc;
@@ -5,11 +5,8 @@ use collections::HashSet;
use fs::Fs;
use gpui::{DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, Render, Task};
use language_model::LanguageModelRegistry;
-use language_models::{
- AllLanguageModelSettings, OpenAiCompatibleSettingsContent,
- provider::open_ai_compatible::{AvailableModel, ModelCapabilities},
-};
-use settings::update_settings_file;
+use language_models::provider::open_ai_compatible::{AvailableModel, ModelCapabilities};
+use settings::{OpenAiCompatibleSettingsContent, update_settings_file};
use ui::{
Banner, Checkbox, KeyBinding, Modal, ModalFooter, ModalHeader, Section, ToggleState, prelude::*,
};
@@ -238,15 +235,19 @@ fn save_provider_to_settings(
task.await
.map_err(|_| "Failed to write API key to keychain")?;
cx.update(|cx| {
- update_settings_file::<AllLanguageModelSettings>(fs, cx, |settings, _cx| {
- settings.language_models.getO
- settings.openai_compatible.get_or_insert_default().insert(
- provider_name,
- OpenAiCompatibleSettingsContent {
- api_url,
- available_models: models,
- },
- );
+ update_settings_file(fs, cx, |settings, _cx| {
+ settings
+ .language_models
+ .get_or_insert_default()
+ .openai_compatible
+ .get_or_insert_default()
+ .insert(
+ provider_name,
+ OpenAiCompatibleSettingsContent {
+ api_url,
+ available_models: models,
+ },
+ );
});
})
.ok();
@@ -422,18 +422,17 @@ impl ConfigureContextServerModal {
workspace.update(cx, |workspace, cx| {
let fs = workspace.app_state().fs.clone();
let original_server_id = self.original_server_id.clone();
- update_settings_file::<ProjectSettings>(
- fs.clone(),
- cx,
- move |project_settings, _| {
- if let Some(original_id) = original_server_id {
- if original_id != id {
- project_settings.context_servers.remove(&original_id.0);
- }
+ update_settings_file(fs.clone(), cx, move |current, _| {
+ if let Some(original_id) = original_server_id {
+ if original_id != id {
+ current.project.context_servers.remove(&original_id.0);
}
- project_settings.context_servers.insert(id.0, settings);
- },
- );
+ }
+ current
+ .project
+ .context_servers
+ .insert(id.0, settings.into());
+ });
});
} else if let Some(existing_server) = existing_server {
self.context_server_store
@@ -10,6 +10,7 @@ use project::agent_server_store::{
AgentServerCommand, AllAgentServersSettings, CLAUDE_CODE_NAME, GEMINI_NAME,
};
use serde::{Deserialize, Serialize};
+use settings::DefaultAgentView as DefaultView;
use zed_actions::OpenBrowser;
use zed_actions::agent::{OpenClaudeCodeOnboardingModal, ReauthenticateAgent};
@@ -33,7 +34,7 @@ use agent::{
history_store::{HistoryEntryId, HistoryStore},
thread_store::{TextThreadStore, ThreadStore},
};
-use agent_settings::{AgentDockPosition, AgentSettings, DefaultAgentView};
+use agent_settings::AgentSettings;
use ai_onboarding::AgentPanelOnboarding;
use anyhow::{Result, anyhow};
use assistant_context::{AssistantContext, ContextEvent, ContextSummary};
@@ -1424,11 +1425,7 @@ impl Focusable for AgentPanel {
}
fn agent_panel_dock_position(cx: &App) -> DockPosition {
- match AgentSettings::get_global(cx).dock {
- AgentDockPosition::Left => DockPosition::Left,
- AgentDockPosition::Bottom => DockPosition::Bottom,
- AgentDockPosition::Right => DockPosition::Right,
- }
+ AgentSettings::get_global(cx).dock
}
impl EventEmitter<PanelEvent> for AgentPanel {}
@@ -69,8 +69,9 @@ fn remove_context_server_settings(
fs: Arc<dyn Fs>,
cx: &mut App,
) {
- update_settings_file::<ProjectSettings>(fs, cx, move |settings, _| {
+ update_settings_file(fs, cx, move |settings, _| {
settings
+ .project
.context_servers
.retain(|server_id, _| !context_server_ids.contains(server_id));
});
@@ -45,3 +45,6 @@ workspace-hack.workspace = true
workspace.workspace = true
zed_actions.workspace = true
zlog.workspace = true
+
+[dev-dependencies]
+db = {workspace = true, features = ["test-support"]}
@@ -264,8 +264,8 @@ pub(crate) fn render_ai_setup_page(
);
let fs = <dyn Fs>::global(cx);
- update_settings_file::<DisableAiSettings>(fs, cx, move |ai_settings, _| {
- ai_settings.disable_ai = Some(enabled);
+ update_settings_file(fs, cx, move |settings, _| {
+ settings.disable_ai = Some(enabled);
});
},
)
@@ -186,8 +186,8 @@ impl PickerDelegate for BaseKeymapSelectorDelegate {
value = base_keymap.to_string()
);
- update_settings_file::<BaseKeymap>(self.fs.clone(), cx, move |setting, _| {
- setting.base_keymap = Some(base_keymap)
+ update_settings_file(self.fs.clone(), cx, move |setting, _| {
+ setting.base_keymap = Some(base_keymap.into())
});
}
@@ -194,27 +194,27 @@ fn render_theme_section(tab_index: &mut isize, cx: &mut App) -> impl IntoElement
fn write_mode_change(mode: ThemeMode, cx: &mut App) {
let fs = <dyn Fs>::global(cx);
- update_settings_file::<ThemeSettings>(fs, cx, move |settings, _cx| {
- settings.set_mode(mode);
+ update_settings_file(fs, cx, move |settings, _cx| {
+ theme::set_mode(settings, mode);
});
}
fn write_theme_change(theme: impl Into<Arc<str>>, theme_mode: ThemeMode, cx: &mut App) {
let fs = <dyn Fs>::global(cx);
let theme = theme.into();
- update_settings_file::<ThemeSettings>(fs, cx, move |settings, cx| {
+ update_settings_file(fs, cx, move |settings, cx| {
if theme_mode == ThemeMode::System {
let (light_theme, dark_theme) =
get_theme_family_themes(&theme).unwrap_or((theme.as_ref(), theme.as_ref()));
- settings.theme = Some(ThemeSelection::Dynamic {
+ settings.theme.theme = Some(settings::ThemeSelection::Dynamic {
mode: ThemeMode::System,
light: ThemeName(light_theme.into()),
dark: ThemeName(dark_theme.into()),
});
} else {
let appearance = *SystemAppearance::global(cx);
- settings.set_theme(theme, appearance);
+ theme::set_theme(settings, theme, appearance);
}
});
}
@@ -247,10 +247,10 @@ fn render_telemetry_section(tab_index: &mut isize, cx: &App) -> impl IntoElement
ToggleState::Indeterminate => { return; },
};
- update_settings_file::<TelemetrySettings>(
+ update_settings_file(
fs.clone(),
cx,
- move |setting, _| setting.metrics = Some(enabled),
+ move |setting, _| setting.telemetry.get_or_insert_default().metrics = Some(enabled),
);
// This telemetry event shouldn't fire when it's off. If it does we'll be alerted
@@ -286,10 +286,10 @@ fn render_telemetry_section(tab_index: &mut isize, cx: &App) -> impl IntoElement
ToggleState::Indeterminate => { return; },
};
- update_settings_file::<TelemetrySettings>(
+ update_settings_file(
fs.clone(),
cx,
- move |setting, _| setting.diagnostics = Some(enabled),
+ move |setting, _| setting.telemetry.get_or_insert_default().diagnostics = Some(enabled),
);
// This telemetry event shouldn't fire when it's off. If it does we'll be alerted
@@ -358,8 +358,8 @@ fn render_base_keymap_section(tab_index: &mut isize, cx: &mut App) -> impl IntoE
fn write_keymap_base(keymap_base: BaseKeymap, cx: &App) {
let fs = <dyn Fs>::global(cx);
- update_settings_file::<BaseKeymap>(fs, cx, move |setting, _| {
- setting.base_keymap = Some(keymap_base);
+ update_settings_file(fs, cx, move |setting, _| {
+ setting.base_keymap = Some(keymap_base.into());
});
telemetry::event!("Welcome Keymap Changed", keymap = keymap_base);
@@ -387,7 +387,7 @@ fn render_vim_mode_switch(tab_index: &mut isize, cx: &mut App) -> impl IntoEleme
return;
}
};
- update_settings_file::<VimModeSetting>(fs.clone(), cx, move |setting, _| {
+ update_settings_file(fs.clone(), cx, move |setting, _| {
setting.vim_mode = Some(vim_mode);
});
@@ -34,13 +34,13 @@ fn write_show_mini_map(show: ShowMinimap, cx: &mut App) {
curr_settings.minimap.show = show;
EditorSettings::override_global(curr_settings, cx);
- update_settings_file::<EditorSettings>(fs, cx, move |editor_settings, _| {
+ update_settings_file(fs, cx, move |settings, _| {
telemetry::event!(
"Welcome Minimap Clicked",
- from = editor_settings.minimap.unwrap_or_default(),
+ from = settings.editor.minimap.clone().unwrap_or_default(),
to = show
);
- editor_settings.minimap.get_or_insert_default().show = Some(show);
+ settings.editor.minimap.get_or_insert_default().show = Some(show);
});
}
@@ -58,8 +58,10 @@ fn write_inlay_hints(enabled: bool, cx: &mut App) {
curr_settings.defaults.inlay_hints.enabled = enabled;
AllLanguageSettings::override_global(curr_settings, cx);
- update_settings_file::<AllLanguageSettings>(fs, cx, move |all_language_settings, cx| {
- all_language_settings
+ update_settings_file(fs, cx, move |settings, cx| {
+ settings
+ .project
+ .all_languages
.defaults
.inlay_hints
.get_or_insert_with(|| {
@@ -80,64 +82,61 @@ fn write_git_blame(enabled: bool, cx: &mut App) {
let fs = <dyn Fs>::global(cx);
let mut curr_settings = ProjectSettings::get_global(cx).clone();
- curr_settings
- .git
- .inline_blame
- .get_or_insert_default()
- .enabled = enabled;
+ curr_settings.git.inline_blame.enabled = enabled;
ProjectSettings::override_global(curr_settings, cx);
- update_settings_file::<ProjectSettings>(fs, cx, move |project_settings, _| {
- project_settings
+ update_settings_file(fs, cx, move |settings, _| {
+ settings
.git
+ .get_or_insert_default()
.inline_blame
.get_or_insert_default()
- .enabled = enabled;
+ .enabled = Some(enabled);
});
}
fn write_ui_font_family(font: SharedString, cx: &mut App) {
let fs = <dyn Fs>::global(cx);
- update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
+ update_settings_file(fs, cx, move |settings, _| {
telemetry::event!(
"Welcome Font Changed",
type = "ui font",
- old = theme_settings.ui_font_family,
+ old = settings.theme.ui_font_family,
new = font
);
- theme_settings.ui_font_family = Some(FontFamilyName(font.into()));
+ settings.theme.ui_font_family = Some(FontFamilyName(font.into()));
});
}
fn write_ui_font_size(size: Pixels, cx: &mut App) {
let fs = <dyn Fs>::global(cx);
- update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
- theme_settings.ui_font_size = Some(size.into());
+ update_settings_file(fs, cx, move |settings, _| {
+ settings.theme.ui_font_size = Some(size.into());
});
}
fn write_buffer_font_size(size: Pixels, cx: &mut App) {
let fs = <dyn Fs>::global(cx);
- update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
- theme_settings.buffer_font_size = Some(size.into());
+ update_settings_file(fs, cx, move |settings, _| {
+ settings.theme.buffer_font_size = Some(size.into());
});
}
fn write_buffer_font_family(font_family: SharedString, cx: &mut App) {
let fs = <dyn Fs>::global(cx);
- update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
+ update_settings_file(fs, cx, move |settings, _| {
telemetry::event!(
"Welcome Font Changed",
type = "editor font",
- old = theme_settings.buffer_font_family,
+ old = settings.theme.buffer_font_family,
new = font_family
);
- theme_settings.buffer_font_family = Some(FontFamilyName(font_family.into()));
+ settings.theme.buffer_font_family = Some(FontFamilyName(font_family.into()));
});
}
@@ -153,8 +152,9 @@ fn write_font_ligatures(enabled: bool, cx: &mut App) {
let fs = <dyn Fs>::global(cx);
let bit = if enabled { 1 } else { 0 };
- update_settings_file::<ThemeSettings>(fs, cx, move |theme_settings, _| {
- let mut features = theme_settings
+ update_settings_file(fs, cx, move |settings, _| {
+ let mut features = settings
+ .theme
.buffer_font_features
.as_mut()
.map(|features| features.tag_value_list().to_vec())
@@ -166,7 +166,7 @@ fn write_font_ligatures(enabled: bool, cx: &mut App) {
features.push(("calt".into(), bit));
}
- theme_settings.buffer_font_features = Some(FontFeatures(Arc::new(features)));
+ settings.theme.buffer_font_features = Some(FontFeatures(Arc::new(features)));
});
}
@@ -180,8 +180,8 @@ fn read_format_on_save(cx: &App) -> bool {
fn write_format_on_save(format_on_save: bool, cx: &mut App) {
let fs = <dyn Fs>::global(cx);
- update_settings_file::<AllLanguageSettings>(fs, cx, move |language_settings, _| {
- language_settings.defaults.format_on_save = Some(match format_on_save {
+ update_settings_file(fs, cx, move |settings, _| {
+ settings.project.all_languages.defaults.format_on_save = Some(match format_on_save {
true => FormatOnSave::On,
false => FormatOnSave::Off,
});
@@ -150,6 +150,18 @@ impl From<settings::ContextServerSettingsContent> for ContextServerSettings {
}
}
}
+impl Into<settings::ContextServerSettingsContent> for ContextServerSettings {
+ fn into(self) -> settings::ContextServerSettingsContent {
+ match self {
+ ContextServerSettings::Custom { enabled, command } => {
+ settings::ContextServerSettingsContent::Custom { enabled, command }
+ }
+ ContextServerSettings::Extension { enabled, settings } => {
+ settings::ContextServerSettingsContent::Extension { enabled, settings }
+ }
+ }
+ }
+}
impl ContextServerSettings {
pub fn default_extension() -> Self {
@@ -42,6 +42,20 @@ impl From<BaseKeymapContent> for BaseKeymap {
}
}
}
+impl Into<BaseKeymapContent> for BaseKeymap {
+ fn into(self) -> BaseKeymapContent {
+ match self {
+ BaseKeymap::VSCode => BaseKeymapContent::VSCode,
+ BaseKeymap::JetBrains => BaseKeymapContent::JetBrains,
+ BaseKeymap::SublimeText => BaseKeymapContent::SublimeText,
+ BaseKeymap::Atom => BaseKeymapContent::Atom,
+ BaseKeymap::TextMate => BaseKeymapContent::TextMate,
+ BaseKeymap::Emacs => BaseKeymapContent::Emacs,
+ BaseKeymap::Cursor => BaseKeymapContent::Cursor,
+ BaseKeymap::None => BaseKeymapContent::None,
+ }
+ }
+}
impl Display for BaseKeymap {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
@@ -4,6 +4,8 @@ use schemars::{JsonSchema, json_schema};
use serde::{Deserialize, Serialize};
use std::{borrow::Cow, path::PathBuf, sync::Arc};
+use crate::DockPosition;
+
#[derive(Clone, PartialEq, Serialize, Deserialize, JsonSchema, Debug, Default)]
pub struct AgentSettingsContent {
/// Whether the Agent is enabled.
@@ -17,7 +19,7 @@ pub struct AgentSettingsContent {
/// Where to dock the agent panel.
///
/// Default: right
- pub dock: Option<AgentDockPosition>,
+ pub dock: Option<DockPosition>,
/// Default width in pixels when the agent panel is docked to the left or right.
///
/// Default: 640
@@ -103,7 +105,7 @@ pub struct AgentSettingsContent {
}
impl AgentSettingsContent {
- pub fn set_dock(&mut self, dock: AgentDockPosition) {
+ pub fn set_dock(&mut self, dock: DockPosition) {
self.dock = Some(dock);
}
@@ -174,15 +176,6 @@ pub struct ContextServerPresetContent {
pub tools: IndexMap<Arc<str>, bool>,
}
-#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
-#[serde(rename_all = "snake_case")]
-pub enum AgentDockPosition {
- Left,
- #[default]
- Right,
- Bottom,
-}
-
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum DefaultAgentView {
@@ -416,26 +416,32 @@ impl IconThemeSelection {
}
// impl ThemeSettingsContent {
-// /// Sets the theme for the given appearance to the theme with the specified name.
-// pub fn set_theme(&mut self, theme_name: impl Into<Arc<str>>, appearance: Appearance) {
-// if let Some(selection) = self.theme.as_mut() {
-// let theme_to_update = match selection {
-// ThemeSelection::Static(theme) => theme,
-// ThemeSelection::Dynamic { mode, light, dark } => match mode {
-// ThemeMode::Light => light,
-// ThemeMode::Dark => dark,
-// ThemeMode::System => match appearance {
-// Appearance::Light => light,
-// Appearance::Dark => dark,
-// },
-// },
-// };
+/// Sets the theme for the given appearance to the theme with the specified name.
+pub fn set_theme(
+ current: &mut SettingsContent,
+ theme_name: impl Into<Arc<str>>,
+ appearance: Appearance,
+) {
+ if let Some(selection) = current.theme.theme.as_mut() {
+ let theme_to_update = match selection {
+ settings::ThemeSelection::Static(theme) => theme,
+ settings::ThemeSelection::Dynamic { mode, light, dark } => match mode {
+ ThemeMode::Light => light,
+ ThemeMode::Dark => dark,
+ ThemeMode::System => match appearance {
+ Appearance::Light => light,
+ Appearance::Dark => dark,
+ },
+ },
+ };
-// *theme_to_update = ThemeName(theme_name.into());
-// } else {
-// self.theme = Some(ThemeSelection::Static(ThemeName(theme_name.into())));
-// }
-// }
+ *theme_to_update = ThemeName(theme_name.into());
+ } else {
+ current.theme.theme = Some(settings::ThemeSelection::Static(ThemeName(
+ theme_name.into(),
+ )));
+ }
+}
// /// Sets the icon theme for the given appearance to the icon theme with the specified name.
// pub fn set_icon_theme(&mut self, icon_theme_name: String, appearance: Appearance) {
@@ -460,56 +466,58 @@ impl IconThemeSelection {
// }
// }
-// /// Sets the mode for the theme.
-// pub fn set_mode(&mut self, mode: ThemeMode) {
-// if let Some(selection) = self.theme.as_mut() {
-// match selection {
-// ThemeSelection::Static(theme) => {
-// // If the theme was previously set to a single static theme,
-// // we don't know whether it was a light or dark theme, so we
-// // just use it for both.
-// self.theme = Some(ThemeSelection::Dynamic {
-// mode,
-// light: theme.clone(),
-// dark: theme.clone(),
-// });
-// }
-// ThemeSelection::Dynamic {
-// mode: mode_to_update,
-// ..
-// } => *mode_to_update = mode,
-// }
-// } else {
-// self.theme = Some(ThemeSelection::Dynamic {
-// mode,
-// light: ThemeName(ThemeSettings::DEFAULT_LIGHT_THEME.into()),
-// dark: ThemeName(ThemeSettings::DEFAULT_DARK_THEME.into()),
-// });
-// }
+/// Sets the mode for the theme.
+pub fn set_mode(content: &mut SettingsContent, mode: ThemeMode) {
+ let theme = content.theme.as_mut();
-// if let Some(selection) = self.icon_theme.as_mut() {
-// match selection {
-// IconThemeSelection::Static(icon_theme) => {
-// // If the icon theme was previously set to a single static
-// // theme, we don't know whether it was a light or dark
-// // theme, so we just use it for both.
-// self.icon_theme = Some(IconThemeSelection::Dynamic {
-// mode,
-// light: icon_theme.clone(),
-// dark: icon_theme.clone(),
-// });
-// }
-// IconThemeSelection::Dynamic {
-// mode: mode_to_update,
-// ..
-// } => *mode_to_update = mode,
-// }
-// } else {
-// self.icon_theme = Some(IconThemeSelection::Static(IconThemeName(
-// DEFAULT_ICON_THEME_NAME.into(),
-// )));
-// }
-// }
+ if let Some(selection) = theme.theme.as_mut() {
+ match selection {
+ settings::ThemeSelection::Static(theme) => {
+ // If the theme was previously set to a single static theme,
+ // we don't know whether it was a light or dark theme, so we
+ // just use it for both.
+ *selection = settings::ThemeSelection::Dynamic {
+ mode,
+ light: theme.clone(),
+ dark: theme.clone(),
+ };
+ }
+ settings::ThemeSelection::Dynamic {
+ mode: mode_to_update,
+ ..
+ } => *mode_to_update = mode,
+ }
+ } else {
+ theme.theme = Some(settings::ThemeSelection::Dynamic {
+ mode,
+ light: ThemeName(ThemeSettings::DEFAULT_LIGHT_THEME.into()),
+ dark: ThemeName(ThemeSettings::DEFAULT_DARK_THEME.into()),
+ });
+ }
+
+ if let Some(selection) = theme.icon_theme.as_mut() {
+ match selection {
+ settings::IconThemeSelection::Static(icon_theme) => {
+ // If the icon theme was previously set to a single static
+ // theme, we don't know whether it was a light or dark
+ // theme, so we just use it for both.
+ *selection = settings::IconThemeSelection::Dynamic {
+ mode,
+ light: icon_theme.clone(),
+ dark: icon_theme.clone(),
+ };
+ }
+ settings::IconThemeSelection::Dynamic {
+ mode: mode_to_update,
+ ..
+ } => *mode_to_update = mode,
+ }
+ } else {
+ theme.icon_theme = Some(settings::IconThemeSelection::Static(IconThemeName(
+ DEFAULT_ICON_THEME_NAME.into(),
+ )));
+ }
+}
// }
/// The buffer's line height.