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