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