Cargo.lock 🔗
@@ -3596,6 +3596,7 @@ dependencies = [
"schemars",
"serde",
"serde_json",
+ "settings",
"smol",
"tempfile",
"url",
Ben Kunkle created
Cargo.lock | 1
assets/settings/default.json | 13
crates/agent_ui/src/slash_command_settings.rs | 24
crates/call/src/call_settings.rs | 37
crates/context_server/Cargo.toml | 3
crates/context_server/src/context_server.rs | 27
crates/project/src/project.rs | 36
crates/project/src/project_settings.rs | 648 +++++++++---------
crates/settings/src/settings_content.rs | 98 +-
crates/settings/src/settings_content/project.rs | 384 +++++++++++
crates/settings/src/vscode_import.rs | 5
11 files changed, 829 insertions(+), 447 deletions(-)
@@ -3596,6 +3596,7 @@ dependencies = [
"schemars",
"serde",
"serde_json",
+ "settings",
"smol",
"tempfile",
"url",
@@ -1807,6 +1807,15 @@
"api_url": "https://api.mistral.ai/v1"
}
},
+ "session": {
+ /// Whether or not to restore unsaved buffers on restart.
+ ///
+ /// If this is true, user won't be prompted whether to save/discard
+ /// dirty files when closing the application.
+ ///
+ /// Default: true
+ "restore_unsaved_buffers": true
+ },
// Zed's Prettier integration settings.
// Allows to enable/disable formatting with Prettier
// and configure default Prettier, used when no project-level Prettier installation is found.
@@ -1845,6 +1854,10 @@
// }
// }
},
+ // DAP Specific settings.
+ "dap": {
+ // Specify the DAP name as a key here.
+ },
// Common language server settings.
"global_lsp_settings": {
// Whether to show the LSP servers button in the status bar.
@@ -5,32 +5,30 @@ use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
/// Settings for slash commands.
-#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema, SettingsUi, SettingsKey)]
-#[settings_key(key = "slash_commands")]
+#[derive(Debug, Default, Clone)]
pub struct SlashCommandSettings {
/// Settings for the `/cargo-workspace` slash command.
- #[serde(default)]
pub cargo_workspace: CargoWorkspaceCommandSettings,
}
/// Settings for the `/cargo-workspace` slash command.
-#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema)]
+#[derive(Debug, Default, Clone)]
pub struct CargoWorkspaceCommandSettings {
/// Whether `/cargo-workspace` is enabled.
- #[serde(default)]
pub enabled: bool,
}
impl Settings for SlashCommandSettings {
- type FileContent = Self;
+ fn from_defaults(content: &settings::SettingsContent, cx: &mut App) -> Self {
+ Self {
+ cargo_workspace: CargoWorkspaceCommandSettings {
+ enabled: content.project.slash_commands.unwrap(),
+ },
+ }
+ }
- fn load(sources: SettingsSources<Self::FileContent>, _cx: &mut App) -> Result<Self> {
- SettingsSources::<Self::FileContent>::json_merge_with(
- [sources.default]
- .into_iter()
- .chain(sources.user)
- .chain(sources.server),
- )
+ fn refine(&mut self, content: &settings::SettingsContent, cx: &mut App) {
+ todo!()
}
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
@@ -3,6 +3,7 @@ use gpui::App;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
+use util::MergeFrom;
#[derive(Deserialize, Debug)]
pub struct CallSettings {
@@ -10,27 +11,25 @@ pub struct CallSettings {
pub share_on_join: bool,
}
-/// Configuration of voice calls in Zed.
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi, SettingsKey)]
-#[settings_key(key = "calls")]
-pub struct CallSettingsContent {
- /// Whether the microphone should be muted when joining a channel or a call.
- ///
- /// Default: false
- pub mute_on_join: Option<bool>,
-
- /// Whether your current project should be shared when joining an empty channel.
- ///
- /// Default: false
- pub share_on_join: Option<bool>,
-}
-
impl Settings for CallSettings {
- type FileContent = CallSettingsContent;
+ fn from_defaults(content: &settings::SettingsContent, cx: &mut App) -> Self {
+ let call = content.call.unwrap();
+ CallSettings {
+ mute_on_join: call.mute_on_join.unwrap(),
+ share_on_join: call.share_on_join.unwrap(),
+ }
+ }
- fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
- sources.json_merge()
+ fn refine(&mut self, content: &settings::SettingsContent, cx: &mut App) {
+ if let Some(call) = content.call.clone() {
+ self.mute_on_join.merge_from(call.mute_on_join);
+ self.share_on_join.merge_from(call.share_on_join);
+ }
}
- fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
+ fn import_from_vscode(
+ _vscode: &settings::VsCodeSettings,
+ _current: &settings::SettingsContent,
+ ) {
+ }
}
@@ -25,8 +25,9 @@ net.workspace = true
parking_lot.workspace = true
postage.workspace = true
schemars.workspace = true
-serde.workspace = true
serde_json.workspace = true
+serde.workspace = true
+settings.workspace = true
smol.workspace = true
tempfile.workspace = true
url = { workspace = true, features = ["serde"] }
@@ -17,6 +17,7 @@ use gpui::AsyncApp;
use parking_lot::RwLock;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
+pub use settings::ContextServerCommand;
use util::redact::should_redact;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -28,32 +29,6 @@ impl Display for ContextServerId {
}
}
-#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema)]
-pub struct ContextServerCommand {
- #[serde(rename = "command")]
- pub path: PathBuf,
- pub args: Vec<String>,
- pub env: Option<HashMap<String, String>>,
- /// Timeout for tool calls in milliseconds. Defaults to 60000 (60 seconds) if not specified.
- pub timeout: Option<u64>,
-}
-
-impl std::fmt::Debug for ContextServerCommand {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let filtered_env = self.env.as_ref().map(|env| {
- env.iter()
- .map(|(k, v)| (k, if should_redact(k) { "[REDACTED]" } else { v }))
- .collect::<Vec<_>>()
- });
-
- f.debug_struct("ContextServerCommand")
- .field("path", &self.path)
- .field("args", &self.args)
- .field("env", &filtered_env)
- .finish()
- }
-}
-
enum ContextServerTransport {
Stdio(ContextServerCommand, Option<PathBuf>),
Custom(Arc<dyn crate::transport::Transport>),
@@ -979,7 +979,7 @@ pub struct DisableAiSettings {
impl settings::Settings for DisableAiSettings {
fn from_defaults(content: &settings::SettingsContent, _cx: &mut App) -> Self {
Self {
- disable_ai: content.project.disable_ai.unwrap(),
+ disable_ai: content.disable_ai.unwrap(),
}
}
@@ -3246,21 +3246,7 @@ impl Project {
let first_insertion = self.buffers_needing_diff.len() == 1;
let settings = ProjectSettings::get_global(cx);
- let delay = if let Some(delay) = settings.git.gutter_debounce {
- delay
- } else {
- if first_insertion {
- let this = cx.weak_entity();
- cx.defer(move |cx| {
- if let Some(this) = this.upgrade() {
- this.update(cx, |this, cx| {
- this.recalculate_buffer_diffs(cx).detach();
- });
- }
- });
- }
- return;
- };
+ let delay = settings.git.gutter_debounce;
const MIN_DELAY: u64 = 50;
let delay = delay.max(MIN_DELAY);
@@ -5648,11 +5634,11 @@ mod disable_ai_settings_tests {
cx.update(|cx| {
let mut store = SettingsStore::new(cx, &settings::test_settings());
store.register_setting::<DisableAiSettings>(cx);
- fn ai_disabled(cx: &App) -> bool {
- DisableAiSettings::get_global(cx).disable_ai
- }
// Test 1: Default is false (AI enabled)
- assert!(!ai_disabled(cx), "Default should allow AI");
+ assert!(
+ !DisableAiSettings::get_global(cx).disable_ai,
+ "Default should allow AI"
+ );
let disable_true = serde_json::json!({
"disable_ai": true
@@ -5665,11 +5651,17 @@ mod disable_ai_settings_tests {
store.set_user_settings(&disable_false, cx).unwrap();
store.set_global_settings(&disable_true, cx).unwrap();
- assert!(ai_disabled(cx), "Local false cannot override global true");
+ assert!(
+ DisableAiSettings::get_global(cx).disable_ai,
+ "Local false cannot override global true"
+ );
store.set_global_settings(&disable_false, cx).unwrap();
store.set_user_settings(&disable_true, cx).unwrap();
- assert!(ai_disabled(cx), "Local false cannot override global true");
+ assert!(
+ DisableAiSettings::get_global(cx).disable_ai,
+ "Local false cannot override global true"
+ );
});
}
}
@@ -1,10 +1,14 @@
use anyhow::Context as _;
+use clock::Global;
use collections::HashMap;
use context_server::ContextServerCommand;
use dap::adapters::DebugAdapterName;
use fs::Fs;
use futures::StreamExt as _;
-use gpui::{App, AsyncApp, BorrowAppContext, Context, Entity, EventEmitter, Subscription, Task};
+use gpui::{
+ App, AsyncApp, BorrowAppContext, Context, Entity, EventEmitter, SharedString, Subscription,
+ Task,
+};
use lsp::LanguageServerName;
use paths::{
EDITORCONFIG_NAME, local_debug_file_relative_path, local_settings_file_relative_path,
@@ -13,7 +17,7 @@ use paths::{
};
use rpc::{
AnyProtoClient, TypedEnvelope,
- proto::{self, FromProto, REMOTE_SERVER_PROJECT_ID, ToProto},
+ proto::{self, FromProto, Message, REMOTE_SERVER_PROJECT_ID, ToProto},
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
@@ -28,7 +32,7 @@ use std::{
time::Duration,
};
use task::{DebugTaskFile, TaskTemplates, VsCodeDebugTaskFile, VsCodeTaskFile};
-use util::{ResultExt, serde::default_true};
+use util::{MergeFrom as _, ResultExt, serde::default_true};
use worktree::{PathChange, UpdatedEntriesSet, Worktree, WorktreeId};
use crate::{
@@ -36,8 +40,7 @@ use crate::{
worktree_store::{WorktreeStore, WorktreeStoreEvent},
};
-#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi, SettingsKey)]
-#[settings_key(None)]
+#[derive(Debug, Clone)]
pub struct ProjectSettings {
/// Configuration for language servers.
///
@@ -47,50 +50,49 @@ pub struct ProjectSettings {
/// To override settings for a language, add an entry for that language server's
/// name to the lsp value.
/// Default: null
- #[serde(default)]
- pub lsp: HashMap<LanguageServerName, LspSettings>,
+ // todo! should these hash map types be Map<key, SettingsContent> or Map<Key, Settings>
+ pub lsp: HashMap<LanguageServerName, settings::LspSettingsContent>,
/// Common language server settings.
- #[serde(default)]
pub global_lsp_settings: GlobalLspSettings,
/// Configuration for Debugger-related features
- #[serde(default)]
pub dap: HashMap<DebugAdapterName, DapSettings>,
/// Settings for context servers used for AI-related features.
- #[serde(default)]
pub context_servers: HashMap<Arc<str>, ContextServerSettings>,
/// Configuration for Diagnostics-related features.
- #[serde(default)]
pub diagnostics: DiagnosticsSettings,
/// Configuration for Git-related features
- #[serde(default)]
pub git: GitSettings,
/// Configuration for Node-related features
- #[serde(default)]
pub node: NodeBinarySettings,
/// Configuration for how direnv configuration should be loaded
- #[serde(default)]
pub load_direnv: DirenvSettings,
/// Configuration for session-related features
- #[serde(default)]
pub session: SessionSettings,
}
-#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
-#[serde(rename_all = "snake_case")]
+#[derive(Debug, Clone, Default, PartialEq)]
pub struct DapSettings {
- pub binary: Option<String>,
- #[serde(default)]
+ pub binary: String,
pub args: Vec<String>,
}
+/// Common language server settings.
+#[derive(Debug, Clone, PartialEq)]
+pub struct GlobalLspSettings {
+ /// Whether to show the LSP servers button in the status bar.
+ ///
+ /// Default: `true`
+ pub button: bool,
+}
+
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
#[serde(tag = "source", rename_all = "snake_case")]
pub enum ContextServerSettings {
@@ -114,14 +116,17 @@ pub enum ContextServerSettings {
},
}
-/// Common language server settings.
-#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
-pub struct GlobalLspSettings {
- /// Whether to show the LSP servers button in the status bar.
- ///
- /// Default: `true`
- #[serde(default = "default_true")]
- pub button: bool,
+impl From<settings::ContextServerSettingsContent> for ContextServerSettings {
+ fn from(value: settings::ContextServerSettingsContent) -> Self {
+ match value {
+ settings::ContextServerSettingsContent::Custom { enabled, command } => {
+ ContextServerSettings::Custom { enabled, command }
+ }
+ settings::ContextServerSettingsContent::Extension { enabled, settings } => {
+ ContextServerSettings::Extension { enabled, settings }
+ }
+ }
+ }
}
impl ContextServerSettings {
@@ -147,140 +152,6 @@ impl ContextServerSettings {
}
}
-#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
-pub struct NodeBinarySettings {
- /// The path to the Node binary.
- pub path: Option<String>,
- /// The path to the npm binary Zed should use (defaults to `.path/../npm`).
- pub npm_path: Option<String>,
- /// If enabled, Zed will download its own copy of Node.
- #[serde(default)]
- pub ignore_system_version: bool,
-}
-
-#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
-#[serde(rename_all = "snake_case")]
-pub enum DirenvSettings {
- /// Load direnv configuration through a shell hook
- ShellHook,
- /// Load direnv configuration directly using `direnv export json`
- #[default]
- Direct,
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
-#[serde(default)]
-pub struct DiagnosticsSettings {
- /// Whether to show the project diagnostics button in the status bar.
- pub button: bool,
-
- /// Whether or not to include warning diagnostics.
- pub include_warnings: bool,
-
- /// Settings for using LSP pull diagnostics mechanism in Zed.
- pub lsp_pull_diagnostics: LspPullDiagnosticsSettings,
-
- /// Settings for showing inline diagnostics.
- pub inline: InlineDiagnosticsSettings,
-}
-
-#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
-#[serde(default)]
-pub struct LspPullDiagnosticsSettings {
- /// Whether to pull for diagnostics or not.
- ///
- /// Default: true
- #[serde(default = "default_true")]
- pub enabled: bool,
- /// Minimum time to wait before pulling diagnostics from the language server(s).
- /// 0 turns the debounce off.
- ///
- /// Default: 50
- #[serde(default = "default_lsp_diagnostics_pull_debounce_ms")]
- pub debounce_ms: u64,
-}
-
-fn default_lsp_diagnostics_pull_debounce_ms() -> u64 {
- 50
-}
-
-#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
-#[serde(default)]
-pub struct InlineDiagnosticsSettings {
- /// Whether or not to show inline diagnostics
- ///
- /// Default: false
- pub enabled: bool,
- /// Whether to only show the inline diagnostics after a delay after the
- /// last editor event.
- ///
- /// Default: 150
- #[serde(default = "default_inline_diagnostics_update_debounce_ms")]
- pub update_debounce_ms: u64,
- /// The amount of padding between the end of the source line and the start
- /// of the inline diagnostic in units of columns.
- ///
- /// Default: 4
- #[serde(default = "default_inline_diagnostics_padding")]
- pub padding: u32,
- /// The minimum column to display inline diagnostics. This setting can be
- /// used to horizontally align inline diagnostics at some position. Lines
- /// longer than this value will still push diagnostics further to the right.
- ///
- /// Default: 0
- pub min_column: u32,
-
- pub max_severity: Option<DiagnosticSeverity>,
-}
-
-fn default_inline_diagnostics_update_debounce_ms() -> u64 {
- 150
-}
-
-fn default_inline_diagnostics_padding() -> u32 {
- 4
-}
-
-impl Default for DiagnosticsSettings {
- fn default() -> Self {
- Self {
- button: true,
- include_warnings: true,
- lsp_pull_diagnostics: LspPullDiagnosticsSettings::default(),
- inline: InlineDiagnosticsSettings::default(),
- }
- }
-}
-
-impl Default for LspPullDiagnosticsSettings {
- fn default() -> Self {
- Self {
- enabled: true,
- debounce_ms: default_lsp_diagnostics_pull_debounce_ms(),
- }
- }
-}
-
-impl Default for InlineDiagnosticsSettings {
- fn default() -> Self {
- Self {
- enabled: false,
- update_debounce_ms: default_inline_diagnostics_update_debounce_ms(),
- padding: default_inline_diagnostics_padding(),
- min_column: 0,
- max_severity: None,
- }
- }
-}
-
-impl Default for GlobalLspSettings {
- fn default() -> Self {
- Self {
- button: default_true(),
- }
- }
-}
-
#[derive(
Clone,
Copy,
@@ -301,7 +172,6 @@ pub enum DiagnosticSeverity {
Error,
Warning,
Info,
- #[serde(alias = "all")]
Hint,
}
@@ -317,6 +187,18 @@ impl DiagnosticSeverity {
}
}
+impl From<settings::DiagnosticSeverityContent> for DiagnosticSeverity {
+ fn from(severity: settings::DiagnosticSeverityContent) -> Self {
+ match severity {
+ settings::DiagnosticSeverityContent::Off => DiagnosticSeverity::Off,
+ settings::DiagnosticSeverityContent::Error => DiagnosticSeverity::Error,
+ settings::DiagnosticSeverityContent::Warning => DiagnosticSeverity::Warning,
+ settings::DiagnosticSeverityContent::Info => DiagnosticSeverity::Info,
+ settings::DiagnosticSeverityContent::Hint => DiagnosticSeverity::Hint,
+ }
+ }
+}
+
/// Determines the severity of the diagnostic that should be moved to.
#[derive(PartialEq, PartialOrd, Clone, Copy, Debug, Eq, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
@@ -390,126 +272,90 @@ impl GoToDiagnosticSeverityFilter {
}
}
-#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
+#[derive(Copy, Clone, Debug)]
pub struct GitSettings {
/// Whether or not to show the git gutter.
///
/// Default: tracked_files
- pub git_gutter: Option<GitGutterSetting>,
+ pub git_gutter: settings::GitGutterSetting,
/// Sets the debounce threshold (in milliseconds) after which changes are reflected in the git gutter.
///
/// Default: null
- pub gutter_debounce: Option<u64>,
+ pub gutter_debounce: u64,
/// Whether or not to show git blame data inline in
/// the currently focused line.
///
/// Default: on
- pub inline_blame: Option<InlineBlameSettings>,
+ pub inline_blame: InlineBlameSettings,
/// Which information to show in the branch picker.
///
/// Default: on
- pub branch_picker: Option<BranchPickerSettings>,
+ pub branch_picker: BranchPickerSettings,
/// How hunks are displayed visually in the editor.
///
/// Default: staged_hollow
- pub hunk_style: Option<GitHunkStyleSetting>,
-}
-
-impl GitSettings {
- pub fn inline_blame_enabled(&self) -> bool {
- #[allow(unknown_lints, clippy::manual_unwrap_or_default)]
- match self.inline_blame {
- Some(InlineBlameSettings { enabled, .. }) => enabled,
- _ => false,
- }
- }
-
- pub fn inline_blame_delay(&self) -> Option<Duration> {
- match self.inline_blame {
- Some(InlineBlameSettings { delay_ms, .. }) if delay_ms > 0 => {
- Some(Duration::from_millis(delay_ms))
- }
- _ => None,
- }
- }
-
- pub fn show_inline_commit_summary(&self) -> bool {
- match self.inline_blame {
- Some(InlineBlameSettings {
- show_commit_summary,
- ..
- }) => show_commit_summary,
- _ => false,
- }
- }
-}
-
-#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
-#[serde(rename_all = "snake_case")]
-pub enum GitHunkStyleSetting {
- /// Show unstaged hunks with a filled background and staged hunks hollow.
- #[default]
- StagedHollow,
- /// Show unstaged hunks hollow and staged hunks with a filled background.
- UnstagedHollow,
-}
-
-#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
-#[serde(rename_all = "snake_case")]
-pub enum GitGutterSetting {
- /// Show git gutter in tracked files.
- #[default]
- TrackedFiles,
- /// Hide git gutter
- Hide,
+ pub hunk_style: settings::GitHunkStyleSetting,
}
-#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
-#[serde(rename_all = "snake_case")]
+#[derive(Clone, Copy, Debug)]
pub struct InlineBlameSettings {
/// Whether or not to show git blame data inline in
/// the currently focused line.
///
/// Default: true
- #[serde(default = "default_true")]
pub enabled: bool,
/// Whether to only show the inline blame information
/// after a delay once the cursor stops moving.
///
/// Default: 0
- #[serde(default)]
- pub delay_ms: u64,
+ pub delay_ms: std::time::Duration,
/// The amount of padding between the end of the source line and the start
/// of the inline blame in units of columns.
///
/// Default: 7
- #[serde(default = "default_inline_blame_padding")]
pub padding: u32,
/// The minimum column number to show the inline blame information at
///
/// Default: 0
- #[serde(default)]
pub min_column: u32,
/// Whether to show commit summary as part of the inline blame.
///
/// Default: false
- #[serde(default)]
pub show_commit_summary: bool,
}
-fn default_inline_blame_padding() -> u32 {
- 7
-}
+impl GitSettings {
+ // todo! remove
+ pub fn inline_blame_enabled(&self) -> bool {
+ self.inline_blame.enabled
+ // #[allow(unknown_lints, clippy::manual_unwrap_or_default)]
+ // match self.inline_blame {
+ // Some(InlineBlameSettings { enabled, .. }) => enabled,
+ // _ => false,
+ // }
+ }
-impl Default for InlineBlameSettings {
- fn default() -> Self {
- Self {
- enabled: true,
- delay_ms: 0,
- padding: default_inline_blame_padding(),
- min_column: 0,
- show_commit_summary: false,
- }
+ // todo! remove
+ pub fn inline_blame_delay(&self) -> Option<Duration> {
+ Some(self.inline_blame.delay_ms)
+ // match self.inline_blame {
+ // Some(InlineBlameSettings { delay_ms, .. }) if delay_ms > 0 => {
+ // Some(Duration::from_millis(delay_ms))
+ // }
+ // _ => None,
+ // }
+ }
+
+ // todo! remove
+ pub fn show_inline_commit_summary(&self) -> bool {
+ self.inline_blame.show_commit_summary
+ // match self.inline_blame {
+ // Some(InlineBlameSettings {
+ // show_commit_summary,
+ // ..
+ // }) => show_commit_summary,
+ // _ => false,
+ // }
}
}
@@ -531,93 +377,263 @@ impl Default for BranchPickerSettings {
}
}
-#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Hash)]
-pub struct BinarySettings {
- pub path: Option<String>,
- pub arguments: Option<Vec<String>>,
- pub env: Option<BTreeMap<String, String>>,
- pub ignore_system_version: Option<bool>,
-}
+#[derive(Clone, Debug)]
+pub struct DiagnosticsSettings {
+ /// Whether to show the project diagnostics button in the status bar.
+ pub button: bool,
-#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Hash)]
-pub struct FetchSettings {
- // Whether to consider pre-releases for fetching
- pub pre_release: Option<bool>,
-}
+ /// Whether or not to include warning diagnostics.
+ pub include_warnings: bool,
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Hash)]
-#[serde(rename_all = "snake_case")]
-pub struct LspSettings {
- pub binary: Option<BinarySettings>,
- pub initialization_options: Option<serde_json::Value>,
- pub settings: Option<serde_json::Value>,
- /// If the server supports sending tasks over LSP extensions,
- /// this setting can be used to enable or disable them in Zed.
- /// Default: true
- #[serde(default = "default_true")]
- pub enable_lsp_tasks: bool,
- pub fetch: Option<FetchSettings>,
-}
+ /// Settings for using LSP pull diagnostics mechanism in Zed.
+ pub lsp_pull_diagnostics: LspPullDiagnosticsSettings,
-impl Default for LspSettings {
- fn default() -> Self {
- Self {
- binary: None,
- initialization_options: None,
- settings: None,
- enable_lsp_tasks: true,
- fetch: None,
- }
- }
+ /// Settings for showing inline diagnostics.
+ pub inline: InlineDiagnosticsSettings,
}
-#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
-pub struct SessionSettings {
- /// Whether or not to restore unsaved buffers on restart.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct InlineDiagnosticsSettings {
+ /// Whether or not to show inline diagnostics
///
- /// If this is true, user won't be prompted whether to save/discard
- /// dirty files when closing the application.
+ /// Default: false
+ pub enabled: bool,
+ /// Whether to only show the inline diagnostics after a delay after the
+ /// last editor event.
+ ///
+ /// Default: 150
+ pub update_debounce_ms: u64,
+ /// The amount of padding between the end of the source line and the start
+ /// of the inline diagnostic in units of columns.
+ ///
+ /// Default: 4
+ pub padding: u32,
+ /// The minimum column to display inline diagnostics. This setting can be
+ /// used to horizontally align inline diagnostics at some position. Lines
+ /// longer than this value will still push diagnostics further to the right.
+ ///
+ /// Default: 0
+ pub min_column: u32,
+
+ pub max_severity: DiagnosticSeverity,
+}
+
+#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
+pub struct LspPullDiagnosticsSettings {
+ /// Whether to pull for diagnostics or not.
///
/// Default: true
- pub restore_unsaved_buffers: bool,
+ pub enabled: bool,
+ /// Minimum time to wait before pulling diagnostics from the language server(s).
+ /// 0 turns the debounce off.
+ ///
+ /// Default: 50
+ pub debounce_ms: u64,
}
-impl Default for SessionSettings {
- fn default() -> Self {
+impl Settings for ProjectSettings {
+ fn from_defaults(content: &settings::SettingsContent, cx: &mut App) -> Self {
+ let project = &content.project.clone();
+ let diagnostics = content.diagnostics.as_ref().unwrap();
+ let lsp_pull_diagnostics = diagnostics.lsp_pull_diagnostics.as_ref().unwrap();
+ let inline_diagnostics = diagnostics.inline.as_ref().unwrap();
+
+ let git = content.git.as_ref().unwrap();
+ let git_settings = GitSettings {
+ git_gutter: git.git_gutter.unwrap(),
+ gutter_debounce: git.gutter_debounce.unwrap(),
+ inline_blame: {
+ let inline = git.inline_blame.unwrap();
+ InlineBlameSettings {
+ enabled: inline.enabled.unwrap(),
+ delay_ms: std::time::Duration::from_millis(inline.delay_ms.unwrap()),
+ padding: inline.padding.unwrap(),
+ min_column: inline.min_column.unwrap(),
+ show_commit_summary: inline.show_commit_summary.unwrap(),
+ }
+ },
+ branch_picker: {
+ let branch_picker = git.branch_picker.unwrap();
+ BranchPickerSettings {
+ show_author_name: branch_picker.show_author_name.unwrap(),
+ }
+ },
+ hunk_style: git.hunk_style.unwrap(),
+ };
Self {
- restore_unsaved_buffers: true,
+ context_servers: project
+ .context_servers
+ .clone()
+ .into_iter()
+ .map(|(key, value)| (key, value.into()))
+ .collect(),
+ lsp: project
+ .lsp
+ .clone()
+ .into_iter()
+ .map(|(key, value)| (LanguageServerName(key.into()), value.into()))
+ .collect(),
+ global_lsp_settings: GlobalLspSettings {
+ button: content.global_lsp_settings.unwrap().button.unwrap(),
+ },
+ dap: project
+ .dap
+ .clone()
+ .into_iter()
+ .map(|(key, value)| {
+ (
+ DebugAdapterName(key.into()),
+ DapSettings {
+ binary: value.binary.unwrap(),
+ args: value.args,
+ },
+ )
+ })
+ .collect(),
+ diagnostics: DiagnosticsSettings {
+ button: diagnostics.button.unwrap(),
+ include_warnings: diagnostics.include_warnings.unwrap(),
+ lsp_pull_diagnostics: LspPullDiagnosticsSettings {
+ enabled: lsp_pull_diagnostics.enabled.unwrap(),
+ debounce_ms: lsp_pull_diagnostics.debounce_ms.unwrap(),
+ },
+ inline: InlineDiagnosticsSettings {
+ enabled: inline_diagnostics.enabled.unwrap(),
+ update_debounce_ms: inline_diagnostics.update_debounce_ms.unwrap(),
+ padding: inline_diagnostics.padding.unwrap(),
+ min_column: inline_diagnostics.min_column.unwrap(),
+ max_severity: inline_diagnostics.max_severity.unwrap().into(),
+ },
+ },
+ git: git_settings,
+ node: content.node.clone(),
+ load_direnv: project.load_direnv.unwrap(),
+ session: content.session.clone(),
}
}
-}
-impl Settings for ProjectSettings {
- type FileContent = Self;
+ fn refine(&mut self, content: &settings::SettingsContent, cx: &mut App) {
+ let project = &content.project;
+ self.context_servers.extend(
+ project
+ .context_servers
+ .clone()
+ .into_iter()
+ .map(|(key, value)| (key, value.into())),
+ );
+ self.dap
+ .extend(project.dap.clone().into_iter().filter_map(|(key, value)| {
+ Some((
+ DebugAdapterName(key.into()),
+ DapSettings {
+ binary: value.binary?,
+ args: value.args,
+ },
+ ))
+ }));
+ if let Some(diagnostics) = content.diagnostics.as_ref() {
+ if let Some(inline) = &diagnostics.inline {
+ self.diagnostics.inline.enabled.merge_from(&inline.enabled);
+ self.diagnostics
+ .inline
+ .update_debounce_ms
+ .merge_from(&inline.update_debounce_ms);
+ self.diagnostics.inline.padding.merge_from(&inline.padding);
+ self.diagnostics
+ .inline
+ .min_column
+ .merge_from(&inline.min_column);
+ self.diagnostics
+ .inline
+ .max_severity
+ .merge_from(&inline.max_severity.map(Into::into));
+ }
- fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> anyhow::Result<Self> {
- sources.json_merge()
+ self.diagnostics.button.merge_from(&diagnostics.button);
+ self.diagnostics
+ .include_warnings
+ .merge_from(&diagnostics.include_warnings);
+ if let Some(pull_diagnostics) = &diagnostics.lsp_pull_diagnostics {
+ self.diagnostics
+ .lsp_pull_diagnostics
+ .enabled
+ .merge_from(&pull_diagnostics.enabled);
+ self.diagnostics
+ .lsp_pull_diagnostics
+ .debounce_ms
+ .merge_from(&pull_diagnostics.debounce_ms);
+ }
+ }
+ if let Some(git) = content.git.as_ref() {
+ if let Some(branch_picker) = git.branch_picker.as_ref() {
+ self.git
+ .branch_picker
+ .show_author_name
+ .merge_from(&branch_picker.show_author_name);
+ }
+ if let Some(inline_blame) = git.inline_blame.as_ref() {
+ self.git
+ .inline_blame
+ .enabled
+ .merge_from(&inline_blame.enabled);
+ self.git
+ .inline_blame
+ .delay_ms
+ .merge_from(&inline_blame.delay_ms.map(std::time::Duration::from_millis));
+ self.git
+ .inline_blame
+ .padding
+ .merge_from(&inline_blame.padding);
+ self.git
+ .inline_blame
+ .min_column
+ .merge_from(&inline_blame.min_column);
+ self.git
+ .inline_blame
+ .show_commit_summary
+ .merge_from(&inline_blame.show_commit_summary);
+ }
+ self.git.git_gutter.merge_from(&git.git_gutter);
+ self.git.hunk_style.merge_from(&git.hunk_style);
+ self.git.gutter_debounce.merge_from(&git.gutter_debounce);
+ }
+ self.global_lsp_settings = content.global_lsp_settings.clone();
+ self.load_direnv = content.project.load_direnv.clone();
+ self.lsp.extend(
+ content
+ .project
+ .lsp
+ .clone()
+ .into_iter()
+ .map(|(key, value)| (key, lsp_settings)),
+ );
}
- fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) {
+ fn import_from_vscode(
+ vscode: &settings::VsCodeSettings,
+ current: &mut settings::SettingsContent,
+ ) {
// this just sets the binary name instead of a full path so it relies on path lookup
// resolving to the one you want
- vscode.enum_setting(
- "npm.packageManager",
- &mut current.node.npm_path,
- |s| match s {
- v @ ("npm" | "yarn" | "bun" | "pnpm") => Some(v.to_owned()),
- _ => None,
- },
- );
+ let npm_path = vscode.read_enum_setting("npm.packageManager", |s| match s {
+ v @ ("npm" | "yarn" | "bun" | "pnpm") => Some(v.to_owned()),
+ _ => None,
+ });
+ if npm_path.is_some() {
+ current.node.get_or_insert_default().npm_path = npm_path;
+ }
if let Some(b) = vscode.read_bool("git.blame.editorDecoration.enabled") {
- if let Some(blame) = current.git.inline_blame.as_mut() {
- blame.enabled = b
- } else {
- current.git.inline_blame = Some(InlineBlameSettings {
- enabled: b,
- ..Default::default()
- })
- }
+ // todo! get_or_insert_default is risky considering defaults probably don't correspond
+ // to default.json,
+ // probably need to pass in "defaults" for this type as additional arg, and
+ // use unwrap on those keys
+ current
+ .git
+ .get_or_insert_default()
+ .inline_blame
+ .get_or_insert_default()
+ .enabled = Some(b);
}
#[derive(Deserialize)]
@@ -627,29 +643,27 @@ impl Settings for ProjectSettings {
env: Option<HashMap<String, String>>,
// note: we don't support envFile and type
}
- impl From<VsCodeContextServerCommand> for ContextServerCommand {
- fn from(cmd: VsCodeContextServerCommand) -> Self {
- Self {
- path: cmd.command,
- args: cmd.args.unwrap_or_default(),
- env: cmd.env,
- timeout: None,
- }
- }
- }
if let Some(mcp) = vscode.read_value("mcp").and_then(|v| v.as_object()) {
current
+ .project
.context_servers
.extend(mcp.iter().filter_map(|(k, v)| {
Some((
k.clone().into(),
- ContextServerSettings::Custom {
+ settings::ContextServerSettingsContent::Custom {
enabled: true,
command: serde_json::from_value::<VsCodeContextServerCommand>(
v.clone(),
)
- .ok()?
- .into(),
+ .ok()
+ .map(|cmd| {
+ settings::ContextServerCommand {
+ path: cmd.command,
+ args: cmd.args.unwrap_or_default(),
+ env: cmd.env,
+ timeout: None,
+ }
+ })?,
},
))
}));
@@ -740,7 +754,7 @@ impl SettingsObserver {
if Some(new_settings) != user_settings.as_ref() {
if let Some(new_settings_string) = serde_json::to_string(new_settings).ok()
{
- user_settings = Some(new_settings.clone());
+ user_settings = new_settings.clone();
upstream_client
.send(proto::UpdateUserSettings {
project_id: REMOTE_SERVER_PROJECT_ID,
@@ -1,19 +1,21 @@
mod agent;
mod language;
+mod project;
mod terminal;
mod theme;
pub use agent::*;
pub use language::*;
+pub use project::*;
pub use terminal::*;
pub use theme::*;
-use std::env;
-
use collections::HashMap;
use gpui::{App, SharedString};
use release_channel::ReleaseChannel;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
+use std::env;
+pub use util::serde::default_true;
use crate::ActiveSettingsProfileName;
@@ -37,9 +39,18 @@ pub struct SettingsContent {
pub debugger: Option<DebuggerSettingsContent>,
+ /// Configuration for Diagnostics-related features.
+ pub diagnostics: Option<DiagnosticsSettingsContent>,
+
+ /// Configuration for Git-related features
+ pub git: Option<GitSettings>,
+
/// The list of custom Git hosting providers.
pub git_hosting_providers: Option<Vec<GitHostingProviderConfig>>,
+ /// Common language server settings.
+ pub global_lsp_settings: Option<GlobalLspSettingsContent>,
+
/// Whether or not to enable Helix mode.
///
/// Default: false
@@ -50,11 +61,16 @@ pub struct SettingsContent {
/// Example: {"log": {"client": "warn"}}
pub log: Option<HashMap<String, String>>,
+ /// Configuration for Node-related features
+ pub node: Option<NodeBinarySettings>,
+
pub proxy: Option<String>,
/// The URL of the Zed server to connect to.
pub server_url: Option<String>,
+ /// Configuration for session-related features
+ pub session: Option<SessionSettings>,
/// Control what info is collected by Zed.
pub telemetry: Option<TelemetrySettingsContent>,
@@ -67,6 +83,9 @@ pub struct SettingsContent {
///
/// Default: false
pub vim_mode: Option<bool>,
+
+ // Settings related to calls in Zed
+ pub calls: Option<CallSettingsContent>,
}
impl SettingsContent {
@@ -147,17 +166,6 @@ pub enum BaseKeymapContent {
None,
}
-#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
-pub struct ProjectSettingsContent {
- #[serde(flatten)]
- pub all_languages: AllLanguageSettingsContent,
-
- #[serde(flatten)]
- pub worktree: WorktreeSettingsContent,
-
- pub disable_ai: Option<bool>,
-}
-
#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, Debug)]
pub struct TitleBarSettingsContent {
/// Controls when the title bar is visible: "always" | "never" | "hide_in_full_screen".
@@ -246,42 +254,6 @@ pub enum GitHostingProviderKind {
Bitbucket,
}
-#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
-pub struct WorktreeSettingsContent {
- /// The displayed name of this project. If not set, the root directory name
- /// will be displayed.
- ///
- /// Default: none
- pub project_name: Option<String>,
-
- /// Completely ignore files matching globs from `file_scan_exclusions`. Overrides
- /// `file_scan_inclusions`.
- ///
- /// Default: [
- /// "**/.git",
- /// "**/.svn",
- /// "**/.hg",
- /// "**/.jj",
- /// "**/CVS",
- /// "**/.DS_Store",
- /// "**/Thumbs.db",
- /// "**/.classpath",
- /// "**/.settings"
- /// ]
- pub file_scan_exclusions: Option<Vec<String>>,
-
- /// Always include files that match these globs when scanning for files, even if they're
- /// ignored by git. This setting is overridden by `file_scan_exclusions`.
- /// Default: [
- /// ".env*",
- /// "docker-compose.*.yml",
- /// ]
- pub file_scan_inclusions: Option<Vec<String>>,
-
- /// Treat the files matching these globs as `.env` files.
- /// Default: [ "**/.env*" ]
- pub private_files: Option<Vec<String>>,
-}
/// Control what info is collected by Zed.
#[derive(Default, Clone, Serialize, Deserialize, JsonSchema, Debug)]
pub struct TelemetrySettingsContent {
@@ -348,3 +320,31 @@ pub enum DockPosition {
Bottom,
Right,
}
+
+/// Settings for slash commands.
+#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema)]
+pub struct SlashCommandSettings {
+ /// Settings for the `/cargo-workspace` slash command.
+ pub cargo_workspace: Option<CargoWorkspaceCommandSettings>,
+}
+
+/// Settings for the `/cargo-workspace` slash command.
+#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema)]
+pub struct CargoWorkspaceCommandSettings {
+ /// Whether `/cargo-workspace` is enabled.
+ pub enabled: Option<bool>,
+}
+
+/// Configuration of voice calls in Zed.
+#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)]
+pub struct CallSettingsContent {
+ /// Whether the microphone should be muted when joining a channel or a call.
+ ///
+ /// Default: false
+ pub mute_on_join: Option<bool>,
+
+ /// Whether your current project should be shared when joining an empty channel.
+ ///
+ /// Default: false
+ pub share_on_join: Option<bool>,
+}
@@ -0,0 +1,384 @@
+use std::{path::PathBuf, sync::Arc};
+
+use collections::{BTreeMap, HashMap};
+use schemars::JsonSchema;
+use serde::{Deserialize, Serialize};
+use util::serde::default_true;
+
+use crate::AllLanguageSettingsContent;
+
+#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize, JsonSchema)]
+pub struct ProjectSettingsContent {
+ #[serde(flatten)]
+ pub all_languages: AllLanguageSettingsContent,
+
+ #[serde(flatten)]
+ pub worktree: WorktreeSettingsContent,
+
+ /// Configuration for language servers.
+ ///
+ /// The following settings can be overridden for specific language servers:
+ /// - initialization_options
+ ///
+ /// To override settings for a language, add an entry for that language server's
+ /// name to the lsp value.
+ /// Default: null
+ #[serde(default)]
+ pub lsp: HashMap<Arc<str>, LspSettingsContent>,
+
+ /// Configuration for Debugger-related features
+ #[serde(default)]
+ pub dap: HashMap<Arc<str>, DapSettingsContent>,
+
+ /// Settings for context servers used for AI-related features.
+ #[serde(default)]
+ pub context_servers: HashMap<Arc<str>, ContextServerSettingsContent>,
+
+ /// Configuration for how direnv configuration should be loaded
+ pub load_direnv: Option<DirenvSettings>,
+
+ /// Settings for slash commands.
+ pub slash_commands: Option<SlashCommandSettings>,
+}
+
+#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
+pub struct WorktreeSettingsContent {
+ /// The displayed name of this project. If not set, the root directory name
+ /// will be displayed.
+ ///
+ /// Default: none
+ pub project_name: Option<String>,
+
+ /// Completely ignore files matching globs from `file_scan_exclusions`. Overrides
+ /// `file_scan_inclusions`.
+ ///
+ /// Default: [
+ /// "**/.git",
+ /// "**/.svn",
+ /// "**/.hg",
+ /// "**/.jj",
+ /// "**/CVS",
+ /// "**/.DS_Store",
+ /// "**/Thumbs.db",
+ /// "**/.classpath",
+ /// "**/.settings"
+ /// ]
+ pub file_scan_exclusions: Option<Vec<String>>,
+
+ /// Always include files that match these globs when scanning for files, even if they're
+ /// ignored by git. This setting is overridden by `file_scan_exclusions`.
+ /// Default: [
+ /// ".env*",
+ /// "docker-compose.*.yml",
+ /// ]
+ pub file_scan_inclusions: Option<Vec<String>>,
+
+ /// Treat the files matching these globs as `.env` files.
+ /// Default: [ "**/.env*" ]
+ pub private_files: Option<Vec<String>>,
+}
+
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Hash)]
+#[serde(rename_all = "snake_case")]
+pub struct LspSettingsContent {
+ pub binary: Option<BinarySettings>,
+ pub initialization_options: Option<serde_json::Value>,
+ pub settings: Option<serde_json::Value>,
+ /// If the server supports sending tasks over LSP extensions,
+ /// this setting can be used to enable or disable them in Zed.
+ /// Default: true
+ #[serde(default = "default_true")]
+ pub enable_lsp_tasks: bool,
+ pub fetch: Option<FetchSettings>,
+}
+
+impl Default for LspSettingsContent {
+ fn default() -> Self {
+ Self {
+ binary: None,
+ initialization_options: None,
+ settings: None,
+ enable_lsp_tasks: true,
+ fetch: None,
+ }
+ }
+}
+
+#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Hash)]
+pub struct BinarySettings {
+ pub path: Option<String>,
+ pub arguments: Option<Vec<String>>,
+ pub env: Option<BTreeMap<String, String>>,
+ pub ignore_system_version: Option<bool>,
+}
+
+#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Hash)]
+pub struct FetchSettings {
+ // Whether to consider pre-releases for fetching
+ pub pre_release: Option<bool>,
+}
+
+/// Common language server settings.
+#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
+pub struct GlobalLspSettingsContent {
+ /// Whether to show the LSP servers button in the status bar.
+ ///
+ /// Default: `true`
+ pub button: Option<bool>,
+}
+
+// todo! binary is actually just required, shouldn't be an option
+#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub struct DapSettingsContent {
+ pub binary: Option<String>,
+ #[serde(default)]
+ pub args: Vec<String>,
+}
+
+#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
+pub struct SessionSettings {
+ /// Whether or not to restore unsaved buffers on restart.
+ ///
+ /// If this is true, user won't be prompted whether to save/discard
+ /// dirty files when closing the application.
+ ///
+ /// Default: true
+ pub restore_unsaved_buffers: bool,
+}
+
+impl Default for SessionSettings {
+ fn default() -> Self {
+ Self {
+ restore_unsaved_buffers: true,
+ }
+ }
+}
+
+#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
+#[serde(tag = "source", rename_all = "snake_case")]
+pub enum ContextServerSettingsContent {
+ Custom {
+ /// Whether the context server is enabled.
+ #[serde(default = "default_true")]
+ enabled: bool,
+
+ #[serde(flatten)]
+ command: ContextServerCommand,
+ },
+ Extension {
+ /// Whether the context server is enabled.
+ #[serde(default = "default_true")]
+ enabled: bool,
+ /// The settings for this context server specified by the extension.
+ ///
+ /// Consult the documentation for the context server to see what settings
+ /// are supported.
+ settings: serde_json::Value,
+ },
+}
+
+#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema)]
+pub struct ContextServerCommand {
+ #[serde(rename = "command")]
+ pub path: PathBuf,
+ pub args: Vec<String>,
+ pub env: Option<HashMap<String, String>>,
+ /// Timeout for tool calls in milliseconds. Defaults to 60000 (60 seconds) if not specified.
+ pub timeout: Option<u64>,
+}
+
+impl std::fmt::Debug for ContextServerCommand {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let filtered_env = self.env.as_ref().map(|env| {
+ env.iter()
+ .map(|(k, v)| {
+ (
+ k,
+ if util::redact::should_redact(k) {
+ "[REDACTED]"
+ } else {
+ v
+ },
+ )
+ })
+ .collect::<Vec<_>>()
+ });
+
+ f.debug_struct("ContextServerCommand")
+ .field("path", &self.path)
+ .field("args", &self.args)
+ .field("env", &filtered_env)
+ .finish()
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
+pub struct GitSettings {
+ /// Whether or not to show the git gutter.
+ ///
+ /// Default: tracked_files
+ pub git_gutter: Option<GitGutterSetting>,
+ /// Sets the debounce threshold (in milliseconds) after which changes are reflected in the git gutter.
+ ///
+ /// Default: null
+ pub gutter_debounce: Option<u64>,
+ /// Whether or not to show git blame data inline in
+ /// the currently focused line.
+ ///
+ /// Default: on
+ pub inline_blame: Option<InlineBlameSettings>,
+ /// Which information to show in the branch picker.
+ ///
+ /// Default: on
+ pub branch_picker: Option<BranchPickerSettingsContent>,
+ /// How hunks are displayed visually in the editor.
+ ///
+ /// Default: staged_hollow
+ pub hunk_style: Option<GitHunkStyleSetting>,
+}
+
+#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum GitGutterSetting {
+ /// Show git gutter in tracked files.
+ #[default]
+ TrackedFiles,
+ /// Hide git gutter
+ Hide,
+}
+
+#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub struct InlineBlameSettings {
+ /// Whether or not to show git blame data inline in
+ /// the currently focused line.
+ ///
+ /// Default: true
+ pub enabled: Option<bool>,
+ /// Whether to only show the inline blame information
+ /// after a delay once the cursor stops moving.
+ ///
+ /// Default: 0
+ pub delay_ms: Option<u64>,
+ /// The amount of padding between the end of the source line and the start
+ /// of the inline blame in units of columns.
+ ///
+ /// Default: 7
+ pub padding: Option<u32>,
+ /// The minimum column number to show the inline blame information at
+ ///
+ /// Default: 0
+ pub min_column: Option<u32>,
+ /// Whether to show commit summary as part of the inline blame.
+ ///
+ /// Default: false
+ pub show_commit_summary: Option<bool>,
+}
+
+#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub struct BranchPickerSettingsContent {
+ /// Whether to show author name as part of the commit information.
+ ///
+ /// Default: false
+ pub show_author_name: Option<bool>,
+}
+
+#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum GitHunkStyleSetting {
+ /// Show unstaged hunks with a filled background and staged hunks hollow.
+ #[default]
+ StagedHollow,
+ /// Show unstaged hunks hollow and staged hunks with a filled background.
+ UnstagedHollow,
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
+pub struct DiagnosticsSettingsContent {
+ /// Whether to show the project diagnostics button in the status bar.
+ pub button: Option<bool>,
+
+ /// Whether or not to include warning diagnostics.
+ pub include_warnings: Option<bool>,
+
+ /// Settings for using LSP pull diagnostics mechanism in Zed.
+ pub lsp_pull_diagnostics: Option<LspPullDiagnosticsSettingsContent>,
+
+ /// Settings for showing inline diagnostics.
+ pub inline: Option<InlineDiagnosticsSettingsContent>,
+}
+
+#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
+pub struct LspPullDiagnosticsSettingsContent {
+ /// Whether to pull for diagnostics or not.
+ ///
+ /// Default: true
+ pub enabled: Option<bool>,
+ /// Minimum time to wait before pulling diagnostics from the language server(s).
+ /// 0 turns the debounce off.
+ ///
+ /// Default: 50
+ pub debounce_ms: Option<u64>,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, JsonSchema, Eq)]
+pub struct InlineDiagnosticsSettingsContent {
+ /// Whether or not to show inline diagnostics
+ ///
+ /// Default: false
+ pub enabled: Option<bool>,
+ /// Whether to only show the inline diagnostics after a delay after the
+ /// last editor event.
+ ///
+ /// Default: 150
+ pub update_debounce_ms: Option<u64>,
+ /// The amount of padding between the end of the source line and the start
+ /// of the inline diagnostic in units of columns.
+ ///
+ /// Default: 4
+ pub padding: Option<u32>,
+ /// The minimum column to display inline diagnostics. This setting can be
+ /// used to horizontally align inline diagnostics at some position. Lines
+ /// longer than this value will still push diagnostics further to the right.
+ ///
+ /// Default: 0
+ pub min_column: Option<u32>,
+
+ pub max_severity: Option<DiagnosticSeverityContent>,
+}
+
+#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
+pub struct NodeBinarySettings {
+ /// The path to the Node binary.
+ pub path: Option<String>,
+ /// The path to the npm binary Zed should use (defaults to `.path/../npm`).
+ pub npm_path: Option<String>,
+ /// If enabled, Zed will download its own copy of Node.
+ pub ignore_system_version: Option<bool>,
+}
+
+#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum DirenvSettings {
+ /// Load direnv configuration through a shell hook
+ ShellHook,
+ /// Load direnv configuration directly using `direnv export json`
+ #[default]
+ Direct,
+}
+
+#[derive(
+ Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, JsonSchema,
+)]
+#[serde(rename_all = "snake_case")]
+pub enum DiagnosticSeverityContent {
+ // No diagnostics are shown.
+ Off,
+ Error,
+ Warning,
+ Info,
+ #[serde(alias = "all")]
+ Hint,
+}
@@ -135,4 +135,9 @@ impl VsCodeSettings {
*setting = Some(s)
}
}
+
+ // todo! replace enum_setting
+ pub fn read_enum_setting<T>(&self, key: &str, f: impl FnOnce(&str) -> Option<T>) -> Option<T> {
+ self.content.get(key).and_then(Value::as_str).and_then(f)
+ }
}