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