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;
  14use serde::{Serialize, de::DeserializeOwned};
  15use serde_json::{Value, json};
  16use smallvec::SmallVec;
  17use std::{
  18    any::{Any, TypeId, type_name},
  19    fmt::Debug,
  20    ops::Range,
  21    path::{Path, PathBuf},
  22    str::{self, FromStr},
  23    sync::Arc,
  24};
  25use util::{ResultExt as _, merge_non_null_json_value_into, schemars::DefaultDenyUnknownFields};
  26
  27pub type EditorconfigProperties = ec4rs::Properties;
  28
  29use crate::{
  30    ActiveSettingsProfileName, ParameterizedJsonSchema, SettingsJsonSchemaParams, SettingsUiEntry,
  31    VsCodeSettings, WorktreeId, parse_json_with_comments, replace_value_in_json_text,
  32    settings_content::{
  33        ExtensionsSettingsContent, ProjectSettingsContent, ServerSettingsContent, SettingsContent,
  34        UserSettingsContent,
  35    },
  36    update_value_in_json_text,
  37};
  38
  39pub trait SettingsKey: 'static + Send + Sync {
  40    /// The name of a key within the JSON file from which this setting should
  41    /// be deserialized. If this is `None`, then the setting will be deserialized
  42    /// from the root object.
  43    const KEY: Option<&'static str>;
  44
  45    const FALLBACK_KEY: Option<&'static str> = None;
  46}
  47
  48/// A value that can be defined as a user setting.
  49///
  50/// Settings can be loaded from a combination of multiple JSON files.
  51pub trait Settings: 'static + Send + Sync + Sized {
  52    /// The name of the keys in the [`FileContent`](Self::FileContent) that should
  53    /// always be written to a settings file, even if their value matches the default
  54    /// value.
  55    ///
  56    /// This is useful for tagged [`FileContent`](Self::FileContent)s where the tag
  57    /// is a "version" field that should always be persisted, even if the current
  58    /// user settings match the current version of the settings.
  59    const PRESERVED_KEYS: Option<&'static [&'static str]> = None;
  60
  61    fn from_file(content: &SettingsContent, cx: &mut App) -> Option<Self>;
  62
  63    fn refine(&mut self, content: &SettingsContent, cx: &mut App);
  64
  65    fn missing_default() -> anyhow::Error {
  66        anyhow::anyhow!("missing default for: {}", std::any::type_name::<Self>())
  67    }
  68
  69    /// Use [the helpers in the vscode_import module](crate::vscode_import) to apply known
  70    /// equivalent settings from a vscode config to our config
  71    fn import_from_vscode(vscode: &VsCodeSettings, current: &mut SettingsContent);
  72
  73    #[track_caller]
  74    fn register(cx: &mut App)
  75    where
  76        Self: Sized,
  77    {
  78        SettingsStore::update_global(cx, |store, cx| {
  79            store.register_setting::<Self>(cx);
  80        });
  81    }
  82
  83    #[track_caller]
  84    fn get<'a>(path: Option<SettingsLocation>, cx: &'a App) -> &'a Self
  85    where
  86        Self: Sized,
  87    {
  88        cx.global::<SettingsStore>().get(path)
  89    }
  90
  91    #[track_caller]
  92    fn get_global(cx: &App) -> &Self
  93    where
  94        Self: Sized,
  95    {
  96        cx.global::<SettingsStore>().get(None)
  97    }
  98
  99    #[track_caller]
 100    fn try_get(cx: &App) -> Option<&Self>
 101    where
 102        Self: Sized,
 103    {
 104        if cx.has_global::<SettingsStore>() {
 105            cx.global::<SettingsStore>().try_get(None)
 106        } else {
 107            None
 108        }
 109    }
 110
 111    #[track_caller]
 112    fn try_read_global<R>(cx: &AsyncApp, f: impl FnOnce(&Self) -> R) -> Option<R>
 113    where
 114        Self: Sized,
 115    {
 116        cx.try_read_global(|s: &SettingsStore, _| f(s.get(None)))
 117    }
 118
 119    #[track_caller]
 120    fn override_global(settings: Self, cx: &mut App)
 121    where
 122        Self: Sized,
 123    {
 124        cx.global_mut::<SettingsStore>().override_global(settings)
 125    }
 126}
 127
 128#[derive(Clone, Copy, Debug)]
 129pub struct SettingsSources<'a, T> {
 130    /// The default Zed settings.
 131    pub default: &'a T,
 132    /// Global settings (loaded before user settings).
 133    pub global: Option<&'a T>,
 134    /// Settings provided by extensions.
 135    pub extensions: Option<&'a T>,
 136    /// The user settings.
 137    pub user: Option<&'a T>,
 138    /// The user settings for the current release channel.
 139    pub release_channel: Option<&'a T>,
 140    /// The user settings for the current operating system.
 141    pub operating_system: Option<&'a T>,
 142    /// The settings associated with an enabled settings profile
 143    pub profile: Option<&'a T>,
 144    /// The server's settings.
 145    pub server: Option<&'a T>,
 146    /// The project settings, ordered from least specific to most specific.
 147    pub project: &'a [&'a T],
 148}
 149
 150impl<'a, T: Serialize> SettingsSources<'a, T> {
 151    /// Returns an iterator over the default settings as well as all settings customizations.
 152    pub fn defaults_and_customizations(&self) -> impl Iterator<Item = &T> {
 153        [self.default].into_iter().chain(self.customizations())
 154    }
 155
 156    /// Returns an iterator over all of the settings customizations.
 157    pub fn customizations(&self) -> impl Iterator<Item = &T> {
 158        self.global
 159            .into_iter()
 160            .chain(self.extensions)
 161            .chain(self.user)
 162            .chain(self.release_channel)
 163            .chain(self.operating_system)
 164            .chain(self.profile)
 165            .chain(self.server)
 166            .chain(self.project.iter().copied())
 167    }
 168
 169    /// Returns the settings after performing a JSON merge of the provided customizations.
 170    ///
 171    /// Customizations later in the iterator win out over the earlier ones.
 172    pub fn json_merge_with<O: DeserializeOwned>(
 173        customizations: impl Iterator<Item = &'a T>,
 174    ) -> Result<O> {
 175        let mut merged = Value::Null;
 176        for value in customizations {
 177            merge_non_null_json_value_into(serde_json::to_value(value).unwrap(), &mut merged);
 178        }
 179        Ok(serde_json::from_value(merged)?)
 180    }
 181
 182    /// Returns the settings after performing a JSON merge of the customizations into the
 183    /// default settings.
 184    ///
 185    /// More-specific customizations win out over the less-specific ones.
 186    pub fn json_merge<O: DeserializeOwned>(&'a self) -> Result<O> {
 187        Self::json_merge_with(self.defaults_and_customizations())
 188    }
 189}
 190
 191#[derive(Clone, Copy, Debug)]
 192pub struct SettingsLocation<'a> {
 193    pub worktree_id: WorktreeId,
 194    pub path: &'a Path,
 195}
 196
 197/// A set of strongly-typed setting values defined via multiple config files.
 198pub struct SettingsStore {
 199    setting_values: HashMap<TypeId, Box<dyn AnySettingValue>>,
 200    default_settings: SettingsContent,
 201    user_settings: Option<UserSettingsContent>,
 202    global_settings: Option<SettingsContent>,
 203
 204    extension_settings: Option<SettingsContent>,
 205    server_settings: Option<SettingsContent>,
 206    local_settings: BTreeMap<(WorktreeId, Arc<Path>), SettingsContent>,
 207    raw_editorconfig_settings: BTreeMap<(WorktreeId, Arc<Path>), (String, Option<Editorconfig>)>,
 208
 209    _setting_file_updates: Task<()>,
 210    setting_file_updates_tx:
 211        mpsc::UnboundedSender<Box<dyn FnOnce(AsyncApp) -> LocalBoxFuture<'static, Result<()>>>>,
 212}
 213
 214#[derive(Clone)]
 215pub struct Editorconfig {
 216    pub is_root: bool,
 217    pub sections: SmallVec<[Section; 5]>,
 218}
 219
 220impl FromStr for Editorconfig {
 221    type Err = anyhow::Error;
 222
 223    fn from_str(contents: &str) -> Result<Self, Self::Err> {
 224        let parser = ConfigParser::new_buffered(contents.as_bytes())
 225            .context("creating editorconfig parser")?;
 226        let is_root = parser.is_root;
 227        let sections = parser
 228            .collect::<Result<SmallVec<_>, _>>()
 229            .context("parsing editorconfig sections")?;
 230        Ok(Self { is_root, sections })
 231    }
 232}
 233
 234#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 235pub enum LocalSettingsKind {
 236    Settings,
 237    Tasks,
 238    Editorconfig,
 239    Debug,
 240}
 241
 242impl Global for SettingsStore {}
 243
 244#[derive(Debug)]
 245struct SettingValue<T> {
 246    global_value: Option<T>,
 247    local_values: Vec<(WorktreeId, Arc<Path>, T)>,
 248}
 249
 250trait AnySettingValue: 'static + Send + Sync {
 251    fn setting_type_name(&self) -> &'static str;
 252
 253    fn from_file(&self, s: &SettingsContent, cx: &mut App) -> Option<Box<dyn Any>>;
 254    fn refine(&self, value: &mut dyn Any, s: &[&SettingsContent], cx: &mut App);
 255
 256    fn value_for_path(&self, path: Option<SettingsLocation>) -> &dyn Any;
 257    fn all_local_values(&self) -> Vec<(WorktreeId, Arc<Path>, &dyn Any)>;
 258    fn set_global_value(&mut self, value: Box<dyn Any>);
 259    fn set_local_value(&mut self, root_id: WorktreeId, path: Arc<Path>, value: Box<dyn Any>);
 260    fn json_schema(&self, generator: &mut schemars::SchemaGenerator) -> schemars::Schema;
 261    fn edits_for_update(
 262        &self,
 263        raw_settings: &serde_json::Value,
 264        tab_size: usize,
 265        vscode_settings: &VsCodeSettings,
 266        text: &mut String,
 267        edits: &mut Vec<(Range<usize>, String)>,
 268    );
 269    fn settings_ui_item(&self) -> SettingsUiEntry;
 270}
 271
 272struct DeserializedSetting(Box<dyn Any>);
 273
 274impl SettingsStore {
 275    pub fn new(cx: &App, default_settings: &str) -> Self {
 276        let (setting_file_updates_tx, mut setting_file_updates_rx) = mpsc::unbounded();
 277        let default_settings = parse_json_with_comments(default_settings).unwrap();
 278        Self {
 279            setting_values: Default::default(),
 280            default_settings,
 281            global_settings: None,
 282            server_settings: None,
 283            user_settings: Some(Default::default()), // todo!()
 284            extension_settings: None,
 285            local_settings: BTreeMap::default(),
 286            raw_editorconfig_settings: BTreeMap::default(),
 287            setting_file_updates_tx,
 288            _setting_file_updates: cx.spawn(async move |cx| {
 289                while let Some(setting_file_update) = setting_file_updates_rx.next().await {
 290                    (setting_file_update)(cx.clone()).await.log_err();
 291                }
 292            }),
 293        }
 294    }
 295
 296    pub fn observe_active_settings_profile_name(cx: &mut App) -> gpui::Subscription {
 297        cx.observe_global::<ActiveSettingsProfileName>(|cx| {
 298            Self::update_global(cx, |store, cx| {
 299                store.recompute_values(None, cx).log_err();
 300            });
 301        })
 302    }
 303
 304    pub fn update<C, R>(cx: &mut C, f: impl FnOnce(&mut Self, &mut C) -> R) -> R
 305    where
 306        C: BorrowAppContext,
 307    {
 308        cx.update_global(f)
 309    }
 310
 311    /// Add a new type of setting to the store.
 312    pub fn register_setting<T: Settings>(&mut self, cx: &mut App) {
 313        let setting_type_id = TypeId::of::<T>();
 314        let entry = self.setting_values.entry(setting_type_id);
 315
 316        if matches!(entry, hash_map::Entry::Occupied(_)) {
 317            return;
 318        }
 319
 320        let setting_value = entry.or_insert(Box::new(SettingValue::<T> {
 321            global_value: None,
 322            local_values: Vec::new(),
 323        }));
 324
 325        let mut refinements = Vec::default();
 326
 327        if let Some(extension_settings) = self.extension_settings.as_ref() {
 328            refinements.push(extension_settings)
 329        }
 330
 331        if let Some(user_settings) = self.user_settings.as_ref() {
 332            refinements.push(&user_settings.content);
 333            if let Some(release_channel) = user_settings.for_release_channel() {
 334                refinements.push(release_channel)
 335            }
 336            if let Some(os) = user_settings.for_os() {
 337                refinements.push(os)
 338            }
 339            if let Some(profile) = user_settings.for_profile(cx) {
 340                refinements.push(profile)
 341            }
 342        }
 343
 344        if let Some(server_settings) = self.server_settings.as_ref() {
 345            refinements.push(server_settings)
 346        }
 347        // todo!() unwrap...
 348        let mut value = T::from_file(&self.default_settings, cx).unwrap();
 349        for refinement in refinements {
 350            value.refine(refinement, cx)
 351        }
 352
 353        setting_value.set_global_value(Box::new(value));
 354
 355        // todo!() local settings
 356        // (they weren't handled before...)
 357    }
 358
 359    /// Get the value of a setting.
 360    ///
 361    /// Panics if the given setting type has not been registered, or if there is no
 362    /// value for this setting.
 363    pub fn get<T: Settings>(&self, path: Option<SettingsLocation>) -> &T {
 364        self.setting_values
 365            .get(&TypeId::of::<T>())
 366            .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>()))
 367            .value_for_path(path)
 368            .downcast_ref::<T>()
 369            .expect("no default value for setting type")
 370    }
 371
 372    /// Get the value of a setting.
 373    ///
 374    /// Does not panic
 375    pub fn try_get<T: Settings>(&self, path: Option<SettingsLocation>) -> Option<&T> {
 376        self.setting_values
 377            .get(&TypeId::of::<T>())
 378            .map(|value| value.value_for_path(path))
 379            .and_then(|value| value.downcast_ref::<T>())
 380    }
 381
 382    /// Get all values from project specific settings
 383    pub fn get_all_locals<T: Settings>(&self) -> Vec<(WorktreeId, Arc<Path>, &T)> {
 384        self.setting_values
 385            .get(&TypeId::of::<T>())
 386            .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>()))
 387            .all_local_values()
 388            .into_iter()
 389            .map(|(id, path, any)| {
 390                (
 391                    id,
 392                    path,
 393                    any.downcast_ref::<T>()
 394                        .expect("wrong value type for setting"),
 395                )
 396            })
 397            .collect()
 398    }
 399
 400    /// Override the global value for a setting.
 401    ///
 402    /// The given value will be overwritten if the user settings file changes.
 403    pub fn override_global<T: Settings>(&mut self, value: T) {
 404        self.setting_values
 405            .get_mut(&TypeId::of::<T>())
 406            .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>()))
 407            .set_global_value(Box::new(value))
 408    }
 409
 410    /// Get the user's settings as a raw JSON value.
 411    ///
 412    /// For user-facing functionality use the typed setting interface.
 413    /// (e.g. ProjectSettings::get_global(cx))
 414    pub fn raw_user_settings(&self) -> Option<&UserSettingsContent> {
 415        self.user_settings.as_ref()
 416    }
 417
 418    /// Replaces current settings with the values from the given JSON.
 419    pub fn set_raw_user_settings(
 420        &mut self,
 421        new_settings: UserSettingsContent,
 422        cx: &mut App,
 423    ) -> Result<()> {
 424        self.user_settings = Some(new_settings);
 425        self.recompute_values(None, cx)?;
 426        Ok(())
 427    }
 428
 429    /// Get the configured settings profile names.
 430    pub fn configured_settings_profiles(&self) -> impl Iterator<Item = &str> {
 431        self.user_settings
 432            .iter()
 433            .flat_map(|settings| settings.profiles.keys().map(|k| k.as_str()))
 434    }
 435
 436    /// Access the raw JSON value of the default settings.
 437    pub fn raw_default_settings(&self) -> &SettingsContent {
 438        &self.default_settings
 439    }
 440
 441    #[cfg(any(test, feature = "test-support"))]
 442    pub fn test(cx: &mut App) -> Self {
 443        Self::new(cx, &crate::test_settings())
 444    }
 445
 446    /// Updates the value of a setting in the user's global configuration.
 447    ///
 448    /// This is only for tests. Normally, settings are only loaded from
 449    /// JSON files.
 450    #[cfg(any(test, feature = "test-support"))]
 451    pub fn update_user_settings(
 452        &mut self,
 453        cx: &mut App,
 454        update: impl FnOnce(&mut SettingsContent),
 455    ) {
 456        let mut content = self.user_settings.as_ref().unwrap().content.clone();
 457        update(&mut content);
 458        let new_text = serde_json::to_string(&UserSettingsContent {
 459            content,
 460            ..Default::default()
 461        })
 462        .unwrap();
 463        self.set_user_settings(&new_text, cx).unwrap();
 464    }
 465
 466    pub async fn load_settings(fs: &Arc<dyn Fs>) -> Result<String> {
 467        match fs.load(paths::settings_file()).await {
 468            result @ Ok(_) => result,
 469            Err(err) => {
 470                if let Some(e) = err.downcast_ref::<std::io::Error>()
 471                    && e.kind() == std::io::ErrorKind::NotFound
 472                {
 473                    return Ok(crate::initial_user_settings_content().to_string());
 474                }
 475                Err(err)
 476            }
 477        }
 478    }
 479
 480    fn update_settings_file_inner(
 481        &self,
 482        fs: Arc<dyn Fs>,
 483        update: impl 'static + Send + FnOnce(String, AsyncApp) -> Result<String>,
 484    ) -> oneshot::Receiver<Result<()>> {
 485        let (tx, rx) = oneshot::channel::<Result<()>>();
 486        self.setting_file_updates_tx
 487            .unbounded_send(Box::new(move |cx: AsyncApp| {
 488                async move {
 489                    let res = async move {
 490                        let old_text = Self::load_settings(&fs).await?;
 491                        let new_text = update(old_text, cx)?;
 492                        let settings_path = paths::settings_file().as_path();
 493                        if fs.is_file(settings_path).await {
 494                            let resolved_path =
 495                                fs.canonicalize(settings_path).await.with_context(|| {
 496                                    format!(
 497                                        "Failed to canonicalize settings path {:?}",
 498                                        settings_path
 499                                    )
 500                                })?;
 501
 502                            fs.atomic_write(resolved_path.clone(), new_text)
 503                                .await
 504                                .with_context(|| {
 505                                    format!("Failed to write settings to file {:?}", resolved_path)
 506                                })?;
 507                        } else {
 508                            fs.atomic_write(settings_path.to_path_buf(), new_text)
 509                                .await
 510                                .with_context(|| {
 511                                    format!("Failed to write settings to file {:?}", settings_path)
 512                                })?;
 513                        }
 514                        anyhow::Ok(())
 515                    }
 516                    .await;
 517
 518                    let new_res = match &res {
 519                        Ok(_) => anyhow::Ok(()),
 520                        Err(e) => Err(anyhow::anyhow!("Failed to write settings to file {:?}", e)),
 521                    };
 522
 523                    _ = tx.send(new_res);
 524                    res
 525                }
 526                .boxed_local()
 527            }))
 528            .map_err(|err| anyhow::format_err!("Failed to update settings file: {}", err))
 529            .log_with_level(log::Level::Warn);
 530        return rx;
 531    }
 532
 533    pub fn update_settings_file_at_path(
 534        &self,
 535        fs: Arc<dyn Fs>,
 536        path: &[impl AsRef<str>],
 537        new_value: serde_json::Value,
 538    ) -> oneshot::Receiver<Result<()>> {
 539        let key_path = path
 540            .into_iter()
 541            .map(AsRef::as_ref)
 542            .map(SharedString::new)
 543            .collect::<Vec<_>>();
 544        let update = move |mut old_text: String, cx: AsyncApp| {
 545            cx.read_global(|store: &SettingsStore, _cx| {
 546                // todo(settings_ui) use `update_value_in_json_text` for merging new and old objects with comment preservation, needs old value though...
 547                let (range, replacement) = replace_value_in_json_text(
 548                    &old_text,
 549                    key_path.as_slice(),
 550                    store.json_tab_size(),
 551                    Some(&new_value),
 552                    None,
 553                );
 554                old_text.replace_range(range, &replacement);
 555                old_text
 556            })
 557        };
 558        self.update_settings_file_inner(fs, update)
 559    }
 560
 561    pub fn update_settings_file(
 562        &self,
 563        fs: Arc<dyn Fs>,
 564        update: impl 'static + Send + FnOnce(&mut SettingsContent, &App),
 565    ) {
 566        _ = self.update_settings_file_inner(fs, move |old_text: String, cx: AsyncApp| {
 567            cx.read_global(|store: &SettingsStore, cx| {
 568                store.new_text_for_update(old_text, |content| update(content, cx))
 569            })
 570        });
 571    }
 572
 573    pub fn import_vscode_settings(
 574        &self,
 575        fs: Arc<dyn Fs>,
 576        vscode_settings: VsCodeSettings,
 577    ) -> oneshot::Receiver<Result<()>> {
 578        self.update_settings_file_inner(fs, move |old_text: String, cx: AsyncApp| {
 579            cx.read_global(|store: &SettingsStore, _cx| {
 580                store.get_vscode_edits(old_text, &vscode_settings)
 581            })
 582        })
 583    }
 584
 585    pub fn settings_ui_items(&self) -> impl IntoIterator<Item = SettingsUiEntry> {
 586        self.setting_values
 587            .values()
 588            .map(|item| item.settings_ui_item())
 589    }
 590}
 591
 592impl SettingsStore {
 593    /// Updates the value of a setting in a JSON file, returning the new text
 594    /// for that JSON file.
 595    pub fn new_text_for_update(
 596        &self,
 597        old_text: String,
 598        update: impl FnOnce(&mut SettingsContent),
 599    ) -> String {
 600        let edits = self.edits_for_update(&old_text, update);
 601        let mut new_text = old_text;
 602        for (range, replacement) in edits.into_iter() {
 603            new_text.replace_range(range, &replacement);
 604        }
 605        new_text
 606    }
 607
 608    pub fn get_vscode_edits(&self, mut old_text: String, vscode: &VsCodeSettings) -> String {
 609        let mut new_text = old_text.clone();
 610        let mut edits: Vec<(Range<usize>, String)> = Vec::new();
 611        let raw_settings = parse_json_with_comments::<Value>(&old_text).unwrap_or_default();
 612        let tab_size = self.json_tab_size();
 613        for v in self.setting_values.values() {
 614            v.edits_for_update(&raw_settings, tab_size, vscode, &mut old_text, &mut edits);
 615        }
 616        for (range, replacement) in edits.into_iter() {
 617            new_text.replace_range(range, &replacement);
 618        }
 619        new_text
 620    }
 621
 622    /// Updates the value of a setting in a JSON file, returning a list
 623    /// of edits to apply to the JSON file.
 624    pub fn edits_for_update(
 625        &self,
 626        text: &str,
 627        update: impl FnOnce(&mut SettingsContent),
 628    ) -> Vec<(Range<usize>, String)> {
 629        let old_content: UserSettingsContent = serde_json::from_str(text).unwrap_or_default();
 630        let mut new_content = old_content.clone();
 631        update(&mut new_content.content);
 632
 633        let old_value = serde_json::to_value(&old_content).unwrap();
 634        let new_value = serde_json::to_value(new_content).unwrap();
 635
 636        let mut key_path = Vec::new();
 637        let mut edits = Vec::new();
 638        let tab_size = self.json_tab_size();
 639        let mut text = text.to_string();
 640        update_value_in_json_text(
 641            &mut text,
 642            &mut key_path,
 643            tab_size,
 644            &old_value,
 645            &new_value,
 646            &[], // todo!() is this still needed?
 647            &mut edits,
 648        );
 649        edits
 650    }
 651
 652    pub fn json_tab_size(&self) -> usize {
 653        2
 654    }
 655
 656    /// Sets the default settings via a JSON string.
 657    ///
 658    /// The string should contain a JSON object with a default value for every setting.
 659    pub fn set_default_settings(
 660        &mut self,
 661        default_settings_content: &str,
 662        cx: &mut App,
 663    ) -> Result<()> {
 664        self.default_settings = parse_json_with_comments(default_settings_content)?;
 665        self.recompute_values(None, cx)?;
 666        Ok(())
 667    }
 668
 669    /// Sets the user settings via a JSON string.
 670    pub fn set_user_settings(&mut self, user_settings_content: &str, cx: &mut App) -> Result<()> {
 671        let settings: UserSettingsContent = if user_settings_content.is_empty() {
 672            parse_json_with_comments("{}")?
 673        } else {
 674            parse_json_with_comments(user_settings_content)?
 675        };
 676
 677        self.user_settings = Some(settings);
 678        self.recompute_values(None, cx)?;
 679        Ok(())
 680    }
 681
 682    /// Sets the global settings via a JSON string.
 683    pub fn set_global_settings(
 684        &mut self,
 685        global_settings_content: &str,
 686        cx: &mut App,
 687    ) -> Result<()> {
 688        let settings: SettingsContent = if global_settings_content.is_empty() {
 689            parse_json_with_comments("{}")?
 690        } else {
 691            parse_json_with_comments(global_settings_content)?
 692        };
 693
 694        self.global_settings = Some(settings);
 695        self.recompute_values(None, cx)?;
 696        Ok(())
 697    }
 698
 699    pub fn set_server_settings(
 700        &mut self,
 701        server_settings_content: &str,
 702        cx: &mut App,
 703    ) -> Result<()> {
 704        let settings: Option<ServerSettingsContent> = if server_settings_content.is_empty() {
 705            None
 706        } else {
 707            parse_json_with_comments(server_settings_content)?
 708        };
 709
 710        // Rewrite the server settings into a content type
 711        self.server_settings = settings.map(|settings| SettingsContent {
 712            project: settings.project,
 713            ..Default::default()
 714        });
 715
 716        todo!();
 717        // self.server_settings = Some(settings);
 718        self.recompute_values(None, cx)?;
 719        Ok(())
 720    }
 721
 722    /// Add or remove a set of local settings via a JSON string.
 723    pub fn set_local_settings(
 724        &mut self,
 725        root_id: WorktreeId,
 726        directory_path: Arc<Path>,
 727        kind: LocalSettingsKind,
 728        settings_content: Option<&str>,
 729        cx: &mut App,
 730    ) -> std::result::Result<(), InvalidSettingsError> {
 731        let mut zed_settings_changed = false;
 732        match (
 733            kind,
 734            settings_content
 735                .map(|content| content.trim())
 736                .filter(|content| !content.is_empty()),
 737        ) {
 738            (LocalSettingsKind::Tasks, _) => {
 739                return Err(InvalidSettingsError::Tasks {
 740                    message: "Attempted to submit tasks into the settings store".to_string(),
 741                    path: directory_path.join(task_file_name()),
 742                });
 743            }
 744            (LocalSettingsKind::Debug, _) => {
 745                return Err(InvalidSettingsError::Debug {
 746                    message: "Attempted to submit debugger config into the settings store"
 747                        .to_string(),
 748                    path: directory_path.join(task_file_name()),
 749                });
 750            }
 751            (LocalSettingsKind::Settings, None) => {
 752                zed_settings_changed = self
 753                    .local_settings
 754                    .remove(&(root_id, directory_path.clone()))
 755                    .is_some()
 756            }
 757            (LocalSettingsKind::Editorconfig, None) => {
 758                self.raw_editorconfig_settings
 759                    .remove(&(root_id, directory_path.clone()));
 760            }
 761            (LocalSettingsKind::Settings, Some(settings_contents)) => {
 762                let new_settings = parse_json_with_comments::<ProjectSettingsContent>(
 763                    settings_contents,
 764                )
 765                .map_err(|e| InvalidSettingsError::LocalSettings {
 766                    path: directory_path.join(local_settings_file_relative_path()),
 767                    message: e.to_string(),
 768                })?;
 769                match self.local_settings.entry((root_id, directory_path.clone())) {
 770                    btree_map::Entry::Vacant(v) => {
 771                        v.insert(SettingsContent {
 772                            project: new_settings,
 773                            ..Default::default()
 774                        });
 775                        zed_settings_changed = true;
 776                    }
 777                    btree_map::Entry::Occupied(mut o) => {
 778                        if &o.get().project != &new_settings {
 779                            o.insert(SettingsContent {
 780                                project: new_settings,
 781                                ..Default::default()
 782                            });
 783                            zed_settings_changed = true;
 784                        }
 785                    }
 786                }
 787            }
 788            (LocalSettingsKind::Editorconfig, Some(editorconfig_contents)) => {
 789                match self
 790                    .raw_editorconfig_settings
 791                    .entry((root_id, directory_path.clone()))
 792                {
 793                    btree_map::Entry::Vacant(v) => match editorconfig_contents.parse() {
 794                        Ok(new_contents) => {
 795                            v.insert((editorconfig_contents.to_owned(), Some(new_contents)));
 796                        }
 797                        Err(e) => {
 798                            v.insert((editorconfig_contents.to_owned(), None));
 799                            return Err(InvalidSettingsError::Editorconfig {
 800                                message: e.to_string(),
 801                                path: directory_path.join(EDITORCONFIG_NAME),
 802                            });
 803                        }
 804                    },
 805                    btree_map::Entry::Occupied(mut o) => {
 806                        if o.get().0 != editorconfig_contents {
 807                            match editorconfig_contents.parse() {
 808                                Ok(new_contents) => {
 809                                    o.insert((
 810                                        editorconfig_contents.to_owned(),
 811                                        Some(new_contents),
 812                                    ));
 813                                }
 814                                Err(e) => {
 815                                    o.insert((editorconfig_contents.to_owned(), None));
 816                                    return Err(InvalidSettingsError::Editorconfig {
 817                                        message: e.to_string(),
 818                                        path: directory_path.join(EDITORCONFIG_NAME),
 819                                    });
 820                                }
 821                            }
 822                        }
 823                    }
 824                }
 825            }
 826        };
 827
 828        if zed_settings_changed {
 829            self.recompute_values(Some((root_id, &directory_path)), cx)?;
 830        }
 831        Ok(())
 832    }
 833
 834    pub fn set_extension_settings(
 835        &mut self,
 836        content: ExtensionsSettingsContent,
 837        cx: &mut App,
 838    ) -> Result<()> {
 839        self.extension_settings = Some(SettingsContent {
 840            project: ProjectSettingsContent {
 841                all_languages: content.all_languages,
 842            },
 843            ..Default::default()
 844        });
 845        self.recompute_values(None, cx)?;
 846        Ok(())
 847    }
 848
 849    /// Add or remove a set of local settings via a JSON string.
 850    pub fn clear_local_settings(&mut self, root_id: WorktreeId, cx: &mut App) -> Result<()> {
 851        self.local_settings
 852            .retain(|(worktree_id, _), _| worktree_id != &root_id);
 853        self.recompute_values(Some((root_id, "".as_ref())), cx)?;
 854        Ok(())
 855    }
 856
 857    pub fn local_settings(
 858        &self,
 859        root_id: WorktreeId,
 860    ) -> impl '_ + Iterator<Item = (Arc<Path>, String)> {
 861        self.local_settings
 862            .range(
 863                (root_id, Path::new("").into())
 864                    ..(
 865                        WorktreeId::from_usize(root_id.to_usize() + 1),
 866                        Path::new("").into(),
 867                    ),
 868            )
 869            .map(|((_, path), content)| (path.clone(), serde_json::to_string(content).unwrap()))
 870    }
 871
 872    pub fn local_editorconfig_settings(
 873        &self,
 874        root_id: WorktreeId,
 875    ) -> impl '_ + Iterator<Item = (Arc<Path>, String, Option<Editorconfig>)> {
 876        self.raw_editorconfig_settings
 877            .range(
 878                (root_id, Path::new("").into())
 879                    ..(
 880                        WorktreeId::from_usize(root_id.to_usize() + 1),
 881                        Path::new("").into(),
 882                    ),
 883            )
 884            .map(|((_, path), (content, parsed_content))| {
 885                (path.clone(), content.clone(), parsed_content.clone())
 886            })
 887    }
 888
 889    pub fn json_schema(&self, schema_params: &SettingsJsonSchemaParams, cx: &App) -> Value {
 890        let mut generator = schemars::generate::SchemaSettings::draft2019_09()
 891            .with_transform(DefaultDenyUnknownFields)
 892            .into_generator();
 893
 894        let schema = UserSettingsContent::json_schema(&mut generator);
 895
 896        // add schemas which are determined at runtime
 897        for parameterized_json_schema in inventory::iter::<ParameterizedJsonSchema>() {
 898            (parameterized_json_schema.add_and_get_ref)(&mut generator, schema_params, cx);
 899        }
 900
 901        schema.to_value()
 902    }
 903
 904    fn recompute_values(
 905        &mut self,
 906        changed_local_path: Option<(WorktreeId, &Path)>,
 907        cx: &mut App,
 908    ) -> std::result::Result<(), InvalidSettingsError> {
 909        // Reload the global and local values for every setting.
 910        let mut project_settings_stack = Vec::<&SettingsContent>::new();
 911        let mut paths_stack = Vec::<Option<(WorktreeId, &Path)>>::new();
 912
 913        let mut refinements = Vec::default();
 914
 915        if let Some(extension_settings) = self.extension_settings.as_ref() {
 916            refinements.push(extension_settings)
 917        }
 918
 919        if let Some(user_settings) = self.user_settings.as_ref() {
 920            refinements.push(&user_settings.content);
 921            if let Some(release_channel) = user_settings.for_release_channel() {
 922                refinements.push(release_channel)
 923            }
 924            if let Some(os) = user_settings.for_os() {
 925                refinements.push(os)
 926            }
 927            if let Some(profile) = user_settings.for_profile(cx) {
 928                refinements.push(profile)
 929            }
 930        }
 931
 932        if let Some(server_settings) = self.server_settings.as_ref() {
 933            refinements.push(server_settings)
 934        }
 935
 936        for setting_value in self.setting_values.values_mut() {
 937            // If the global settings file changed, reload the global value for the field.
 938            if changed_local_path.is_none() {
 939                let mut value = setting_value.from_file(&self.default_settings, cx).unwrap();
 940                setting_value.refine(value.as_mut(), &refinements, cx);
 941                setting_value.set_global_value(value);
 942            }
 943
 944            // Reload the local values for the setting.
 945            paths_stack.clear();
 946            project_settings_stack.clear();
 947            for ((root_id, directory_path), local_settings) in &self.local_settings {
 948                // Build a stack of all of the local values for that setting.
 949                while let Some(prev_entry) = paths_stack.last() {
 950                    if let Some((prev_root_id, prev_path)) = prev_entry
 951                        && (root_id != prev_root_id || !directory_path.starts_with(prev_path))
 952                    {
 953                        paths_stack.pop();
 954                        project_settings_stack.pop();
 955                        continue;
 956                    }
 957                    break;
 958                }
 959
 960                // NOTE: this kind of condition existing in the old code too,
 961                // but is there a problem when a setting is removed from a file?
 962                if setting_value.from_file(local_settings, cx).is_some() {
 963                    paths_stack.push(Some((*root_id, directory_path.as_ref())));
 964                    project_settings_stack.push(local_settings);
 965
 966                    // If a local settings file changed, then avoid recomputing local
 967                    // settings for any path outside of that directory.
 968                    if changed_local_path.is_some_and(|(changed_root_id, changed_local_path)| {
 969                        *root_id != changed_root_id
 970                            || !directory_path.starts_with(changed_local_path)
 971                    }) {
 972                        continue;
 973                    }
 974
 975                    let mut value = setting_value.from_file(&self.default_settings, cx).unwrap();
 976                    setting_value.refine(value.as_mut(), &refinements, cx);
 977                    setting_value.refine(value.as_mut(), &project_settings_stack, cx);
 978                    setting_value.set_local_value(*root_id, directory_path.clone(), value);
 979                }
 980            }
 981        }
 982        Ok(())
 983    }
 984
 985    pub fn editorconfig_properties(
 986        &self,
 987        for_worktree: WorktreeId,
 988        for_path: &Path,
 989    ) -> Option<EditorconfigProperties> {
 990        let mut properties = EditorconfigProperties::new();
 991
 992        for (directory_with_config, _, parsed_editorconfig) in
 993            self.local_editorconfig_settings(for_worktree)
 994        {
 995            if !for_path.starts_with(&directory_with_config) {
 996                properties.use_fallbacks();
 997                return Some(properties);
 998            }
 999            let parsed_editorconfig = parsed_editorconfig?;
1000            if parsed_editorconfig.is_root {
1001                properties = EditorconfigProperties::new();
1002            }
1003            for section in parsed_editorconfig.sections {
1004                section.apply_to(&mut properties, for_path).log_err()?;
1005            }
1006        }
1007
1008        properties.use_fallbacks();
1009        Some(properties)
1010    }
1011}
1012
1013#[derive(Debug, Clone, PartialEq)]
1014pub enum InvalidSettingsError {
1015    LocalSettings { path: PathBuf, message: String },
1016    UserSettings { message: String },
1017    ServerSettings { message: String },
1018    DefaultSettings { message: String },
1019    Editorconfig { path: PathBuf, message: String },
1020    Tasks { path: PathBuf, message: String },
1021    Debug { path: PathBuf, message: String },
1022}
1023
1024impl std::fmt::Display for InvalidSettingsError {
1025    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1026        match self {
1027            InvalidSettingsError::LocalSettings { message, .. }
1028            | InvalidSettingsError::UserSettings { message }
1029            | InvalidSettingsError::ServerSettings { message }
1030            | InvalidSettingsError::DefaultSettings { message }
1031            | InvalidSettingsError::Tasks { message, .. }
1032            | InvalidSettingsError::Editorconfig { message, .. }
1033            | InvalidSettingsError::Debug { message, .. } => {
1034                write!(f, "{message}")
1035            }
1036        }
1037    }
1038}
1039impl std::error::Error for InvalidSettingsError {}
1040
1041impl Debug for SettingsStore {
1042    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1043        f.debug_struct("SettingsStore")
1044            .field(
1045                "types",
1046                &self
1047                    .setting_values
1048                    .values()
1049                    .map(|value| value.setting_type_name())
1050                    .collect::<Vec<_>>(),
1051            )
1052            .field("default_settings", &self.default_settings)
1053            .field("user_settings", &self.user_settings)
1054            .field("local_settings", &self.local_settings)
1055            .finish_non_exhaustive()
1056    }
1057}
1058
1059impl<T: Settings> AnySettingValue for SettingValue<T> {
1060    fn from_file(&self, s: &SettingsContent, cx: &mut App) -> Option<Box<dyn Any>> {
1061        (type_name::<T>(), TypeId::of::<T>());
1062        T::from_file(s, cx).map(|result| Box::new(result) as _)
1063    }
1064
1065    fn refine(&self, value: &mut dyn Any, refinements: &[&SettingsContent], cx: &mut App) {
1066        (type_name::<T>(), TypeId::of::<T>());
1067        let value = value.downcast_mut::<T>().unwrap();
1068        for refinement in refinements {
1069            value.refine(refinement, cx)
1070        }
1071    }
1072
1073    fn setting_type_name(&self) -> &'static str {
1074        type_name::<T>()
1075    }
1076
1077    fn all_local_values(&self) -> Vec<(WorktreeId, Arc<Path>, &dyn Any)> {
1078        self.local_values
1079            .iter()
1080            .map(|(id, path, value)| (*id, path.clone(), value as _))
1081            .collect()
1082    }
1083
1084    fn value_for_path(&self, path: Option<SettingsLocation>) -> &dyn Any {
1085        if let Some(SettingsLocation { worktree_id, path }) = path {
1086            for (settings_root_id, settings_path, value) in self.local_values.iter().rev() {
1087                if worktree_id == *settings_root_id && path.starts_with(settings_path) {
1088                    return value;
1089                }
1090            }
1091        }
1092
1093        self.global_value
1094            .as_ref()
1095            .unwrap_or_else(|| panic!("no default value for setting {}", self.setting_type_name()))
1096    }
1097
1098    fn set_global_value(&mut self, value: Box<dyn Any>) {
1099        self.global_value = Some(*value.downcast().unwrap());
1100    }
1101
1102    fn set_local_value(&mut self, root_id: WorktreeId, path: Arc<Path>, value: Box<dyn Any>) {
1103        let value = *value.downcast().unwrap();
1104        match self
1105            .local_values
1106            .binary_search_by_key(&(root_id, &path), |e| (e.0, &e.1))
1107        {
1108            Ok(ix) => self.local_values[ix].2 = value,
1109            Err(ix) => self.local_values.insert(ix, (root_id, path, value)),
1110        }
1111    }
1112
1113    fn json_schema(&self, generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
1114        todo!()
1115        // T::FileContent::json_schema(generator)
1116    }
1117
1118    fn edits_for_update(
1119        &self,
1120        raw_settings: &serde_json::Value,
1121        tab_size: usize,
1122        vscode_settings: &VsCodeSettings,
1123        text: &mut String,
1124        edits: &mut Vec<(Range<usize>, String)>,
1125    ) {
1126        todo!()
1127        // let (key, deserialized_setting) = self.deserialize_setting_with_key(raw_settings);
1128        // let old_content = match deserialized_setting {
1129        //     Ok(content) => content.0.downcast::<T::FileContent>().unwrap(),
1130        //     Err(_) => Box::<<T as Settings>::FileContent>::default(),
1131        // };
1132        // let mut new_content = old_content.clone();
1133        // T::import_from_vscode(vscode_settings, &mut new_content);
1134
1135        // let old_value = serde_json::to_value(&old_content).unwrap();
1136        // let new_value = serde_json::to_value(new_content).unwrap();
1137
1138        // let mut key_path = Vec::new();
1139        // if let Some(key) = key {
1140        //     key_path.push(key);
1141        // }
1142
1143        // update_value_in_json_text(
1144        //     text,
1145        //     &mut key_path,
1146        //     tab_size,
1147        //     &old_value,
1148        //     &new_value,
1149        //     T::PRESERVED_KEYS.unwrap_or_default(),
1150        //     edits,
1151        // );
1152    }
1153
1154    fn settings_ui_item(&self) -> SettingsUiEntry {
1155        todo!()
1156        // <<T as Settings>::FileContent as SettingsUi>::settings_ui_entry()
1157    }
1158}
1159
1160#[cfg(test)]
1161mod tests {
1162    use crate::{
1163        TitleBarSettingsContent, TitleBarVisibilityContent, VsCodeSettingsSource, default_settings,
1164        settings_content::LanguageSettingsContent, test_settings,
1165    };
1166
1167    use super::*;
1168    // This is so the SettingsUi macro can still work properly
1169    use crate as settings;
1170    use serde::Deserialize;
1171    use settings_ui_macros::{SettingsKey, SettingsUi};
1172    use unindent::Unindent;
1173    use util::MergeFrom;
1174
1175    #[derive(Debug, PartialEq)]
1176    struct AutoUpdateSetting {
1177        auto_update: bool,
1178    }
1179
1180    impl Settings for AutoUpdateSetting {
1181        fn from_file(content: &SettingsContent, _: &mut App) -> Option<Self> {
1182            content
1183                .auto_update
1184                .map(|auto_update| AutoUpdateSetting { auto_update })
1185        }
1186
1187        fn refine(&mut self, content: &SettingsContent, _: &mut App) {
1188            if let Some(auto_update) = content.auto_update {
1189                self.auto_update = auto_update;
1190            }
1191        }
1192
1193        fn import_from_vscode(_: &VsCodeSettings, _: &mut SettingsContent) {}
1194    }
1195
1196    #[derive(Debug, PartialEq)]
1197    struct TitleBarSettings {
1198        show: TitleBarVisibilityContent,
1199    }
1200
1201    impl Settings for TitleBarSettings {
1202        fn from_file(content: &SettingsContent, _: &mut App) -> Option<Self> {
1203            let content = content.title_bar?;
1204            Some(TitleBarSettings {
1205                show: content.show?,
1206            })
1207        }
1208
1209        fn refine(&mut self, content: &SettingsContent, _: &mut App) {
1210            let Some(content) = content.title_bar else {
1211                return;
1212            };
1213            self.show.merge_from(&content.show)
1214        }
1215
1216        fn import_from_vscode(_: &VsCodeSettings, _: &mut SettingsContent) {}
1217    }
1218
1219    #[gpui::test]
1220    fn test_settings_store_basic(cx: &mut App) {
1221        let mut store = SettingsStore::new(cx, &default_settings());
1222        store.register_setting::<AutoUpdateSetting>(cx);
1223        store.register_setting::<TitleBarSettings>(cx);
1224        // store.register_setting::<MultiKeySettings>(cx);
1225
1226        assert_eq!(
1227            store.get::<AutoUpdateSetting>(None),
1228            &AutoUpdateSetting { auto_update: true }
1229        );
1230        // assert_eq!(
1231        //     store.get::<UserSettings>(None),
1232        //     &UserSettings {
1233        //         name: "John Doe".to_string(),
1234        //         age: 30,
1235        //         staff: false,
1236        //     }
1237        // );
1238        // assert_eq!(
1239        //     store.get::<MultiKeySettings>(None),
1240        //     &MultiKeySettings {
1241        //         key1: String::new(),
1242        //         key2: String::new(),
1243        //     }
1244        // );
1245
1246        store
1247            .set_user_settings(
1248                r#"{
1249                    "auto_update": false,
1250                }"#,
1251                cx,
1252            )
1253            .unwrap();
1254
1255        assert_eq!(
1256            store.get::<AutoUpdateSetting>(None),
1257            &AutoUpdateSetting { auto_update: false }
1258        );
1259        // assert_eq!(
1260        //     store.get::<UserSettings>(None),
1261        //     &UserSettings {
1262        //         name: "John Doe".to_string(),
1263        //         age: 31,
1264        //         staff: false
1265        //     }
1266        // );
1267
1268        store
1269            .set_local_settings(
1270                WorktreeId::from_usize(1),
1271                Path::new("/root1").into(),
1272                LocalSettingsKind::Settings,
1273                Some(r#"{ "user": { "staff": true } }"#),
1274                cx,
1275            )
1276            .unwrap();
1277        store
1278            .set_local_settings(
1279                WorktreeId::from_usize(1),
1280                Path::new("/root1/subdir").into(),
1281                LocalSettingsKind::Settings,
1282                Some(r#"{ "user": { "name": "Jane Doe" } }"#),
1283                cx,
1284            )
1285            .unwrap();
1286
1287        store
1288            .set_local_settings(
1289                WorktreeId::from_usize(1),
1290                Path::new("/root2").into(),
1291                LocalSettingsKind::Settings,
1292                Some(r#"{ "user": { "age": 42 }, "key2": "b" }"#),
1293                cx,
1294            )
1295            .unwrap();
1296
1297        // assert_eq!(
1298        //     store.get::<UserSettings>(Some(SettingsLocation {
1299        //         worktree_id: WorktreeId::from_usize(1),
1300        //         path: Path::new("/root1/something"),
1301        //     })),
1302        //     &UserSettings {
1303        //         name: "John Doe".to_string(),
1304        //         age: 31,
1305        //         staff: true
1306        //     }
1307        // );
1308        // assert_eq!(
1309        //     store.get::<UserSettings>(Some(SettingsLocation {
1310        //         worktree_id: WorktreeId::from_usize(1),
1311        //         path: Path::new("/root1/subdir/something")
1312        //     })),
1313        //     &UserSettings {
1314        //         name: "Jane Doe".to_string(),
1315        //         age: 31,
1316        //         staff: true
1317        //     }
1318        // );
1319        // assert_eq!(
1320        //     store.get::<UserSettings>(Some(SettingsLocation {
1321        //         worktree_id: WorktreeId::from_usize(1),
1322        //         path: Path::new("/root2/something")
1323        //     })),
1324        //     &UserSettings {
1325        //         name: "John Doe".to_string(),
1326        //         age: 42,
1327        //         staff: false
1328        //     }
1329        // );
1330        // assert_eq!(
1331        //     store.get::<MultiKeySettings>(Some(SettingsLocation {
1332        //         worktree_id: WorktreeId::from_usize(1),
1333        //         path: Path::new("/root2/something")
1334        //     })),
1335        //     &MultiKeySettings {
1336        //         key1: "a".to_string(),
1337        //         key2: "b".to_string(),
1338        //     }
1339        // );
1340    }
1341
1342    // #[gpui::test]
1343    // fn test_setting_store_assign_json_before_register(cx: &mut App) {
1344    //     let mut store = SettingsStore::new(cx);
1345    //     store
1346    //         .set_default_settings(
1347    //             r#"{
1348    //                 "turbo": true,
1349    //                 "user": {
1350    //                     "name": "John Doe",
1351    //                     "age": 30,
1352    //                     "staff": false
1353    //                 },
1354    //                 "key1": "x"
1355    //             }"#,
1356    //             cx,
1357    //         )
1358    //         .unwrap();
1359    //     store
1360    //         .set_user_settings(r#"{ "turbo": false }"#, cx)
1361    //         .unwrap();
1362    //     store.register_setting::<UserSettings>(cx);
1363    //     store.register_setting::<TurboSetting>(cx);
1364
1365    //     assert_eq!(store.get::<TurboSetting>(None), &TurboSetting(false));
1366    //     assert_eq!(
1367    //         store.get::<UserSettings>(None),
1368    //         &UserSettings {
1369    //             name: "John Doe".to_string(),
1370    //             age: 30,
1371    //             staff: false,
1372    //         }
1373    //     );
1374
1375    //     store.register_setting::<MultiKeySettings>(cx);
1376    //     assert_eq!(
1377    //         store.get::<MultiKeySettings>(None),
1378    //         &MultiKeySettings {
1379    //             key1: "x".into(),
1380    //             key2: String::new(),
1381    //         }
1382    //     );
1383    // }
1384
1385    fn check_settings_update(
1386        store: &mut SettingsStore,
1387        old_json: String,
1388        update: fn(&mut SettingsContent),
1389        expected_new_json: String,
1390        cx: &mut App,
1391    ) {
1392        store.set_user_settings(&old_json, cx).ok();
1393        let edits = store.edits_for_update(&old_json, update);
1394        let mut new_json = old_json;
1395        for (range, replacement) in edits.into_iter() {
1396            new_json.replace_range(range, &replacement);
1397        }
1398        pretty_assertions::assert_eq!(new_json, expected_new_json);
1399    }
1400
1401    #[gpui::test]
1402    fn test_setting_store_update(cx: &mut App) {
1403        let mut store = SettingsStore::new(cx, &test_settings());
1404        // store.register_setting::<MultiKeySettings>(cx);
1405        // store.register_setting::<UserSettings>(cx);
1406        // store.register_setting::<LanguageSettings>(cx);
1407
1408        // entries added and updated
1409        check_settings_update(
1410            &mut store,
1411            r#"{
1412                "languages": {
1413                    "JSON": {
1414                        "auto_indent": true
1415                    }
1416                }
1417            }"#
1418            .unindent(),
1419            |settings| {
1420                settings
1421                    .languages_mut()
1422                    .get_mut("JSON")
1423                    .unwrap()
1424                    .auto_indent = Some(false);
1425
1426                settings.languages_mut().insert(
1427                    "Rust".into(),
1428                    LanguageSettingsContent {
1429                        auto_indent: Some(true),
1430                        ..Default::default()
1431                    },
1432                );
1433            },
1434            r#"{
1435                "languages": {
1436                    "Rust": {
1437                        "auto_indent": true
1438                    },
1439                    "JSON": {
1440                        "auto_indent": false
1441                    }
1442                }
1443            }"#
1444            .unindent(),
1445            cx,
1446        );
1447
1448        // entries removed
1449        check_settings_update(
1450            &mut store,
1451            r#"{
1452                "languages": {
1453                    "Rust": {
1454                        "language_setting_2": true
1455                    },
1456                    "JSON": {
1457                        "language_setting_1": false
1458                    }
1459                }
1460            }"#
1461            .unindent(),
1462            |settings| {
1463                settings.languages_mut().remove("JSON").unwrap();
1464            },
1465            r#"{
1466                "languages": {
1467                    "Rust": {
1468                        "language_setting_2": true
1469                    }
1470                }
1471            }"#
1472            .unindent(),
1473            cx,
1474        );
1475
1476        check_settings_update(
1477            &mut store,
1478            r#"{
1479                "languages": {
1480                    "Rust": {
1481                        "language_setting_2": true
1482                    },
1483                    "JSON": {
1484                        "language_setting_1": false
1485                    }
1486                }
1487            }"#
1488            .unindent(),
1489            |settings| {
1490                settings.languages_mut().remove("Rust").unwrap();
1491            },
1492            r#"{
1493                "languages": {
1494                    "JSON": {
1495                        "language_setting_1": false
1496                    }
1497                }
1498            }"#
1499            .unindent(),
1500            cx,
1501        );
1502
1503        // // weird formatting
1504        // check_settings_update(
1505        //     &mut store,
1506        //     r#"{
1507        //         "user":   { "age": 36, "name": "Max", "staff": true }
1508        //         }"#
1509        //     .unindent(),
1510        //     |settings| settings.age = Some(37),
1511        //     r#"{
1512        //         "user":   { "age": 37, "name": "Max", "staff": true }
1513        //         }"#
1514        //     .unindent(),
1515        //     cx,
1516        // );
1517
1518        // // single-line formatting, other keys
1519        // check_settings_update::<MultiKeySettings>(
1520        //     &mut store,
1521        //     r#"{ "one": 1, "two": 2 }"#.unindent(),
1522        //     |settings| settings.key1 = Some("x".into()),
1523        //     r#"{ "key1": "x", "one": 1, "two": 2 }"#.unindent(),
1524        //     cx,
1525        // );
1526
1527        // // empty object
1528        // check_settings_update::<UserSettings>(
1529        //     &mut store,
1530        //     r#"{
1531        //         "user": {}
1532        //     }"#
1533        //     .unindent(),
1534        //     |settings| settings.age = Some(37),
1535        //     r#"{
1536        //         "user": {
1537        //             "age": 37
1538        //         }
1539        //     }"#
1540        //     .unindent(),
1541        //     cx,
1542        // );
1543
1544        // // no content
1545        // check_settings_update::<UserSettings>(
1546        //     &mut store,
1547        //     r#""#.unindent(),
1548        //     |settings| settings.age = Some(37),
1549        //     r#"{
1550        //         "user": {
1551        //             "age": 37
1552        //         }
1553        //     }
1554        //     "#
1555        //     .unindent(),
1556        //     cx,
1557        // );
1558
1559        // check_settings_update::<UserSettings>(
1560        //     &mut store,
1561        //     r#"{
1562        //     }
1563        //     "#
1564        //     .unindent(),
1565        //     |settings| settings.age = Some(37),
1566        //     r#"{
1567        //         "user": {
1568        //             "age": 37
1569        //         }
1570        //     }
1571        //     "#
1572        //     .unindent(),
1573        //     cx,
1574        // );
1575    }
1576
1577    // #[gpui::test]
1578    // fn test_vscode_import(cx: &mut App) {
1579    //     let mut store = SettingsStore::new(cx);
1580    //     store.register_setting::<UserSettings>(cx);
1581    //     store.register_setting::<JournalSettings>(cx);
1582    //     store.register_setting::<LanguageSettings>(cx);
1583    //     store.register_setting::<MultiKeySettings>(cx);
1584
1585    //     // create settings that werent present
1586    //     check_vscode_import(
1587    //         &mut store,
1588    //         r#"{
1589    //         }
1590    //         "#
1591    //         .unindent(),
1592    //         r#" { "user.age": 37 } "#.to_owned(),
1593    //         r#"{
1594    //             "user": {
1595    //                 "age": 37
1596    //             }
1597    //         }
1598    //         "#
1599    //         .unindent(),
1600    //         cx,
1601    //     );
1602
1603    //     // persist settings that were present
1604    //     check_vscode_import(
1605    //         &mut store,
1606    //         r#"{
1607    //             "user": {
1608    //                 "staff": true,
1609    //                 "age": 37
1610    //             }
1611    //         }
1612    //         "#
1613    //         .unindent(),
1614    //         r#"{ "user.age": 42 }"#.to_owned(),
1615    //         r#"{
1616    //             "user": {
1617    //                 "staff": true,
1618    //                 "age": 42
1619    //             }
1620    //         }
1621    //         "#
1622    //         .unindent(),
1623    //         cx,
1624    //     );
1625
1626    //     // don't clobber settings that aren't present in vscode
1627    //     check_vscode_import(
1628    //         &mut store,
1629    //         r#"{
1630    //             "user": {
1631    //                 "staff": true,
1632    //                 "age": 37
1633    //             }
1634    //         }
1635    //         "#
1636    //         .unindent(),
1637    //         r#"{}"#.to_owned(),
1638    //         r#"{
1639    //             "user": {
1640    //                 "staff": true,
1641    //                 "age": 37
1642    //             }
1643    //         }
1644    //         "#
1645    //         .unindent(),
1646    //         cx,
1647    //     );
1648
1649    //     // custom enum
1650    //     check_vscode_import(
1651    //         &mut store,
1652    //         r#"{
1653    //             "journal": {
1654    //             "hour_format": "hour12"
1655    //             }
1656    //         }
1657    //         "#
1658    //         .unindent(),
1659    //         r#"{ "time_format": "24" }"#.to_owned(),
1660    //         r#"{
1661    //             "journal": {
1662    //             "hour_format": "hour24"
1663    //             }
1664    //         }
1665    //         "#
1666    //         .unindent(),
1667    //         cx,
1668    //     );
1669
1670    //     // Multiple keys for one setting
1671    //     check_vscode_import(
1672    //         &mut store,
1673    //         r#"{
1674    //             "key1": "value"
1675    //         }
1676    //         "#
1677    //         .unindent(),
1678    //         r#"{
1679    //             "key_1_first": "hello",
1680    //             "key_1_second": "world"
1681    //         }"#
1682    //         .to_owned(),
1683    //         r#"{
1684    //             "key1": "hello world"
1685    //         }
1686    //         "#
1687    //         .unindent(),
1688    //         cx,
1689    //     );
1690
1691    //     // Merging lists together entries added and updated
1692    //     check_vscode_import(
1693    //         &mut store,
1694    //         r#"{
1695    //             "languages": {
1696    //                 "JSON": {
1697    //                     "language_setting_1": true
1698    //                 },
1699    //                 "Rust": {
1700    //                     "language_setting_2": true
1701    //                 }
1702    //             }
1703    //         }"#
1704    //         .unindent(),
1705    //         r#"{
1706    //             "vscode_languages": [
1707    //                 {
1708    //                     "name": "JavaScript",
1709    //                     "language_setting_1": true
1710    //                 },
1711    //                 {
1712    //                     "name": "Rust",
1713    //                     "language_setting_2": false
1714    //                 }
1715    //             ]
1716    //         }"#
1717    //         .to_owned(),
1718    //         r#"{
1719    //             "languages": {
1720    //                 "JavaScript": {
1721    //                     "language_setting_1": true
1722    //                 },
1723    //                 "JSON": {
1724    //                     "language_setting_1": true
1725    //                 },
1726    //                 "Rust": {
1727    //                     "language_setting_2": false
1728    //                 }
1729    //             }
1730    //         }"#
1731    //         .unindent(),
1732    //         cx,
1733    //     );
1734    // }
1735
1736    // fn check_vscode_import(
1737    //     store: &mut SettingsStore,
1738    //     old: String,
1739    //     vscode: String,
1740    //     expected: String,
1741    //     cx: &mut App,
1742    // ) {
1743    //     store.set_user_settings(&old, cx).ok();
1744    //     let new = store.get_vscode_edits(
1745    //         old,
1746    //         &VsCodeSettings::from_str(&vscode, VsCodeSettingsSource::VsCode).unwrap(),
1747    //     );
1748    //     pretty_assertions::assert_eq!(new, expected);
1749    // }
1750
1751    // #[derive(Debug, PartialEq, Deserialize, SettingsUi)]
1752    // struct UserSettings {
1753    //     name: String,
1754    //     age: u32,
1755    //     staff: bool,
1756    // }
1757
1758    // #[derive(Default, Clone, Serialize, Deserialize, JsonSchema, SettingsUi, SettingsKey)]
1759    // #[settings_key(key = "user")]
1760    // struct UserSettingsContent {
1761    //     name: Option<String>,
1762    //     age: Option<u32>,
1763    //     staff: Option<bool>,
1764    // }
1765
1766    // impl Settings for UserSettings {
1767    //     type FileContent = UserSettingsContent;
1768
1769    //     fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
1770    //         sources.json_merge()
1771    //     }
1772
1773    //     fn import_from_vscode(vscode: &VsCodeSettings, current: &mut Self::FileContent) {
1774    //         vscode.u32_setting("user.age", &mut current.age);
1775    //     }
1776    // }
1777
1778    // #[derive(Debug, Deserialize, PartialEq)]
1779    // struct TurboSetting(bool);
1780
1781    // #[derive(
1782    //     Copy,
1783    //     Clone,
1784    //     PartialEq,
1785    //     Eq,
1786    //     Debug,
1787    //     Default,
1788    //     serde::Serialize,
1789    //     serde::Deserialize,
1790    //     SettingsUi,
1791    //     SettingsKey,
1792    //     JsonSchema,
1793    // )]
1794    // #[serde(default)]
1795    // #[settings_key(None)]
1796    // pub struct TurboSettingContent {
1797    //     turbo: Option<bool>,
1798    // }
1799
1800    // impl Settings for TurboSetting {
1801    //     type FileContent = TurboSettingContent;
1802
1803    //     fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
1804    //         Ok(Self(
1805    //             sources
1806    //                 .user
1807    //                 .or(sources.server)
1808    //                 .unwrap_or(sources.default)
1809    //                 .turbo
1810    //                 .unwrap_or_default(),
1811    //         ))
1812    //     }
1813
1814    //     fn import_from_vscode(_vscode: &VsCodeSettings, _current: &mut Self::FileContent) {}
1815    // }
1816
1817    // #[derive(Clone, Debug, PartialEq, Deserialize)]
1818    // struct MultiKeySettings {
1819    //     #[serde(default)]
1820    //     key1: String,
1821    //     #[serde(default)]
1822    //     key2: String,
1823    // }
1824
1825    // #[derive(Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi, SettingsKey)]
1826    // #[settings_key(None)]
1827    // struct MultiKeySettingsJson {
1828    //     key1: Option<String>,
1829    //     key2: Option<String>,
1830    // }
1831
1832    // impl Settings for MultiKeySettings {
1833    //     type FileContent = MultiKeySettingsJson;
1834
1835    //     fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
1836    //         sources.json_merge()
1837    //     }
1838
1839    //     fn import_from_vscode(vscode: &VsCodeSettings, current: &mut Self::FileContent) {
1840    //         let first_value = vscode.read_string("key_1_first");
1841    //         let second_value = vscode.read_string("key_1_second");
1842
1843    //         if let Some((first, second)) = first_value.zip(second_value) {
1844    //             current.key1 = Some(format!("{} {}", first, second));
1845    //         }
1846    //     }
1847    // }
1848
1849    // #[derive(Debug, Deserialize)]
1850    // struct JournalSettings {
1851    //     #[expect(unused)]
1852    //     pub path: String,
1853    //     #[expect(unused)]
1854    //     pub hour_format: HourFormat,
1855    // }
1856
1857    // #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1858    // #[serde(rename_all = "snake_case")]
1859    // enum HourFormat {
1860    //     Hour12,
1861    //     Hour24,
1862    // }
1863
1864    // #[derive(
1865    //     Clone, Default, Debug, Serialize, Deserialize, JsonSchema, SettingsUi, SettingsKey,
1866    // )]
1867    // #[settings_key(key = "journal")]
1868    // struct JournalSettingsJson {
1869    //     pub path: Option<String>,
1870    //     pub hour_format: Option<HourFormat>,
1871    // }
1872
1873    // impl Settings for JournalSettings {
1874    //     type FileContent = JournalSettingsJson;
1875
1876    //     fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
1877    //         sources.json_merge()
1878    //     }
1879
1880    //     fn import_from_vscode(vscode: &VsCodeSettings, current: &mut Self::FileContent) {
1881    //         vscode.enum_setting("time_format", &mut current.hour_format, |s| match s {
1882    //             "12" => Some(HourFormat::Hour12),
1883    //             "24" => Some(HourFormat::Hour24),
1884    //             _ => None,
1885    //         });
1886    //     }
1887    // }
1888
1889    // #[gpui::test]
1890    // fn test_global_settings(cx: &mut App) {
1891    //     let mut store = SettingsStore::new(cx);
1892    //     store.register_setting::<UserSettings>(cx);
1893    //     store
1894    //         .set_default_settings(
1895    //             r#"{
1896    //                 "user": {
1897    //                     "name": "John Doe",
1898    //                     "age": 30,
1899    //                     "staff": false
1900    //                 }
1901    //             }"#,
1902    //             cx,
1903    //         )
1904    //         .unwrap();
1905
1906    //     // Set global settings - these should override defaults but not user settings
1907    //     store
1908    //         .set_global_settings(
1909    //             r#"{
1910    //                 "user": {
1911    //                     "name": "Global User",
1912    //                     "age": 35,
1913    //                     "staff": true
1914    //                 }
1915    //             }"#,
1916    //             cx,
1917    //         )
1918    //         .unwrap();
1919
1920    //     // Before user settings, global settings should apply
1921    //     assert_eq!(
1922    //         store.get::<UserSettings>(None),
1923    //         &UserSettings {
1924    //             name: "Global User".to_string(),
1925    //             age: 35,
1926    //             staff: true,
1927    //         }
1928    //     );
1929
1930    //     // Set user settings - these should override both defaults and global
1931    //     store
1932    //         .set_user_settings(
1933    //             r#"{
1934    //                 "user": {
1935    //                     "age": 40
1936    //                 }
1937    //             }"#,
1938    //             cx,
1939    //         )
1940    //         .unwrap();
1941
1942    //     // User settings should override global settings
1943    //     assert_eq!(
1944    //         store.get::<UserSettings>(None),
1945    //         &UserSettings {
1946    //             name: "Global User".to_string(), // Name from global settings
1947    //             age: 40,                         // Age from user settings
1948    //             staff: true,                     // Staff from global settings
1949    //         }
1950    //     );
1951    // }
1952
1953    // #[derive(
1954    //     Clone, Debug, Default, Serialize, Deserialize, JsonSchema, SettingsUi, SettingsKey,
1955    // )]
1956    // #[settings_key(None)]
1957    // struct LanguageSettings {
1958    //     #[serde(default)]
1959    //     languages: HashMap<String, LanguageSettingEntry>,
1960    // }
1961
1962    // #[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
1963    // struct LanguageSettingEntry {
1964    //     language_setting_1: Option<bool>,
1965    //     language_setting_2: Option<bool>,
1966    // }
1967
1968    // impl Settings for LanguageSettings {
1969    //     type FileContent = Self;
1970
1971    //     fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
1972    //         sources.json_merge()
1973    //     }
1974
1975    //     fn import_from_vscode(vscode: &VsCodeSettings, current: &mut Self::FileContent) {
1976    //         current.languages.extend(
1977    //             vscode
1978    //                 .read_value("vscode_languages")
1979    //                 .and_then(|value| value.as_array())
1980    //                 .map(|languages| {
1981    //                     languages
1982    //                         .iter()
1983    //                         .filter_map(|value| value.as_object())
1984    //                         .filter_map(|item| {
1985    //                             let mut rest = item.clone();
1986    //                             let name = rest.remove("name")?.as_str()?.to_string();
1987    //                             let entry = serde_json::from_value::<LanguageSettingEntry>(
1988    //                                 serde_json::Value::Object(rest),
1989    //                             )
1990    //                             .ok()?;
1991
1992    //                             Some((name, entry))
1993    //                         })
1994    //                 })
1995    //                 .into_iter()
1996    //                 .flatten(),
1997    //         );
1998    //     }
1999    // }
2000}