settings_store.rs

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