use anyhow::Context as _;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, Task};use lsp::LanguageServerName;use paths::{ EDITORCONFIG_NAME, local_debug_file_relative_path, local_settings_file_relative_path, local_tasks_file_relative_path, local_vscode_launch_file_relative_path, local_vscode_tasks_file_relative_path, task_file_name,};use rpc::{ AnyProtoClient, TypedEnvelope, proto::{self, FromProto, ToProto},};use schemars::JsonSchema;use serde::{Deserialize, Serialize};use settings::{ InvalidSettingsError, LocalSettingsKind, Settings, SettingsLocation, SettingsSources, SettingsStore, parse_json_with_comments, watch_config_file,};use std::{ path::{Path, PathBuf}, sync::Arc, time::Duration,};use task::{DebugTaskFile, TaskTemplates, VsCodeDebugTaskFile, VsCodeTaskFile};use util::{ResultExt, serde::default_true};use worktree::{PathChange, UpdatedEntriesSet, Worktree, WorktreeId}; use crate::{ task_store::{TaskSettingsLocation, TaskStore}, worktree_store::{WorktreeStore, WorktreeStoreEvent},}; #[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]#[schemars(deny_unknown_fields)]pub struct ProjectSettings { /// 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<LanguageServerName, LspSettings>, /// 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>, ContextServerConfiguration>, /// 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")]pub struct DapSettings { pub binary: Option<String>,} #[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, Debug, Default)]pub struct ContextServerConfiguration { /// The command to run this context server. /// /// This will override the command set by an extension. pub command: Option<ContextServerCommand>, /// The settings for this context server. /// /// Consult the documentation for the context server to see what settings /// are supported. pub settings: Option<serde_json::Value>,} #[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 showing inline diagnostics. pub inline: InlineDiagnosticsSettings, /// Configuration, related to Rust language diagnostics. pub cargo: Option<CargoDiagnosticsSettings>,} impl DiagnosticsSettings { pub fn fetch_cargo_diagnostics(&self) -> bool { self.cargo.as_ref().map_or(false, |cargo_diagnostics| { cargo_diagnostics.fetch_cargo_diagnostics }) }} #[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 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: Option<DiagnosticSeverity>,} #[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]pub struct CargoDiagnosticsSettings { /// When enabled, Zed disables rust-analyzer's check on save and starts to query /// Cargo diagnostics separately. /// /// Default: false #[serde(default)] pub fetch_cargo_diagnostics: bool,} #[derive( Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, JsonSchema,)]#[serde(rename_all = "snake_case")]pub enum DiagnosticSeverity { // No diagnostics are shown. Off, Error, Warning, Info, Hint,} impl DiagnosticSeverity { pub fn into_lsp(self) -> Option<lsp::DiagnosticSeverity> { match self { DiagnosticSeverity::Off => None, DiagnosticSeverity::Error => Some(lsp::DiagnosticSeverity::ERROR), DiagnosticSeverity::Warning => Some(lsp::DiagnosticSeverity::WARNING), DiagnosticSeverity::Info => Some(lsp::DiagnosticSeverity::INFORMATION), DiagnosticSeverity::Hint => Some(lsp::DiagnosticSeverity::HINT), } }} impl Default for DiagnosticsSettings { fn default() -> Self { Self { button: true, include_warnings: true, inline: Default::default(), cargo: Default::default(), } }} impl Default for InlineDiagnosticsSettings { fn default() -> Self { Self { enabled: false, update_debounce_ms: 150, padding: 4, min_column: 0, max_severity: None, } }} #[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>, /// 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: Some(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,} #[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 #[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 pub delay_ms: Option<u64>, /// 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 #[serde(default)] pub show_commit_summary: bool,} #[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]pub struct BinarySettings { pub path: Option<String>, pub arguments: Option<Vec<String>>, // this can't be an FxHashMap because the extension APIs require the default SipHash pub env: Option<std::collections::HashMap<String, String>>, pub ignore_system_version: Option<bool>,} #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]#[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,} impl Default for LspSettings { fn default() -> Self { Self { binary: None, initialization_options: None, settings: None, enable_lsp_tasks: true, } }} #[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, } }} impl Settings for ProjectSettings { const KEY: Option<&'static str> = None; type FileContent = Self; fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> anyhow::Result<Self> { sources.json_merge() } fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) { // 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, }, ); 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() }) } } #[derive(Deserialize)] struct VsCodeContextServerCommand { command: String, args: Option<Vec<String>>, 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, } } } if let Some(mcp) = vscode.read_value("mcp").and_then(|v| v.as_object()) { current .context_servers .extend(mcp.iter().filter_map(|(k, v)| { Some(( k.clone().into(), ContextServerConfiguration { command: Some( serde_json::from_value::<VsCodeContextServerCommand>(v.clone()) .ok()? .into(), ), settings: None, }, )) })); } // TODO: translate lsp settings for rust-analyzer and other popular ones to old.lsp }} pub enum SettingsObserverMode { Local(Arc<dyn Fs>), Remote,} #[derive(Clone, Debug, PartialEq)]pub enum SettingsObserverEvent { LocalSettingsUpdated(Result<PathBuf, InvalidSettingsError>), LocalTasksUpdated(Result<PathBuf, InvalidSettingsError>),} impl EventEmitter<SettingsObserverEvent> for SettingsObserver {} pub struct SettingsObserver { mode: SettingsObserverMode, downstream_client: Option<AnyProtoClient>, worktree_store: Entity<WorktreeStore>, project_id: u64, task_store: Entity<TaskStore>, _global_task_config_watcher: Task<()>,} /// SettingsObserver observers changes to .zed/{settings, task}.json files in local worktrees/// (or the equivalent protobuf messages from upstream) and updates local settings/// and sends notifications downstream./// In ssh mode it also monitors ~/.config/zed/{settings, task}.json and sends the content/// upstream.impl SettingsObserver { pub fn init(client: &AnyProtoClient) { client.add_entity_message_handler(Self::handle_update_worktree_settings); } pub fn new_local( fs: Arc<dyn Fs>, worktree_store: Entity<WorktreeStore>, task_store: Entity<TaskStore>, cx: &mut Context<Self>, ) -> Self { cx.subscribe(&worktree_store, Self::on_worktree_store_event) .detach(); Self { worktree_store, task_store, mode: SettingsObserverMode::Local(fs.clone()), downstream_client: None, project_id: 0, _global_task_config_watcher: Self::subscribe_to_global_task_file_changes( fs.clone(), paths::tasks_file().clone(), cx, ), }Lines 1–500 of 968. Load more
use anyhow::Context as _; 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, Task}; use lsp::LanguageServerName; use paths::{ EDITORCONFIG_NAME, local_debug_file_relative_path, local_settings_file_relative_path, local_tasks_file_relative_path, local_vscode_launch_file_relative_path, local_vscode_tasks_file_relative_path, task_file_name, }; use rpc::{ AnyProtoClient, TypedEnvelope, proto::{self, FromProto, ToProto}, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use settings::{ InvalidSettingsError, LocalSettingsKind, Settings, SettingsLocation, SettingsSources, SettingsStore, parse_json_with_comments, watch_config_file, }; use std::{ path::{Path, PathBuf}, sync::Arc, time::Duration, }; use task::{DebugTaskFile, TaskTemplates, VsCodeDebugTaskFile, VsCodeTaskFile}; use util::{ResultExt, serde::default_true}; use worktree::{PathChange, UpdatedEntriesSet, Worktree, WorktreeId}; use crate::{ task_store::{TaskSettingsLocation, TaskStore}, worktree_store::{WorktreeStore, WorktreeStoreEvent}, }; #[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)] #[schemars(deny_unknown_fields)] pub struct ProjectSettings { /// 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<LanguageServerName, LspSettings>, /// 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>, ContextServerConfiguration>, /// 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")] pub struct DapSettings { pub binary: Option<String>, } #[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema, Debug, Default)] pub struct ContextServerConfiguration { /// The command to run this context server. /// /// This will override the command set by an extension. pub command: Option<ContextServerCommand>, /// The settings for this context server. /// /// Consult the documentation for the context server to see what settings /// are supported. pub settings: Option<serde_json::Value>, } #[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 showing inline diagnostics. pub inline: InlineDiagnosticsSettings, /// Configuration, related to Rust language diagnostics. pub cargo: Option<CargoDiagnosticsSettings>, } impl DiagnosticsSettings { pub fn fetch_cargo_diagnostics(&self) -> bool { self.cargo.as_ref().map_or(false, |cargo_diagnostics| { cargo_diagnostics.fetch_cargo_diagnostics }) } } #[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 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: Option<DiagnosticSeverity>, } #[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] pub struct CargoDiagnosticsSettings { /// When enabled, Zed disables rust-analyzer's check on save and starts to query /// Cargo diagnostics separately. /// /// Default: false #[serde(default)] pub fetch_cargo_diagnostics: bool, } #[derive( Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, JsonSchema, )] #[serde(rename_all = "snake_case")] pub enum DiagnosticSeverity { // No diagnostics are shown. Off, Error, Warning, Info, Hint, } impl DiagnosticSeverity { pub fn into_lsp(self) -> Option<lsp::DiagnosticSeverity> { match self { DiagnosticSeverity::Off => None, DiagnosticSeverity::Error => Some(lsp::DiagnosticSeverity::ERROR), DiagnosticSeverity::Warning => Some(lsp::DiagnosticSeverity::WARNING), DiagnosticSeverity::Info => Some(lsp::DiagnosticSeverity::INFORMATION), DiagnosticSeverity::Hint => Some(lsp::DiagnosticSeverity::HINT), } } } impl Default for DiagnosticsSettings { fn default() -> Self { Self { button: true, include_warnings: true, inline: Default::default(), cargo: Default::default(), } } } impl Default for InlineDiagnosticsSettings { fn default() -> Self { Self { enabled: false, update_debounce_ms: 150, padding: 4, min_column: 0, max_severity: None, } } } #[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>, /// 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: Some(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, } #[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 #[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 pub delay_ms: Option<u64>, /// 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 #[serde(default)] pub show_commit_summary: bool, } #[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] pub struct BinarySettings { pub path: Option<String>, pub arguments: Option<Vec<String>>, // this can't be an FxHashMap because the extension APIs require the default SipHash pub env: Option<std::collections::HashMap<String, String>>, pub ignore_system_version: Option<bool>, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] #[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, } impl Default for LspSettings { fn default() -> Self { Self { binary: None, initialization_options: None, settings: None, enable_lsp_tasks: true, } } } #[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, } } } impl Settings for ProjectSettings { const KEY: Option<&'static str> = None; type FileContent = Self; fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> anyhow::Result<Self> { sources.json_merge() } fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) { // 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, }, ); 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() }) } } #[derive(Deserialize)] struct VsCodeContextServerCommand { command: String, args: Option<Vec<String>>, 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, } } } if let Some(mcp) = vscode.read_value("mcp").and_then(|v| v.as_object()) { current .context_servers .extend(mcp.iter().filter_map(|(k, v)| { Some(( k.clone().into(), ContextServerConfiguration { command: Some( serde_json::from_value::<VsCodeContextServerCommand>(v.clone()) .ok()? .into(), ), settings: None, }, )) })); } // TODO: translate lsp settings for rust-analyzer and other popular ones to old.lsp } } pub enum SettingsObserverMode { Local(Arc<dyn Fs>), Remote, } #[derive(Clone, Debug, PartialEq)] pub enum SettingsObserverEvent { LocalSettingsUpdated(Result<PathBuf, InvalidSettingsError>), LocalTasksUpdated(Result<PathBuf, InvalidSettingsError>), } impl EventEmitter<SettingsObserverEvent> for SettingsObserver {} pub struct SettingsObserver { mode: SettingsObserverMode, downstream_client: Option<AnyProtoClient>, worktree_store: Entity<WorktreeStore>, project_id: u64, task_store: Entity<TaskStore>, _global_task_config_watcher: Task<()>, } /// SettingsObserver observers changes to .zed/{settings, task}.json files in local worktrees /// (or the equivalent protobuf messages from upstream) and updates local settings /// and sends notifications downstream. /// In ssh mode it also monitors ~/.config/zed/{settings, task}.json and sends the content /// upstream. impl SettingsObserver { pub fn init(client: &AnyProtoClient) { client.add_entity_message_handler(Self::handle_update_worktree_settings); } pub fn new_local( fs: Arc<dyn Fs>, worktree_store: Entity<WorktreeStore>, task_store: Entity<TaskStore>, cx: &mut Context<Self>, ) -> Self { cx.subscribe(&worktree_store, Self::on_worktree_store_event) .detach(); Self { worktree_store, task_store, mode: SettingsObserverMode::Local(fs.clone()), downstream_client: None, project_id: 0, _global_task_config_watcher: Self::subscribe_to_global_task_file_changes( fs.clone(), paths::tasks_file().clone(), cx, ), }