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(
1402            cx,
1403            r#"{
1404                "auto_update": false,
1405                "user": {
1406                    "name": "John Doe",
1407                    "age": 30,
1408                    "staff": false
1409                }
1410            }"#,
1411        );
1412        store.register_setting::<AutoUpdateSetting>(cx);
1413        store.register_setting::<TitleBarSettings>(cx);
1414        // store.register_setting::<MultiKeySettings>(cx);
1415
1416        assert_eq!(
1417            store.get::<AutoUpdateSetting>(None),
1418            &AutoUpdateSetting { auto_update: false }
1419        );
1420        // assert_eq!(
1421        //     store.get::<UserSettings>(None),
1422        //     &UserSettings {
1423        //         name: "John Doe".to_string(),
1424        //         age: 30,
1425        //         staff: false,
1426        //     }
1427        // );
1428        // assert_eq!(
1429        //     store.get::<MultiKeySettings>(None),
1430        //     &MultiKeySettings {
1431        //         key1: String::new(),
1432        //         key2: String::new(),
1433        //     }
1434        // );
1435
1436        store
1437            .set_user_settings(
1438                r#"{
1439                    "auto_update": true,
1440                    "user": { "age": 31 },
1441                    "key1": "a"
1442                }"#,
1443                cx,
1444            )
1445            .unwrap();
1446
1447        assert_eq!(
1448            store.get::<AutoUpdateSetting>(None),
1449            &AutoUpdateSetting { auto_update: true }
1450        );
1451        // assert_eq!(
1452        //     store.get::<UserSettings>(None),
1453        //     &UserSettings {
1454        //         name: "John Doe".to_string(),
1455        //         age: 31,
1456        //         staff: false
1457        //     }
1458        // );
1459
1460        store
1461            .set_local_settings(
1462                WorktreeId::from_usize(1),
1463                Path::new("/root1").into(),
1464                LocalSettingsKind::Settings,
1465                Some(r#"{ "user": { "staff": true } }"#),
1466                cx,
1467            )
1468            .unwrap();
1469        store
1470            .set_local_settings(
1471                WorktreeId::from_usize(1),
1472                Path::new("/root1/subdir").into(),
1473                LocalSettingsKind::Settings,
1474                Some(r#"{ "user": { "name": "Jane Doe" } }"#),
1475                cx,
1476            )
1477            .unwrap();
1478
1479        store
1480            .set_local_settings(
1481                WorktreeId::from_usize(1),
1482                Path::new("/root2").into(),
1483                LocalSettingsKind::Settings,
1484                Some(r#"{ "user": { "age": 42 }, "key2": "b" }"#),
1485                cx,
1486            )
1487            .unwrap();
1488
1489        // assert_eq!(
1490        //     store.get::<UserSettings>(Some(SettingsLocation {
1491        //         worktree_id: WorktreeId::from_usize(1),
1492        //         path: Path::new("/root1/something"),
1493        //     })),
1494        //     &UserSettings {
1495        //         name: "John Doe".to_string(),
1496        //         age: 31,
1497        //         staff: true
1498        //     }
1499        // );
1500        // assert_eq!(
1501        //     store.get::<UserSettings>(Some(SettingsLocation {
1502        //         worktree_id: WorktreeId::from_usize(1),
1503        //         path: Path::new("/root1/subdir/something")
1504        //     })),
1505        //     &UserSettings {
1506        //         name: "Jane Doe".to_string(),
1507        //         age: 31,
1508        //         staff: true
1509        //     }
1510        // );
1511        // assert_eq!(
1512        //     store.get::<UserSettings>(Some(SettingsLocation {
1513        //         worktree_id: WorktreeId::from_usize(1),
1514        //         path: Path::new("/root2/something")
1515        //     })),
1516        //     &UserSettings {
1517        //         name: "John Doe".to_string(),
1518        //         age: 42,
1519        //         staff: false
1520        //     }
1521        // );
1522        // assert_eq!(
1523        //     store.get::<MultiKeySettings>(Some(SettingsLocation {
1524        //         worktree_id: WorktreeId::from_usize(1),
1525        //         path: Path::new("/root2/something")
1526        //     })),
1527        //     &MultiKeySettings {
1528        //         key1: "a".to_string(),
1529        //         key2: "b".to_string(),
1530        //     }
1531        // );
1532    }
1533
1534    // #[gpui::test]
1535    // fn test_setting_store_assign_json_before_register(cx: &mut App) {
1536    //     let mut store = SettingsStore::new(cx);
1537    //     store
1538    //         .set_default_settings(
1539    //             r#"{
1540    //                 "turbo": true,
1541    //                 "user": {
1542    //                     "name": "John Doe",
1543    //                     "age": 30,
1544    //                     "staff": false
1545    //                 },
1546    //                 "key1": "x"
1547    //             }"#,
1548    //             cx,
1549    //         )
1550    //         .unwrap();
1551    //     store
1552    //         .set_user_settings(r#"{ "turbo": false }"#, cx)
1553    //         .unwrap();
1554    //     store.register_setting::<UserSettings>(cx);
1555    //     store.register_setting::<TurboSetting>(cx);
1556
1557    //     assert_eq!(store.get::<TurboSetting>(None), &TurboSetting(false));
1558    //     assert_eq!(
1559    //         store.get::<UserSettings>(None),
1560    //         &UserSettings {
1561    //             name: "John Doe".to_string(),
1562    //             age: 30,
1563    //             staff: false,
1564    //         }
1565    //     );
1566
1567    //     store.register_setting::<MultiKeySettings>(cx);
1568    //     assert_eq!(
1569    //         store.get::<MultiKeySettings>(None),
1570    //         &MultiKeySettings {
1571    //             key1: "x".into(),
1572    //             key2: String::new(),
1573    //         }
1574    //     );
1575    // }
1576
1577    fn check_settings_update(
1578        store: &mut SettingsStore,
1579        old_json: String,
1580        update: fn(&mut SettingsContent),
1581        expected_new_json: String,
1582        cx: &mut App,
1583    ) {
1584        store.set_user_settings(&old_json, cx).ok();
1585        let edits = store.edits_for_update(&old_json, update);
1586        let mut new_json = old_json;
1587        for (range, replacement) in edits.into_iter() {
1588            new_json.replace_range(range, &replacement);
1589        }
1590        pretty_assertions::assert_eq!(new_json, expected_new_json);
1591    }
1592
1593    #[gpui::test]
1594    fn test_setting_store_update(cx: &mut App) {
1595        let mut store = SettingsStore::new(cx, &test_settings());
1596        // store.register_setting::<MultiKeySettings>(cx);
1597        // store.register_setting::<UserSettings>(cx);
1598        // store.register_setting::<LanguageSettings>(cx);
1599
1600        // entries added and updated
1601        check_settings_update(
1602            &mut store,
1603            r#"{
1604                "languages": {
1605                    "JSON": {
1606                        "auto_indent": true
1607                    }
1608                }
1609            }"#
1610            .unindent(),
1611            |settings| {
1612                settings
1613                    .languages_mut()
1614                    .get_mut("JSON")
1615                    .unwrap()
1616                    .auto_indent = Some(false);
1617
1618                settings.languages_mut().insert(
1619                    "Rust".into(),
1620                    LanguageSettingsContent {
1621                        auto_indent: Some(true),
1622                        ..Default::default()
1623                    },
1624                );
1625            },
1626            r#"{
1627                "languages": {
1628                    "Rust": {
1629                        "auto_indent": true
1630                    },
1631                    "JSON": {
1632                        "auto_indent": false
1633                    }
1634                }
1635            }"#
1636            .unindent(),
1637            cx,
1638        );
1639
1640        // entries removed
1641        check_settings_update(
1642            &mut store,
1643            r#"{
1644                "languages": {
1645                    "Rust": {
1646                        "language_setting_2": true
1647                    },
1648                    "JSON": {
1649                        "language_setting_1": false
1650                    }
1651                }
1652            }"#
1653            .unindent(),
1654            |settings| {
1655                settings.languages_mut().remove("JSON").unwrap();
1656            },
1657            r#"{
1658                "languages": {
1659                    "Rust": {
1660                        "language_setting_2": true
1661                    }
1662                }
1663            }"#
1664            .unindent(),
1665            cx,
1666        );
1667
1668        check_settings_update(
1669            &mut store,
1670            r#"{
1671                "languages": {
1672                    "Rust": {
1673                        "language_setting_2": true
1674                    },
1675                    "JSON": {
1676                        "language_setting_1": false
1677                    }
1678                }
1679            }"#
1680            .unindent(),
1681            |settings| {
1682                settings.languages_mut().remove("Rust").unwrap();
1683            },
1684            r#"{
1685                "languages": {
1686                    "JSON": {
1687                        "language_setting_1": false
1688                    }
1689                }
1690            }"#
1691            .unindent(),
1692            cx,
1693        );
1694
1695        // // weird formatting
1696        // check_settings_update(
1697        //     &mut store,
1698        //     r#"{
1699        //         "user":   { "age": 36, "name": "Max", "staff": true }
1700        //         }"#
1701        //     .unindent(),
1702        //     |settings| settings.age = Some(37),
1703        //     r#"{
1704        //         "user":   { "age": 37, "name": "Max", "staff": true }
1705        //         }"#
1706        //     .unindent(),
1707        //     cx,
1708        // );
1709
1710        // // single-line formatting, other keys
1711        // check_settings_update::<MultiKeySettings>(
1712        //     &mut store,
1713        //     r#"{ "one": 1, "two": 2 }"#.unindent(),
1714        //     |settings| settings.key1 = Some("x".into()),
1715        //     r#"{ "key1": "x", "one": 1, "two": 2 }"#.unindent(),
1716        //     cx,
1717        // );
1718
1719        // // empty object
1720        // check_settings_update::<UserSettings>(
1721        //     &mut store,
1722        //     r#"{
1723        //         "user": {}
1724        //     }"#
1725        //     .unindent(),
1726        //     |settings| settings.age = Some(37),
1727        //     r#"{
1728        //         "user": {
1729        //             "age": 37
1730        //         }
1731        //     }"#
1732        //     .unindent(),
1733        //     cx,
1734        // );
1735
1736        // // no content
1737        // check_settings_update::<UserSettings>(
1738        //     &mut store,
1739        //     r#""#.unindent(),
1740        //     |settings| settings.age = Some(37),
1741        //     r#"{
1742        //         "user": {
1743        //             "age": 37
1744        //         }
1745        //     }
1746        //     "#
1747        //     .unindent(),
1748        //     cx,
1749        // );
1750
1751        // check_settings_update::<UserSettings>(
1752        //     &mut store,
1753        //     r#"{
1754        //     }
1755        //     "#
1756        //     .unindent(),
1757        //     |settings| settings.age = Some(37),
1758        //     r#"{
1759        //         "user": {
1760        //             "age": 37
1761        //         }
1762        //     }
1763        //     "#
1764        //     .unindent(),
1765        //     cx,
1766        // );
1767    }
1768
1769    // #[gpui::test]
1770    // fn test_vscode_import(cx: &mut App) {
1771    //     let mut store = SettingsStore::new(cx);
1772    //     store.register_setting::<UserSettings>(cx);
1773    //     store.register_setting::<JournalSettings>(cx);
1774    //     store.register_setting::<LanguageSettings>(cx);
1775    //     store.register_setting::<MultiKeySettings>(cx);
1776
1777    //     // create settings that werent present
1778    //     check_vscode_import(
1779    //         &mut store,
1780    //         r#"{
1781    //         }
1782    //         "#
1783    //         .unindent(),
1784    //         r#" { "user.age": 37 } "#.to_owned(),
1785    //         r#"{
1786    //             "user": {
1787    //                 "age": 37
1788    //             }
1789    //         }
1790    //         "#
1791    //         .unindent(),
1792    //         cx,
1793    //     );
1794
1795    //     // persist settings that were present
1796    //     check_vscode_import(
1797    //         &mut store,
1798    //         r#"{
1799    //             "user": {
1800    //                 "staff": true,
1801    //                 "age": 37
1802    //             }
1803    //         }
1804    //         "#
1805    //         .unindent(),
1806    //         r#"{ "user.age": 42 }"#.to_owned(),
1807    //         r#"{
1808    //             "user": {
1809    //                 "staff": true,
1810    //                 "age": 42
1811    //             }
1812    //         }
1813    //         "#
1814    //         .unindent(),
1815    //         cx,
1816    //     );
1817
1818    //     // don't clobber settings that aren't present in vscode
1819    //     check_vscode_import(
1820    //         &mut store,
1821    //         r#"{
1822    //             "user": {
1823    //                 "staff": true,
1824    //                 "age": 37
1825    //             }
1826    //         }
1827    //         "#
1828    //         .unindent(),
1829    //         r#"{}"#.to_owned(),
1830    //         r#"{
1831    //             "user": {
1832    //                 "staff": true,
1833    //                 "age": 37
1834    //             }
1835    //         }
1836    //         "#
1837    //         .unindent(),
1838    //         cx,
1839    //     );
1840
1841    //     // custom enum
1842    //     check_vscode_import(
1843    //         &mut store,
1844    //         r#"{
1845    //             "journal": {
1846    //             "hour_format": "hour12"
1847    //             }
1848    //         }
1849    //         "#
1850    //         .unindent(),
1851    //         r#"{ "time_format": "24" }"#.to_owned(),
1852    //         r#"{
1853    //             "journal": {
1854    //             "hour_format": "hour24"
1855    //             }
1856    //         }
1857    //         "#
1858    //         .unindent(),
1859    //         cx,
1860    //     );
1861
1862    //     // Multiple keys for one setting
1863    //     check_vscode_import(
1864    //         &mut store,
1865    //         r#"{
1866    //             "key1": "value"
1867    //         }
1868    //         "#
1869    //         .unindent(),
1870    //         r#"{
1871    //             "key_1_first": "hello",
1872    //             "key_1_second": "world"
1873    //         }"#
1874    //         .to_owned(),
1875    //         r#"{
1876    //             "key1": "hello world"
1877    //         }
1878    //         "#
1879    //         .unindent(),
1880    //         cx,
1881    //     );
1882
1883    //     // Merging lists together entries added and updated
1884    //     check_vscode_import(
1885    //         &mut store,
1886    //         r#"{
1887    //             "languages": {
1888    //                 "JSON": {
1889    //                     "language_setting_1": true
1890    //                 },
1891    //                 "Rust": {
1892    //                     "language_setting_2": true
1893    //                 }
1894    //             }
1895    //         }"#
1896    //         .unindent(),
1897    //         r#"{
1898    //             "vscode_languages": [
1899    //                 {
1900    //                     "name": "JavaScript",
1901    //                     "language_setting_1": true
1902    //                 },
1903    //                 {
1904    //                     "name": "Rust",
1905    //                     "language_setting_2": false
1906    //                 }
1907    //             ]
1908    //         }"#
1909    //         .to_owned(),
1910    //         r#"{
1911    //             "languages": {
1912    //                 "JavaScript": {
1913    //                     "language_setting_1": true
1914    //                 },
1915    //                 "JSON": {
1916    //                     "language_setting_1": true
1917    //                 },
1918    //                 "Rust": {
1919    //                     "language_setting_2": false
1920    //                 }
1921    //             }
1922    //         }"#
1923    //         .unindent(),
1924    //         cx,
1925    //     );
1926    // }
1927
1928    // fn check_vscode_import(
1929    //     store: &mut SettingsStore,
1930    //     old: String,
1931    //     vscode: String,
1932    //     expected: String,
1933    //     cx: &mut App,
1934    // ) {
1935    //     store.set_user_settings(&old, cx).ok();
1936    //     let new = store.get_vscode_edits(
1937    //         old,
1938    //         &VsCodeSettings::from_str(&vscode, VsCodeSettingsSource::VsCode).unwrap(),
1939    //     );
1940    //     pretty_assertions::assert_eq!(new, expected);
1941    // }
1942
1943    // #[derive(Debug, PartialEq, Deserialize, SettingsUi)]
1944    // struct UserSettings {
1945    //     name: String,
1946    //     age: u32,
1947    //     staff: bool,
1948    // }
1949
1950    // #[derive(Default, Clone, Serialize, Deserialize, JsonSchema, SettingsUi, SettingsKey)]
1951    // #[settings_key(key = "user")]
1952    // struct UserSettingsContent {
1953    //     name: Option<String>,
1954    //     age: Option<u32>,
1955    //     staff: Option<bool>,
1956    // }
1957
1958    // impl Settings for UserSettings {
1959    //     type FileContent = UserSettingsContent;
1960
1961    //     fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
1962    //         sources.json_merge()
1963    //     }
1964
1965    //     fn import_from_vscode(vscode: &VsCodeSettings, current: &mut Self::FileContent) {
1966    //         vscode.u32_setting("user.age", &mut current.age);
1967    //     }
1968    // }
1969
1970    // #[derive(Debug, Deserialize, PartialEq)]
1971    // struct TurboSetting(bool);
1972
1973    // #[derive(
1974    //     Copy,
1975    //     Clone,
1976    //     PartialEq,
1977    //     Eq,
1978    //     Debug,
1979    //     Default,
1980    //     serde::Serialize,
1981    //     serde::Deserialize,
1982    //     SettingsUi,
1983    //     SettingsKey,
1984    //     JsonSchema,
1985    // )]
1986    // #[serde(default)]
1987    // #[settings_key(None)]
1988    // pub struct TurboSettingContent {
1989    //     turbo: Option<bool>,
1990    // }
1991
1992    // impl Settings for TurboSetting {
1993    //     type FileContent = TurboSettingContent;
1994
1995    //     fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
1996    //         Ok(Self(
1997    //             sources
1998    //                 .user
1999    //                 .or(sources.server)
2000    //                 .unwrap_or(sources.default)
2001    //                 .turbo
2002    //                 .unwrap_or_default(),
2003    //         ))
2004    //     }
2005
2006    //     fn import_from_vscode(_vscode: &VsCodeSettings, _current: &mut Self::FileContent) {}
2007    // }
2008
2009    // #[derive(Clone, Debug, PartialEq, Deserialize)]
2010    // struct MultiKeySettings {
2011    //     #[serde(default)]
2012    //     key1: String,
2013    //     #[serde(default)]
2014    //     key2: String,
2015    // }
2016
2017    // #[derive(Clone, Default, Serialize, Deserialize, JsonSchema, SettingsUi, SettingsKey)]
2018    // #[settings_key(None)]
2019    // struct MultiKeySettingsJson {
2020    //     key1: Option<String>,
2021    //     key2: Option<String>,
2022    // }
2023
2024    // impl Settings for MultiKeySettings {
2025    //     type FileContent = MultiKeySettingsJson;
2026
2027    //     fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
2028    //         sources.json_merge()
2029    //     }
2030
2031    //     fn import_from_vscode(vscode: &VsCodeSettings, current: &mut Self::FileContent) {
2032    //         let first_value = vscode.read_string("key_1_first");
2033    //         let second_value = vscode.read_string("key_1_second");
2034
2035    //         if let Some((first, second)) = first_value.zip(second_value) {
2036    //             current.key1 = Some(format!("{} {}", first, second));
2037    //         }
2038    //     }
2039    // }
2040
2041    // #[derive(Debug, Deserialize)]
2042    // struct JournalSettings {
2043    //     #[expect(unused)]
2044    //     pub path: String,
2045    //     #[expect(unused)]
2046    //     pub hour_format: HourFormat,
2047    // }
2048
2049    // #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
2050    // #[serde(rename_all = "snake_case")]
2051    // enum HourFormat {
2052    //     Hour12,
2053    //     Hour24,
2054    // }
2055
2056    // #[derive(
2057    //     Clone, Default, Debug, Serialize, Deserialize, JsonSchema, SettingsUi, SettingsKey,
2058    // )]
2059    // #[settings_key(key = "journal")]
2060    // struct JournalSettingsJson {
2061    //     pub path: Option<String>,
2062    //     pub hour_format: Option<HourFormat>,
2063    // }
2064
2065    // impl Settings for JournalSettings {
2066    //     type FileContent = JournalSettingsJson;
2067
2068    //     fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
2069    //         sources.json_merge()
2070    //     }
2071
2072    //     fn import_from_vscode(vscode: &VsCodeSettings, current: &mut Self::FileContent) {
2073    //         vscode.enum_setting("time_format", &mut current.hour_format, |s| match s {
2074    //             "12" => Some(HourFormat::Hour12),
2075    //             "24" => Some(HourFormat::Hour24),
2076    //             _ => None,
2077    //         });
2078    //     }
2079    // }
2080
2081    // #[gpui::test]
2082    // fn test_global_settings(cx: &mut App) {
2083    //     let mut store = SettingsStore::new(cx);
2084    //     store.register_setting::<UserSettings>(cx);
2085    //     store
2086    //         .set_default_settings(
2087    //             r#"{
2088    //                 "user": {
2089    //                     "name": "John Doe",
2090    //                     "age": 30,
2091    //                     "staff": false
2092    //                 }
2093    //             }"#,
2094    //             cx,
2095    //         )
2096    //         .unwrap();
2097
2098    //     // Set global settings - these should override defaults but not user settings
2099    //     store
2100    //         .set_global_settings(
2101    //             r#"{
2102    //                 "user": {
2103    //                     "name": "Global User",
2104    //                     "age": 35,
2105    //                     "staff": true
2106    //                 }
2107    //             }"#,
2108    //             cx,
2109    //         )
2110    //         .unwrap();
2111
2112    //     // Before user settings, global settings should apply
2113    //     assert_eq!(
2114    //         store.get::<UserSettings>(None),
2115    //         &UserSettings {
2116    //             name: "Global User".to_string(),
2117    //             age: 35,
2118    //             staff: true,
2119    //         }
2120    //     );
2121
2122    //     // Set user settings - these should override both defaults and global
2123    //     store
2124    //         .set_user_settings(
2125    //             r#"{
2126    //                 "user": {
2127    //                     "age": 40
2128    //                 }
2129    //             }"#,
2130    //             cx,
2131    //         )
2132    //         .unwrap();
2133
2134    //     // User settings should override global settings
2135    //     assert_eq!(
2136    //         store.get::<UserSettings>(None),
2137    //         &UserSettings {
2138    //             name: "Global User".to_string(), // Name from global settings
2139    //             age: 40,                         // Age from user settings
2140    //             staff: true,                     // Staff from global settings
2141    //         }
2142    //     );
2143    // }
2144
2145    // #[derive(
2146    //     Clone, Debug, Default, Serialize, Deserialize, JsonSchema, SettingsUi, SettingsKey,
2147    // )]
2148    // #[settings_key(None)]
2149    // struct LanguageSettings {
2150    //     #[serde(default)]
2151    //     languages: HashMap<String, LanguageSettingEntry>,
2152    // }
2153
2154    // #[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
2155    // struct LanguageSettingEntry {
2156    //     language_setting_1: Option<bool>,
2157    //     language_setting_2: Option<bool>,
2158    // }
2159
2160    // impl Settings for LanguageSettings {
2161    //     type FileContent = Self;
2162
2163    //     fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
2164    //         sources.json_merge()
2165    //     }
2166
2167    //     fn import_from_vscode(vscode: &VsCodeSettings, current: &mut Self::FileContent) {
2168    //         current.languages.extend(
2169    //             vscode
2170    //                 .read_value("vscode_languages")
2171    //                 .and_then(|value| value.as_array())
2172    //                 .map(|languages| {
2173    //                     languages
2174    //                         .iter()
2175    //                         .filter_map(|value| value.as_object())
2176    //                         .filter_map(|item| {
2177    //                             let mut rest = item.clone();
2178    //                             let name = rest.remove("name")?.as_str()?.to_string();
2179    //                             let entry = serde_json::from_value::<LanguageSettingEntry>(
2180    //                                 serde_json::Value::Object(rest),
2181    //                             )
2182    //                             .ok()?;
2183
2184    //                             Some((name, entry))
2185    //                         })
2186    //                 })
2187    //                 .into_iter()
2188    //                 .flatten(),
2189    //         );
2190    //     }
2191    // }
2192}