settings_store.rs

   1use anyhow::{Context as _, Result};
   2use collections::{BTreeMap, HashMap, btree_map, hash_map};
   3use ec4rs::{ConfigParser, PropertiesSource, Section};
   4use fs::Fs;
   5use futures::{
   6    FutureExt, StreamExt,
   7    channel::{mpsc, oneshot},
   8    future::LocalBoxFuture,
   9};
  10use gpui::{App, AsyncApp, BorrowAppContext, Global, SharedString, Task, UpdateGlobal};
  11
  12use paths::{EDITORCONFIG_NAME, local_settings_file_relative_path, task_file_name};
  13use schemars::{JsonSchema, json_schema};
  14use serde_json::Value;
  15use smallvec::SmallVec;
  16use std::{
  17    any::{Any, TypeId, type_name},
  18    fmt::Debug,
  19    ops::Range,
  20    path::PathBuf,
  21    rc::Rc,
  22    str::{self, FromStr},
  23    sync::Arc,
  24};
  25use util::{
  26    ResultExt as _,
  27    rel_path::RelPath,
  28    schemars::{AllowTrailingCommas, DefaultDenyUnknownFields, replace_subschema},
  29};
  30
  31pub type EditorconfigProperties = ec4rs::Properties;
  32
  33use crate::settings_content::{
  34    ExtensionsSettingsContent, FontFamilyName, IconThemeName, LanguageSettingsContent,
  35    LanguageToSettingsMap, LspSettings, LspSettingsMap, ProjectSettingsContent, SettingsContent,
  36    ThemeName, UserSettingsContent,
  37};
  38use crate::{
  39    ActiveSettingsProfileName, ParseStatus, UserSettingsContentExt, VsCodeSettings, WorktreeId,
  40};
  41use settings_content::{RootUserSettings, merge_from::MergeFrom};
  42
  43use settings_json::{infer_json_indent_size, update_value_in_json_text};
  44
  45pub const LSP_SETTINGS_SCHEMA_URL_PREFIX: &str = "zed://schemas/settings/lsp/";
  46
  47pub trait SettingsKey: 'static + Send + Sync {
  48    /// The name of a key within the JSON file from which this setting should
  49    /// be deserialized. If this is `None`, then the setting will be deserialized
  50    /// from the root object.
  51    const KEY: Option<&'static str>;
  52
  53    const FALLBACK_KEY: Option<&'static str> = None;
  54}
  55
  56/// A value that can be defined as a user setting.
  57///
  58/// Settings can be loaded from a combination of multiple JSON files.
  59pub trait Settings: 'static + Send + Sync + Sized {
  60    /// The name of the keys in the [`FileContent`](Self::FileContent) that should
  61    /// always be written to a settings file, even if their value matches the default
  62    /// value.
  63    ///
  64    /// This is useful for tagged [`FileContent`](Self::FileContent)s where the tag
  65    /// is a "version" field that should always be persisted, even if the current
  66    /// user settings match the current version of the settings.
  67    const PRESERVED_KEYS: Option<&'static [&'static str]> = None;
  68
  69    /// Read the value from default.json.
  70    ///
  71    /// This function *should* panic if default values are missing,
  72    /// and you should add a default to default.json for documentation.
  73    fn from_settings(content: &SettingsContent) -> Self;
  74
  75    #[track_caller]
  76    fn register(cx: &mut App)
  77    where
  78        Self: Sized,
  79    {
  80        SettingsStore::update_global(cx, |store, _| {
  81            store.register_setting::<Self>();
  82        });
  83    }
  84
  85    #[track_caller]
  86    fn get<'a>(path: Option<SettingsLocation>, cx: &'a App) -> &'a Self
  87    where
  88        Self: Sized,
  89    {
  90        cx.global::<SettingsStore>().get(path)
  91    }
  92
  93    #[track_caller]
  94    fn get_global(cx: &App) -> &Self
  95    where
  96        Self: Sized,
  97    {
  98        cx.global::<SettingsStore>().get(None)
  99    }
 100
 101    #[track_caller]
 102    fn try_get(cx: &App) -> Option<&Self>
 103    where
 104        Self: Sized,
 105    {
 106        if cx.has_global::<SettingsStore>() {
 107            cx.global::<SettingsStore>().try_get(None)
 108        } else {
 109            None
 110        }
 111    }
 112
 113    #[track_caller]
 114    fn try_read_global<R>(cx: &AsyncApp, f: impl FnOnce(&Self) -> R) -> Option<R>
 115    where
 116        Self: Sized,
 117    {
 118        cx.try_read_global(|s: &SettingsStore, _| f(s.get(None)))
 119    }
 120
 121    #[track_caller]
 122    fn override_global(settings: Self, cx: &mut App)
 123    where
 124        Self: Sized,
 125    {
 126        cx.global_mut::<SettingsStore>().override_global(settings)
 127    }
 128}
 129
 130pub struct RegisteredSetting {
 131    pub settings_value: fn() -> Box<dyn AnySettingValue>,
 132    pub from_settings: fn(&SettingsContent) -> Box<dyn Any>,
 133    pub id: fn() -> TypeId,
 134}
 135
 136inventory::collect!(RegisteredSetting);
 137
 138#[derive(Clone, Copy, Debug)]
 139pub struct SettingsLocation<'a> {
 140    pub worktree_id: WorktreeId,
 141    pub path: &'a RelPath,
 142}
 143
 144pub struct SettingsStore {
 145    setting_values: HashMap<TypeId, Box<dyn AnySettingValue>>,
 146    default_settings: Rc<SettingsContent>,
 147    user_settings: Option<UserSettingsContent>,
 148    global_settings: Option<Box<SettingsContent>>,
 149
 150    extension_settings: Option<Box<SettingsContent>>,
 151    server_settings: Option<Box<SettingsContent>>,
 152
 153    merged_settings: Rc<SettingsContent>,
 154
 155    local_settings: BTreeMap<(WorktreeId, Arc<RelPath>), SettingsContent>,
 156    raw_editorconfig_settings: BTreeMap<(WorktreeId, Arc<RelPath>), (String, Option<Editorconfig>)>,
 157
 158    _setting_file_updates: Task<()>,
 159    setting_file_updates_tx:
 160        mpsc::UnboundedSender<Box<dyn FnOnce(AsyncApp) -> LocalBoxFuture<'static, Result<()>>>>,
 161    file_errors: BTreeMap<SettingsFile, SettingsParseResult>,
 162}
 163
 164#[derive(Clone, PartialEq, Eq, Debug)]
 165pub enum SettingsFile {
 166    Default,
 167    Global,
 168    User,
 169    Server,
 170    /// Represents project settings in ssh projects as well as local projects
 171    Project((WorktreeId, Arc<RelPath>)),
 172}
 173
 174impl PartialOrd for SettingsFile {
 175    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
 176        Some(self.cmp(other))
 177    }
 178}
 179
 180/// Sorted in order of precedence
 181impl Ord for SettingsFile {
 182    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
 183        use SettingsFile::*;
 184        use std::cmp::Ordering;
 185        match (self, other) {
 186            (User, User) => Ordering::Equal,
 187            (Server, Server) => Ordering::Equal,
 188            (Default, Default) => Ordering::Equal,
 189            (Project((id1, rel_path1)), Project((id2, rel_path2))) => id1
 190                .cmp(id2)
 191                .then_with(|| rel_path1.cmp(rel_path2).reverse()),
 192            (Project(_), _) => Ordering::Less,
 193            (_, Project(_)) => Ordering::Greater,
 194            (Server, _) => Ordering::Less,
 195            (_, Server) => Ordering::Greater,
 196            (User, _) => Ordering::Less,
 197            (_, User) => Ordering::Greater,
 198            (Global, _) => Ordering::Less,
 199            (_, Global) => Ordering::Greater,
 200        }
 201    }
 202}
 203
 204#[derive(Clone)]
 205pub struct Editorconfig {
 206    pub is_root: bool,
 207    pub sections: SmallVec<[Section; 5]>,
 208}
 209
 210impl FromStr for Editorconfig {
 211    type Err = anyhow::Error;
 212
 213    fn from_str(contents: &str) -> Result<Self, Self::Err> {
 214        let parser = ConfigParser::new_buffered(contents.as_bytes())
 215            .context("creating editorconfig parser")?;
 216        let is_root = parser.is_root;
 217        let sections = parser
 218            .collect::<Result<SmallVec<_>, _>>()
 219            .context("parsing editorconfig sections")?;
 220        Ok(Self { is_root, sections })
 221    }
 222}
 223
 224#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 225pub enum LocalSettingsKind {
 226    Settings,
 227    Tasks,
 228    Editorconfig,
 229    Debug,
 230}
 231
 232impl Global for SettingsStore {}
 233
 234#[doc(hidden)]
 235#[derive(Debug)]
 236pub struct SettingValue<T> {
 237    #[doc(hidden)]
 238    pub global_value: Option<T>,
 239    #[doc(hidden)]
 240    pub local_values: Vec<(WorktreeId, Arc<RelPath>, T)>,
 241}
 242
 243#[doc(hidden)]
 244pub trait AnySettingValue: 'static + Send + Sync {
 245    fn setting_type_name(&self) -> &'static str;
 246
 247    fn from_settings(&self, s: &SettingsContent) -> Box<dyn Any>;
 248
 249    fn value_for_path(&self, path: Option<SettingsLocation>) -> &dyn Any;
 250    fn all_local_values(&self) -> Vec<(WorktreeId, Arc<RelPath>, &dyn Any)>;
 251    fn set_global_value(&mut self, value: Box<dyn Any>);
 252    fn set_local_value(&mut self, root_id: WorktreeId, path: Arc<RelPath>, value: Box<dyn Any>);
 253    fn clear_local_values(&mut self, root_id: WorktreeId);
 254}
 255
 256/// Parameters that are used when generating some JSON schemas at runtime.
 257pub struct SettingsJsonSchemaParams<'a> {
 258    pub language_names: &'a [String],
 259    pub font_names: &'a [String],
 260    pub theme_names: &'a [SharedString],
 261    pub icon_theme_names: &'a [SharedString],
 262    pub lsp_adapter_names: &'a [String],
 263}
 264
 265impl SettingsStore {
 266    pub fn new(cx: &App, default_settings: &str) -> Self {
 267        let (setting_file_updates_tx, mut setting_file_updates_rx) = mpsc::unbounded();
 268        let default_settings: Rc<SettingsContent> =
 269            SettingsContent::parse_json_with_comments(default_settings)
 270                .unwrap()
 271                .into();
 272        let mut this = Self {
 273            setting_values: Default::default(),
 274            default_settings: default_settings.clone(),
 275            global_settings: None,
 276            server_settings: None,
 277            user_settings: None,
 278            extension_settings: None,
 279
 280            merged_settings: default_settings,
 281            local_settings: BTreeMap::default(),
 282            raw_editorconfig_settings: BTreeMap::default(),
 283            setting_file_updates_tx,
 284            _setting_file_updates: cx.spawn(async move |cx| {
 285                while let Some(setting_file_update) = setting_file_updates_rx.next().await {
 286                    (setting_file_update)(cx.clone()).await.log_err();
 287                }
 288            }),
 289            file_errors: BTreeMap::default(),
 290        };
 291
 292        this.load_settings_types();
 293
 294        this
 295    }
 296
 297    pub fn observe_active_settings_profile_name(cx: &mut App) -> gpui::Subscription {
 298        cx.observe_global::<ActiveSettingsProfileName>(|cx| {
 299            Self::update_global(cx, |store, cx| {
 300                store.recompute_values(None, cx);
 301            });
 302        })
 303    }
 304
 305    pub fn update<C, R>(cx: &mut C, f: impl FnOnce(&mut Self, &mut C) -> R) -> R
 306    where
 307        C: BorrowAppContext,
 308    {
 309        cx.update_global(f)
 310    }
 311
 312    /// Add a new type of setting to the store.
 313    pub fn register_setting<T: Settings>(&mut self) {
 314        self.register_setting_internal(&RegisteredSetting {
 315            settings_value: || {
 316                Box::new(SettingValue::<T> {
 317                    global_value: None,
 318                    local_values: Vec::new(),
 319                })
 320            },
 321            from_settings: |content| Box::new(T::from_settings(content)),
 322            id: || TypeId::of::<T>(),
 323        });
 324    }
 325
 326    fn load_settings_types(&mut self) {
 327        for registered_setting in inventory::iter::<RegisteredSetting>() {
 328            self.register_setting_internal(registered_setting);
 329        }
 330    }
 331
 332    fn register_setting_internal(&mut self, registered_setting: &RegisteredSetting) {
 333        let entry = self.setting_values.entry((registered_setting.id)());
 334
 335        if matches!(entry, hash_map::Entry::Occupied(_)) {
 336            return;
 337        }
 338
 339        let setting_value = entry.or_insert((registered_setting.settings_value)());
 340        let value = (registered_setting.from_settings)(&self.merged_settings);
 341        setting_value.set_global_value(value);
 342    }
 343
 344    /// Get the value of a setting.
 345    ///
 346    /// Panics if the given setting type has not been registered, or if there is no
 347    /// value for this setting.
 348    pub fn get<T: Settings>(&self, path: Option<SettingsLocation>) -> &T {
 349        self.setting_values
 350            .get(&TypeId::of::<T>())
 351            .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>()))
 352            .value_for_path(path)
 353            .downcast_ref::<T>()
 354            .expect("no default value for setting type")
 355    }
 356
 357    /// Get the value of a setting.
 358    ///
 359    /// Does not panic
 360    pub fn try_get<T: Settings>(&self, path: Option<SettingsLocation>) -> Option<&T> {
 361        self.setting_values
 362            .get(&TypeId::of::<T>())
 363            .map(|value| value.value_for_path(path))
 364            .and_then(|value| value.downcast_ref::<T>())
 365    }
 366
 367    /// Get all values from project specific settings
 368    pub fn get_all_locals<T: Settings>(&self) -> Vec<(WorktreeId, Arc<RelPath>, &T)> {
 369        self.setting_values
 370            .get(&TypeId::of::<T>())
 371            .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>()))
 372            .all_local_values()
 373            .into_iter()
 374            .map(|(id, path, any)| {
 375                (
 376                    id,
 377                    path,
 378                    any.downcast_ref::<T>()
 379                        .expect("wrong value type for setting"),
 380                )
 381            })
 382            .collect()
 383    }
 384
 385    /// Override the global value for a setting.
 386    ///
 387    /// The given value will be overwritten if the user settings file changes.
 388    pub fn override_global<T: Settings>(&mut self, value: T) {
 389        self.setting_values
 390            .get_mut(&TypeId::of::<T>())
 391            .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>()))
 392            .set_global_value(Box::new(value))
 393    }
 394
 395    /// Get the user's settings content.
 396    ///
 397    /// For user-facing functionality use the typed setting interface.
 398    /// (e.g. ProjectSettings::get_global(cx))
 399    pub fn raw_user_settings(&self) -> Option<&UserSettingsContent> {
 400        self.user_settings.as_ref()
 401    }
 402
 403    /// Get the default settings content as a raw JSON value.
 404    pub fn raw_default_settings(&self) -> &SettingsContent {
 405        &self.default_settings
 406    }
 407
 408    /// Get the configured settings profile names.
 409    pub fn configured_settings_profiles(&self) -> impl Iterator<Item = &str> {
 410        self.user_settings
 411            .iter()
 412            .flat_map(|settings| settings.profiles.keys().map(|k| k.as_str()))
 413    }
 414
 415    #[cfg(any(test, feature = "test-support"))]
 416    pub fn test(cx: &mut App) -> Self {
 417        Self::new(cx, &crate::test_settings())
 418    }
 419
 420    /// Updates the value of a setting in the user's global configuration.
 421    ///
 422    /// This is only for tests. Normally, settings are only loaded from
 423    /// JSON files.
 424    #[cfg(any(test, feature = "test-support"))]
 425    pub fn update_user_settings(
 426        &mut self,
 427        cx: &mut App,
 428        update: impl FnOnce(&mut SettingsContent),
 429    ) {
 430        let mut content = self.user_settings.clone().unwrap_or_default().content;
 431        update(&mut content);
 432        let new_text = serde_json::to_string(&UserSettingsContent {
 433            content,
 434            ..Default::default()
 435        })
 436        .unwrap();
 437        _ = self.set_user_settings(&new_text, cx);
 438    }
 439
 440    pub async fn load_settings(fs: &Arc<dyn Fs>) -> Result<String> {
 441        match fs.load(paths::settings_file()).await {
 442            result @ Ok(_) => result,
 443            Err(err) => {
 444                if let Some(e) = err.downcast_ref::<std::io::Error>()
 445                    && e.kind() == std::io::ErrorKind::NotFound
 446                {
 447                    return Ok(crate::initial_user_settings_content().to_string());
 448                }
 449                Err(err)
 450            }
 451        }
 452    }
 453
 454    fn update_settings_file_inner(
 455        &self,
 456        fs: Arc<dyn Fs>,
 457        update: impl 'static + Send + FnOnce(String, AsyncApp) -> Result<String>,
 458    ) -> oneshot::Receiver<Result<()>> {
 459        let (tx, rx) = oneshot::channel::<Result<()>>();
 460        self.setting_file_updates_tx
 461            .unbounded_send(Box::new(move |cx: AsyncApp| {
 462                async move {
 463                    let res = async move {
 464                        let old_text = Self::load_settings(&fs).await?;
 465                        let new_text = update(old_text, cx)?;
 466                        let settings_path = paths::settings_file().as_path();
 467                        if fs.is_file(settings_path).await {
 468                            let resolved_path =
 469                                fs.canonicalize(settings_path).await.with_context(|| {
 470                                    format!(
 471                                        "Failed to canonicalize settings path {:?}",
 472                                        settings_path
 473                                    )
 474                                })?;
 475
 476                            fs.atomic_write(resolved_path.clone(), new_text)
 477                                .await
 478                                .with_context(|| {
 479                                    format!("Failed to write settings to file {:?}", resolved_path)
 480                                })?;
 481                        } else {
 482                            fs.atomic_write(settings_path.to_path_buf(), new_text)
 483                                .await
 484                                .with_context(|| {
 485                                    format!("Failed to write settings to file {:?}", settings_path)
 486                                })?;
 487                        }
 488                        anyhow::Ok(())
 489                    }
 490                    .await;
 491
 492                    let new_res = match &res {
 493                        Ok(_) => anyhow::Ok(()),
 494                        Err(e) => Err(anyhow::anyhow!("Failed to write settings to file {:?}", e)),
 495                    };
 496
 497                    _ = tx.send(new_res);
 498                    res
 499                }
 500                .boxed_local()
 501            }))
 502            .map_err(|err| anyhow::format_err!("Failed to update settings file: {}", err))
 503            .log_with_level(log::Level::Warn);
 504        return rx;
 505    }
 506
 507    pub fn update_settings_file(
 508        &self,
 509        fs: Arc<dyn Fs>,
 510        update: impl 'static + Send + FnOnce(&mut SettingsContent, &App),
 511    ) {
 512        _ = self.update_settings_file_inner(fs, move |old_text: String, cx: AsyncApp| {
 513            Ok(cx.read_global(|store: &SettingsStore, cx| {
 514                store.new_text_for_update(old_text, |content| update(content, cx))
 515            }))
 516        });
 517    }
 518
 519    pub fn import_vscode_settings(
 520        &self,
 521        fs: Arc<dyn Fs>,
 522        vscode_settings: VsCodeSettings,
 523    ) -> oneshot::Receiver<Result<()>> {
 524        self.update_settings_file_inner(fs, move |old_text: String, cx: AsyncApp| {
 525            Ok(cx.read_global(|store: &SettingsStore, _cx| {
 526                store.get_vscode_edits(old_text, &vscode_settings)
 527            }))
 528        })
 529    }
 530
 531    pub fn get_all_files(&self) -> Vec<SettingsFile> {
 532        let mut files = Vec::from_iter(
 533            self.local_settings
 534                .keys()
 535                // rev because these are sorted by path, so highest precedence is last
 536                .rev()
 537                .cloned()
 538                .map(SettingsFile::Project),
 539        );
 540
 541        if self.server_settings.is_some() {
 542            files.push(SettingsFile::Server);
 543        }
 544        // ignoring profiles
 545        // ignoring os profiles
 546        // ignoring release channel profiles
 547        // ignoring global
 548        // ignoring extension
 549
 550        if self.user_settings.is_some() {
 551            files.push(SettingsFile::User);
 552        }
 553        files.push(SettingsFile::Default);
 554        files
 555    }
 556
 557    pub fn get_content_for_file(&self, file: SettingsFile) -> Option<&SettingsContent> {
 558        match file {
 559            SettingsFile::User => self
 560                .user_settings
 561                .as_ref()
 562                .map(|settings| settings.content.as_ref()),
 563            SettingsFile::Default => Some(self.default_settings.as_ref()),
 564            SettingsFile::Server => self.server_settings.as_deref(),
 565            SettingsFile::Project(ref key) => self.local_settings.get(key),
 566            SettingsFile::Global => self.global_settings.as_deref(),
 567        }
 568    }
 569
 570    pub fn get_overrides_for_field<T>(
 571        &self,
 572        target_file: SettingsFile,
 573        get: fn(&SettingsContent) -> &Option<T>,
 574    ) -> Vec<SettingsFile> {
 575        let all_files = self.get_all_files();
 576        let mut found_file = false;
 577        let mut overrides = Vec::new();
 578
 579        for file in all_files.into_iter().rev() {
 580            if !found_file {
 581                found_file = file == target_file;
 582                continue;
 583            }
 584
 585            if let SettingsFile::Project((wt_id, ref path)) = file
 586                && let SettingsFile::Project((target_wt_id, ref target_path)) = target_file
 587                && (wt_id != target_wt_id || !target_path.starts_with(path))
 588            {
 589                // if requesting value from a local file, don't return values from local files in different worktrees
 590                continue;
 591            }
 592
 593            let Some(content) = self.get_content_for_file(file.clone()) else {
 594                continue;
 595            };
 596            if get(content).is_some() {
 597                overrides.push(file);
 598            }
 599        }
 600
 601        overrides
 602    }
 603
 604    /// Checks the given file, and files that the passed file overrides for the given field.
 605    /// Returns the first file found that contains the value.
 606    /// The value will only be None if no file contains the value.
 607    /// I.e. if no file contains the value, returns `(File::Default, None)`
 608    pub fn get_value_from_file<'a, T: 'a>(
 609        &'a self,
 610        target_file: SettingsFile,
 611        pick: fn(&'a SettingsContent) -> Option<T>,
 612    ) -> (SettingsFile, Option<T>) {
 613        self.get_value_from_file_inner(target_file, pick, true)
 614    }
 615
 616    /// Same as `Self::get_value_from_file` except that it does not include the current file.
 617    /// Therefore it returns the value that was potentially overloaded by the target file.
 618    pub fn get_value_up_to_file<'a, T: 'a>(
 619        &'a self,
 620        target_file: SettingsFile,
 621        pick: fn(&'a SettingsContent) -> Option<T>,
 622    ) -> (SettingsFile, Option<T>) {
 623        self.get_value_from_file_inner(target_file, pick, false)
 624    }
 625
 626    fn get_value_from_file_inner<'a, T: 'a>(
 627        &'a self,
 628        target_file: SettingsFile,
 629        pick: fn(&'a SettingsContent) -> Option<T>,
 630        include_target_file: bool,
 631    ) -> (SettingsFile, Option<T>) {
 632        // todo(settings_ui): Add a metadata field for overriding the "overrides" tag, for contextually different settings
 633        //  e.g. disable AI isn't overridden, or a vec that gets extended instead or some such
 634
 635        // todo(settings_ui) cache all files
 636        let all_files = self.get_all_files();
 637        let mut found_file = false;
 638
 639        for file in all_files.into_iter() {
 640            if !found_file && file != SettingsFile::Default {
 641                if file != target_file {
 642                    continue;
 643                }
 644                found_file = true;
 645                if !include_target_file {
 646                    continue;
 647                }
 648            }
 649
 650            if let SettingsFile::Project((worktree_id, ref path)) = file
 651                && let SettingsFile::Project((target_worktree_id, ref target_path)) = target_file
 652                && (worktree_id != target_worktree_id || !target_path.starts_with(&path))
 653            {
 654                // if requesting value from a local file, don't return values from local files in different worktrees
 655                continue;
 656            }
 657
 658            let Some(content) = self.get_content_for_file(file.clone()) else {
 659                continue;
 660            };
 661            if let Some(value) = pick(content) {
 662                return (file, Some(value));
 663            }
 664        }
 665
 666        (SettingsFile::Default, None)
 667    }
 668
 669    #[inline(always)]
 670    fn parse_and_migrate_zed_settings<SettingsContentType: RootUserSettings>(
 671        &mut self,
 672        user_settings_content: &str,
 673        file: SettingsFile,
 674    ) -> (Option<SettingsContentType>, SettingsParseResult) {
 675        let mut migration_status = MigrationStatus::NotNeeded;
 676        let (settings, parse_status) = if user_settings_content.is_empty() {
 677            SettingsContentType::parse_json("{}")
 678        } else {
 679            let migration_res = migrator::migrate_settings(user_settings_content);
 680            migration_status = match &migration_res {
 681                Ok(Some(_)) => MigrationStatus::Succeeded,
 682                Ok(None) => MigrationStatus::NotNeeded,
 683                Err(err) => MigrationStatus::Failed {
 684                    error: err.to_string(),
 685                },
 686            };
 687            let content = match &migration_res {
 688                Ok(Some(content)) => content,
 689                Ok(None) => user_settings_content,
 690                Err(_) => user_settings_content,
 691            };
 692            SettingsContentType::parse_json(content)
 693        };
 694
 695        let result = SettingsParseResult {
 696            parse_status,
 697            migration_status,
 698        };
 699        self.file_errors.insert(file, result.clone());
 700        return (settings, result);
 701    }
 702
 703    pub fn error_for_file(&self, file: SettingsFile) -> Option<SettingsParseResult> {
 704        self.file_errors
 705            .get(&file)
 706            .filter(|parse_result| parse_result.requires_user_action())
 707            .cloned()
 708    }
 709}
 710
 711impl SettingsStore {
 712    /// Updates the value of a setting in a JSON file, returning the new text
 713    /// for that JSON file.
 714    pub fn new_text_for_update(
 715        &self,
 716        old_text: String,
 717        update: impl FnOnce(&mut SettingsContent),
 718    ) -> String {
 719        let edits = self.edits_for_update(&old_text, update);
 720        let mut new_text = old_text;
 721        for (range, replacement) in edits.into_iter() {
 722            new_text.replace_range(range, &replacement);
 723        }
 724        new_text
 725    }
 726
 727    pub fn get_vscode_edits(&self, old_text: String, vscode: &VsCodeSettings) -> String {
 728        self.new_text_for_update(old_text, |content| {
 729            content.merge_from(&vscode.settings_content())
 730        })
 731    }
 732
 733    /// Updates the value of a setting in a JSON file, returning a list
 734    /// of edits to apply to the JSON file.
 735    pub fn edits_for_update(
 736        &self,
 737        text: &str,
 738        update: impl FnOnce(&mut SettingsContent),
 739    ) -> Vec<(Range<usize>, String)> {
 740        let old_content = UserSettingsContent::parse_json_with_comments(text)
 741            .log_err()
 742            .unwrap_or_default();
 743        let mut new_content = old_content.clone();
 744        update(&mut new_content.content);
 745
 746        let old_value = serde_json::to_value(&old_content).unwrap();
 747        let new_value = serde_json::to_value(new_content).unwrap();
 748
 749        let mut key_path = Vec::new();
 750        let mut edits = Vec::new();
 751        let tab_size = infer_json_indent_size(&text);
 752        let mut text = text.to_string();
 753        update_value_in_json_text(
 754            &mut text,
 755            &mut key_path,
 756            tab_size,
 757            &old_value,
 758            &new_value,
 759            &mut edits,
 760        );
 761        edits
 762    }
 763
 764    /// Sets the default settings via a JSON string.
 765    ///
 766    /// The string should contain a JSON object with a default value for every setting.
 767    pub fn set_default_settings(
 768        &mut self,
 769        default_settings_content: &str,
 770        cx: &mut App,
 771    ) -> Result<()> {
 772        self.default_settings =
 773            SettingsContent::parse_json_with_comments(default_settings_content)?.into();
 774        self.recompute_values(None, cx);
 775        Ok(())
 776    }
 777
 778    /// Sets the user settings via a JSON string.
 779    #[must_use]
 780    pub fn set_user_settings(
 781        &mut self,
 782        user_settings_content: &str,
 783        cx: &mut App,
 784    ) -> SettingsParseResult {
 785        let (settings, parse_result) = self.parse_and_migrate_zed_settings::<UserSettingsContent>(
 786            user_settings_content,
 787            SettingsFile::User,
 788        );
 789
 790        if let Some(settings) = settings {
 791            self.user_settings = Some(settings);
 792            self.recompute_values(None, cx);
 793        }
 794        return parse_result;
 795    }
 796
 797    /// Sets the global settings via a JSON string.
 798    #[must_use]
 799    pub fn set_global_settings(
 800        &mut self,
 801        global_settings_content: &str,
 802        cx: &mut App,
 803    ) -> SettingsParseResult {
 804        let (settings, parse_result) = self.parse_and_migrate_zed_settings::<SettingsContent>(
 805            global_settings_content,
 806            SettingsFile::Global,
 807        );
 808
 809        if let Some(settings) = settings {
 810            self.global_settings = Some(Box::new(settings));
 811            self.recompute_values(None, cx);
 812        }
 813        return parse_result;
 814    }
 815
 816    pub fn set_server_settings(
 817        &mut self,
 818        server_settings_content: &str,
 819        cx: &mut App,
 820    ) -> Result<()> {
 821        let settings = if server_settings_content.is_empty() {
 822            None
 823        } else {
 824            Option::<SettingsContent>::parse_json_with_comments(server_settings_content)?
 825        };
 826
 827        // Rewrite the server settings into a content type
 828        self.server_settings = settings.map(|settings| Box::new(settings));
 829
 830        self.recompute_values(None, cx);
 831        Ok(())
 832    }
 833
 834    /// Add or remove a set of local settings via a JSON string.
 835    pub fn set_local_settings(
 836        &mut self,
 837        root_id: WorktreeId,
 838        directory_path: Arc<RelPath>,
 839        kind: LocalSettingsKind,
 840        settings_content: Option<&str>,
 841        cx: &mut App,
 842    ) -> std::result::Result<(), InvalidSettingsError> {
 843        let mut zed_settings_changed = false;
 844        match (
 845            kind,
 846            settings_content
 847                .map(|content| content.trim())
 848                .filter(|content| !content.is_empty()),
 849        ) {
 850            (LocalSettingsKind::Tasks, _) => {
 851                return Err(InvalidSettingsError::Tasks {
 852                    message: "Attempted to submit tasks into the settings store".to_string(),
 853                    path: directory_path
 854                        .join(RelPath::unix(task_file_name()).unwrap())
 855                        .as_std_path()
 856                        .to_path_buf(),
 857                });
 858            }
 859            (LocalSettingsKind::Debug, _) => {
 860                return Err(InvalidSettingsError::Debug {
 861                    message: "Attempted to submit debugger config into the settings store"
 862                        .to_string(),
 863                    path: directory_path
 864                        .join(RelPath::unix(task_file_name()).unwrap())
 865                        .as_std_path()
 866                        .to_path_buf(),
 867                });
 868            }
 869            (LocalSettingsKind::Settings, None) => {
 870                zed_settings_changed = self
 871                    .local_settings
 872                    .remove(&(root_id, directory_path.clone()))
 873                    .is_some();
 874                self.file_errors
 875                    .remove(&SettingsFile::Project((root_id, directory_path.clone())));
 876            }
 877            (LocalSettingsKind::Editorconfig, None) => {
 878                self.raw_editorconfig_settings
 879                    .remove(&(root_id, directory_path.clone()));
 880            }
 881            (LocalSettingsKind::Settings, Some(settings_contents)) => {
 882                let (new_settings, parse_result) = self
 883                    .parse_and_migrate_zed_settings::<ProjectSettingsContent>(
 884                        settings_contents,
 885                        SettingsFile::Project((root_id, directory_path.clone())),
 886                    );
 887                match parse_result.parse_status {
 888                    ParseStatus::Success => Ok(()),
 889                    ParseStatus::Failed { error } => Err(InvalidSettingsError::LocalSettings {
 890                        path: directory_path.join(local_settings_file_relative_path()),
 891                        message: error,
 892                    }),
 893                }?;
 894                if let Some(new_settings) = new_settings {
 895                    match self.local_settings.entry((root_id, directory_path.clone())) {
 896                        btree_map::Entry::Vacant(v) => {
 897                            v.insert(SettingsContent {
 898                                project: new_settings,
 899                                ..Default::default()
 900                            });
 901                            zed_settings_changed = true;
 902                        }
 903                        btree_map::Entry::Occupied(mut o) => {
 904                            if &o.get().project != &new_settings {
 905                                o.insert(SettingsContent {
 906                                    project: new_settings,
 907                                    ..Default::default()
 908                                });
 909                                zed_settings_changed = true;
 910                            }
 911                        }
 912                    }
 913                }
 914            }
 915            (LocalSettingsKind::Editorconfig, Some(editorconfig_contents)) => {
 916                match self
 917                    .raw_editorconfig_settings
 918                    .entry((root_id, directory_path.clone()))
 919                {
 920                    btree_map::Entry::Vacant(v) => match editorconfig_contents.parse() {
 921                        Ok(new_contents) => {
 922                            v.insert((editorconfig_contents.to_owned(), Some(new_contents)));
 923                        }
 924                        Err(e) => {
 925                            v.insert((editorconfig_contents.to_owned(), None));
 926                            return Err(InvalidSettingsError::Editorconfig {
 927                                message: e.to_string(),
 928                                path: directory_path
 929                                    .join(RelPath::unix(EDITORCONFIG_NAME).unwrap()),
 930                            });
 931                        }
 932                    },
 933                    btree_map::Entry::Occupied(mut o) => {
 934                        if o.get().0 != editorconfig_contents {
 935                            match editorconfig_contents.parse() {
 936                                Ok(new_contents) => {
 937                                    o.insert((
 938                                        editorconfig_contents.to_owned(),
 939                                        Some(new_contents),
 940                                    ));
 941                                }
 942                                Err(e) => {
 943                                    o.insert((editorconfig_contents.to_owned(), None));
 944                                    return Err(InvalidSettingsError::Editorconfig {
 945                                        message: e.to_string(),
 946                                        path: directory_path
 947                                            .join(RelPath::unix(EDITORCONFIG_NAME).unwrap()),
 948                                    });
 949                                }
 950                            }
 951                        }
 952                    }
 953                }
 954            }
 955        };
 956
 957        if zed_settings_changed {
 958            self.recompute_values(Some((root_id, &directory_path)), cx);
 959        }
 960        Ok(())
 961    }
 962
 963    pub fn set_extension_settings(
 964        &mut self,
 965        content: ExtensionsSettingsContent,
 966        cx: &mut App,
 967    ) -> Result<()> {
 968        self.extension_settings = Some(Box::new(SettingsContent {
 969            project: ProjectSettingsContent {
 970                all_languages: content.all_languages,
 971                ..Default::default()
 972            },
 973            ..Default::default()
 974        }));
 975        self.recompute_values(None, cx);
 976        Ok(())
 977    }
 978
 979    /// Add or remove a set of local settings via a JSON string.
 980    pub fn clear_local_settings(&mut self, root_id: WorktreeId, cx: &mut App) -> Result<()> {
 981        self.local_settings
 982            .retain(|(worktree_id, _), _| worktree_id != &root_id);
 983        self.raw_editorconfig_settings
 984            .retain(|(worktree_id, _), _| worktree_id != &root_id);
 985        for setting_value in self.setting_values.values_mut() {
 986            setting_value.clear_local_values(root_id);
 987        }
 988        self.recompute_values(Some((root_id, RelPath::empty())), cx);
 989        Ok(())
 990    }
 991
 992    pub fn local_settings(
 993        &self,
 994        root_id: WorktreeId,
 995    ) -> impl '_ + Iterator<Item = (Arc<RelPath>, &ProjectSettingsContent)> {
 996        self.local_settings
 997            .range(
 998                (root_id, RelPath::empty().into())
 999                    ..(
1000                        WorktreeId::from_usize(root_id.to_usize() + 1),
1001                        RelPath::empty().into(),
1002                    ),
1003            )
1004            .map(|((_, path), content)| (path.clone(), &content.project))
1005    }
1006
1007    pub fn local_editorconfig_settings(
1008        &self,
1009        root_id: WorktreeId,
1010    ) -> impl '_ + Iterator<Item = (Arc<RelPath>, String, Option<Editorconfig>)> {
1011        self.raw_editorconfig_settings
1012            .range(
1013                (root_id, RelPath::empty().into())
1014                    ..(
1015                        WorktreeId::from_usize(root_id.to_usize() + 1),
1016                        RelPath::empty().into(),
1017                    ),
1018            )
1019            .map(|((_, path), (content, parsed_content))| {
1020                (path.clone(), content.clone(), parsed_content.clone())
1021            })
1022    }
1023
1024    pub fn json_schema(&self, params: &SettingsJsonSchemaParams) -> Value {
1025        let mut generator = schemars::generate::SchemaSettings::draft2019_09()
1026            .with_transform(DefaultDenyUnknownFields)
1027            .with_transform(AllowTrailingCommas)
1028            .into_generator();
1029
1030        UserSettingsContent::json_schema(&mut generator);
1031
1032        let language_settings_content_ref = generator
1033            .subschema_for::<LanguageSettingsContent>()
1034            .to_value();
1035
1036        generator.subschema_for::<LspSettings>();
1037
1038        let lsp_settings_def = generator
1039            .definitions()
1040            .get("LspSettings")
1041            .expect("LspSettings should be defined")
1042            .clone();
1043
1044        replace_subschema::<LanguageToSettingsMap>(&mut generator, || {
1045            json_schema!({
1046                "type": "object",
1047                "properties": params
1048                    .language_names
1049                    .iter()
1050                    .map(|name| {
1051                        (
1052                            name.clone(),
1053                            language_settings_content_ref.clone(),
1054                        )
1055                    })
1056                    .collect::<serde_json::Map<_, _>>(),
1057                "errorMessage": "No language with this name is installed."
1058            })
1059        });
1060
1061        replace_subschema::<FontFamilyName>(&mut generator, || {
1062            json_schema!({
1063                "type": "string",
1064                "enum": params.font_names,
1065            })
1066        });
1067
1068        replace_subschema::<ThemeName>(&mut generator, || {
1069            json_schema!({
1070                "type": "string",
1071                "enum": params.theme_names,
1072            })
1073        });
1074
1075        replace_subschema::<IconThemeName>(&mut generator, || {
1076            json_schema!({
1077                "type": "string",
1078                "enum": params.icon_theme_names,
1079            })
1080        });
1081
1082        replace_subschema::<LspSettingsMap>(&mut generator, || {
1083            let mut lsp_properties = serde_json::Map::new();
1084
1085            for adapter_name in params.lsp_adapter_names {
1086                let mut base_lsp_settings = lsp_settings_def
1087                    .as_object()
1088                    .expect("LspSettings should be an object")
1089                    .clone();
1090
1091                if let Some(properties) = base_lsp_settings.get_mut("properties") {
1092                    if let Some(props_obj) = properties.as_object_mut() {
1093                        props_obj.insert(
1094                            "initialization_options".to_string(),
1095                            serde_json::json!({
1096                                "$ref": format!("{LSP_SETTINGS_SCHEMA_URL_PREFIX}{adapter_name}")
1097                            }),
1098                        );
1099                    }
1100                }
1101
1102                lsp_properties.insert(
1103                    adapter_name.clone(),
1104                    serde_json::Value::Object(base_lsp_settings),
1105                );
1106            }
1107
1108            json_schema!({
1109                "type": "object",
1110                "properties": lsp_properties,
1111            })
1112        });
1113
1114        generator
1115            .root_schema_for::<UserSettingsContent>()
1116            .to_value()
1117    }
1118
1119    fn recompute_values(
1120        &mut self,
1121        changed_local_path: Option<(WorktreeId, &RelPath)>,
1122        cx: &mut App,
1123    ) {
1124        // Reload the global and local values for every setting.
1125        let mut project_settings_stack = Vec::<SettingsContent>::new();
1126        let mut paths_stack = Vec::<Option<(WorktreeId, &RelPath)>>::new();
1127
1128        if changed_local_path.is_none() {
1129            let mut merged = self.default_settings.as_ref().clone();
1130            merged.merge_from_option(self.extension_settings.as_deref());
1131            merged.merge_from_option(self.global_settings.as_deref());
1132            if let Some(user_settings) = self.user_settings.as_ref() {
1133                merged.merge_from(&user_settings.content);
1134                merged.merge_from_option(user_settings.for_release_channel());
1135                merged.merge_from_option(user_settings.for_os());
1136                merged.merge_from_option(user_settings.for_profile(cx));
1137            }
1138            merged.merge_from_option(self.server_settings.as_deref());
1139            self.merged_settings = Rc::new(merged);
1140
1141            for setting_value in self.setting_values.values_mut() {
1142                let value = setting_value.from_settings(&self.merged_settings);
1143                setting_value.set_global_value(value);
1144            }
1145        }
1146
1147        for ((root_id, directory_path), local_settings) in &self.local_settings {
1148            // Build a stack of all of the local values for that setting.
1149            while let Some(prev_entry) = paths_stack.last() {
1150                if let Some((prev_root_id, prev_path)) = prev_entry
1151                    && (root_id != prev_root_id || !directory_path.starts_with(prev_path))
1152                {
1153                    paths_stack.pop();
1154                    project_settings_stack.pop();
1155                    continue;
1156                }
1157                break;
1158            }
1159
1160            paths_stack.push(Some((*root_id, directory_path.as_ref())));
1161            let mut merged_local_settings = if let Some(deepest) = project_settings_stack.last() {
1162                (*deepest).clone()
1163            } else {
1164                self.merged_settings.as_ref().clone()
1165            };
1166            merged_local_settings.merge_from(local_settings);
1167
1168            project_settings_stack.push(merged_local_settings);
1169
1170            // If a local settings file changed, then avoid recomputing local
1171            // settings for any path outside of that directory.
1172            if changed_local_path.is_some_and(|(changed_root_id, changed_local_path)| {
1173                *root_id != changed_root_id || !directory_path.starts_with(changed_local_path)
1174            }) {
1175                continue;
1176            }
1177
1178            for setting_value in self.setting_values.values_mut() {
1179                let value = setting_value.from_settings(&project_settings_stack.last().unwrap());
1180                setting_value.set_local_value(*root_id, directory_path.clone(), value);
1181            }
1182        }
1183    }
1184
1185    pub fn editorconfig_properties(
1186        &self,
1187        for_worktree: WorktreeId,
1188        for_path: &RelPath,
1189    ) -> Option<EditorconfigProperties> {
1190        let mut properties = EditorconfigProperties::new();
1191
1192        for (directory_with_config, _, parsed_editorconfig) in
1193            self.local_editorconfig_settings(for_worktree)
1194        {
1195            if !for_path.starts_with(&directory_with_config) {
1196                properties.use_fallbacks();
1197                return Some(properties);
1198            }
1199            let parsed_editorconfig = parsed_editorconfig?;
1200            if parsed_editorconfig.is_root {
1201                properties = EditorconfigProperties::new();
1202            }
1203            for section in parsed_editorconfig.sections {
1204                section
1205                    .apply_to(&mut properties, for_path.as_std_path())
1206                    .log_err()?;
1207            }
1208        }
1209
1210        properties.use_fallbacks();
1211        Some(properties)
1212    }
1213}
1214
1215/// The result of parsing settings, including any migration attempts
1216#[derive(Debug, Clone, PartialEq, Eq)]
1217pub struct SettingsParseResult {
1218    /// The result of parsing the settings file (possibly after migration)
1219    pub parse_status: ParseStatus,
1220    /// The result of attempting to migrate the settings file
1221    pub migration_status: MigrationStatus,
1222}
1223
1224#[derive(Debug, Clone, PartialEq, Eq)]
1225pub enum MigrationStatus {
1226    /// No migration was needed - settings are up to date
1227    NotNeeded,
1228    /// Settings were automatically migrated in memory, but the file needs to be updated
1229    Succeeded,
1230    /// Migration was attempted but failed. Original settings were parsed instead.
1231    Failed { error: String },
1232}
1233
1234impl Default for SettingsParseResult {
1235    fn default() -> Self {
1236        Self {
1237            parse_status: ParseStatus::Success,
1238            migration_status: MigrationStatus::NotNeeded,
1239        }
1240    }
1241}
1242
1243impl SettingsParseResult {
1244    pub fn unwrap(self) -> bool {
1245        self.result().unwrap()
1246    }
1247
1248    pub fn expect(self, message: &str) -> bool {
1249        self.result().expect(message)
1250    }
1251
1252    /// Formats the ParseResult as a Result type. This is a lossy conversion
1253    pub fn result(self) -> Result<bool> {
1254        let migration_result = match self.migration_status {
1255            MigrationStatus::NotNeeded => Ok(false),
1256            MigrationStatus::Succeeded => Ok(true),
1257            MigrationStatus::Failed { error } => {
1258                Err(anyhow::format_err!(error)).context("Failed to migrate settings")
1259            }
1260        };
1261
1262        let parse_result = match self.parse_status {
1263            ParseStatus::Success => Ok(()),
1264            ParseStatus::Failed { error } => {
1265                Err(anyhow::format_err!(error)).context("Failed to parse settings")
1266            }
1267        };
1268
1269        match (migration_result, parse_result) {
1270            (migration_result @ Ok(_), Ok(())) => migration_result,
1271            (Err(migration_err), Ok(())) => Err(migration_err),
1272            (_, Err(parse_err)) => Err(parse_err),
1273        }
1274    }
1275
1276    /// Returns true if there were any errors migrating and parsing the settings content or if migration was required but there were no errors
1277    pub fn requires_user_action(&self) -> bool {
1278        matches!(self.parse_status, ParseStatus::Failed { .. })
1279            || matches!(
1280                self.migration_status,
1281                MigrationStatus::Succeeded | MigrationStatus::Failed { .. }
1282            )
1283    }
1284
1285    pub fn ok(self) -> Option<bool> {
1286        self.result().ok()
1287    }
1288
1289    pub fn parse_error(&self) -> Option<String> {
1290        match &self.parse_status {
1291            ParseStatus::Failed { error } => Some(error.clone()),
1292            ParseStatus::Success => None,
1293        }
1294    }
1295}
1296
1297#[derive(Debug, Clone, PartialEq)]
1298pub enum InvalidSettingsError {
1299    LocalSettings { path: Arc<RelPath>, message: String },
1300    UserSettings { message: String },
1301    ServerSettings { message: String },
1302    DefaultSettings { message: String },
1303    Editorconfig { path: Arc<RelPath>, message: String },
1304    Tasks { path: PathBuf, message: String },
1305    Debug { path: PathBuf, message: String },
1306}
1307
1308impl std::fmt::Display for InvalidSettingsError {
1309    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1310        match self {
1311            InvalidSettingsError::LocalSettings { message, .. }
1312            | InvalidSettingsError::UserSettings { message }
1313            | InvalidSettingsError::ServerSettings { message }
1314            | InvalidSettingsError::DefaultSettings { message }
1315            | InvalidSettingsError::Tasks { message, .. }
1316            | InvalidSettingsError::Editorconfig { message, .. }
1317            | InvalidSettingsError::Debug { message, .. } => {
1318                write!(f, "{message}")
1319            }
1320        }
1321    }
1322}
1323impl std::error::Error for InvalidSettingsError {}
1324
1325impl Debug for SettingsStore {
1326    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1327        f.debug_struct("SettingsStore")
1328            .field(
1329                "types",
1330                &self
1331                    .setting_values
1332                    .values()
1333                    .map(|value| value.setting_type_name())
1334                    .collect::<Vec<_>>(),
1335            )
1336            .field("default_settings", &self.default_settings)
1337            .field("user_settings", &self.user_settings)
1338            .field("local_settings", &self.local_settings)
1339            .finish_non_exhaustive()
1340    }
1341}
1342
1343impl<T: Settings> AnySettingValue for SettingValue<T> {
1344    fn from_settings(&self, s: &SettingsContent) -> Box<dyn Any> {
1345        Box::new(T::from_settings(s)) as _
1346    }
1347
1348    fn setting_type_name(&self) -> &'static str {
1349        type_name::<T>()
1350    }
1351
1352    fn all_local_values(&self) -> Vec<(WorktreeId, Arc<RelPath>, &dyn Any)> {
1353        self.local_values
1354            .iter()
1355            .map(|(id, path, value)| (*id, path.clone(), value as _))
1356            .collect()
1357    }
1358
1359    fn value_for_path(&self, path: Option<SettingsLocation>) -> &dyn Any {
1360        if let Some(SettingsLocation { worktree_id, path }) = path {
1361            for (settings_root_id, settings_path, value) in self.local_values.iter().rev() {
1362                if worktree_id == *settings_root_id && path.starts_with(settings_path) {
1363                    return value;
1364                }
1365            }
1366        }
1367
1368        self.global_value
1369            .as_ref()
1370            .unwrap_or_else(|| panic!("no default value for setting {}", self.setting_type_name()))
1371    }
1372
1373    fn set_global_value(&mut self, value: Box<dyn Any>) {
1374        self.global_value = Some(*value.downcast().unwrap());
1375    }
1376
1377    fn set_local_value(&mut self, root_id: WorktreeId, path: Arc<RelPath>, value: Box<dyn Any>) {
1378        let value = *value.downcast().unwrap();
1379        match self
1380            .local_values
1381            .binary_search_by_key(&(root_id, &path), |e| (e.0, &e.1))
1382        {
1383            Ok(ix) => self.local_values[ix].2 = value,
1384            Err(ix) => self.local_values.insert(ix, (root_id, path, value)),
1385        }
1386    }
1387
1388    fn clear_local_values(&mut self, root_id: WorktreeId) {
1389        self.local_values
1390            .retain(|(worktree_id, _, _)| *worktree_id != root_id);
1391    }
1392}
1393
1394#[cfg(test)]
1395mod tests {
1396    use std::num::NonZeroU32;
1397
1398    use crate::{
1399        ClosePosition, ItemSettingsContent, VsCodeSettingsSource, default_settings,
1400        settings_content::LanguageSettingsContent, test_settings,
1401    };
1402
1403    use super::*;
1404    use unindent::Unindent;
1405    use util::rel_path::rel_path;
1406
1407    #[derive(Debug, PartialEq)]
1408    struct AutoUpdateSetting {
1409        auto_update: bool,
1410    }
1411
1412    impl Settings for AutoUpdateSetting {
1413        fn from_settings(content: &SettingsContent) -> Self {
1414            AutoUpdateSetting {
1415                auto_update: content.auto_update.unwrap(),
1416            }
1417        }
1418    }
1419
1420    #[derive(Debug, PartialEq)]
1421    struct ItemSettings {
1422        close_position: ClosePosition,
1423        git_status: bool,
1424    }
1425
1426    impl Settings for ItemSettings {
1427        fn from_settings(content: &SettingsContent) -> Self {
1428            let content = content.tabs.clone().unwrap();
1429            ItemSettings {
1430                close_position: content.close_position.unwrap(),
1431                git_status: content.git_status.unwrap(),
1432            }
1433        }
1434    }
1435
1436    #[derive(Debug, PartialEq)]
1437    struct DefaultLanguageSettings {
1438        tab_size: NonZeroU32,
1439        preferred_line_length: u32,
1440    }
1441
1442    impl Settings for DefaultLanguageSettings {
1443        fn from_settings(content: &SettingsContent) -> Self {
1444            let content = &content.project.all_languages.defaults;
1445            DefaultLanguageSettings {
1446                tab_size: content.tab_size.unwrap(),
1447                preferred_line_length: content.preferred_line_length.unwrap(),
1448            }
1449        }
1450    }
1451
1452    #[derive(Debug, PartialEq)]
1453    struct ThemeSettings {
1454        buffer_font_family: FontFamilyName,
1455        buffer_font_fallbacks: Vec<FontFamilyName>,
1456    }
1457
1458    impl Settings for ThemeSettings {
1459        fn from_settings(content: &SettingsContent) -> Self {
1460            let content = content.theme.clone();
1461            ThemeSettings {
1462                buffer_font_family: content.buffer_font_family.unwrap(),
1463                buffer_font_fallbacks: content.buffer_font_fallbacks.unwrap(),
1464            }
1465        }
1466    }
1467
1468    #[gpui::test]
1469    fn test_settings_store_basic(cx: &mut App) {
1470        let mut store = SettingsStore::new(cx, &default_settings());
1471        store.register_setting::<AutoUpdateSetting>();
1472        store.register_setting::<ItemSettings>();
1473        store.register_setting::<DefaultLanguageSettings>();
1474
1475        assert_eq!(
1476            store.get::<AutoUpdateSetting>(None),
1477            &AutoUpdateSetting { auto_update: true }
1478        );
1479        assert_eq!(
1480            store.get::<ItemSettings>(None).close_position,
1481            ClosePosition::Right
1482        );
1483
1484        store
1485            .set_user_settings(
1486                r#"{
1487                    "auto_update": false,
1488                    "tabs": {
1489                      "close_position": "left"
1490                    }
1491                }"#,
1492                cx,
1493            )
1494            .unwrap();
1495
1496        assert_eq!(
1497            store.get::<AutoUpdateSetting>(None),
1498            &AutoUpdateSetting { auto_update: false }
1499        );
1500        assert_eq!(
1501            store.get::<ItemSettings>(None).close_position,
1502            ClosePosition::Left
1503        );
1504
1505        store
1506            .set_local_settings(
1507                WorktreeId::from_usize(1),
1508                rel_path("root1").into(),
1509                LocalSettingsKind::Settings,
1510                Some(r#"{ "tab_size": 5 }"#),
1511                cx,
1512            )
1513            .unwrap();
1514        store
1515            .set_local_settings(
1516                WorktreeId::from_usize(1),
1517                rel_path("root1/subdir").into(),
1518                LocalSettingsKind::Settings,
1519                Some(r#"{ "preferred_line_length": 50 }"#),
1520                cx,
1521            )
1522            .unwrap();
1523
1524        store
1525            .set_local_settings(
1526                WorktreeId::from_usize(1),
1527                rel_path("root2").into(),
1528                LocalSettingsKind::Settings,
1529                Some(r#"{ "tab_size": 9, "auto_update": true}"#),
1530                cx,
1531            )
1532            .unwrap();
1533
1534        assert_eq!(
1535            store.get::<DefaultLanguageSettings>(Some(SettingsLocation {
1536                worktree_id: WorktreeId::from_usize(1),
1537                path: rel_path("root1/something"),
1538            })),
1539            &DefaultLanguageSettings {
1540                preferred_line_length: 80,
1541                tab_size: 5.try_into().unwrap(),
1542            }
1543        );
1544        assert_eq!(
1545            store.get::<DefaultLanguageSettings>(Some(SettingsLocation {
1546                worktree_id: WorktreeId::from_usize(1),
1547                path: rel_path("root1/subdir/something"),
1548            })),
1549            &DefaultLanguageSettings {
1550                preferred_line_length: 50,
1551                tab_size: 5.try_into().unwrap(),
1552            }
1553        );
1554        assert_eq!(
1555            store.get::<DefaultLanguageSettings>(Some(SettingsLocation {
1556                worktree_id: WorktreeId::from_usize(1),
1557                path: rel_path("root2/something"),
1558            })),
1559            &DefaultLanguageSettings {
1560                preferred_line_length: 80,
1561                tab_size: 9.try_into().unwrap(),
1562            }
1563        );
1564        assert_eq!(
1565            store.get::<AutoUpdateSetting>(Some(SettingsLocation {
1566                worktree_id: WorktreeId::from_usize(1),
1567                path: rel_path("root2/something")
1568            })),
1569            &AutoUpdateSetting { auto_update: false }
1570        );
1571    }
1572
1573    #[gpui::test]
1574    fn test_setting_store_assign_json_before_register(cx: &mut App) {
1575        let mut store = SettingsStore::new(cx, &test_settings());
1576        store
1577            .set_user_settings(r#"{ "auto_update": false }"#, cx)
1578            .unwrap();
1579        store.register_setting::<AutoUpdateSetting>();
1580
1581        assert_eq!(
1582            store.get::<AutoUpdateSetting>(None),
1583            &AutoUpdateSetting { auto_update: false }
1584        );
1585    }
1586
1587    #[track_caller]
1588    fn check_settings_update(
1589        store: &mut SettingsStore,
1590        old_json: String,
1591        update: fn(&mut SettingsContent),
1592        expected_new_json: String,
1593        cx: &mut App,
1594    ) {
1595        store.set_user_settings(&old_json, cx).ok();
1596        let edits = store.edits_for_update(&old_json, update);
1597        let mut new_json = old_json;
1598        for (range, replacement) in edits.into_iter() {
1599            new_json.replace_range(range, &replacement);
1600        }
1601        pretty_assertions::assert_eq!(new_json, expected_new_json);
1602    }
1603
1604    #[gpui::test]
1605    fn test_setting_store_update(cx: &mut App) {
1606        let mut store = SettingsStore::new(cx, &test_settings());
1607
1608        // entries added and updated
1609        check_settings_update(
1610            &mut store,
1611            r#"{
1612                "languages": {
1613                    "JSON": {
1614                        "auto_indent": true
1615                    }
1616                }
1617            }"#
1618            .unindent(),
1619            |settings| {
1620                settings
1621                    .languages_mut()
1622                    .get_mut("JSON")
1623                    .unwrap()
1624                    .auto_indent = Some(false);
1625
1626                settings.languages_mut().insert(
1627                    "Rust".into(),
1628                    LanguageSettingsContent {
1629                        auto_indent: Some(true),
1630                        ..Default::default()
1631                    },
1632                );
1633            },
1634            r#"{
1635                "languages": {
1636                    "Rust": {
1637                        "auto_indent": true
1638                    },
1639                    "JSON": {
1640                        "auto_indent": false
1641                    }
1642                }
1643            }"#
1644            .unindent(),
1645            cx,
1646        );
1647
1648        // entries removed
1649        check_settings_update(
1650            &mut store,
1651            r#"{
1652                "languages": {
1653                    "Rust": {
1654                        "language_setting_2": true
1655                    },
1656                    "JSON": {
1657                        "language_setting_1": false
1658                    }
1659                }
1660            }"#
1661            .unindent(),
1662            |settings| {
1663                settings.languages_mut().remove("JSON").unwrap();
1664            },
1665            r#"{
1666                "languages": {
1667                    "Rust": {
1668                        "language_setting_2": true
1669                    }
1670                }
1671            }"#
1672            .unindent(),
1673            cx,
1674        );
1675
1676        check_settings_update(
1677            &mut store,
1678            r#"{
1679                "languages": {
1680                    "Rust": {
1681                        "language_setting_2": true
1682                    },
1683                    "JSON": {
1684                        "language_setting_1": false
1685                    }
1686                }
1687            }"#
1688            .unindent(),
1689            |settings| {
1690                settings.languages_mut().remove("Rust").unwrap();
1691            },
1692            r#"{
1693                "languages": {
1694                    "JSON": {
1695                        "language_setting_1": false
1696                    }
1697                }
1698            }"#
1699            .unindent(),
1700            cx,
1701        );
1702
1703        // weird formatting
1704        check_settings_update(
1705            &mut store,
1706            r#"{
1707                "tabs":   { "close_position": "left", "name": "Max"  }
1708                }"#
1709            .unindent(),
1710            |settings| {
1711                settings.tabs.as_mut().unwrap().close_position = Some(ClosePosition::Left);
1712            },
1713            r#"{
1714                "tabs":   { "close_position": "left", "name": "Max"  }
1715                }"#
1716            .unindent(),
1717            cx,
1718        );
1719
1720        // single-line formatting, other keys
1721        check_settings_update(
1722            &mut store,
1723            r#"{ "one": 1, "two": 2 }"#.to_owned(),
1724            |settings| settings.auto_update = Some(true),
1725            r#"{ "auto_update": true, "one": 1, "two": 2 }"#.to_owned(),
1726            cx,
1727        );
1728
1729        // empty object
1730        check_settings_update(
1731            &mut store,
1732            r#"{
1733                "tabs": {}
1734            }"#
1735            .unindent(),
1736            |settings| settings.tabs.as_mut().unwrap().close_position = Some(ClosePosition::Left),
1737            r#"{
1738                "tabs": {
1739                    "close_position": "left"
1740                }
1741            }"#
1742            .unindent(),
1743            cx,
1744        );
1745
1746        // no content
1747        check_settings_update(
1748            &mut store,
1749            r#""#.unindent(),
1750            |settings| {
1751                settings.tabs = Some(ItemSettingsContent {
1752                    git_status: Some(true),
1753                    ..Default::default()
1754                })
1755            },
1756            r#"{
1757              "tabs": {
1758                "git_status": true
1759              }
1760            }
1761            "#
1762            .unindent(),
1763            cx,
1764        );
1765
1766        check_settings_update(
1767            &mut store,
1768            r#"{
1769            }
1770            "#
1771            .unindent(),
1772            |settings| settings.title_bar.get_or_insert_default().show_branch_name = Some(true),
1773            r#"{
1774              "title_bar": {
1775                "show_branch_name": true
1776              }
1777            }
1778            "#
1779            .unindent(),
1780            cx,
1781        );
1782    }
1783
1784    #[gpui::test]
1785    fn test_vscode_import(cx: &mut App) {
1786        let mut store = SettingsStore::new(cx, &test_settings());
1787        store.register_setting::<DefaultLanguageSettings>();
1788        store.register_setting::<ItemSettings>();
1789        store.register_setting::<AutoUpdateSetting>();
1790        store.register_setting::<ThemeSettings>();
1791
1792        // create settings that werent present
1793        check_vscode_import(
1794            &mut store,
1795            r#"{
1796            }
1797            "#
1798            .unindent(),
1799            r#" { "editor.tabSize": 37 } "#.to_owned(),
1800            r#"{
1801              "base_keymap": "VSCode",
1802              "tab_size": 37
1803            }
1804            "#
1805            .unindent(),
1806            cx,
1807        );
1808
1809        // persist settings that were present
1810        check_vscode_import(
1811            &mut store,
1812            r#"{
1813                "preferred_line_length": 99,
1814            }
1815            "#
1816            .unindent(),
1817            r#"{ "editor.tabSize": 42 }"#.to_owned(),
1818            r#"{
1819                "base_keymap": "VSCode",
1820                "tab_size": 42,
1821                "preferred_line_length": 99,
1822            }
1823            "#
1824            .unindent(),
1825            cx,
1826        );
1827
1828        // don't clobber settings that aren't present in vscode
1829        check_vscode_import(
1830            &mut store,
1831            r#"{
1832                "preferred_line_length": 99,
1833                "tab_size": 42
1834            }
1835            "#
1836            .unindent(),
1837            r#"{}"#.to_owned(),
1838            r#"{
1839                "base_keymap": "VSCode",
1840                "preferred_line_length": 99,
1841                "tab_size": 42
1842            }
1843            "#
1844            .unindent(),
1845            cx,
1846        );
1847
1848        // custom enum
1849        check_vscode_import(
1850            &mut store,
1851            r#"{
1852            }
1853            "#
1854            .unindent(),
1855            r#"{ "git.decorations.enabled": true }"#.to_owned(),
1856            r#"{
1857              "project_panel": {
1858                "git_status": true
1859              },
1860              "outline_panel": {
1861                "git_status": true
1862              },
1863              "base_keymap": "VSCode",
1864              "tabs": {
1865                "git_status": true
1866              }
1867            }
1868            "#
1869            .unindent(),
1870            cx,
1871        );
1872
1873        // font-family
1874        check_vscode_import(
1875            &mut store,
1876            r#"{
1877            }
1878            "#
1879            .unindent(),
1880            r#"{ "editor.fontFamily": "Cascadia Code, 'Consolas', Courier New" }"#.to_owned(),
1881            r#"{
1882              "base_keymap": "VSCode",
1883              "buffer_font_fallbacks": [
1884                "Consolas",
1885                "Courier New"
1886              ],
1887              "buffer_font_family": "Cascadia Code"
1888            }
1889            "#
1890            .unindent(),
1891            cx,
1892        );
1893    }
1894
1895    #[track_caller]
1896    fn check_vscode_import(
1897        store: &mut SettingsStore,
1898        old: String,
1899        vscode: String,
1900        expected: String,
1901        cx: &mut App,
1902    ) {
1903        store.set_user_settings(&old, cx).ok();
1904        let new = store.get_vscode_edits(
1905            old,
1906            &VsCodeSettings::from_str(&vscode, VsCodeSettingsSource::VsCode).unwrap(),
1907        );
1908        pretty_assertions::assert_eq!(new, expected);
1909    }
1910
1911    #[gpui::test]
1912    fn test_update_git_settings(cx: &mut App) {
1913        let store = SettingsStore::new(cx, &test_settings());
1914
1915        let actual = store.new_text_for_update("{}".to_string(), |current| {
1916            current
1917                .git
1918                .get_or_insert_default()
1919                .inline_blame
1920                .get_or_insert_default()
1921                .enabled = Some(true);
1922        });
1923        pretty_assertions::assert_str_eq!(
1924            actual,
1925            r#"{
1926              "git": {
1927                "inline_blame": {
1928                  "enabled": true
1929                }
1930              }
1931            }
1932            "#
1933            .unindent()
1934        );
1935    }
1936
1937    #[gpui::test]
1938    fn test_global_settings(cx: &mut App) {
1939        let mut store = SettingsStore::new(cx, &test_settings());
1940        store.register_setting::<ItemSettings>();
1941
1942        // Set global settings - these should override defaults but not user settings
1943        store
1944            .set_global_settings(
1945                r#"{
1946                    "tabs": {
1947                        "close_position": "right",
1948                        "git_status": true,
1949                    }
1950                }"#,
1951                cx,
1952            )
1953            .unwrap();
1954
1955        // Before user settings, global settings should apply
1956        assert_eq!(
1957            store.get::<ItemSettings>(None),
1958            &ItemSettings {
1959                close_position: ClosePosition::Right,
1960                git_status: true,
1961            }
1962        );
1963
1964        // Set user settings - these should override both defaults and global
1965        store
1966            .set_user_settings(
1967                r#"{
1968                    "tabs": {
1969                        "close_position": "left"
1970                    }
1971                }"#,
1972                cx,
1973            )
1974            .unwrap();
1975
1976        // User settings should override global settings
1977        assert_eq!(
1978            store.get::<ItemSettings>(None),
1979            &ItemSettings {
1980                close_position: ClosePosition::Left,
1981                git_status: true, // Staff from global settings
1982            }
1983        );
1984    }
1985
1986    #[gpui::test]
1987    fn test_get_value_for_field_basic(cx: &mut App) {
1988        let mut store = SettingsStore::new(cx, &test_settings());
1989        store.register_setting::<DefaultLanguageSettings>();
1990
1991        store
1992            .set_user_settings(r#"{"preferred_line_length": 0}"#, cx)
1993            .unwrap();
1994        let local = (WorktreeId::from_usize(0), RelPath::empty().into_arc());
1995        store
1996            .set_local_settings(
1997                local.0,
1998                local.1.clone(),
1999                LocalSettingsKind::Settings,
2000                Some(r#"{}"#),
2001                cx,
2002            )
2003            .unwrap();
2004
2005        fn get(content: &SettingsContent) -> Option<&u32> {
2006            content
2007                .project
2008                .all_languages
2009                .defaults
2010                .preferred_line_length
2011                .as_ref()
2012        }
2013
2014        let default_value = *get(&store.default_settings).unwrap();
2015
2016        assert_eq!(
2017            store.get_value_from_file(SettingsFile::Project(local.clone()), get),
2018            (SettingsFile::User, Some(&0))
2019        );
2020        assert_eq!(
2021            store.get_value_from_file(SettingsFile::User, get),
2022            (SettingsFile::User, Some(&0))
2023        );
2024        store.set_user_settings(r#"{}"#, cx).unwrap();
2025        assert_eq!(
2026            store.get_value_from_file(SettingsFile::Project(local.clone()), get),
2027            (SettingsFile::Default, Some(&default_value))
2028        );
2029        store
2030            .set_local_settings(
2031                local.0,
2032                local.1.clone(),
2033                LocalSettingsKind::Settings,
2034                Some(r#"{"preferred_line_length": 80}"#),
2035                cx,
2036            )
2037            .unwrap();
2038        assert_eq!(
2039            store.get_value_from_file(SettingsFile::Project(local.clone()), get),
2040            (SettingsFile::Project(local), Some(&80))
2041        );
2042        assert_eq!(
2043            store.get_value_from_file(SettingsFile::User, get),
2044            (SettingsFile::Default, Some(&default_value))
2045        );
2046    }
2047
2048    #[gpui::test]
2049    fn test_get_value_for_field_local_worktrees_dont_interfere(cx: &mut App) {
2050        let mut store = SettingsStore::new(cx, &test_settings());
2051        store.register_setting::<DefaultLanguageSettings>();
2052        store.register_setting::<AutoUpdateSetting>();
2053
2054        let local_1 = (WorktreeId::from_usize(0), RelPath::empty().into_arc());
2055
2056        let local_1_child = (
2057            WorktreeId::from_usize(0),
2058            RelPath::new(
2059                std::path::Path::new("child1"),
2060                util::paths::PathStyle::Posix,
2061            )
2062            .unwrap()
2063            .into_arc(),
2064        );
2065
2066        let local_2 = (WorktreeId::from_usize(1), RelPath::empty().into_arc());
2067        let local_2_child = (
2068            WorktreeId::from_usize(1),
2069            RelPath::new(
2070                std::path::Path::new("child2"),
2071                util::paths::PathStyle::Posix,
2072            )
2073            .unwrap()
2074            .into_arc(),
2075        );
2076
2077        fn get(content: &SettingsContent) -> Option<&u32> {
2078            content
2079                .project
2080                .all_languages
2081                .defaults
2082                .preferred_line_length
2083                .as_ref()
2084        }
2085
2086        store
2087            .set_local_settings(
2088                local_1.0,
2089                local_1.1.clone(),
2090                LocalSettingsKind::Settings,
2091                Some(r#"{"preferred_line_length": 1}"#),
2092                cx,
2093            )
2094            .unwrap();
2095        store
2096            .set_local_settings(
2097                local_1_child.0,
2098                local_1_child.1.clone(),
2099                LocalSettingsKind::Settings,
2100                Some(r#"{}"#),
2101                cx,
2102            )
2103            .unwrap();
2104        store
2105            .set_local_settings(
2106                local_2.0,
2107                local_2.1.clone(),
2108                LocalSettingsKind::Settings,
2109                Some(r#"{"preferred_line_length": 2}"#),
2110                cx,
2111            )
2112            .unwrap();
2113        store
2114            .set_local_settings(
2115                local_2_child.0,
2116                local_2_child.1.clone(),
2117                LocalSettingsKind::Settings,
2118                Some(r#"{}"#),
2119                cx,
2120            )
2121            .unwrap();
2122
2123        // each local child should only inherit from it's parent
2124        assert_eq!(
2125            store.get_value_from_file(SettingsFile::Project(local_2_child), get),
2126            (SettingsFile::Project(local_2), Some(&2))
2127        );
2128        assert_eq!(
2129            store.get_value_from_file(SettingsFile::Project(local_1_child.clone()), get),
2130            (SettingsFile::Project(local_1.clone()), Some(&1))
2131        );
2132
2133        // adjacent children should be treated as siblings not inherit from each other
2134        let local_1_adjacent_child = (local_1.0, rel_path("adjacent_child").into_arc());
2135        store
2136            .set_local_settings(
2137                local_1_adjacent_child.0,
2138                local_1_adjacent_child.1.clone(),
2139                LocalSettingsKind::Settings,
2140                Some(r#"{}"#),
2141                cx,
2142            )
2143            .unwrap();
2144        store
2145            .set_local_settings(
2146                local_1_child.0,
2147                local_1_child.1.clone(),
2148                LocalSettingsKind::Settings,
2149                Some(r#"{"preferred_line_length": 3}"#),
2150                cx,
2151            )
2152            .unwrap();
2153
2154        assert_eq!(
2155            store.get_value_from_file(SettingsFile::Project(local_1_adjacent_child.clone()), get),
2156            (SettingsFile::Project(local_1.clone()), Some(&1))
2157        );
2158        store
2159            .set_local_settings(
2160                local_1_adjacent_child.0,
2161                local_1_adjacent_child.1,
2162                LocalSettingsKind::Settings,
2163                Some(r#"{"preferred_line_length": 3}"#),
2164                cx,
2165            )
2166            .unwrap();
2167        store
2168            .set_local_settings(
2169                local_1_child.0,
2170                local_1_child.1.clone(),
2171                LocalSettingsKind::Settings,
2172                Some(r#"{}"#),
2173                cx,
2174            )
2175            .unwrap();
2176        assert_eq!(
2177            store.get_value_from_file(SettingsFile::Project(local_1_child), get),
2178            (SettingsFile::Project(local_1), Some(&1))
2179        );
2180    }
2181
2182    #[gpui::test]
2183    fn test_get_overrides_for_field(cx: &mut App) {
2184        let mut store = SettingsStore::new(cx, &test_settings());
2185        store.register_setting::<DefaultLanguageSettings>();
2186
2187        let wt0_root = (WorktreeId::from_usize(0), RelPath::empty().into_arc());
2188        let wt0_child1 = (WorktreeId::from_usize(0), rel_path("child1").into_arc());
2189        let wt0_child2 = (WorktreeId::from_usize(0), rel_path("child2").into_arc());
2190
2191        let wt1_root = (WorktreeId::from_usize(1), RelPath::empty().into_arc());
2192        let wt1_subdir = (WorktreeId::from_usize(1), rel_path("subdir").into_arc());
2193
2194        fn get(content: &SettingsContent) -> &Option<u32> {
2195            &content.project.all_languages.defaults.preferred_line_length
2196        }
2197
2198        store
2199            .set_user_settings(r#"{"preferred_line_length": 100}"#, cx)
2200            .unwrap();
2201
2202        store
2203            .set_local_settings(
2204                wt0_root.0,
2205                wt0_root.1.clone(),
2206                LocalSettingsKind::Settings,
2207                Some(r#"{"preferred_line_length": 80}"#),
2208                cx,
2209            )
2210            .unwrap();
2211        store
2212            .set_local_settings(
2213                wt0_child1.0,
2214                wt0_child1.1.clone(),
2215                LocalSettingsKind::Settings,
2216                Some(r#"{"preferred_line_length": 120}"#),
2217                cx,
2218            )
2219            .unwrap();
2220        store
2221            .set_local_settings(
2222                wt0_child2.0,
2223                wt0_child2.1.clone(),
2224                LocalSettingsKind::Settings,
2225                Some(r#"{}"#),
2226                cx,
2227            )
2228            .unwrap();
2229
2230        store
2231            .set_local_settings(
2232                wt1_root.0,
2233                wt1_root.1.clone(),
2234                LocalSettingsKind::Settings,
2235                Some(r#"{"preferred_line_length": 90}"#),
2236                cx,
2237            )
2238            .unwrap();
2239        store
2240            .set_local_settings(
2241                wt1_subdir.0,
2242                wt1_subdir.1.clone(),
2243                LocalSettingsKind::Settings,
2244                Some(r#"{}"#),
2245                cx,
2246            )
2247            .unwrap();
2248
2249        let overrides = store.get_overrides_for_field(SettingsFile::Default, get);
2250        assert_eq!(
2251            overrides,
2252            vec![
2253                SettingsFile::User,
2254                SettingsFile::Project(wt0_root.clone()),
2255                SettingsFile::Project(wt0_child1.clone()),
2256                SettingsFile::Project(wt1_root.clone()),
2257            ]
2258        );
2259
2260        let overrides = store.get_overrides_for_field(SettingsFile::User, get);
2261        assert_eq!(
2262            overrides,
2263            vec![
2264                SettingsFile::Project(wt0_root.clone()),
2265                SettingsFile::Project(wt0_child1.clone()),
2266                SettingsFile::Project(wt1_root.clone()),
2267            ]
2268        );
2269
2270        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt0_root), get);
2271        assert_eq!(overrides, vec![]);
2272
2273        let overrides =
2274            store.get_overrides_for_field(SettingsFile::Project(wt0_child1.clone()), get);
2275        assert_eq!(overrides, vec![]);
2276
2277        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt0_child2), get);
2278        assert_eq!(overrides, vec![]);
2279
2280        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt1_root), get);
2281        assert_eq!(overrides, vec![]);
2282
2283        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt1_subdir), get);
2284        assert_eq!(overrides, vec![]);
2285
2286        let wt0_deep_child = (
2287            WorktreeId::from_usize(0),
2288            rel_path("child1/subdir").into_arc(),
2289        );
2290        store
2291            .set_local_settings(
2292                wt0_deep_child.0,
2293                wt0_deep_child.1.clone(),
2294                LocalSettingsKind::Settings,
2295                Some(r#"{"preferred_line_length": 140}"#),
2296                cx,
2297            )
2298            .unwrap();
2299
2300        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt0_deep_child), get);
2301        assert_eq!(overrides, vec![]);
2302
2303        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt0_child1), get);
2304        assert_eq!(overrides, vec![]);
2305    }
2306
2307    #[test]
2308    fn test_file_ord() {
2309        let wt0_root =
2310            SettingsFile::Project((WorktreeId::from_usize(0), RelPath::empty().into_arc()));
2311        let wt0_child1 =
2312            SettingsFile::Project((WorktreeId::from_usize(0), rel_path("child1").into_arc()));
2313        let wt0_child2 =
2314            SettingsFile::Project((WorktreeId::from_usize(0), rel_path("child2").into_arc()));
2315
2316        let wt1_root =
2317            SettingsFile::Project((WorktreeId::from_usize(1), RelPath::empty().into_arc()));
2318        let wt1_subdir =
2319            SettingsFile::Project((WorktreeId::from_usize(1), rel_path("subdir").into_arc()));
2320
2321        let mut files = vec![
2322            &wt1_root,
2323            &SettingsFile::Default,
2324            &wt0_root,
2325            &wt1_subdir,
2326            &wt0_child2,
2327            &SettingsFile::Server,
2328            &wt0_child1,
2329            &SettingsFile::User,
2330        ];
2331
2332        files.sort();
2333        pretty_assertions::assert_eq!(
2334            files,
2335            vec![
2336                &wt0_child2,
2337                &wt0_child1,
2338                &wt0_root,
2339                &wt1_subdir,
2340                &wt1_root,
2341                &SettingsFile::Server,
2342                &SettingsFile::User,
2343                &SettingsFile::Default,
2344            ]
2345        )
2346    }
2347
2348    #[gpui::test]
2349    fn test_lsp_settings_schema_generation(cx: &mut App) {
2350        let store = SettingsStore::test(cx);
2351
2352        let schema = store.json_schema(&SettingsJsonSchemaParams {
2353            language_names: &["Rust".to_string(), "TypeScript".to_string()],
2354            font_names: &["Zed Mono".to_string()],
2355            theme_names: &["One Dark".into()],
2356            icon_theme_names: &["Zed Icons".into()],
2357            lsp_adapter_names: &[
2358                "rust-analyzer".to_string(),
2359                "typescript-language-server".to_string(),
2360            ],
2361        });
2362
2363        let properties = schema
2364            .pointer("/$defs/LspSettingsMap/properties")
2365            .expect("LspSettingsMap should have properties")
2366            .as_object()
2367            .unwrap();
2368
2369        assert!(properties.contains_key("rust-analyzer"));
2370        assert!(properties.contains_key("typescript-language-server"));
2371
2372        let init_options_ref = properties
2373            .get("rust-analyzer")
2374            .unwrap()
2375            .pointer("/properties/initialization_options/$ref")
2376            .expect("initialization_options should have a $ref")
2377            .as_str()
2378            .unwrap();
2379
2380        assert_eq!(init_options_ref, "zed://schemas/settings/lsp/rust-analyzer");
2381    }
2382}