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