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