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,
  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: SettingsContentType = if user_settings_content.is_empty() {
 670            parse_json_with_comments("{}").expect("Empty settings should always be valid")
 671        } else {
 672            let migration_res = migrator::migrate_settings(user_settings_content);
 673            let content = match &migration_res {
 674                Ok(Some(content)) => content,
 675                Ok(None) => user_settings_content,
 676                Err(_) => user_settings_content,
 677            };
 678            let parse_result = parse_json_with_comments(content);
 679            migration_status = match migration_res {
 680                Ok(Some(_)) => MigrationStatus::Succeeded,
 681                Ok(None) => MigrationStatus::NotNeeded,
 682                Err(err) => MigrationStatus::Failed {
 683                    error: err.to_string(),
 684                },
 685            };
 686            match parse_result {
 687                Ok(settings) => settings,
 688                Err(err) => {
 689                    let result = SettingsParseResult {
 690                        parse_status: ParseStatus::Failed {
 691                            error: err.to_string(),
 692                        },
 693                        migration_status,
 694                    };
 695                    self.file_errors.insert(file, result.clone());
 696                    return (None, result);
 697                }
 698            }
 699        };
 700
 701        let result = SettingsParseResult {
 702            parse_status: ParseStatus::Success,
 703            migration_status,
 704        };
 705        self.file_errors.insert(file, result.clone());
 706        return (Some(settings), result);
 707    }
 708
 709    pub fn error_for_file(&self, file: SettingsFile) -> Option<SettingsParseResult> {
 710        self.file_errors
 711            .get(&file)
 712            .filter(|parse_result| parse_result.requires_user_action())
 713            .cloned()
 714    }
 715}
 716
 717impl SettingsStore {
 718    /// Updates the value of a setting in a JSON file, returning the new text
 719    /// for that JSON file.
 720    pub fn new_text_for_update(
 721        &self,
 722        old_text: String,
 723        update: impl FnOnce(&mut SettingsContent),
 724    ) -> String {
 725        let edits = self.edits_for_update(&old_text, update);
 726        let mut new_text = old_text;
 727        for (range, replacement) in edits.into_iter() {
 728            new_text.replace_range(range, &replacement);
 729        }
 730        new_text
 731    }
 732
 733    pub fn get_vscode_edits(&self, old_text: String, vscode: &VsCodeSettings) -> String {
 734        self.new_text_for_update(old_text, |content| {
 735            content.merge_from(&vscode.settings_content())
 736        })
 737    }
 738
 739    /// Updates the value of a setting in a JSON file, returning a list
 740    /// of edits to apply to the JSON file.
 741    pub fn edits_for_update(
 742        &self,
 743        text: &str,
 744        update: impl FnOnce(&mut SettingsContent),
 745    ) -> Vec<(Range<usize>, String)> {
 746        let old_content: UserSettingsContent =
 747            parse_json_with_comments(text).log_err().unwrap_or_default();
 748        let mut new_content = old_content.clone();
 749        update(&mut new_content.content);
 750
 751        let old_value = serde_json::to_value(&old_content).unwrap();
 752        let new_value = serde_json::to_value(new_content).unwrap();
 753
 754        let mut key_path = Vec::new();
 755        let mut edits = Vec::new();
 756        let tab_size = infer_json_indent_size(&text);
 757        let mut text = text.to_string();
 758        update_value_in_json_text(
 759            &mut text,
 760            &mut key_path,
 761            tab_size,
 762            &old_value,
 763            &new_value,
 764            &mut edits,
 765        );
 766        edits
 767    }
 768
 769    /// Sets the default settings via a JSON string.
 770    ///
 771    /// The string should contain a JSON object with a default value for every setting.
 772    pub fn set_default_settings(
 773        &mut self,
 774        default_settings_content: &str,
 775        cx: &mut App,
 776    ) -> Result<()> {
 777        self.default_settings = parse_json_with_comments(default_settings_content)?;
 778        self.recompute_values(None, cx);
 779        Ok(())
 780    }
 781
 782    /// Sets the user settings via a JSON string.
 783    #[must_use]
 784    pub fn set_user_settings(
 785        &mut self,
 786        user_settings_content: &str,
 787        cx: &mut App,
 788    ) -> SettingsParseResult {
 789        let (settings, parse_result) = self.parse_and_migrate_zed_settings::<UserSettingsContent>(
 790            user_settings_content,
 791            SettingsFile::User,
 792        );
 793
 794        if let Some(settings) = settings {
 795            self.user_settings = Some(settings);
 796            self.recompute_values(None, cx);
 797        }
 798        return parse_result;
 799    }
 800
 801    /// Sets the global settings via a JSON string.
 802    #[must_use]
 803    pub fn set_global_settings(
 804        &mut self,
 805        global_settings_content: &str,
 806        cx: &mut App,
 807    ) -> SettingsParseResult {
 808        let (settings, parse_result) = self.parse_and_migrate_zed_settings::<SettingsContent>(
 809            global_settings_content,
 810            SettingsFile::Global,
 811        );
 812
 813        if let Some(settings) = settings {
 814            self.global_settings = Some(Box::new(settings));
 815            self.recompute_values(None, cx);
 816        }
 817        return parse_result;
 818    }
 819
 820    pub fn set_server_settings(
 821        &mut self,
 822        server_settings_content: &str,
 823        cx: &mut App,
 824    ) -> Result<()> {
 825        let settings: Option<SettingsContent> = if server_settings_content.is_empty() {
 826            None
 827        } else {
 828            parse_json_with_comments(server_settings_content)?
 829        };
 830
 831        // Rewrite the server settings into a content type
 832        self.server_settings = settings.map(|settings| Box::new(settings));
 833
 834        self.recompute_values(None, cx);
 835        Ok(())
 836    }
 837
 838    /// Add or remove a set of local settings via a JSON string.
 839    pub fn set_local_settings(
 840        &mut self,
 841        root_id: WorktreeId,
 842        directory_path: Arc<RelPath>,
 843        kind: LocalSettingsKind,
 844        settings_content: Option<&str>,
 845        cx: &mut App,
 846    ) -> std::result::Result<(), InvalidSettingsError> {
 847        let mut zed_settings_changed = false;
 848        match (
 849            kind,
 850            settings_content
 851                .map(|content| content.trim())
 852                .filter(|content| !content.is_empty()),
 853        ) {
 854            (LocalSettingsKind::Tasks, _) => {
 855                return Err(InvalidSettingsError::Tasks {
 856                    message: "Attempted to submit tasks into the settings store".to_string(),
 857                    path: directory_path
 858                        .join(RelPath::unix(task_file_name()).unwrap())
 859                        .as_std_path()
 860                        .to_path_buf(),
 861                });
 862            }
 863            (LocalSettingsKind::Debug, _) => {
 864                return Err(InvalidSettingsError::Debug {
 865                    message: "Attempted to submit debugger config into the settings store"
 866                        .to_string(),
 867                    path: directory_path
 868                        .join(RelPath::unix(task_file_name()).unwrap())
 869                        .as_std_path()
 870                        .to_path_buf(),
 871                });
 872            }
 873            (LocalSettingsKind::Settings, None) => {
 874                zed_settings_changed = self
 875                    .local_settings
 876                    .remove(&(root_id, directory_path.clone()))
 877                    .is_some();
 878                self.file_errors
 879                    .remove(&SettingsFile::Project((root_id, directory_path.clone())));
 880            }
 881            (LocalSettingsKind::Editorconfig, None) => {
 882                self.raw_editorconfig_settings
 883                    .remove(&(root_id, directory_path.clone()));
 884            }
 885            (LocalSettingsKind::Settings, Some(settings_contents)) => {
 886                let (new_settings, parse_result) = self
 887                    .parse_and_migrate_zed_settings::<ProjectSettingsContent>(
 888                        settings_contents,
 889                        SettingsFile::Project((root_id, directory_path.clone())),
 890                    );
 891                match parse_result.parse_status {
 892                    ParseStatus::Success => Ok(()),
 893                    ParseStatus::Failed { error } => Err(InvalidSettingsError::LocalSettings {
 894                        path: directory_path.join(local_settings_file_relative_path()),
 895                        message: error,
 896                    }),
 897                }?;
 898                if let Some(new_settings) = new_settings {
 899                    match self.local_settings.entry((root_id, directory_path.clone())) {
 900                        btree_map::Entry::Vacant(v) => {
 901                            v.insert(SettingsContent {
 902                                project: new_settings,
 903                                ..Default::default()
 904                            });
 905                            zed_settings_changed = true;
 906                        }
 907                        btree_map::Entry::Occupied(mut o) => {
 908                            if &o.get().project != &new_settings {
 909                                o.insert(SettingsContent {
 910                                    project: new_settings,
 911                                    ..Default::default()
 912                                });
 913                                zed_settings_changed = true;
 914                            }
 915                        }
 916                    }
 917                }
 918            }
 919            (LocalSettingsKind::Editorconfig, Some(editorconfig_contents)) => {
 920                match self
 921                    .raw_editorconfig_settings
 922                    .entry((root_id, directory_path.clone()))
 923                {
 924                    btree_map::Entry::Vacant(v) => match editorconfig_contents.parse() {
 925                        Ok(new_contents) => {
 926                            v.insert((editorconfig_contents.to_owned(), Some(new_contents)));
 927                        }
 928                        Err(e) => {
 929                            v.insert((editorconfig_contents.to_owned(), None));
 930                            return Err(InvalidSettingsError::Editorconfig {
 931                                message: e.to_string(),
 932                                path: directory_path
 933                                    .join(RelPath::unix(EDITORCONFIG_NAME).unwrap()),
 934                            });
 935                        }
 936                    },
 937                    btree_map::Entry::Occupied(mut o) => {
 938                        if o.get().0 != editorconfig_contents {
 939                            match editorconfig_contents.parse() {
 940                                Ok(new_contents) => {
 941                                    o.insert((
 942                                        editorconfig_contents.to_owned(),
 943                                        Some(new_contents),
 944                                    ));
 945                                }
 946                                Err(e) => {
 947                                    o.insert((editorconfig_contents.to_owned(), None));
 948                                    return Err(InvalidSettingsError::Editorconfig {
 949                                        message: e.to_string(),
 950                                        path: directory_path
 951                                            .join(RelPath::unix(EDITORCONFIG_NAME).unwrap()),
 952                                    });
 953                                }
 954                            }
 955                        }
 956                    }
 957                }
 958            }
 959        };
 960
 961        if zed_settings_changed {
 962            self.recompute_values(Some((root_id, &directory_path)), cx);
 963        }
 964        Ok(())
 965    }
 966
 967    pub fn set_extension_settings(
 968        &mut self,
 969        content: ExtensionsSettingsContent,
 970        cx: &mut App,
 971    ) -> Result<()> {
 972        self.extension_settings = Some(Box::new(SettingsContent {
 973            project: ProjectSettingsContent {
 974                all_languages: content.all_languages,
 975                ..Default::default()
 976            },
 977            ..Default::default()
 978        }));
 979        self.recompute_values(None, cx);
 980        Ok(())
 981    }
 982
 983    /// Add or remove a set of local settings via a JSON string.
 984    pub fn clear_local_settings(&mut self, root_id: WorktreeId, cx: &mut App) -> Result<()> {
 985        self.local_settings
 986            .retain(|(worktree_id, _), _| worktree_id != &root_id);
 987        self.recompute_values(Some((root_id, RelPath::empty())), cx);
 988        Ok(())
 989    }
 990
 991    pub fn local_settings(
 992        &self,
 993        root_id: WorktreeId,
 994    ) -> impl '_ + Iterator<Item = (Arc<RelPath>, &ProjectSettingsContent)> {
 995        self.local_settings
 996            .range(
 997                (root_id, RelPath::empty().into())
 998                    ..(
 999                        WorktreeId::from_usize(root_id.to_usize() + 1),
1000                        RelPath::empty().into(),
1001                    ),
1002            )
1003            .map(|((_, path), content)| (path.clone(), &content.project))
1004    }
1005
1006    pub fn local_editorconfig_settings(
1007        &self,
1008        root_id: WorktreeId,
1009    ) -> impl '_ + Iterator<Item = (Arc<RelPath>, String, Option<Editorconfig>)> {
1010        self.raw_editorconfig_settings
1011            .range(
1012                (root_id, RelPath::empty().into())
1013                    ..(
1014                        WorktreeId::from_usize(root_id.to_usize() + 1),
1015                        RelPath::empty().into(),
1016                    ),
1017            )
1018            .map(|((_, path), (content, parsed_content))| {
1019                (path.clone(), content.clone(), parsed_content.clone())
1020            })
1021    }
1022
1023    pub fn json_schema(&self, params: &SettingsJsonSchemaParams) -> Value {
1024        let mut generator = schemars::generate::SchemaSettings::draft2019_09()
1025            .with_transform(DefaultDenyUnknownFields)
1026            .into_generator();
1027
1028        UserSettingsContent::json_schema(&mut generator);
1029
1030        let language_settings_content_ref = generator
1031            .subschema_for::<LanguageSettingsContent>()
1032            .to_value();
1033
1034        replace_subschema::<LanguageToSettingsMap>(&mut generator, || {
1035            json_schema!({
1036                "type": "object",
1037                "properties": params
1038                    .language_names
1039                    .iter()
1040                    .map(|name| {
1041                        (
1042                            name.clone(),
1043                            language_settings_content_ref.clone(),
1044                        )
1045                    })
1046                    .collect::<serde_json::Map<_, _>>(),
1047                "errorMessage": "No language with this name is installed."
1048            })
1049        });
1050
1051        replace_subschema::<FontFamilyName>(&mut generator, || {
1052            json_schema!({
1053                "type": "string",
1054                "enum": params.font_names,
1055            })
1056        });
1057
1058        replace_subschema::<ThemeName>(&mut generator, || {
1059            json_schema!({
1060                "type": "string",
1061                "enum": params.theme_names,
1062            })
1063        });
1064
1065        replace_subschema::<IconThemeName>(&mut generator, || {
1066            json_schema!({
1067                "type": "string",
1068                "enum": params.icon_theme_names,
1069            })
1070        });
1071
1072        generator
1073            .root_schema_for::<UserSettingsContent>()
1074            .to_value()
1075    }
1076
1077    fn recompute_values(
1078        &mut self,
1079        changed_local_path: Option<(WorktreeId, &RelPath)>,
1080        cx: &mut App,
1081    ) {
1082        // Reload the global and local values for every setting.
1083        let mut project_settings_stack = Vec::<SettingsContent>::new();
1084        let mut paths_stack = Vec::<Option<(WorktreeId, &RelPath)>>::new();
1085
1086        if changed_local_path.is_none() {
1087            let mut merged = self.default_settings.as_ref().clone();
1088            merged.merge_from_option(self.extension_settings.as_deref());
1089            merged.merge_from_option(self.global_settings.as_deref());
1090            if let Some(user_settings) = self.user_settings.as_ref() {
1091                merged.merge_from(&user_settings.content);
1092                merged.merge_from_option(user_settings.for_release_channel());
1093                merged.merge_from_option(user_settings.for_os());
1094                merged.merge_from_option(user_settings.for_profile(cx));
1095            }
1096            merged.merge_from_option(self.server_settings.as_deref());
1097            self.merged_settings = Rc::new(merged);
1098
1099            for setting_value in self.setting_values.values_mut() {
1100                let value = setting_value.from_settings(&self.merged_settings);
1101                setting_value.set_global_value(value);
1102            }
1103        }
1104
1105        for ((root_id, directory_path), local_settings) in &self.local_settings {
1106            // Build a stack of all of the local values for that setting.
1107            while let Some(prev_entry) = paths_stack.last() {
1108                if let Some((prev_root_id, prev_path)) = prev_entry
1109                    && (root_id != prev_root_id || !directory_path.starts_with(prev_path))
1110                {
1111                    paths_stack.pop();
1112                    project_settings_stack.pop();
1113                    continue;
1114                }
1115                break;
1116            }
1117
1118            paths_stack.push(Some((*root_id, directory_path.as_ref())));
1119            let mut merged_local_settings = if let Some(deepest) = project_settings_stack.last() {
1120                (*deepest).clone()
1121            } else {
1122                self.merged_settings.as_ref().clone()
1123            };
1124            merged_local_settings.merge_from(local_settings);
1125
1126            project_settings_stack.push(merged_local_settings);
1127
1128            // If a local settings file changed, then avoid recomputing local
1129            // settings for any path outside of that directory.
1130            if changed_local_path.is_some_and(|(changed_root_id, changed_local_path)| {
1131                *root_id != changed_root_id || !directory_path.starts_with(changed_local_path)
1132            }) {
1133                continue;
1134            }
1135
1136            for setting_value in self.setting_values.values_mut() {
1137                let value = setting_value.from_settings(&project_settings_stack.last().unwrap());
1138                setting_value.set_local_value(*root_id, directory_path.clone(), value);
1139            }
1140        }
1141    }
1142
1143    pub fn editorconfig_properties(
1144        &self,
1145        for_worktree: WorktreeId,
1146        for_path: &RelPath,
1147    ) -> Option<EditorconfigProperties> {
1148        let mut properties = EditorconfigProperties::new();
1149
1150        for (directory_with_config, _, parsed_editorconfig) in
1151            self.local_editorconfig_settings(for_worktree)
1152        {
1153            if !for_path.starts_with(&directory_with_config) {
1154                properties.use_fallbacks();
1155                return Some(properties);
1156            }
1157            let parsed_editorconfig = parsed_editorconfig?;
1158            if parsed_editorconfig.is_root {
1159                properties = EditorconfigProperties::new();
1160            }
1161            for section in parsed_editorconfig.sections {
1162                section
1163                    .apply_to(&mut properties, for_path.as_std_path())
1164                    .log_err()?;
1165            }
1166        }
1167
1168        properties.use_fallbacks();
1169        Some(properties)
1170    }
1171}
1172
1173/// The result of parsing settings, including any migration attempts
1174#[derive(Debug, Clone, PartialEq, Eq)]
1175pub struct SettingsParseResult {
1176    /// The result of parsing the settings file (possibly after migration)
1177    pub parse_status: ParseStatus,
1178    /// The result of attempting to migrate the settings file
1179    pub migration_status: MigrationStatus,
1180}
1181
1182#[derive(Debug, Clone, PartialEq, Eq)]
1183pub enum ParseStatus {
1184    /// Settings were parsed successfully
1185    Success,
1186    /// Settings failed to parse
1187    Failed { error: String },
1188}
1189
1190#[derive(Debug, Clone, PartialEq, Eq)]
1191pub enum MigrationStatus {
1192    /// No migration was needed - settings are up to date
1193    NotNeeded,
1194    /// Settings were automatically migrated in memory, but the file needs to be updated
1195    Succeeded,
1196    /// Migration was attempted but failed. Original settings were parsed instead.
1197    Failed { error: String },
1198}
1199
1200impl Default for SettingsParseResult {
1201    fn default() -> Self {
1202        Self {
1203            parse_status: ParseStatus::Success,
1204            migration_status: MigrationStatus::NotNeeded,
1205        }
1206    }
1207}
1208
1209impl SettingsParseResult {
1210    pub fn unwrap(self) -> bool {
1211        self.result().unwrap()
1212    }
1213
1214    pub fn expect(self, message: &str) -> bool {
1215        self.result().expect(message)
1216    }
1217
1218    /// Formats the ParseResult as a Result type. This is a lossy conversion
1219    pub fn result(self) -> Result<bool> {
1220        let migration_result = match self.migration_status {
1221            MigrationStatus::NotNeeded => Ok(false),
1222            MigrationStatus::Succeeded => Ok(true),
1223            MigrationStatus::Failed { error } => {
1224                Err(anyhow::format_err!(error)).context("Failed to migrate settings")
1225            }
1226        };
1227
1228        let parse_result = match self.parse_status {
1229            ParseStatus::Success => Ok(()),
1230            ParseStatus::Failed { error } => {
1231                Err(anyhow::format_err!(error)).context("Failed to parse settings")
1232            }
1233        };
1234
1235        match (migration_result, parse_result) {
1236            (migration_result @ Ok(_), Ok(())) => migration_result,
1237            (Err(migration_err), Ok(())) => Err(migration_err),
1238            (_, Err(parse_err)) => Err(parse_err),
1239        }
1240    }
1241
1242    /// Returns true if there were any errors migrating and parsing the settings content or if migration was required but there were no errors
1243    pub fn requires_user_action(&self) -> bool {
1244        matches!(self.parse_status, ParseStatus::Failed { .. })
1245            || matches!(
1246                self.migration_status,
1247                MigrationStatus::Succeeded | MigrationStatus::Failed { .. }
1248            )
1249    }
1250
1251    pub fn ok(self) -> Option<bool> {
1252        self.result().ok()
1253    }
1254
1255    pub fn parse_error(&self) -> Option<String> {
1256        match &self.parse_status {
1257            ParseStatus::Failed { error } => Some(error.clone()),
1258            ParseStatus::Success => None,
1259        }
1260    }
1261}
1262
1263#[derive(Debug, Clone, PartialEq)]
1264pub enum InvalidSettingsError {
1265    LocalSettings { path: Arc<RelPath>, message: String },
1266    UserSettings { message: String },
1267    ServerSettings { message: String },
1268    DefaultSettings { message: String },
1269    Editorconfig { path: Arc<RelPath>, message: String },
1270    Tasks { path: PathBuf, message: String },
1271    Debug { path: PathBuf, message: String },
1272}
1273
1274impl std::fmt::Display for InvalidSettingsError {
1275    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1276        match self {
1277            InvalidSettingsError::LocalSettings { message, .. }
1278            | InvalidSettingsError::UserSettings { message }
1279            | InvalidSettingsError::ServerSettings { message }
1280            | InvalidSettingsError::DefaultSettings { message }
1281            | InvalidSettingsError::Tasks { message, .. }
1282            | InvalidSettingsError::Editorconfig { message, .. }
1283            | InvalidSettingsError::Debug { message, .. } => {
1284                write!(f, "{message}")
1285            }
1286        }
1287    }
1288}
1289impl std::error::Error for InvalidSettingsError {}
1290
1291impl Debug for SettingsStore {
1292    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1293        f.debug_struct("SettingsStore")
1294            .field(
1295                "types",
1296                &self
1297                    .setting_values
1298                    .values()
1299                    .map(|value| value.setting_type_name())
1300                    .collect::<Vec<_>>(),
1301            )
1302            .field("default_settings", &self.default_settings)
1303            .field("user_settings", &self.user_settings)
1304            .field("local_settings", &self.local_settings)
1305            .finish_non_exhaustive()
1306    }
1307}
1308
1309impl<T: Settings> AnySettingValue for SettingValue<T> {
1310    fn from_settings(&self, s: &SettingsContent) -> Box<dyn Any> {
1311        Box::new(T::from_settings(s)) as _
1312    }
1313
1314    fn setting_type_name(&self) -> &'static str {
1315        type_name::<T>()
1316    }
1317
1318    fn all_local_values(&self) -> Vec<(WorktreeId, Arc<RelPath>, &dyn Any)> {
1319        self.local_values
1320            .iter()
1321            .map(|(id, path, value)| (*id, path.clone(), value as _))
1322            .collect()
1323    }
1324
1325    fn value_for_path(&self, path: Option<SettingsLocation>) -> &dyn Any {
1326        if let Some(SettingsLocation { worktree_id, path }) = path {
1327            for (settings_root_id, settings_path, value) in self.local_values.iter().rev() {
1328                if worktree_id == *settings_root_id && path.starts_with(settings_path) {
1329                    return value;
1330                }
1331            }
1332        }
1333
1334        self.global_value
1335            .as_ref()
1336            .unwrap_or_else(|| panic!("no default value for setting {}", self.setting_type_name()))
1337    }
1338
1339    fn set_global_value(&mut self, value: Box<dyn Any>) {
1340        self.global_value = Some(*value.downcast().unwrap());
1341    }
1342
1343    fn set_local_value(&mut self, root_id: WorktreeId, path: Arc<RelPath>, value: Box<dyn Any>) {
1344        let value = *value.downcast().unwrap();
1345        match self
1346            .local_values
1347            .binary_search_by_key(&(root_id, &path), |e| (e.0, &e.1))
1348        {
1349            Ok(ix) => self.local_values[ix].2 = value,
1350            Err(ix) => self.local_values.insert(ix, (root_id, path, value)),
1351        }
1352    }
1353}
1354
1355#[cfg(test)]
1356mod tests {
1357    use std::num::NonZeroU32;
1358
1359    use crate::{
1360        ClosePosition, ItemSettingsContent, VsCodeSettingsSource, default_settings,
1361        settings_content::LanguageSettingsContent, test_settings,
1362    };
1363
1364    use super::*;
1365    use unindent::Unindent;
1366    use util::rel_path::rel_path;
1367
1368    #[derive(Debug, PartialEq)]
1369    struct AutoUpdateSetting {
1370        auto_update: bool,
1371    }
1372
1373    impl Settings for AutoUpdateSetting {
1374        fn from_settings(content: &SettingsContent) -> Self {
1375            AutoUpdateSetting {
1376                auto_update: content.auto_update.unwrap(),
1377            }
1378        }
1379    }
1380
1381    #[derive(Debug, PartialEq)]
1382    struct ItemSettings {
1383        close_position: ClosePosition,
1384        git_status: bool,
1385    }
1386
1387    impl Settings for ItemSettings {
1388        fn from_settings(content: &SettingsContent) -> Self {
1389            let content = content.tabs.clone().unwrap();
1390            ItemSettings {
1391                close_position: content.close_position.unwrap(),
1392                git_status: content.git_status.unwrap(),
1393            }
1394        }
1395    }
1396
1397    #[derive(Debug, PartialEq)]
1398    struct DefaultLanguageSettings {
1399        tab_size: NonZeroU32,
1400        preferred_line_length: u32,
1401    }
1402
1403    impl Settings for DefaultLanguageSettings {
1404        fn from_settings(content: &SettingsContent) -> Self {
1405            let content = &content.project.all_languages.defaults;
1406            DefaultLanguageSettings {
1407                tab_size: content.tab_size.unwrap(),
1408                preferred_line_length: content.preferred_line_length.unwrap(),
1409            }
1410        }
1411    }
1412
1413    #[derive(Debug, PartialEq)]
1414    struct ThemeSettings {
1415        buffer_font_family: FontFamilyName,
1416        buffer_font_fallbacks: Vec<FontFamilyName>,
1417    }
1418
1419    impl Settings for ThemeSettings {
1420        fn from_settings(content: &SettingsContent) -> Self {
1421            let content = content.theme.clone();
1422            ThemeSettings {
1423                buffer_font_family: content.buffer_font_family.unwrap(),
1424                buffer_font_fallbacks: content.buffer_font_fallbacks.unwrap(),
1425            }
1426        }
1427    }
1428
1429    #[gpui::test]
1430    fn test_settings_store_basic(cx: &mut App) {
1431        let mut store = SettingsStore::new(cx, &default_settings());
1432        store.register_setting::<AutoUpdateSetting>();
1433        store.register_setting::<ItemSettings>();
1434        store.register_setting::<DefaultLanguageSettings>();
1435
1436        assert_eq!(
1437            store.get::<AutoUpdateSetting>(None),
1438            &AutoUpdateSetting { auto_update: true }
1439        );
1440        assert_eq!(
1441            store.get::<ItemSettings>(None).close_position,
1442            ClosePosition::Right
1443        );
1444
1445        store
1446            .set_user_settings(
1447                r#"{
1448                    "auto_update": false,
1449                    "tabs": {
1450                      "close_position": "left"
1451                    }
1452                }"#,
1453                cx,
1454            )
1455            .unwrap();
1456
1457        assert_eq!(
1458            store.get::<AutoUpdateSetting>(None),
1459            &AutoUpdateSetting { auto_update: false }
1460        );
1461        assert_eq!(
1462            store.get::<ItemSettings>(None).close_position,
1463            ClosePosition::Left
1464        );
1465
1466        store
1467            .set_local_settings(
1468                WorktreeId::from_usize(1),
1469                rel_path("root1").into(),
1470                LocalSettingsKind::Settings,
1471                Some(r#"{ "tab_size": 5 }"#),
1472                cx,
1473            )
1474            .unwrap();
1475        store
1476            .set_local_settings(
1477                WorktreeId::from_usize(1),
1478                rel_path("root1/subdir").into(),
1479                LocalSettingsKind::Settings,
1480                Some(r#"{ "preferred_line_length": 50 }"#),
1481                cx,
1482            )
1483            .unwrap();
1484
1485        store
1486            .set_local_settings(
1487                WorktreeId::from_usize(1),
1488                rel_path("root2").into(),
1489                LocalSettingsKind::Settings,
1490                Some(r#"{ "tab_size": 9, "auto_update": true}"#),
1491                cx,
1492            )
1493            .unwrap();
1494
1495        assert_eq!(
1496            store.get::<DefaultLanguageSettings>(Some(SettingsLocation {
1497                worktree_id: WorktreeId::from_usize(1),
1498                path: rel_path("root1/something"),
1499            })),
1500            &DefaultLanguageSettings {
1501                preferred_line_length: 80,
1502                tab_size: 5.try_into().unwrap(),
1503            }
1504        );
1505        assert_eq!(
1506            store.get::<DefaultLanguageSettings>(Some(SettingsLocation {
1507                worktree_id: WorktreeId::from_usize(1),
1508                path: rel_path("root1/subdir/something"),
1509            })),
1510            &DefaultLanguageSettings {
1511                preferred_line_length: 50,
1512                tab_size: 5.try_into().unwrap(),
1513            }
1514        );
1515        assert_eq!(
1516            store.get::<DefaultLanguageSettings>(Some(SettingsLocation {
1517                worktree_id: WorktreeId::from_usize(1),
1518                path: rel_path("root2/something"),
1519            })),
1520            &DefaultLanguageSettings {
1521                preferred_line_length: 80,
1522                tab_size: 9.try_into().unwrap(),
1523            }
1524        );
1525        assert_eq!(
1526            store.get::<AutoUpdateSetting>(Some(SettingsLocation {
1527                worktree_id: WorktreeId::from_usize(1),
1528                path: rel_path("root2/something")
1529            })),
1530            &AutoUpdateSetting { auto_update: false }
1531        );
1532    }
1533
1534    #[gpui::test]
1535    fn test_setting_store_assign_json_before_register(cx: &mut App) {
1536        let mut store = SettingsStore::new(cx, &test_settings());
1537        store
1538            .set_user_settings(r#"{ "auto_update": false }"#, cx)
1539            .unwrap();
1540        store.register_setting::<AutoUpdateSetting>();
1541
1542        assert_eq!(
1543            store.get::<AutoUpdateSetting>(None),
1544            &AutoUpdateSetting { auto_update: false }
1545        );
1546    }
1547
1548    #[track_caller]
1549    fn check_settings_update(
1550        store: &mut SettingsStore,
1551        old_json: String,
1552        update: fn(&mut SettingsContent),
1553        expected_new_json: String,
1554        cx: &mut App,
1555    ) {
1556        store.set_user_settings(&old_json, cx).ok();
1557        let edits = store.edits_for_update(&old_json, update);
1558        let mut new_json = old_json;
1559        for (range, replacement) in edits.into_iter() {
1560            new_json.replace_range(range, &replacement);
1561        }
1562        pretty_assertions::assert_eq!(new_json, expected_new_json);
1563    }
1564
1565    #[gpui::test]
1566    fn test_setting_store_update(cx: &mut App) {
1567        let mut store = SettingsStore::new(cx, &test_settings());
1568
1569        // entries added and updated
1570        check_settings_update(
1571            &mut store,
1572            r#"{
1573                "languages": {
1574                    "JSON": {
1575                        "auto_indent": true
1576                    }
1577                }
1578            }"#
1579            .unindent(),
1580            |settings| {
1581                settings
1582                    .languages_mut()
1583                    .get_mut("JSON")
1584                    .unwrap()
1585                    .auto_indent = Some(false);
1586
1587                settings.languages_mut().insert(
1588                    "Rust".into(),
1589                    LanguageSettingsContent {
1590                        auto_indent: Some(true),
1591                        ..Default::default()
1592                    },
1593                );
1594            },
1595            r#"{
1596                "languages": {
1597                    "Rust": {
1598                        "auto_indent": true
1599                    },
1600                    "JSON": {
1601                        "auto_indent": false
1602                    }
1603                }
1604            }"#
1605            .unindent(),
1606            cx,
1607        );
1608
1609        // entries removed
1610        check_settings_update(
1611            &mut store,
1612            r#"{
1613                "languages": {
1614                    "Rust": {
1615                        "language_setting_2": true
1616                    },
1617                    "JSON": {
1618                        "language_setting_1": false
1619                    }
1620                }
1621            }"#
1622            .unindent(),
1623            |settings| {
1624                settings.languages_mut().remove("JSON").unwrap();
1625            },
1626            r#"{
1627                "languages": {
1628                    "Rust": {
1629                        "language_setting_2": true
1630                    }
1631                }
1632            }"#
1633            .unindent(),
1634            cx,
1635        );
1636
1637        check_settings_update(
1638            &mut store,
1639            r#"{
1640                "languages": {
1641                    "Rust": {
1642                        "language_setting_2": true
1643                    },
1644                    "JSON": {
1645                        "language_setting_1": false
1646                    }
1647                }
1648            }"#
1649            .unindent(),
1650            |settings| {
1651                settings.languages_mut().remove("Rust").unwrap();
1652            },
1653            r#"{
1654                "languages": {
1655                    "JSON": {
1656                        "language_setting_1": false
1657                    }
1658                }
1659            }"#
1660            .unindent(),
1661            cx,
1662        );
1663
1664        // weird formatting
1665        check_settings_update(
1666            &mut store,
1667            r#"{
1668                "tabs":   { "close_position": "left", "name": "Max"  }
1669                }"#
1670            .unindent(),
1671            |settings| {
1672                settings.tabs.as_mut().unwrap().close_position = Some(ClosePosition::Left);
1673            },
1674            r#"{
1675                "tabs":   { "close_position": "left", "name": "Max"  }
1676                }"#
1677            .unindent(),
1678            cx,
1679        );
1680
1681        // single-line formatting, other keys
1682        check_settings_update(
1683            &mut store,
1684            r#"{ "one": 1, "two": 2 }"#.to_owned(),
1685            |settings| settings.auto_update = Some(true),
1686            r#"{ "auto_update": true, "one": 1, "two": 2 }"#.to_owned(),
1687            cx,
1688        );
1689
1690        // empty object
1691        check_settings_update(
1692            &mut store,
1693            r#"{
1694                "tabs": {}
1695            }"#
1696            .unindent(),
1697            |settings| settings.tabs.as_mut().unwrap().close_position = Some(ClosePosition::Left),
1698            r#"{
1699                "tabs": {
1700                    "close_position": "left"
1701                }
1702            }"#
1703            .unindent(),
1704            cx,
1705        );
1706
1707        // no content
1708        check_settings_update(
1709            &mut store,
1710            r#""#.unindent(),
1711            |settings| {
1712                settings.tabs = Some(ItemSettingsContent {
1713                    git_status: Some(true),
1714                    ..Default::default()
1715                })
1716            },
1717            r#"{
1718              "tabs": {
1719                "git_status": true
1720              }
1721            }
1722            "#
1723            .unindent(),
1724            cx,
1725        );
1726
1727        check_settings_update(
1728            &mut store,
1729            r#"{
1730            }
1731            "#
1732            .unindent(),
1733            |settings| settings.title_bar.get_or_insert_default().show_branch_name = Some(true),
1734            r#"{
1735              "title_bar": {
1736                "show_branch_name": true
1737              }
1738            }
1739            "#
1740            .unindent(),
1741            cx,
1742        );
1743    }
1744
1745    #[gpui::test]
1746    fn test_vscode_import(cx: &mut App) {
1747        let mut store = SettingsStore::new(cx, &test_settings());
1748        store.register_setting::<DefaultLanguageSettings>();
1749        store.register_setting::<ItemSettings>();
1750        store.register_setting::<AutoUpdateSetting>();
1751        store.register_setting::<ThemeSettings>();
1752
1753        // create settings that werent present
1754        check_vscode_import(
1755            &mut store,
1756            r#"{
1757            }
1758            "#
1759            .unindent(),
1760            r#" { "editor.tabSize": 37 } "#.to_owned(),
1761            r#"{
1762              "base_keymap": "VSCode",
1763              "tab_size": 37
1764            }
1765            "#
1766            .unindent(),
1767            cx,
1768        );
1769
1770        // persist settings that were present
1771        check_vscode_import(
1772            &mut store,
1773            r#"{
1774                "preferred_line_length": 99,
1775            }
1776            "#
1777            .unindent(),
1778            r#"{ "editor.tabSize": 42 }"#.to_owned(),
1779            r#"{
1780                "base_keymap": "VSCode",
1781                "tab_size": 42,
1782                "preferred_line_length": 99,
1783            }
1784            "#
1785            .unindent(),
1786            cx,
1787        );
1788
1789        // don't clobber settings that aren't present in vscode
1790        check_vscode_import(
1791            &mut store,
1792            r#"{
1793                "preferred_line_length": 99,
1794                "tab_size": 42
1795            }
1796            "#
1797            .unindent(),
1798            r#"{}"#.to_owned(),
1799            r#"{
1800                "base_keymap": "VSCode",
1801                "preferred_line_length": 99,
1802                "tab_size": 42
1803            }
1804            "#
1805            .unindent(),
1806            cx,
1807        );
1808
1809        // custom enum
1810        check_vscode_import(
1811            &mut store,
1812            r#"{
1813            }
1814            "#
1815            .unindent(),
1816            r#"{ "git.decorations.enabled": true }"#.to_owned(),
1817            r#"{
1818              "project_panel": {
1819                "git_status": true
1820              },
1821              "outline_panel": {
1822                "git_status": true
1823              },
1824              "base_keymap": "VSCode",
1825              "tabs": {
1826                "git_status": true
1827              }
1828            }
1829            "#
1830            .unindent(),
1831            cx,
1832        );
1833
1834        // font-family
1835        check_vscode_import(
1836            &mut store,
1837            r#"{
1838            }
1839            "#
1840            .unindent(),
1841            r#"{ "editor.fontFamily": "Cascadia Code, 'Consolas', Courier New" }"#.to_owned(),
1842            r#"{
1843              "base_keymap": "VSCode",
1844              "buffer_font_fallbacks": [
1845                "Consolas",
1846                "Courier New"
1847              ],
1848              "buffer_font_family": "Cascadia Code"
1849            }
1850            "#
1851            .unindent(),
1852            cx,
1853        );
1854    }
1855
1856    #[track_caller]
1857    fn check_vscode_import(
1858        store: &mut SettingsStore,
1859        old: String,
1860        vscode: String,
1861        expected: String,
1862        cx: &mut App,
1863    ) {
1864        store.set_user_settings(&old, cx).ok();
1865        let new = store.get_vscode_edits(
1866            old,
1867            &VsCodeSettings::from_str(&vscode, VsCodeSettingsSource::VsCode).unwrap(),
1868        );
1869        pretty_assertions::assert_eq!(new, expected);
1870    }
1871
1872    #[gpui::test]
1873    fn test_update_git_settings(cx: &mut App) {
1874        let store = SettingsStore::new(cx, &test_settings());
1875
1876        let actual = store.new_text_for_update("{}".to_string(), |current| {
1877            current
1878                .git
1879                .get_or_insert_default()
1880                .inline_blame
1881                .get_or_insert_default()
1882                .enabled = Some(true);
1883        });
1884        pretty_assertions::assert_str_eq!(
1885            actual,
1886            r#"{
1887              "git": {
1888                "inline_blame": {
1889                  "enabled": true
1890                }
1891              }
1892            }
1893            "#
1894            .unindent()
1895        );
1896    }
1897
1898    #[gpui::test]
1899    fn test_global_settings(cx: &mut App) {
1900        let mut store = SettingsStore::new(cx, &test_settings());
1901        store.register_setting::<ItemSettings>();
1902
1903        // Set global settings - these should override defaults but not user settings
1904        store
1905            .set_global_settings(
1906                r#"{
1907                    "tabs": {
1908                        "close_position": "right",
1909                        "git_status": true,
1910                    }
1911                }"#,
1912                cx,
1913            )
1914            .unwrap();
1915
1916        // Before user settings, global settings should apply
1917        assert_eq!(
1918            store.get::<ItemSettings>(None),
1919            &ItemSettings {
1920                close_position: ClosePosition::Right,
1921                git_status: true,
1922            }
1923        );
1924
1925        // Set user settings - these should override both defaults and global
1926        store
1927            .set_user_settings(
1928                r#"{
1929                    "tabs": {
1930                        "close_position": "left"
1931                    }
1932                }"#,
1933                cx,
1934            )
1935            .unwrap();
1936
1937        // User settings should override global settings
1938        assert_eq!(
1939            store.get::<ItemSettings>(None),
1940            &ItemSettings {
1941                close_position: ClosePosition::Left,
1942                git_status: true, // Staff from global settings
1943            }
1944        );
1945    }
1946
1947    #[gpui::test]
1948    fn test_get_value_for_field_basic(cx: &mut App) {
1949        let mut store = SettingsStore::new(cx, &test_settings());
1950        store.register_setting::<DefaultLanguageSettings>();
1951
1952        store
1953            .set_user_settings(r#"{"preferred_line_length": 0}"#, cx)
1954            .unwrap();
1955        let local = (WorktreeId::from_usize(0), RelPath::empty().into_arc());
1956        store
1957            .set_local_settings(
1958                local.0,
1959                local.1.clone(),
1960                LocalSettingsKind::Settings,
1961                Some(r#"{}"#),
1962                cx,
1963            )
1964            .unwrap();
1965
1966        fn get(content: &SettingsContent) -> Option<&u32> {
1967            content
1968                .project
1969                .all_languages
1970                .defaults
1971                .preferred_line_length
1972                .as_ref()
1973        }
1974
1975        let default_value = *get(&store.default_settings).unwrap();
1976
1977        assert_eq!(
1978            store.get_value_from_file(SettingsFile::Project(local.clone()), get),
1979            (SettingsFile::User, Some(&0))
1980        );
1981        assert_eq!(
1982            store.get_value_from_file(SettingsFile::User, get),
1983            (SettingsFile::User, Some(&0))
1984        );
1985        store.set_user_settings(r#"{}"#, cx).unwrap();
1986        assert_eq!(
1987            store.get_value_from_file(SettingsFile::Project(local.clone()), get),
1988            (SettingsFile::Default, Some(&default_value))
1989        );
1990        store
1991            .set_local_settings(
1992                local.0,
1993                local.1.clone(),
1994                LocalSettingsKind::Settings,
1995                Some(r#"{"preferred_line_length": 80}"#),
1996                cx,
1997            )
1998            .unwrap();
1999        assert_eq!(
2000            store.get_value_from_file(SettingsFile::Project(local.clone()), get),
2001            (SettingsFile::Project(local), Some(&80))
2002        );
2003        assert_eq!(
2004            store.get_value_from_file(SettingsFile::User, get),
2005            (SettingsFile::Default, Some(&default_value))
2006        );
2007    }
2008
2009    #[gpui::test]
2010    fn test_get_value_for_field_local_worktrees_dont_interfere(cx: &mut App) {
2011        let mut store = SettingsStore::new(cx, &test_settings());
2012        store.register_setting::<DefaultLanguageSettings>();
2013        store.register_setting::<AutoUpdateSetting>();
2014
2015        let local_1 = (WorktreeId::from_usize(0), RelPath::empty().into_arc());
2016
2017        let local_1_child = (
2018            WorktreeId::from_usize(0),
2019            RelPath::new(
2020                std::path::Path::new("child1"),
2021                util::paths::PathStyle::Posix,
2022            )
2023            .unwrap()
2024            .into_arc(),
2025        );
2026
2027        let local_2 = (WorktreeId::from_usize(1), RelPath::empty().into_arc());
2028        let local_2_child = (
2029            WorktreeId::from_usize(1),
2030            RelPath::new(
2031                std::path::Path::new("child2"),
2032                util::paths::PathStyle::Posix,
2033            )
2034            .unwrap()
2035            .into_arc(),
2036        );
2037
2038        fn get(content: &SettingsContent) -> Option<&u32> {
2039            content
2040                .project
2041                .all_languages
2042                .defaults
2043                .preferred_line_length
2044                .as_ref()
2045        }
2046
2047        store
2048            .set_local_settings(
2049                local_1.0,
2050                local_1.1.clone(),
2051                LocalSettingsKind::Settings,
2052                Some(r#"{"preferred_line_length": 1}"#),
2053                cx,
2054            )
2055            .unwrap();
2056        store
2057            .set_local_settings(
2058                local_1_child.0,
2059                local_1_child.1.clone(),
2060                LocalSettingsKind::Settings,
2061                Some(r#"{}"#),
2062                cx,
2063            )
2064            .unwrap();
2065        store
2066            .set_local_settings(
2067                local_2.0,
2068                local_2.1.clone(),
2069                LocalSettingsKind::Settings,
2070                Some(r#"{"preferred_line_length": 2}"#),
2071                cx,
2072            )
2073            .unwrap();
2074        store
2075            .set_local_settings(
2076                local_2_child.0,
2077                local_2_child.1.clone(),
2078                LocalSettingsKind::Settings,
2079                Some(r#"{}"#),
2080                cx,
2081            )
2082            .unwrap();
2083
2084        // each local child should only inherit from it's parent
2085        assert_eq!(
2086            store.get_value_from_file(SettingsFile::Project(local_2_child), get),
2087            (SettingsFile::Project(local_2), Some(&2))
2088        );
2089        assert_eq!(
2090            store.get_value_from_file(SettingsFile::Project(local_1_child.clone()), get),
2091            (SettingsFile::Project(local_1.clone()), Some(&1))
2092        );
2093
2094        // adjacent children should be treated as siblings not inherit from each other
2095        let local_1_adjacent_child = (local_1.0, rel_path("adjacent_child").into_arc());
2096        store
2097            .set_local_settings(
2098                local_1_adjacent_child.0,
2099                local_1_adjacent_child.1.clone(),
2100                LocalSettingsKind::Settings,
2101                Some(r#"{}"#),
2102                cx,
2103            )
2104            .unwrap();
2105        store
2106            .set_local_settings(
2107                local_1_child.0,
2108                local_1_child.1.clone(),
2109                LocalSettingsKind::Settings,
2110                Some(r#"{"preferred_line_length": 3}"#),
2111                cx,
2112            )
2113            .unwrap();
2114
2115        assert_eq!(
2116            store.get_value_from_file(SettingsFile::Project(local_1_adjacent_child.clone()), get),
2117            (SettingsFile::Project(local_1.clone()), Some(&1))
2118        );
2119        store
2120            .set_local_settings(
2121                local_1_adjacent_child.0,
2122                local_1_adjacent_child.1,
2123                LocalSettingsKind::Settings,
2124                Some(r#"{"preferred_line_length": 3}"#),
2125                cx,
2126            )
2127            .unwrap();
2128        store
2129            .set_local_settings(
2130                local_1_child.0,
2131                local_1_child.1.clone(),
2132                LocalSettingsKind::Settings,
2133                Some(r#"{}"#),
2134                cx,
2135            )
2136            .unwrap();
2137        assert_eq!(
2138            store.get_value_from_file(SettingsFile::Project(local_1_child), get),
2139            (SettingsFile::Project(local_1), Some(&1))
2140        );
2141    }
2142
2143    #[gpui::test]
2144    fn test_get_overrides_for_field(cx: &mut App) {
2145        let mut store = SettingsStore::new(cx, &test_settings());
2146        store.register_setting::<DefaultLanguageSettings>();
2147
2148        let wt0_root = (WorktreeId::from_usize(0), RelPath::empty().into_arc());
2149        let wt0_child1 = (WorktreeId::from_usize(0), rel_path("child1").into_arc());
2150        let wt0_child2 = (WorktreeId::from_usize(0), rel_path("child2").into_arc());
2151
2152        let wt1_root = (WorktreeId::from_usize(1), RelPath::empty().into_arc());
2153        let wt1_subdir = (WorktreeId::from_usize(1), rel_path("subdir").into_arc());
2154
2155        fn get(content: &SettingsContent) -> &Option<u32> {
2156            &content.project.all_languages.defaults.preferred_line_length
2157        }
2158
2159        store
2160            .set_user_settings(r#"{"preferred_line_length": 100}"#, cx)
2161            .unwrap();
2162
2163        store
2164            .set_local_settings(
2165                wt0_root.0,
2166                wt0_root.1.clone(),
2167                LocalSettingsKind::Settings,
2168                Some(r#"{"preferred_line_length": 80}"#),
2169                cx,
2170            )
2171            .unwrap();
2172        store
2173            .set_local_settings(
2174                wt0_child1.0,
2175                wt0_child1.1.clone(),
2176                LocalSettingsKind::Settings,
2177                Some(r#"{"preferred_line_length": 120}"#),
2178                cx,
2179            )
2180            .unwrap();
2181        store
2182            .set_local_settings(
2183                wt0_child2.0,
2184                wt0_child2.1.clone(),
2185                LocalSettingsKind::Settings,
2186                Some(r#"{}"#),
2187                cx,
2188            )
2189            .unwrap();
2190
2191        store
2192            .set_local_settings(
2193                wt1_root.0,
2194                wt1_root.1.clone(),
2195                LocalSettingsKind::Settings,
2196                Some(r#"{"preferred_line_length": 90}"#),
2197                cx,
2198            )
2199            .unwrap();
2200        store
2201            .set_local_settings(
2202                wt1_subdir.0,
2203                wt1_subdir.1.clone(),
2204                LocalSettingsKind::Settings,
2205                Some(r#"{}"#),
2206                cx,
2207            )
2208            .unwrap();
2209
2210        let overrides = store.get_overrides_for_field(SettingsFile::Default, get);
2211        assert_eq!(
2212            overrides,
2213            vec![
2214                SettingsFile::User,
2215                SettingsFile::Project(wt0_root.clone()),
2216                SettingsFile::Project(wt0_child1.clone()),
2217                SettingsFile::Project(wt1_root.clone()),
2218            ]
2219        );
2220
2221        let overrides = store.get_overrides_for_field(SettingsFile::User, get);
2222        assert_eq!(
2223            overrides,
2224            vec![
2225                SettingsFile::Project(wt0_root.clone()),
2226                SettingsFile::Project(wt0_child1.clone()),
2227                SettingsFile::Project(wt1_root.clone()),
2228            ]
2229        );
2230
2231        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt0_root), get);
2232        assert_eq!(overrides, vec![]);
2233
2234        let overrides =
2235            store.get_overrides_for_field(SettingsFile::Project(wt0_child1.clone()), get);
2236        assert_eq!(overrides, vec![]);
2237
2238        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt0_child2), get);
2239        assert_eq!(overrides, vec![]);
2240
2241        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt1_root), get);
2242        assert_eq!(overrides, vec![]);
2243
2244        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt1_subdir), get);
2245        assert_eq!(overrides, vec![]);
2246
2247        let wt0_deep_child = (
2248            WorktreeId::from_usize(0),
2249            rel_path("child1/subdir").into_arc(),
2250        );
2251        store
2252            .set_local_settings(
2253                wt0_deep_child.0,
2254                wt0_deep_child.1.clone(),
2255                LocalSettingsKind::Settings,
2256                Some(r#"{"preferred_line_length": 140}"#),
2257                cx,
2258            )
2259            .unwrap();
2260
2261        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt0_deep_child), get);
2262        assert_eq!(overrides, vec![]);
2263
2264        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt0_child1), get);
2265        assert_eq!(overrides, vec![]);
2266    }
2267
2268    #[test]
2269    fn test_file_ord() {
2270        let wt0_root =
2271            SettingsFile::Project((WorktreeId::from_usize(0), RelPath::empty().into_arc()));
2272        let wt0_child1 =
2273            SettingsFile::Project((WorktreeId::from_usize(0), rel_path("child1").into_arc()));
2274        let wt0_child2 =
2275            SettingsFile::Project((WorktreeId::from_usize(0), rel_path("child2").into_arc()));
2276
2277        let wt1_root =
2278            SettingsFile::Project((WorktreeId::from_usize(1), RelPath::empty().into_arc()));
2279        let wt1_subdir =
2280            SettingsFile::Project((WorktreeId::from_usize(1), rel_path("subdir").into_arc()));
2281
2282        let mut files = vec![
2283            &wt1_root,
2284            &SettingsFile::Default,
2285            &wt0_root,
2286            &wt1_subdir,
2287            &wt0_child2,
2288            &SettingsFile::Server,
2289            &wt0_child1,
2290            &SettingsFile::User,
2291        ];
2292
2293        files.sort();
2294        pretty_assertions::assert_eq!(
2295            files,
2296            vec![
2297                &wt0_child2,
2298                &wt0_child1,
2299                &wt0_root,
2300                &wt1_subdir,
2301                &wt1_root,
2302                &SettingsFile::Server,
2303                &SettingsFile::User,
2304                &SettingsFile::Default,
2305            ]
2306        )
2307    }
2308}