settings_store.rs

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