settings_store.rs

   1use anyhow::{Context as _, Result};
   2use collections::{BTreeMap, HashMap, btree_map, hash_map};
   3use ec4rs::{ConfigParser, PropertiesSource, Section};
   4use fs::Fs;
   5use futures::{
   6    FutureExt, StreamExt,
   7    channel::{mpsc, oneshot},
   8    future::LocalBoxFuture,
   9};
  10use gpui::{App, AsyncApp, BorrowAppContext, Global, SharedString, Task, UpdateGlobal};
  11
  12use paths::{EDITORCONFIG_NAME, local_settings_file_relative_path, task_file_name};
  13use schemars::{JsonSchema, json_schema};
  14use serde_json::Value;
  15use smallvec::SmallVec;
  16use std::{
  17    any::{Any, TypeId, type_name},
  18    fmt::Debug,
  19    ops::Range,
  20    path::PathBuf,
  21    rc::Rc,
  22    str::{self, FromStr},
  23    sync::Arc,
  24};
  25use util::{
  26    ResultExt as _,
  27    rel_path::RelPath,
  28    schemars::{AllowTrailingCommas, DefaultDenyUnknownFields, replace_subschema},
  29};
  30
  31pub type EditorconfigProperties = ec4rs::Properties;
  32
  33use crate::{
  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            .with_transform(AllowTrailingCommas)
1014            .into_generator();
1015
1016        UserSettingsContent::json_schema(&mut generator);
1017
1018        let language_settings_content_ref = generator
1019            .subschema_for::<LanguageSettingsContent>()
1020            .to_value();
1021
1022        replace_subschema::<LanguageToSettingsMap>(&mut generator, || {
1023            json_schema!({
1024                "type": "object",
1025                "properties": params
1026                    .language_names
1027                    .iter()
1028                    .map(|name| {
1029                        (
1030                            name.clone(),
1031                            language_settings_content_ref.clone(),
1032                        )
1033                    })
1034                    .collect::<serde_json::Map<_, _>>(),
1035                "errorMessage": "No language with this name is installed."
1036            })
1037        });
1038
1039        replace_subschema::<FontFamilyName>(&mut generator, || {
1040            json_schema!({
1041                "type": "string",
1042                "enum": params.font_names,
1043            })
1044        });
1045
1046        replace_subschema::<ThemeName>(&mut generator, || {
1047            json_schema!({
1048                "type": "string",
1049                "enum": params.theme_names,
1050            })
1051        });
1052
1053        replace_subschema::<IconThemeName>(&mut generator, || {
1054            json_schema!({
1055                "type": "string",
1056                "enum": params.icon_theme_names,
1057            })
1058        });
1059
1060        generator
1061            .root_schema_for::<UserSettingsContent>()
1062            .to_value()
1063    }
1064
1065    fn recompute_values(
1066        &mut self,
1067        changed_local_path: Option<(WorktreeId, &RelPath)>,
1068        cx: &mut App,
1069    ) {
1070        // Reload the global and local values for every setting.
1071        let mut project_settings_stack = Vec::<SettingsContent>::new();
1072        let mut paths_stack = Vec::<Option<(WorktreeId, &RelPath)>>::new();
1073
1074        if changed_local_path.is_none() {
1075            let mut merged = self.default_settings.as_ref().clone();
1076            merged.merge_from_option(self.extension_settings.as_deref());
1077            merged.merge_from_option(self.global_settings.as_deref());
1078            if let Some(user_settings) = self.user_settings.as_ref() {
1079                merged.merge_from(&user_settings.content);
1080                merged.merge_from_option(user_settings.for_release_channel());
1081                merged.merge_from_option(user_settings.for_os());
1082                merged.merge_from_option(user_settings.for_profile(cx));
1083            }
1084            merged.merge_from_option(self.server_settings.as_deref());
1085            self.merged_settings = Rc::new(merged);
1086
1087            for setting_value in self.setting_values.values_mut() {
1088                let value = setting_value.from_settings(&self.merged_settings);
1089                setting_value.set_global_value(value);
1090            }
1091        }
1092
1093        for ((root_id, directory_path), local_settings) in &self.local_settings {
1094            // Build a stack of all of the local values for that setting.
1095            while let Some(prev_entry) = paths_stack.last() {
1096                if let Some((prev_root_id, prev_path)) = prev_entry
1097                    && (root_id != prev_root_id || !directory_path.starts_with(prev_path))
1098                {
1099                    paths_stack.pop();
1100                    project_settings_stack.pop();
1101                    continue;
1102                }
1103                break;
1104            }
1105
1106            paths_stack.push(Some((*root_id, directory_path.as_ref())));
1107            let mut merged_local_settings = if let Some(deepest) = project_settings_stack.last() {
1108                (*deepest).clone()
1109            } else {
1110                self.merged_settings.as_ref().clone()
1111            };
1112            merged_local_settings.merge_from(local_settings);
1113
1114            project_settings_stack.push(merged_local_settings);
1115
1116            // If a local settings file changed, then avoid recomputing local
1117            // settings for any path outside of that directory.
1118            if changed_local_path.is_some_and(|(changed_root_id, changed_local_path)| {
1119                *root_id != changed_root_id || !directory_path.starts_with(changed_local_path)
1120            }) {
1121                continue;
1122            }
1123
1124            for setting_value in self.setting_values.values_mut() {
1125                let value = setting_value.from_settings(&project_settings_stack.last().unwrap());
1126                setting_value.set_local_value(*root_id, directory_path.clone(), value);
1127            }
1128        }
1129    }
1130
1131    pub fn editorconfig_properties(
1132        &self,
1133        for_worktree: WorktreeId,
1134        for_path: &RelPath,
1135    ) -> Option<EditorconfigProperties> {
1136        let mut properties = EditorconfigProperties::new();
1137
1138        for (directory_with_config, _, parsed_editorconfig) in
1139            self.local_editorconfig_settings(for_worktree)
1140        {
1141            if !for_path.starts_with(&directory_with_config) {
1142                properties.use_fallbacks();
1143                return Some(properties);
1144            }
1145            let parsed_editorconfig = parsed_editorconfig?;
1146            if parsed_editorconfig.is_root {
1147                properties = EditorconfigProperties::new();
1148            }
1149            for section in parsed_editorconfig.sections {
1150                section
1151                    .apply_to(&mut properties, for_path.as_std_path())
1152                    .log_err()?;
1153            }
1154        }
1155
1156        properties.use_fallbacks();
1157        Some(properties)
1158    }
1159}
1160
1161/// The result of parsing settings, including any migration attempts
1162#[derive(Debug, Clone, PartialEq, Eq)]
1163pub struct SettingsParseResult {
1164    /// The result of parsing the settings file (possibly after migration)
1165    pub parse_status: ParseStatus,
1166    /// The result of attempting to migrate the settings file
1167    pub migration_status: MigrationStatus,
1168}
1169
1170#[derive(Debug, Clone, PartialEq, Eq)]
1171pub enum ParseStatus {
1172    /// Settings were parsed successfully
1173    Success,
1174    /// Settings failed to parse
1175    Failed { error: String },
1176}
1177
1178#[derive(Debug, Clone, PartialEq, Eq)]
1179pub enum MigrationStatus {
1180    /// No migration was needed - settings are up to date
1181    NotNeeded,
1182    /// Settings were automatically migrated in memory, but the file needs to be updated
1183    Succeeded,
1184    /// Migration was attempted but failed. Original settings were parsed instead.
1185    Failed { error: String },
1186}
1187
1188impl Default for SettingsParseResult {
1189    fn default() -> Self {
1190        Self {
1191            parse_status: ParseStatus::Success,
1192            migration_status: MigrationStatus::NotNeeded,
1193        }
1194    }
1195}
1196
1197impl SettingsParseResult {
1198    pub fn unwrap(self) -> bool {
1199        self.result().unwrap()
1200    }
1201
1202    pub fn expect(self, message: &str) -> bool {
1203        self.result().expect(message)
1204    }
1205
1206    /// Formats the ParseResult as a Result type. This is a lossy conversion
1207    pub fn result(self) -> Result<bool> {
1208        let migration_result = match self.migration_status {
1209            MigrationStatus::NotNeeded => Ok(false),
1210            MigrationStatus::Succeeded => Ok(true),
1211            MigrationStatus::Failed { error } => {
1212                Err(anyhow::format_err!(error)).context("Failed to migrate settings")
1213            }
1214        };
1215
1216        let parse_result = match self.parse_status {
1217            ParseStatus::Success => Ok(()),
1218            ParseStatus::Failed { error } => {
1219                Err(anyhow::format_err!(error)).context("Failed to parse settings")
1220            }
1221        };
1222
1223        match (migration_result, parse_result) {
1224            (migration_result @ Ok(_), Ok(())) => migration_result,
1225            (Err(migration_err), Ok(())) => Err(migration_err),
1226            (_, Err(parse_err)) => Err(parse_err),
1227        }
1228    }
1229
1230    /// Returns true if there were any errors migrating and parsing the settings content or if migration was required but there were no errors
1231    pub fn requires_user_action(&self) -> bool {
1232        matches!(self.parse_status, ParseStatus::Failed { .. })
1233            || matches!(
1234                self.migration_status,
1235                MigrationStatus::Succeeded | MigrationStatus::Failed { .. }
1236            )
1237    }
1238
1239    pub fn ok(self) -> Option<bool> {
1240        self.result().ok()
1241    }
1242
1243    pub fn parse_error(&self) -> Option<String> {
1244        match &self.parse_status {
1245            ParseStatus::Failed { error } => Some(error.clone()),
1246            ParseStatus::Success => None,
1247        }
1248    }
1249}
1250
1251#[derive(Debug, Clone, PartialEq)]
1252pub enum InvalidSettingsError {
1253    LocalSettings { path: Arc<RelPath>, message: String },
1254    UserSettings { message: String },
1255    ServerSettings { message: String },
1256    DefaultSettings { message: String },
1257    Editorconfig { path: Arc<RelPath>, message: String },
1258    Tasks { path: PathBuf, message: String },
1259    Debug { path: PathBuf, message: String },
1260}
1261
1262impl std::fmt::Display for InvalidSettingsError {
1263    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1264        match self {
1265            InvalidSettingsError::LocalSettings { message, .. }
1266            | InvalidSettingsError::UserSettings { message }
1267            | InvalidSettingsError::ServerSettings { message }
1268            | InvalidSettingsError::DefaultSettings { message }
1269            | InvalidSettingsError::Tasks { message, .. }
1270            | InvalidSettingsError::Editorconfig { message, .. }
1271            | InvalidSettingsError::Debug { message, .. } => {
1272                write!(f, "{message}")
1273            }
1274        }
1275    }
1276}
1277impl std::error::Error for InvalidSettingsError {}
1278
1279impl Debug for SettingsStore {
1280    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1281        f.debug_struct("SettingsStore")
1282            .field(
1283                "types",
1284                &self
1285                    .setting_values
1286                    .values()
1287                    .map(|value| value.setting_type_name())
1288                    .collect::<Vec<_>>(),
1289            )
1290            .field("default_settings", &self.default_settings)
1291            .field("user_settings", &self.user_settings)
1292            .field("local_settings", &self.local_settings)
1293            .finish_non_exhaustive()
1294    }
1295}
1296
1297impl<T: Settings> AnySettingValue for SettingValue<T> {
1298    fn from_settings(&self, s: &SettingsContent) -> Box<dyn Any> {
1299        Box::new(T::from_settings(s)) as _
1300    }
1301
1302    fn setting_type_name(&self) -> &'static str {
1303        type_name::<T>()
1304    }
1305
1306    fn all_local_values(&self) -> Vec<(WorktreeId, Arc<RelPath>, &dyn Any)> {
1307        self.local_values
1308            .iter()
1309            .map(|(id, path, value)| (*id, path.clone(), value as _))
1310            .collect()
1311    }
1312
1313    fn value_for_path(&self, path: Option<SettingsLocation>) -> &dyn Any {
1314        if let Some(SettingsLocation { worktree_id, path }) = path {
1315            for (settings_root_id, settings_path, value) in self.local_values.iter().rev() {
1316                if worktree_id == *settings_root_id && path.starts_with(settings_path) {
1317                    return value;
1318                }
1319            }
1320        }
1321
1322        self.global_value
1323            .as_ref()
1324            .unwrap_or_else(|| panic!("no default value for setting {}", self.setting_type_name()))
1325    }
1326
1327    fn set_global_value(&mut self, value: Box<dyn Any>) {
1328        self.global_value = Some(*value.downcast().unwrap());
1329    }
1330
1331    fn set_local_value(&mut self, root_id: WorktreeId, path: Arc<RelPath>, value: Box<dyn Any>) {
1332        let value = *value.downcast().unwrap();
1333        match self
1334            .local_values
1335            .binary_search_by_key(&(root_id, &path), |e| (e.0, &e.1))
1336        {
1337            Ok(ix) => self.local_values[ix].2 = value,
1338            Err(ix) => self.local_values.insert(ix, (root_id, path, value)),
1339        }
1340    }
1341}
1342
1343#[cfg(test)]
1344mod tests {
1345    use std::num::NonZeroU32;
1346
1347    use crate::{
1348        ClosePosition, ItemSettingsContent, VsCodeSettingsSource, default_settings,
1349        settings_content::LanguageSettingsContent, test_settings,
1350    };
1351
1352    use super::*;
1353    use unindent::Unindent;
1354    use util::rel_path::rel_path;
1355
1356    #[derive(Debug, PartialEq)]
1357    struct AutoUpdateSetting {
1358        auto_update: bool,
1359    }
1360
1361    impl Settings for AutoUpdateSetting {
1362        fn from_settings(content: &SettingsContent) -> Self {
1363            AutoUpdateSetting {
1364                auto_update: content.auto_update.unwrap(),
1365            }
1366        }
1367    }
1368
1369    #[derive(Debug, PartialEq)]
1370    struct ItemSettings {
1371        close_position: ClosePosition,
1372        git_status: bool,
1373    }
1374
1375    impl Settings for ItemSettings {
1376        fn from_settings(content: &SettingsContent) -> Self {
1377            let content = content.tabs.clone().unwrap();
1378            ItemSettings {
1379                close_position: content.close_position.unwrap(),
1380                git_status: content.git_status.unwrap(),
1381            }
1382        }
1383    }
1384
1385    #[derive(Debug, PartialEq)]
1386    struct DefaultLanguageSettings {
1387        tab_size: NonZeroU32,
1388        preferred_line_length: u32,
1389    }
1390
1391    impl Settings for DefaultLanguageSettings {
1392        fn from_settings(content: &SettingsContent) -> Self {
1393            let content = &content.project.all_languages.defaults;
1394            DefaultLanguageSettings {
1395                tab_size: content.tab_size.unwrap(),
1396                preferred_line_length: content.preferred_line_length.unwrap(),
1397            }
1398        }
1399    }
1400
1401    #[derive(Debug, PartialEq)]
1402    struct ThemeSettings {
1403        buffer_font_family: FontFamilyName,
1404        buffer_font_fallbacks: Vec<FontFamilyName>,
1405    }
1406
1407    impl Settings for ThemeSettings {
1408        fn from_settings(content: &SettingsContent) -> Self {
1409            let content = content.theme.clone();
1410            ThemeSettings {
1411                buffer_font_family: content.buffer_font_family.unwrap(),
1412                buffer_font_fallbacks: content.buffer_font_fallbacks.unwrap(),
1413            }
1414        }
1415    }
1416
1417    #[gpui::test]
1418    fn test_settings_store_basic(cx: &mut App) {
1419        let mut store = SettingsStore::new(cx, &default_settings());
1420        store.register_setting::<AutoUpdateSetting>();
1421        store.register_setting::<ItemSettings>();
1422        store.register_setting::<DefaultLanguageSettings>();
1423
1424        assert_eq!(
1425            store.get::<AutoUpdateSetting>(None),
1426            &AutoUpdateSetting { auto_update: true }
1427        );
1428        assert_eq!(
1429            store.get::<ItemSettings>(None).close_position,
1430            ClosePosition::Right
1431        );
1432
1433        store
1434            .set_user_settings(
1435                r#"{
1436                    "auto_update": false,
1437                    "tabs": {
1438                      "close_position": "left"
1439                    }
1440                }"#,
1441                cx,
1442            )
1443            .unwrap();
1444
1445        assert_eq!(
1446            store.get::<AutoUpdateSetting>(None),
1447            &AutoUpdateSetting { auto_update: false }
1448        );
1449        assert_eq!(
1450            store.get::<ItemSettings>(None).close_position,
1451            ClosePosition::Left
1452        );
1453
1454        store
1455            .set_local_settings(
1456                WorktreeId::from_usize(1),
1457                rel_path("root1").into(),
1458                LocalSettingsKind::Settings,
1459                Some(r#"{ "tab_size": 5 }"#),
1460                cx,
1461            )
1462            .unwrap();
1463        store
1464            .set_local_settings(
1465                WorktreeId::from_usize(1),
1466                rel_path("root1/subdir").into(),
1467                LocalSettingsKind::Settings,
1468                Some(r#"{ "preferred_line_length": 50 }"#),
1469                cx,
1470            )
1471            .unwrap();
1472
1473        store
1474            .set_local_settings(
1475                WorktreeId::from_usize(1),
1476                rel_path("root2").into(),
1477                LocalSettingsKind::Settings,
1478                Some(r#"{ "tab_size": 9, "auto_update": true}"#),
1479                cx,
1480            )
1481            .unwrap();
1482
1483        assert_eq!(
1484            store.get::<DefaultLanguageSettings>(Some(SettingsLocation {
1485                worktree_id: WorktreeId::from_usize(1),
1486                path: rel_path("root1/something"),
1487            })),
1488            &DefaultLanguageSettings {
1489                preferred_line_length: 80,
1490                tab_size: 5.try_into().unwrap(),
1491            }
1492        );
1493        assert_eq!(
1494            store.get::<DefaultLanguageSettings>(Some(SettingsLocation {
1495                worktree_id: WorktreeId::from_usize(1),
1496                path: rel_path("root1/subdir/something"),
1497            })),
1498            &DefaultLanguageSettings {
1499                preferred_line_length: 50,
1500                tab_size: 5.try_into().unwrap(),
1501            }
1502        );
1503        assert_eq!(
1504            store.get::<DefaultLanguageSettings>(Some(SettingsLocation {
1505                worktree_id: WorktreeId::from_usize(1),
1506                path: rel_path("root2/something"),
1507            })),
1508            &DefaultLanguageSettings {
1509                preferred_line_length: 80,
1510                tab_size: 9.try_into().unwrap(),
1511            }
1512        );
1513        assert_eq!(
1514            store.get::<AutoUpdateSetting>(Some(SettingsLocation {
1515                worktree_id: WorktreeId::from_usize(1),
1516                path: rel_path("root2/something")
1517            })),
1518            &AutoUpdateSetting { auto_update: false }
1519        );
1520    }
1521
1522    #[gpui::test]
1523    fn test_setting_store_assign_json_before_register(cx: &mut App) {
1524        let mut store = SettingsStore::new(cx, &test_settings());
1525        store
1526            .set_user_settings(r#"{ "auto_update": false }"#, cx)
1527            .unwrap();
1528        store.register_setting::<AutoUpdateSetting>();
1529
1530        assert_eq!(
1531            store.get::<AutoUpdateSetting>(None),
1532            &AutoUpdateSetting { auto_update: false }
1533        );
1534    }
1535
1536    #[track_caller]
1537    fn check_settings_update(
1538        store: &mut SettingsStore,
1539        old_json: String,
1540        update: fn(&mut SettingsContent),
1541        expected_new_json: String,
1542        cx: &mut App,
1543    ) {
1544        store.set_user_settings(&old_json, cx).ok();
1545        let edits = store.edits_for_update(&old_json, update);
1546        let mut new_json = old_json;
1547        for (range, replacement) in edits.into_iter() {
1548            new_json.replace_range(range, &replacement);
1549        }
1550        pretty_assertions::assert_eq!(new_json, expected_new_json);
1551    }
1552
1553    #[gpui::test]
1554    fn test_setting_store_update(cx: &mut App) {
1555        let mut store = SettingsStore::new(cx, &test_settings());
1556
1557        // entries added and updated
1558        check_settings_update(
1559            &mut store,
1560            r#"{
1561                "languages": {
1562                    "JSON": {
1563                        "auto_indent": true
1564                    }
1565                }
1566            }"#
1567            .unindent(),
1568            |settings| {
1569                settings
1570                    .languages_mut()
1571                    .get_mut("JSON")
1572                    .unwrap()
1573                    .auto_indent = Some(false);
1574
1575                settings.languages_mut().insert(
1576                    "Rust".into(),
1577                    LanguageSettingsContent {
1578                        auto_indent: Some(true),
1579                        ..Default::default()
1580                    },
1581                );
1582            },
1583            r#"{
1584                "languages": {
1585                    "Rust": {
1586                        "auto_indent": true
1587                    },
1588                    "JSON": {
1589                        "auto_indent": false
1590                    }
1591                }
1592            }"#
1593            .unindent(),
1594            cx,
1595        );
1596
1597        // entries removed
1598        check_settings_update(
1599            &mut store,
1600            r#"{
1601                "languages": {
1602                    "Rust": {
1603                        "language_setting_2": true
1604                    },
1605                    "JSON": {
1606                        "language_setting_1": false
1607                    }
1608                }
1609            }"#
1610            .unindent(),
1611            |settings| {
1612                settings.languages_mut().remove("JSON").unwrap();
1613            },
1614            r#"{
1615                "languages": {
1616                    "Rust": {
1617                        "language_setting_2": true
1618                    }
1619                }
1620            }"#
1621            .unindent(),
1622            cx,
1623        );
1624
1625        check_settings_update(
1626            &mut store,
1627            r#"{
1628                "languages": {
1629                    "Rust": {
1630                        "language_setting_2": true
1631                    },
1632                    "JSON": {
1633                        "language_setting_1": false
1634                    }
1635                }
1636            }"#
1637            .unindent(),
1638            |settings| {
1639                settings.languages_mut().remove("Rust").unwrap();
1640            },
1641            r#"{
1642                "languages": {
1643                    "JSON": {
1644                        "language_setting_1": false
1645                    }
1646                }
1647            }"#
1648            .unindent(),
1649            cx,
1650        );
1651
1652        // weird formatting
1653        check_settings_update(
1654            &mut store,
1655            r#"{
1656                "tabs":   { "close_position": "left", "name": "Max"  }
1657                }"#
1658            .unindent(),
1659            |settings| {
1660                settings.tabs.as_mut().unwrap().close_position = Some(ClosePosition::Left);
1661            },
1662            r#"{
1663                "tabs":   { "close_position": "left", "name": "Max"  }
1664                }"#
1665            .unindent(),
1666            cx,
1667        );
1668
1669        // single-line formatting, other keys
1670        check_settings_update(
1671            &mut store,
1672            r#"{ "one": 1, "two": 2 }"#.to_owned(),
1673            |settings| settings.auto_update = Some(true),
1674            r#"{ "auto_update": true, "one": 1, "two": 2 }"#.to_owned(),
1675            cx,
1676        );
1677
1678        // empty object
1679        check_settings_update(
1680            &mut store,
1681            r#"{
1682                "tabs": {}
1683            }"#
1684            .unindent(),
1685            |settings| settings.tabs.as_mut().unwrap().close_position = Some(ClosePosition::Left),
1686            r#"{
1687                "tabs": {
1688                    "close_position": "left"
1689                }
1690            }"#
1691            .unindent(),
1692            cx,
1693        );
1694
1695        // no content
1696        check_settings_update(
1697            &mut store,
1698            r#""#.unindent(),
1699            |settings| {
1700                settings.tabs = Some(ItemSettingsContent {
1701                    git_status: Some(true),
1702                    ..Default::default()
1703                })
1704            },
1705            r#"{
1706              "tabs": {
1707                "git_status": true
1708              }
1709            }
1710            "#
1711            .unindent(),
1712            cx,
1713        );
1714
1715        check_settings_update(
1716            &mut store,
1717            r#"{
1718            }
1719            "#
1720            .unindent(),
1721            |settings| settings.title_bar.get_or_insert_default().show_branch_name = Some(true),
1722            r#"{
1723              "title_bar": {
1724                "show_branch_name": true
1725              }
1726            }
1727            "#
1728            .unindent(),
1729            cx,
1730        );
1731    }
1732
1733    #[gpui::test]
1734    fn test_vscode_import(cx: &mut App) {
1735        let mut store = SettingsStore::new(cx, &test_settings());
1736        store.register_setting::<DefaultLanguageSettings>();
1737        store.register_setting::<ItemSettings>();
1738        store.register_setting::<AutoUpdateSetting>();
1739        store.register_setting::<ThemeSettings>();
1740
1741        // create settings that werent present
1742        check_vscode_import(
1743            &mut store,
1744            r#"{
1745            }
1746            "#
1747            .unindent(),
1748            r#" { "editor.tabSize": 37 } "#.to_owned(),
1749            r#"{
1750              "base_keymap": "VSCode",
1751              "tab_size": 37
1752            }
1753            "#
1754            .unindent(),
1755            cx,
1756        );
1757
1758        // persist settings that were present
1759        check_vscode_import(
1760            &mut store,
1761            r#"{
1762                "preferred_line_length": 99,
1763            }
1764            "#
1765            .unindent(),
1766            r#"{ "editor.tabSize": 42 }"#.to_owned(),
1767            r#"{
1768                "base_keymap": "VSCode",
1769                "tab_size": 42,
1770                "preferred_line_length": 99,
1771            }
1772            "#
1773            .unindent(),
1774            cx,
1775        );
1776
1777        // don't clobber settings that aren't present in vscode
1778        check_vscode_import(
1779            &mut store,
1780            r#"{
1781                "preferred_line_length": 99,
1782                "tab_size": 42
1783            }
1784            "#
1785            .unindent(),
1786            r#"{}"#.to_owned(),
1787            r#"{
1788                "base_keymap": "VSCode",
1789                "preferred_line_length": 99,
1790                "tab_size": 42
1791            }
1792            "#
1793            .unindent(),
1794            cx,
1795        );
1796
1797        // custom enum
1798        check_vscode_import(
1799            &mut store,
1800            r#"{
1801            }
1802            "#
1803            .unindent(),
1804            r#"{ "git.decorations.enabled": true }"#.to_owned(),
1805            r#"{
1806              "project_panel": {
1807                "git_status": true
1808              },
1809              "outline_panel": {
1810                "git_status": true
1811              },
1812              "base_keymap": "VSCode",
1813              "tabs": {
1814                "git_status": true
1815              }
1816            }
1817            "#
1818            .unindent(),
1819            cx,
1820        );
1821
1822        // font-family
1823        check_vscode_import(
1824            &mut store,
1825            r#"{
1826            }
1827            "#
1828            .unindent(),
1829            r#"{ "editor.fontFamily": "Cascadia Code, 'Consolas', Courier New" }"#.to_owned(),
1830            r#"{
1831              "base_keymap": "VSCode",
1832              "buffer_font_fallbacks": [
1833                "Consolas",
1834                "Courier New"
1835              ],
1836              "buffer_font_family": "Cascadia Code"
1837            }
1838            "#
1839            .unindent(),
1840            cx,
1841        );
1842    }
1843
1844    #[track_caller]
1845    fn check_vscode_import(
1846        store: &mut SettingsStore,
1847        old: String,
1848        vscode: String,
1849        expected: String,
1850        cx: &mut App,
1851    ) {
1852        store.set_user_settings(&old, cx).ok();
1853        let new = store.get_vscode_edits(
1854            old,
1855            &VsCodeSettings::from_str(&vscode, VsCodeSettingsSource::VsCode).unwrap(),
1856        );
1857        pretty_assertions::assert_eq!(new, expected);
1858    }
1859
1860    #[gpui::test]
1861    fn test_update_git_settings(cx: &mut App) {
1862        let store = SettingsStore::new(cx, &test_settings());
1863
1864        let actual = store.new_text_for_update("{}".to_string(), |current| {
1865            current
1866                .git
1867                .get_or_insert_default()
1868                .inline_blame
1869                .get_or_insert_default()
1870                .enabled = Some(true);
1871        });
1872        pretty_assertions::assert_str_eq!(
1873            actual,
1874            r#"{
1875              "git": {
1876                "inline_blame": {
1877                  "enabled": true
1878                }
1879              }
1880            }
1881            "#
1882            .unindent()
1883        );
1884    }
1885
1886    #[gpui::test]
1887    fn test_global_settings(cx: &mut App) {
1888        let mut store = SettingsStore::new(cx, &test_settings());
1889        store.register_setting::<ItemSettings>();
1890
1891        // Set global settings - these should override defaults but not user settings
1892        store
1893            .set_global_settings(
1894                r#"{
1895                    "tabs": {
1896                        "close_position": "right",
1897                        "git_status": true,
1898                    }
1899                }"#,
1900                cx,
1901            )
1902            .unwrap();
1903
1904        // Before user settings, global settings should apply
1905        assert_eq!(
1906            store.get::<ItemSettings>(None),
1907            &ItemSettings {
1908                close_position: ClosePosition::Right,
1909                git_status: true,
1910            }
1911        );
1912
1913        // Set user settings - these should override both defaults and global
1914        store
1915            .set_user_settings(
1916                r#"{
1917                    "tabs": {
1918                        "close_position": "left"
1919                    }
1920                }"#,
1921                cx,
1922            )
1923            .unwrap();
1924
1925        // User settings should override global settings
1926        assert_eq!(
1927            store.get::<ItemSettings>(None),
1928            &ItemSettings {
1929                close_position: ClosePosition::Left,
1930                git_status: true, // Staff from global settings
1931            }
1932        );
1933    }
1934
1935    #[gpui::test]
1936    fn test_get_value_for_field_basic(cx: &mut App) {
1937        let mut store = SettingsStore::new(cx, &test_settings());
1938        store.register_setting::<DefaultLanguageSettings>();
1939
1940        store
1941            .set_user_settings(r#"{"preferred_line_length": 0}"#, cx)
1942            .unwrap();
1943        let local = (WorktreeId::from_usize(0), RelPath::empty().into_arc());
1944        store
1945            .set_local_settings(
1946                local.0,
1947                local.1.clone(),
1948                LocalSettingsKind::Settings,
1949                Some(r#"{}"#),
1950                cx,
1951            )
1952            .unwrap();
1953
1954        fn get(content: &SettingsContent) -> Option<&u32> {
1955            content
1956                .project
1957                .all_languages
1958                .defaults
1959                .preferred_line_length
1960                .as_ref()
1961        }
1962
1963        let default_value = *get(&store.default_settings).unwrap();
1964
1965        assert_eq!(
1966            store.get_value_from_file(SettingsFile::Project(local.clone()), get),
1967            (SettingsFile::User, Some(&0))
1968        );
1969        assert_eq!(
1970            store.get_value_from_file(SettingsFile::User, get),
1971            (SettingsFile::User, Some(&0))
1972        );
1973        store.set_user_settings(r#"{}"#, cx).unwrap();
1974        assert_eq!(
1975            store.get_value_from_file(SettingsFile::Project(local.clone()), get),
1976            (SettingsFile::Default, Some(&default_value))
1977        );
1978        store
1979            .set_local_settings(
1980                local.0,
1981                local.1.clone(),
1982                LocalSettingsKind::Settings,
1983                Some(r#"{"preferred_line_length": 80}"#),
1984                cx,
1985            )
1986            .unwrap();
1987        assert_eq!(
1988            store.get_value_from_file(SettingsFile::Project(local.clone()), get),
1989            (SettingsFile::Project(local), Some(&80))
1990        );
1991        assert_eq!(
1992            store.get_value_from_file(SettingsFile::User, get),
1993            (SettingsFile::Default, Some(&default_value))
1994        );
1995    }
1996
1997    #[gpui::test]
1998    fn test_get_value_for_field_local_worktrees_dont_interfere(cx: &mut App) {
1999        let mut store = SettingsStore::new(cx, &test_settings());
2000        store.register_setting::<DefaultLanguageSettings>();
2001        store.register_setting::<AutoUpdateSetting>();
2002
2003        let local_1 = (WorktreeId::from_usize(0), RelPath::empty().into_arc());
2004
2005        let local_1_child = (
2006            WorktreeId::from_usize(0),
2007            RelPath::new(
2008                std::path::Path::new("child1"),
2009                util::paths::PathStyle::Posix,
2010            )
2011            .unwrap()
2012            .into_arc(),
2013        );
2014
2015        let local_2 = (WorktreeId::from_usize(1), RelPath::empty().into_arc());
2016        let local_2_child = (
2017            WorktreeId::from_usize(1),
2018            RelPath::new(
2019                std::path::Path::new("child2"),
2020                util::paths::PathStyle::Posix,
2021            )
2022            .unwrap()
2023            .into_arc(),
2024        );
2025
2026        fn get(content: &SettingsContent) -> Option<&u32> {
2027            content
2028                .project
2029                .all_languages
2030                .defaults
2031                .preferred_line_length
2032                .as_ref()
2033        }
2034
2035        store
2036            .set_local_settings(
2037                local_1.0,
2038                local_1.1.clone(),
2039                LocalSettingsKind::Settings,
2040                Some(r#"{"preferred_line_length": 1}"#),
2041                cx,
2042            )
2043            .unwrap();
2044        store
2045            .set_local_settings(
2046                local_1_child.0,
2047                local_1_child.1.clone(),
2048                LocalSettingsKind::Settings,
2049                Some(r#"{}"#),
2050                cx,
2051            )
2052            .unwrap();
2053        store
2054            .set_local_settings(
2055                local_2.0,
2056                local_2.1.clone(),
2057                LocalSettingsKind::Settings,
2058                Some(r#"{"preferred_line_length": 2}"#),
2059                cx,
2060            )
2061            .unwrap();
2062        store
2063            .set_local_settings(
2064                local_2_child.0,
2065                local_2_child.1.clone(),
2066                LocalSettingsKind::Settings,
2067                Some(r#"{}"#),
2068                cx,
2069            )
2070            .unwrap();
2071
2072        // each local child should only inherit from it's parent
2073        assert_eq!(
2074            store.get_value_from_file(SettingsFile::Project(local_2_child), get),
2075            (SettingsFile::Project(local_2), Some(&2))
2076        );
2077        assert_eq!(
2078            store.get_value_from_file(SettingsFile::Project(local_1_child.clone()), get),
2079            (SettingsFile::Project(local_1.clone()), Some(&1))
2080        );
2081
2082        // adjacent children should be treated as siblings not inherit from each other
2083        let local_1_adjacent_child = (local_1.0, rel_path("adjacent_child").into_arc());
2084        store
2085            .set_local_settings(
2086                local_1_adjacent_child.0,
2087                local_1_adjacent_child.1.clone(),
2088                LocalSettingsKind::Settings,
2089                Some(r#"{}"#),
2090                cx,
2091            )
2092            .unwrap();
2093        store
2094            .set_local_settings(
2095                local_1_child.0,
2096                local_1_child.1.clone(),
2097                LocalSettingsKind::Settings,
2098                Some(r#"{"preferred_line_length": 3}"#),
2099                cx,
2100            )
2101            .unwrap();
2102
2103        assert_eq!(
2104            store.get_value_from_file(SettingsFile::Project(local_1_adjacent_child.clone()), get),
2105            (SettingsFile::Project(local_1.clone()), Some(&1))
2106        );
2107        store
2108            .set_local_settings(
2109                local_1_adjacent_child.0,
2110                local_1_adjacent_child.1,
2111                LocalSettingsKind::Settings,
2112                Some(r#"{"preferred_line_length": 3}"#),
2113                cx,
2114            )
2115            .unwrap();
2116        store
2117            .set_local_settings(
2118                local_1_child.0,
2119                local_1_child.1.clone(),
2120                LocalSettingsKind::Settings,
2121                Some(r#"{}"#),
2122                cx,
2123            )
2124            .unwrap();
2125        assert_eq!(
2126            store.get_value_from_file(SettingsFile::Project(local_1_child), get),
2127            (SettingsFile::Project(local_1), Some(&1))
2128        );
2129    }
2130
2131    #[gpui::test]
2132    fn test_get_overrides_for_field(cx: &mut App) {
2133        let mut store = SettingsStore::new(cx, &test_settings());
2134        store.register_setting::<DefaultLanguageSettings>();
2135
2136        let wt0_root = (WorktreeId::from_usize(0), RelPath::empty().into_arc());
2137        let wt0_child1 = (WorktreeId::from_usize(0), rel_path("child1").into_arc());
2138        let wt0_child2 = (WorktreeId::from_usize(0), rel_path("child2").into_arc());
2139
2140        let wt1_root = (WorktreeId::from_usize(1), RelPath::empty().into_arc());
2141        let wt1_subdir = (WorktreeId::from_usize(1), rel_path("subdir").into_arc());
2142
2143        fn get(content: &SettingsContent) -> &Option<u32> {
2144            &content.project.all_languages.defaults.preferred_line_length
2145        }
2146
2147        store
2148            .set_user_settings(r#"{"preferred_line_length": 100}"#, cx)
2149            .unwrap();
2150
2151        store
2152            .set_local_settings(
2153                wt0_root.0,
2154                wt0_root.1.clone(),
2155                LocalSettingsKind::Settings,
2156                Some(r#"{"preferred_line_length": 80}"#),
2157                cx,
2158            )
2159            .unwrap();
2160        store
2161            .set_local_settings(
2162                wt0_child1.0,
2163                wt0_child1.1.clone(),
2164                LocalSettingsKind::Settings,
2165                Some(r#"{"preferred_line_length": 120}"#),
2166                cx,
2167            )
2168            .unwrap();
2169        store
2170            .set_local_settings(
2171                wt0_child2.0,
2172                wt0_child2.1.clone(),
2173                LocalSettingsKind::Settings,
2174                Some(r#"{}"#),
2175                cx,
2176            )
2177            .unwrap();
2178
2179        store
2180            .set_local_settings(
2181                wt1_root.0,
2182                wt1_root.1.clone(),
2183                LocalSettingsKind::Settings,
2184                Some(r#"{"preferred_line_length": 90}"#),
2185                cx,
2186            )
2187            .unwrap();
2188        store
2189            .set_local_settings(
2190                wt1_subdir.0,
2191                wt1_subdir.1.clone(),
2192                LocalSettingsKind::Settings,
2193                Some(r#"{}"#),
2194                cx,
2195            )
2196            .unwrap();
2197
2198        let overrides = store.get_overrides_for_field(SettingsFile::Default, get);
2199        assert_eq!(
2200            overrides,
2201            vec![
2202                SettingsFile::User,
2203                SettingsFile::Project(wt0_root.clone()),
2204                SettingsFile::Project(wt0_child1.clone()),
2205                SettingsFile::Project(wt1_root.clone()),
2206            ]
2207        );
2208
2209        let overrides = store.get_overrides_for_field(SettingsFile::User, get);
2210        assert_eq!(
2211            overrides,
2212            vec![
2213                SettingsFile::Project(wt0_root.clone()),
2214                SettingsFile::Project(wt0_child1.clone()),
2215                SettingsFile::Project(wt1_root.clone()),
2216            ]
2217        );
2218
2219        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt0_root), get);
2220        assert_eq!(overrides, vec![]);
2221
2222        let overrides =
2223            store.get_overrides_for_field(SettingsFile::Project(wt0_child1.clone()), get);
2224        assert_eq!(overrides, vec![]);
2225
2226        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt0_child2), get);
2227        assert_eq!(overrides, vec![]);
2228
2229        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt1_root), get);
2230        assert_eq!(overrides, vec![]);
2231
2232        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt1_subdir), get);
2233        assert_eq!(overrides, vec![]);
2234
2235        let wt0_deep_child = (
2236            WorktreeId::from_usize(0),
2237            rel_path("child1/subdir").into_arc(),
2238        );
2239        store
2240            .set_local_settings(
2241                wt0_deep_child.0,
2242                wt0_deep_child.1.clone(),
2243                LocalSettingsKind::Settings,
2244                Some(r#"{"preferred_line_length": 140}"#),
2245                cx,
2246            )
2247            .unwrap();
2248
2249        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt0_deep_child), get);
2250        assert_eq!(overrides, vec![]);
2251
2252        let overrides = store.get_overrides_for_field(SettingsFile::Project(wt0_child1), get);
2253        assert_eq!(overrides, vec![]);
2254    }
2255
2256    #[test]
2257    fn test_file_ord() {
2258        let wt0_root =
2259            SettingsFile::Project((WorktreeId::from_usize(0), RelPath::empty().into_arc()));
2260        let wt0_child1 =
2261            SettingsFile::Project((WorktreeId::from_usize(0), rel_path("child1").into_arc()));
2262        let wt0_child2 =
2263            SettingsFile::Project((WorktreeId::from_usize(0), rel_path("child2").into_arc()));
2264
2265        let wt1_root =
2266            SettingsFile::Project((WorktreeId::from_usize(1), RelPath::empty().into_arc()));
2267        let wt1_subdir =
2268            SettingsFile::Project((WorktreeId::from_usize(1), rel_path("subdir").into_arc()));
2269
2270        let mut files = vec![
2271            &wt1_root,
2272            &SettingsFile::Default,
2273            &wt0_root,
2274            &wt1_subdir,
2275            &wt0_child2,
2276            &SettingsFile::Server,
2277            &wt0_child1,
2278            &SettingsFile::User,
2279        ];
2280
2281        files.sort();
2282        pretty_assertions::assert_eq!(
2283            files,
2284            vec![
2285                &wt0_child2,
2286                &wt0_child1,
2287                &wt0_root,
2288                &wt1_subdir,
2289                &wt1_root,
2290                &SettingsFile::Server,
2291                &SettingsFile::User,
2292                &SettingsFile::Default,
2293            ]
2294        )
2295    }
2296}