settings_store.rs

   1use anyhow::{anyhow, Result};
   2use collections::{btree_map, hash_map, BTreeMap, HashMap, HashSet};
   3use gpui::AppContext;
   4use lazy_static::lazy_static;
   5use schemars::{gen::SchemaGenerator, schema::RootSchema, JsonSchema};
   6use serde::{de::DeserializeOwned, Deserialize as _, Serialize};
   7use smallvec::SmallVec;
   8use std::{
   9    any::{type_name, Any, TypeId},
  10    fmt::Debug,
  11    mem,
  12    ops::Range,
  13    path::Path,
  14    str,
  15    sync::Arc,
  16};
  17use util::{merge_non_null_json_value_into, RangeExt, ResultExt as _};
  18
  19/// A value that can be defined as a user setting.
  20///
  21/// Settings can be loaded from a combination of multiple JSON files.
  22pub trait Setting: 'static {
  23    /// The name of a key within the JSON file from which this setting should
  24    /// be deserialized. If this is `None`, then the setting will be deserialized
  25    /// from the root object.
  26    const KEY: Option<&'static str>;
  27
  28    /// The type that is stored in an individual JSON file.
  29    type FileContent: Clone + Serialize + DeserializeOwned + JsonSchema;
  30
  31    /// The logic for combining together values from one or more JSON files into the
  32    /// final value for this setting.
  33    ///
  34    /// The user values are ordered from least specific (the global settings file)
  35    /// to most specific (the innermost local settings file).
  36    fn load(
  37        default_value: &Self::FileContent,
  38        user_values: &[&Self::FileContent],
  39        cx: &AppContext,
  40    ) -> Self;
  41
  42    fn json_schema(generator: &mut SchemaGenerator, _: &SettingsJsonSchemaParams) -> RootSchema {
  43        generator.root_schema_for::<Self::FileContent>()
  44    }
  45
  46    fn json_merge(
  47        default_value: &Self::FileContent,
  48        user_values: &[&Self::FileContent],
  49    ) -> Result<Self::FileContent> {
  50        let mut merged = serde_json::Value::Null;
  51        for value in [default_value].iter().chain(user_values) {
  52            merge_non_null_json_value_into(serde_json::to_value(value).unwrap(), &mut merged);
  53        }
  54        Ok(serde_json::from_value(merged)?)
  55    }
  56
  57    fn load_via_json_merge(
  58        default_value: &Self::FileContent,
  59        user_values: &[&Self::FileContent],
  60    ) -> Self
  61    where
  62        Self: DeserializeOwned,
  63    {
  64        let mut merged = serde_json::Value::Null;
  65        for value in [default_value].iter().chain(user_values) {
  66            merge_non_null_json_value_into(serde_json::to_value(value).unwrap(), &mut merged);
  67        }
  68        serde_json::from_value(merged).unwrap()
  69    }
  70}
  71
  72pub struct SettingsJsonSchemaParams<'a> {
  73    pub theme_names: &'a [String],
  74    pub language_names: &'a [String],
  75}
  76
  77/// A set of strongly-typed setting values defined via multiple JSON files.
  78#[derive(Default)]
  79pub struct SettingsStore {
  80    setting_values: HashMap<TypeId, Box<dyn AnySettingValue>>,
  81    default_deserialized_settings: Option<DeserializedSettingMap>,
  82    user_deserialized_settings: Option<DeserializedSettingMap>,
  83    local_deserialized_settings: BTreeMap<Arc<Path>, DeserializedSettingMap>,
  84    changed_setting_types: HashSet<TypeId>,
  85    tab_size_callback: Option<(TypeId, Box<dyn Fn(&dyn Any) -> Option<usize>>)>,
  86}
  87
  88#[derive(Debug)]
  89struct SettingValue<T> {
  90    global_value: Option<T>,
  91    local_values: Vec<(Arc<Path>, T)>,
  92}
  93
  94trait AnySettingValue {
  95    fn key(&self) -> Option<&'static str>;
  96    fn setting_type_name(&self) -> &'static str;
  97    fn deserialize_setting(&self, json: &serde_json::Value) -> Result<DeserializedSetting>;
  98    fn load_setting(
  99        &self,
 100        default_value: &DeserializedSetting,
 101        custom: &[&DeserializedSetting],
 102        cx: &AppContext,
 103    ) -> Box<dyn Any>;
 104    fn value_for_path(&self, path: Option<&Path>) -> &dyn Any;
 105    fn set_global_value(&mut self, value: Box<dyn Any>);
 106    fn set_local_value(&mut self, path: Arc<Path>, value: Box<dyn Any>);
 107    fn json_schema(
 108        &self,
 109        generator: &mut SchemaGenerator,
 110        _: &SettingsJsonSchemaParams,
 111    ) -> RootSchema;
 112}
 113
 114struct DeserializedSetting(Box<dyn Any>);
 115
 116struct DeserializedSettingMap {
 117    untyped: serde_json::Value,
 118    typed: HashMap<TypeId, DeserializedSetting>,
 119}
 120
 121impl SettingsStore {
 122    /// Add a new type of setting to the store.
 123    pub fn register_setting<T: Setting>(&mut self, cx: &AppContext) {
 124        let setting_type_id = TypeId::of::<T>();
 125        let entry = self.setting_values.entry(setting_type_id);
 126        if matches!(entry, hash_map::Entry::Occupied(_)) {
 127            return;
 128        }
 129
 130        let setting_value = entry.or_insert(Box::new(SettingValue::<T> {
 131            global_value: None,
 132            local_values: Vec::new(),
 133        }));
 134
 135        if let Some(default_settings) = self.default_deserialized_settings.as_mut() {
 136            Self::load_setting_in_map(setting_type_id, setting_value, default_settings);
 137
 138            let mut user_values_stack = Vec::new();
 139            if let Some(user_settings) = self.user_deserialized_settings.as_mut() {
 140                Self::load_setting_in_map(setting_type_id, setting_value, user_settings);
 141                if let Some(user_value) = user_settings.typed.get(&setting_type_id) {
 142                    user_values_stack = vec![user_value];
 143                }
 144            }
 145
 146            if let Some(default_deserialized_value) = default_settings.typed.get(&setting_type_id) {
 147                setting_value.set_global_value(setting_value.load_setting(
 148                    default_deserialized_value,
 149                    &user_values_stack,
 150                    cx,
 151                ));
 152            }
 153        }
 154    }
 155
 156    /// Get the value of a setting.
 157    ///
 158    /// Panics if the given setting type has not been registered, or if there is no
 159    /// value for this setting.
 160    pub fn get<T: Setting>(&self, path: Option<&Path>) -> &T {
 161        self.setting_values
 162            .get(&TypeId::of::<T>())
 163            .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>()))
 164            .value_for_path(path)
 165            .downcast_ref::<T>()
 166            .expect("no default value for setting type")
 167    }
 168
 169    /// Get the user's settings as a raw JSON value.
 170    ///
 171    /// This is only for debugging and reporting. For user-facing functionality,
 172    /// use the typed setting interface.
 173    pub fn untyped_user_settings(&self) -> &serde_json::Value {
 174        self.user_deserialized_settings
 175            .as_ref()
 176            .map_or(&serde_json::Value::Null, |s| &s.untyped)
 177    }
 178
 179    #[cfg(any(test, feature = "test-support"))]
 180    pub fn test(cx: &AppContext) -> Self {
 181        let mut this = Self::default();
 182        this.set_default_settings(&crate::test_settings(), cx)
 183            .unwrap();
 184        this
 185    }
 186
 187    /// Override the global value for a particular setting.
 188    ///
 189    /// This is only for tests. Normally, settings are only loaded from
 190    /// JSON files.
 191    #[cfg(any(test, feature = "test-support"))]
 192    pub fn replace_value<T: Setting>(&mut self, value: T) {
 193        self.setting_values
 194            .get_mut(&TypeId::of::<T>())
 195            .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>()))
 196            .set_global_value(Box::new(value))
 197    }
 198
 199    /// Update the value of a setting.
 200    ///
 201    /// Returns a list of edits to apply to the JSON file.
 202    pub fn update<T: Setting>(
 203        &self,
 204        text: &str,
 205        update: impl FnOnce(&mut T::FileContent),
 206    ) -> Vec<(Range<usize>, String)> {
 207        let setting_type_id = TypeId::of::<T>();
 208        let old_content = self
 209            .user_deserialized_settings
 210            .as_ref()
 211            .unwrap()
 212            .typed
 213            .get(&setting_type_id)
 214            .unwrap()
 215            .0
 216            .downcast_ref::<T::FileContent>()
 217            .unwrap()
 218            .clone();
 219        let mut new_content = old_content.clone();
 220        update(&mut new_content);
 221
 222        let mut parser = tree_sitter::Parser::new();
 223        parser.set_language(tree_sitter_json::language()).unwrap();
 224        let tree = parser.parse(text, None).unwrap();
 225
 226        let old_value = &serde_json::to_value(old_content).unwrap();
 227        let new_value = &serde_json::to_value(new_content).unwrap();
 228
 229        let mut key_path = Vec::new();
 230        if let Some(key) = T::KEY {
 231            key_path.push(key);
 232        }
 233
 234        let mut edits = Vec::new();
 235        let tab_size = self.json_tab_size();
 236        update_value_in_json_text(
 237            &text,
 238            &tree,
 239            &mut key_path,
 240            tab_size,
 241            &old_value,
 242            &new_value,
 243            &mut edits,
 244        );
 245        edits.sort_unstable_by_key(|e| e.0.start);
 246        return edits;
 247    }
 248
 249    /// Configure the tab sized when updating JSON files.
 250    pub fn set_json_tab_size_callback<T: Setting>(
 251        &mut self,
 252        get_tab_size: fn(&T) -> Option<usize>,
 253    ) {
 254        self.tab_size_callback = Some((
 255            TypeId::of::<T>(),
 256            Box::new(move |value| get_tab_size(value.downcast_ref::<T>().unwrap())),
 257        ));
 258    }
 259
 260    fn json_tab_size(&self) -> usize {
 261        const DEFAULT_JSON_TAB_SIZE: usize = 2;
 262
 263        if let Some((setting_type_id, callback)) = &self.tab_size_callback {
 264            let setting_value = self.setting_values.get(setting_type_id).unwrap();
 265            let value = setting_value.value_for_path(None);
 266            if let Some(value) = callback(value) {
 267                return value;
 268            }
 269        }
 270
 271        DEFAULT_JSON_TAB_SIZE
 272    }
 273
 274    /// Set the default settings via a JSON string.
 275    ///
 276    /// The string should contain a JSON object with a default value for every setting.
 277    pub fn set_default_settings(
 278        &mut self,
 279        default_settings_content: &str,
 280        cx: &AppContext,
 281    ) -> Result<()> {
 282        let deserialized_setting_map = self.load_setting_map(default_settings_content)?;
 283        if deserialized_setting_map.typed.len() != self.setting_values.len() {
 284            return Err(anyhow!(
 285                "default settings file is missing fields: {:?}",
 286                self.setting_values
 287                    .iter()
 288                    .filter(|(type_id, _)| !deserialized_setting_map.typed.contains_key(type_id))
 289                    .map(|(name, _)| *name)
 290                    .collect::<Vec<_>>()
 291            ));
 292        }
 293        self.default_deserialized_settings = Some(deserialized_setting_map);
 294        self.recompute_values(false, None, None, cx);
 295        Ok(())
 296    }
 297
 298    /// Set the user settings via a JSON string.
 299    pub fn set_user_settings(
 300        &mut self,
 301        user_settings_content: &str,
 302        cx: &AppContext,
 303    ) -> Result<()> {
 304        let user_settings = self.load_setting_map(user_settings_content)?;
 305        let old_user_settings =
 306            mem::replace(&mut self.user_deserialized_settings, Some(user_settings));
 307        self.recompute_values(true, None, old_user_settings, cx);
 308        Ok(())
 309    }
 310
 311    /// Add or remove a set of local settings via a JSON string.
 312    pub fn set_local_settings(
 313        &mut self,
 314        path: Arc<Path>,
 315        settings_content: Option<&str>,
 316        cx: &AppContext,
 317    ) -> Result<()> {
 318        let removed_map = if let Some(settings_content) = settings_content {
 319            self.local_deserialized_settings
 320                .insert(path.clone(), self.load_setting_map(settings_content)?);
 321            None
 322        } else {
 323            self.local_deserialized_settings.remove(&path)
 324        };
 325        self.recompute_values(true, Some(&path), removed_map, cx);
 326        Ok(())
 327    }
 328
 329    pub fn json_schema(&self, schema_params: &SettingsJsonSchemaParams) -> serde_json::Value {
 330        use schemars::{
 331            gen::SchemaSettings,
 332            schema::{Schema, SchemaObject},
 333        };
 334
 335        let settings = SchemaSettings::draft07().with(|settings| {
 336            settings.option_add_null_type = false;
 337        });
 338        let mut generator = SchemaGenerator::new(settings);
 339        let mut combined_schema = RootSchema::default();
 340
 341        for setting_value in self.setting_values.values() {
 342            let setting_schema = setting_value.json_schema(&mut generator, schema_params);
 343            combined_schema
 344                .definitions
 345                .extend(setting_schema.definitions);
 346
 347            let target_schema = if let Some(key) = setting_value.key() {
 348                let key_schema = combined_schema
 349                    .schema
 350                    .object()
 351                    .properties
 352                    .entry(key.to_string())
 353                    .or_insert_with(|| Schema::Object(SchemaObject::default()));
 354                if let Schema::Object(key_schema) = key_schema {
 355                    key_schema
 356                } else {
 357                    continue;
 358                }
 359            } else {
 360                &mut combined_schema.schema
 361            };
 362
 363            merge_schema(target_schema, setting_schema.schema);
 364        }
 365
 366        fn merge_schema(target: &mut SchemaObject, source: SchemaObject) {
 367            if let Some(source) = source.object {
 368                let target_properties = &mut target.object().properties;
 369                for (key, value) in source.properties {
 370                    match target_properties.entry(key) {
 371                        btree_map::Entry::Vacant(e) => {
 372                            e.insert(value);
 373                        }
 374                        btree_map::Entry::Occupied(e) => {
 375                            if let (Schema::Object(target), Schema::Object(src)) =
 376                                (e.into_mut(), value)
 377                            {
 378                                merge_schema(target, src);
 379                            }
 380                        }
 381                    }
 382                }
 383            }
 384
 385            overwrite(&mut target.instance_type, source.instance_type);
 386            overwrite(&mut target.string, source.string);
 387            overwrite(&mut target.number, source.number);
 388            overwrite(&mut target.reference, source.reference);
 389            overwrite(&mut target.array, source.array);
 390            overwrite(&mut target.enum_values, source.enum_values);
 391
 392            fn overwrite<T>(target: &mut Option<T>, source: Option<T>) {
 393                if let Some(source) = source {
 394                    *target = Some(source);
 395                }
 396            }
 397        }
 398
 399        serde_json::to_value(&combined_schema).unwrap()
 400    }
 401
 402    fn recompute_values(
 403        &mut self,
 404        user_settings_changed: bool,
 405        changed_local_path: Option<&Path>,
 406        old_settings_map: Option<DeserializedSettingMap>,
 407        cx: &AppContext,
 408    ) {
 409        // Identify all of the setting types that have changed.
 410        let new_settings_map = if let Some(changed_path) = changed_local_path {
 411            self.local_deserialized_settings.get(changed_path)
 412        } else if user_settings_changed {
 413            self.user_deserialized_settings.as_ref()
 414        } else {
 415            self.default_deserialized_settings.as_ref()
 416        };
 417        self.changed_setting_types.clear();
 418        for map in [old_settings_map.as_ref(), new_settings_map] {
 419            if let Some(map) = map {
 420                self.changed_setting_types.extend(map.typed.keys());
 421            }
 422        }
 423
 424        // Reload the global and local values for every changed setting.
 425        let mut user_values_stack = Vec::<&DeserializedSetting>::new();
 426        for setting_type_id in self.changed_setting_types.iter() {
 427            let setting_value = self.setting_values.get_mut(setting_type_id).unwrap();
 428
 429            // Build the prioritized list of deserialized values to pass to the setting's
 430            // load function.
 431            user_values_stack.clear();
 432            if let Some(user_settings) = &self.user_deserialized_settings {
 433                if let Some(user_value) = user_settings.typed.get(setting_type_id) {
 434                    user_values_stack.push(&user_value);
 435                }
 436            }
 437
 438            let default_deserialized_value = if let Some(value) = self
 439                .default_deserialized_settings
 440                .as_ref()
 441                .and_then(|map| map.typed.get(setting_type_id))
 442            {
 443                value
 444            } else {
 445                continue;
 446            };
 447
 448            // If the global settings file changed, reload the global value for the field.
 449            if changed_local_path.is_none() {
 450                setting_value.set_global_value(setting_value.load_setting(
 451                    default_deserialized_value,
 452                    &user_values_stack,
 453                    cx,
 454                ));
 455            }
 456
 457            // Reload the local values for the setting.
 458            let user_value_stack_len = user_values_stack.len();
 459            for (path, deserialized_values) in &self.local_deserialized_settings {
 460                // If a local settings file changed, then avoid recomputing local
 461                // settings for any path outside of that directory.
 462                if changed_local_path.map_or(false, |changed_local_path| {
 463                    !path.starts_with(changed_local_path)
 464                }) {
 465                    continue;
 466                }
 467
 468                // Ignore recomputing settings for any path that hasn't customized that setting.
 469                let Some(deserialized_value) = deserialized_values.typed.get(setting_type_id) else {
 470                    continue;
 471                };
 472
 473                // Build a stack of all of the local values for that setting.
 474                user_values_stack.truncate(user_value_stack_len);
 475                for (preceding_path, preceding_deserialized_values) in
 476                    &self.local_deserialized_settings
 477                {
 478                    if preceding_path >= path {
 479                        break;
 480                    }
 481                    if !path.starts_with(preceding_path) {
 482                        continue;
 483                    }
 484
 485                    if let Some(preceding_deserialized_value) =
 486                        preceding_deserialized_values.typed.get(setting_type_id)
 487                    {
 488                        user_values_stack.push(&*preceding_deserialized_value);
 489                    }
 490                }
 491                user_values_stack.push(&*deserialized_value);
 492
 493                // Load the local value for the field.
 494                setting_value.set_local_value(
 495                    path.clone(),
 496                    setting_value.load_setting(default_deserialized_value, &user_values_stack, cx),
 497                );
 498            }
 499        }
 500    }
 501
 502    /// Deserialize the given JSON string into a map keyed by setting type.
 503    ///
 504    /// Returns an error if the string doesn't contain a valid JSON object.
 505    fn load_setting_map(&self, json: &str) -> Result<DeserializedSettingMap> {
 506        let mut map = DeserializedSettingMap {
 507            untyped: parse_json_with_comments(json)?,
 508            typed: HashMap::default(),
 509        };
 510        for (setting_type_id, setting_value) in self.setting_values.iter() {
 511            Self::load_setting_in_map(*setting_type_id, setting_value, &mut map);
 512        }
 513        Ok(map)
 514    }
 515
 516    fn load_setting_in_map(
 517        setting_type_id: TypeId,
 518        setting_value: &Box<dyn AnySettingValue>,
 519        map: &mut DeserializedSettingMap,
 520    ) {
 521        let value = if let Some(setting_key) = setting_value.key() {
 522            if let Some(value) = map.untyped.get(setting_key) {
 523                value
 524            } else {
 525                return;
 526            }
 527        } else {
 528            &map.untyped
 529        };
 530
 531        if let Some(deserialized_value) = setting_value.deserialize_setting(&value).log_err() {
 532            map.typed.insert(setting_type_id, deserialized_value);
 533        }
 534    }
 535}
 536
 537impl<T: Setting> AnySettingValue for SettingValue<T> {
 538    fn key(&self) -> Option<&'static str> {
 539        T::KEY
 540    }
 541
 542    fn setting_type_name(&self) -> &'static str {
 543        type_name::<T>()
 544    }
 545
 546    fn load_setting(
 547        &self,
 548        default_value: &DeserializedSetting,
 549        user_values: &[&DeserializedSetting],
 550        cx: &AppContext,
 551    ) -> Box<dyn Any> {
 552        let default_value = default_value.0.downcast_ref::<T::FileContent>().unwrap();
 553        let values: SmallVec<[&T::FileContent; 6]> = user_values
 554            .iter()
 555            .map(|value| value.0.downcast_ref().unwrap())
 556            .collect();
 557        Box::new(T::load(default_value, &values, cx))
 558    }
 559
 560    fn deserialize_setting(&self, json: &serde_json::Value) -> Result<DeserializedSetting> {
 561        let value = T::FileContent::deserialize(json)?;
 562        Ok(DeserializedSetting(Box::new(value)))
 563    }
 564
 565    fn value_for_path(&self, path: Option<&Path>) -> &dyn Any {
 566        if let Some(path) = path {
 567            for (settings_path, value) in self.local_values.iter().rev() {
 568                if path.starts_with(&settings_path) {
 569                    return value;
 570                }
 571            }
 572        }
 573        self.global_value
 574            .as_ref()
 575            .expect("no default value for setting")
 576    }
 577
 578    fn set_global_value(&mut self, value: Box<dyn Any>) {
 579        self.global_value = Some(*value.downcast().unwrap());
 580    }
 581
 582    fn set_local_value(&mut self, path: Arc<Path>, value: Box<dyn Any>) {
 583        let value = *value.downcast().unwrap();
 584        match self.local_values.binary_search_by_key(&&path, |e| &e.0) {
 585            Ok(ix) => self.local_values[ix].1 = value,
 586            Err(ix) => self.local_values.insert(ix, (path, value)),
 587        }
 588    }
 589
 590    fn json_schema(
 591        &self,
 592        generator: &mut SchemaGenerator,
 593        params: &SettingsJsonSchemaParams,
 594    ) -> RootSchema {
 595        T::json_schema(generator, params)
 596    }
 597}
 598
 599// impl Debug for SettingsStore {
 600//     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 601//         return f
 602//             .debug_struct("SettingsStore")
 603//             .field(
 604//                 "setting_value_sets_by_type",
 605//                 &self
 606//                     .setting_values
 607//                     .values()
 608//                     .map(|set| (set.setting_type_name(), set))
 609//                     .collect::<HashMap<_, _>>(),
 610//             )
 611//             .finish_non_exhaustive();
 612//     }
 613// }
 614
 615fn update_value_in_json_text<'a>(
 616    text: &str,
 617    syntax_tree: &tree_sitter::Tree,
 618    key_path: &mut Vec<&'a str>,
 619    tab_size: usize,
 620    old_value: &'a serde_json::Value,
 621    new_value: &'a serde_json::Value,
 622    edits: &mut Vec<(Range<usize>, String)>,
 623) {
 624    // If the old and new values are both objects, then compare them key by key,
 625    // preserving the comments and formatting of the unchanged parts. Otherwise,
 626    // replace the old value with the new value.
 627    if let (serde_json::Value::Object(old_object), serde_json::Value::Object(new_object)) =
 628        (old_value, new_value)
 629    {
 630        for (key, old_sub_value) in old_object.iter() {
 631            key_path.push(key);
 632            let new_sub_value = new_object.get(key).unwrap_or(&serde_json::Value::Null);
 633            update_value_in_json_text(
 634                text,
 635                syntax_tree,
 636                key_path,
 637                tab_size,
 638                old_sub_value,
 639                new_sub_value,
 640                edits,
 641            );
 642            key_path.pop();
 643        }
 644        for (key, new_sub_value) in new_object.iter() {
 645            key_path.push(key);
 646            if !old_object.contains_key(key) {
 647                update_value_in_json_text(
 648                    text,
 649                    syntax_tree,
 650                    key_path,
 651                    tab_size,
 652                    &serde_json::Value::Null,
 653                    new_sub_value,
 654                    edits,
 655                );
 656            }
 657            key_path.pop();
 658        }
 659    } else if old_value != new_value {
 660        let (range, replacement) =
 661            replace_value_in_json_text(text, syntax_tree, &key_path, tab_size, &new_value);
 662        edits.push((range, replacement));
 663    }
 664}
 665
 666fn replace_value_in_json_text(
 667    text: &str,
 668    syntax_tree: &tree_sitter::Tree,
 669    key_path: &[&str],
 670    tab_size: usize,
 671    new_value: impl Serialize,
 672) -> (Range<usize>, String) {
 673    const LANGUAGE_OVERRIDES: &'static str = "language_overrides";
 674    const LANGUAGES: &'static str = "languages";
 675
 676    lazy_static! {
 677        static ref PAIR_QUERY: tree_sitter::Query = tree_sitter::Query::new(
 678            tree_sitter_json::language(),
 679            "(pair key: (string) @key value: (_) @value)",
 680        )
 681        .unwrap();
 682    }
 683
 684    let mut cursor = tree_sitter::QueryCursor::new();
 685
 686    let has_language_overrides = text.contains(LANGUAGE_OVERRIDES);
 687
 688    let mut depth = 0;
 689    let mut last_value_range = 0..0;
 690    let mut first_key_start = None;
 691    let mut existing_value_range = 0..text.len();
 692    let matches = cursor.matches(&PAIR_QUERY, syntax_tree.root_node(), text.as_bytes());
 693    for mat in matches {
 694        if mat.captures.len() != 2 {
 695            continue;
 696        }
 697
 698        let key_range = mat.captures[0].node.byte_range();
 699        let value_range = mat.captures[1].node.byte_range();
 700
 701        // Don't enter sub objects until we find an exact
 702        // match for the current keypath
 703        if last_value_range.contains_inclusive(&value_range) {
 704            continue;
 705        }
 706
 707        last_value_range = value_range.clone();
 708
 709        if key_range.start > existing_value_range.end {
 710            break;
 711        }
 712
 713        first_key_start.get_or_insert_with(|| key_range.start);
 714
 715        let found_key = text
 716            .get(key_range.clone())
 717            .map(|key_text| {
 718                if key_path[depth] == LANGUAGES && has_language_overrides {
 719                    return key_text == format!("\"{}\"", LANGUAGE_OVERRIDES);
 720                } else {
 721                    return key_text == format!("\"{}\"", key_path[depth]);
 722                }
 723            })
 724            .unwrap_or(false);
 725
 726        if found_key {
 727            existing_value_range = value_range;
 728            // Reset last value range when increasing in depth
 729            last_value_range = existing_value_range.start..existing_value_range.start;
 730            depth += 1;
 731
 732            if depth == key_path.len() {
 733                break;
 734            } else {
 735                first_key_start = None;
 736            }
 737        }
 738    }
 739
 740    // We found the exact key we want, insert the new value
 741    if depth == key_path.len() {
 742        let new_val = to_pretty_json(&new_value, tab_size, tab_size * depth);
 743        (existing_value_range, new_val)
 744    } else {
 745        // We have key paths, construct the sub objects
 746        let new_key = if has_language_overrides && key_path[depth] == LANGUAGES {
 747            LANGUAGE_OVERRIDES
 748        } else {
 749            key_path[depth]
 750        };
 751
 752        // We don't have the key, construct the nested objects
 753        let mut new_value = serde_json::to_value(new_value).unwrap();
 754        for key in key_path[(depth + 1)..].iter().rev() {
 755            if has_language_overrides && key == &LANGUAGES {
 756                new_value = serde_json::json!({ LANGUAGE_OVERRIDES.to_string(): new_value });
 757            } else {
 758                new_value = serde_json::json!({ key.to_string(): new_value });
 759            }
 760        }
 761
 762        if let Some(first_key_start) = first_key_start {
 763            let mut row = 0;
 764            let mut column = 0;
 765            for (ix, char) in text.char_indices() {
 766                if ix == first_key_start {
 767                    break;
 768                }
 769                if char == '\n' {
 770                    row += 1;
 771                    column = 0;
 772                } else {
 773                    column += char.len_utf8();
 774                }
 775            }
 776
 777            if row > 0 {
 778                // depth is 0 based, but division needs to be 1 based.
 779                let new_val = to_pretty_json(&new_value, column / (depth + 1), column);
 780                let space = ' ';
 781                let content = format!("\"{new_key}\": {new_val},\n{space:width$}", width = column);
 782                (first_key_start..first_key_start, content)
 783            } else {
 784                let new_val = serde_json::to_string(&new_value).unwrap();
 785                let mut content = format!(r#""{new_key}": {new_val},"#);
 786                content.push(' ');
 787                (first_key_start..first_key_start, content)
 788            }
 789        } else {
 790            new_value = serde_json::json!({ new_key.to_string(): new_value });
 791            let indent_prefix_len = 4 * depth;
 792            let mut new_val = to_pretty_json(&new_value, 4, indent_prefix_len);
 793            if depth == 0 {
 794                new_val.push('\n');
 795            }
 796
 797            (existing_value_range, new_val)
 798        }
 799    }
 800}
 801
 802fn to_pretty_json(value: &impl Serialize, indent_size: usize, indent_prefix_len: usize) -> String {
 803    const SPACES: [u8; 32] = [b' '; 32];
 804
 805    debug_assert!(indent_size <= SPACES.len());
 806    debug_assert!(indent_prefix_len <= SPACES.len());
 807
 808    let mut output = Vec::new();
 809    let mut ser = serde_json::Serializer::with_formatter(
 810        &mut output,
 811        serde_json::ser::PrettyFormatter::with_indent(&SPACES[0..indent_size.min(SPACES.len())]),
 812    );
 813
 814    value.serialize(&mut ser).unwrap();
 815    let text = String::from_utf8(output).unwrap();
 816
 817    let mut adjusted_text = String::new();
 818    for (i, line) in text.split('\n').enumerate() {
 819        if i > 0 {
 820            adjusted_text.push_str(str::from_utf8(&SPACES[0..indent_prefix_len]).unwrap());
 821        }
 822        adjusted_text.push_str(line);
 823        adjusted_text.push('\n');
 824    }
 825    adjusted_text.pop();
 826    adjusted_text
 827}
 828
 829pub fn parse_json_with_comments<T: DeserializeOwned>(content: &str) -> Result<T> {
 830    Ok(serde_json::from_reader(
 831        json_comments::CommentSettings::c_style().strip_comments(content.as_bytes()),
 832    )?)
 833}
 834
 835#[cfg(test)]
 836mod tests {
 837    use super::*;
 838    use serde_derive::Deserialize;
 839    use unindent::Unindent;
 840
 841    #[gpui::test]
 842    fn test_settings_store_basic(cx: &mut AppContext) {
 843        let mut store = SettingsStore::default();
 844        store.register_setting::<UserSettings>(cx);
 845        store.register_setting::<TurboSetting>(cx);
 846        store.register_setting::<MultiKeySettings>(cx);
 847
 848        // error - missing required field in default settings
 849        store
 850            .set_default_settings(
 851                r#"{
 852                    "user": {
 853                        "name": "John Doe",
 854                        "age": 30,
 855                        "staff": false
 856                    }
 857                }"#,
 858                cx,
 859            )
 860            .unwrap_err();
 861
 862        // error - type error in default settings
 863        store
 864            .set_default_settings(
 865                r#"{
 866                    "turbo": "the-wrong-type",
 867                    "user": {
 868                        "name": "John Doe",
 869                        "age": 30,
 870                        "staff": false
 871                    }
 872                }"#,
 873                cx,
 874            )
 875            .unwrap_err();
 876
 877        // valid default settings.
 878        store
 879            .set_default_settings(
 880                r#"{
 881                    "turbo": false,
 882                    "user": {
 883                        "name": "John Doe",
 884                        "age": 30,
 885                        "staff": false
 886                    }
 887                }"#,
 888                cx,
 889            )
 890            .unwrap();
 891
 892        assert_eq!(store.get::<TurboSetting>(None), &TurboSetting(false));
 893        assert_eq!(
 894            store.get::<UserSettings>(None),
 895            &UserSettings {
 896                name: "John Doe".to_string(),
 897                age: 30,
 898                staff: false,
 899            }
 900        );
 901        assert_eq!(
 902            store.get::<MultiKeySettings>(None),
 903            &MultiKeySettings {
 904                key1: String::new(),
 905                key2: String::new(),
 906            }
 907        );
 908
 909        store
 910            .set_user_settings(
 911                r#"{
 912                    "turbo": true,
 913                    "user": { "age": 31 },
 914                    "key1": "a"
 915                }"#,
 916                cx,
 917            )
 918            .unwrap();
 919
 920        assert_eq!(store.get::<TurboSetting>(None), &TurboSetting(true));
 921        assert_eq!(
 922            store.get::<UserSettings>(None),
 923            &UserSettings {
 924                name: "John Doe".to_string(),
 925                age: 31,
 926                staff: false
 927            }
 928        );
 929
 930        store
 931            .set_local_settings(
 932                Path::new("/root1").into(),
 933                Some(r#"{ "user": { "staff": true } }"#),
 934                cx,
 935            )
 936            .unwrap();
 937        store
 938            .set_local_settings(
 939                Path::new("/root1/subdir").into(),
 940                Some(r#"{ "user": { "name": "Jane Doe" } }"#),
 941                cx,
 942            )
 943            .unwrap();
 944
 945        store
 946            .set_local_settings(
 947                Path::new("/root2").into(),
 948                Some(r#"{ "user": { "age": 42 }, "key2": "b" }"#),
 949                cx,
 950            )
 951            .unwrap();
 952
 953        assert_eq!(
 954            store.get::<UserSettings>(Some(Path::new("/root1/something"))),
 955            &UserSettings {
 956                name: "John Doe".to_string(),
 957                age: 31,
 958                staff: true
 959            }
 960        );
 961        assert_eq!(
 962            store.get::<UserSettings>(Some(Path::new("/root1/subdir/something"))),
 963            &UserSettings {
 964                name: "Jane Doe".to_string(),
 965                age: 31,
 966                staff: true
 967            }
 968        );
 969        assert_eq!(
 970            store.get::<UserSettings>(Some(Path::new("/root2/something"))),
 971            &UserSettings {
 972                name: "John Doe".to_string(),
 973                age: 42,
 974                staff: false
 975            }
 976        );
 977        assert_eq!(
 978            store.get::<MultiKeySettings>(Some(Path::new("/root2/something"))),
 979            &MultiKeySettings {
 980                key1: "a".to_string(),
 981                key2: "b".to_string(),
 982            }
 983        );
 984    }
 985
 986    #[gpui::test]
 987    fn test_setting_store_assign_json_before_register(cx: &mut AppContext) {
 988        let mut store = SettingsStore::default();
 989        store
 990            .set_default_settings(
 991                r#"{
 992                    "turbo": true,
 993                    "user": {
 994                        "name": "John Doe",
 995                        "age": 30,
 996                        "staff": false
 997                    },
 998                    "key1": "x"
 999                }"#,
1000                cx,
1001            )
1002            .unwrap();
1003        store
1004            .set_user_settings(r#"{ "turbo": false }"#, cx)
1005            .unwrap();
1006        store.register_setting::<UserSettings>(cx);
1007        store.register_setting::<TurboSetting>(cx);
1008
1009        assert_eq!(store.get::<TurboSetting>(None), &TurboSetting(false));
1010        assert_eq!(
1011            store.get::<UserSettings>(None),
1012            &UserSettings {
1013                name: "John Doe".to_string(),
1014                age: 30,
1015                staff: false,
1016            }
1017        );
1018
1019        store.register_setting::<MultiKeySettings>(cx);
1020        assert_eq!(
1021            store.get::<MultiKeySettings>(None),
1022            &MultiKeySettings {
1023                key1: "x".into(),
1024                key2: String::new(),
1025            }
1026        );
1027    }
1028
1029    #[gpui::test]
1030    fn test_setting_store_update(cx: &mut AppContext) {
1031        let mut store = SettingsStore::default();
1032        store.register_setting::<MultiKeySettings>(cx);
1033        store.register_setting::<UserSettings>(cx);
1034        store.register_setting::<LanguageSettings>(cx);
1035
1036        // entries added and updated
1037        check_settings_update::<LanguageSettings>(
1038            &mut store,
1039            r#"{
1040                "languages": {
1041                    "JSON": {
1042                        "is_enabled": true
1043                    }
1044                }
1045            }"#
1046            .unindent(),
1047            |settings| {
1048                settings.languages.get_mut("JSON").unwrap().is_enabled = false;
1049                settings
1050                    .languages
1051                    .insert("Rust".into(), LanguageSettingEntry { is_enabled: true });
1052            },
1053            r#"{
1054                "languages": {
1055                    "Rust": {
1056                        "is_enabled": true
1057                    },
1058                    "JSON": {
1059                        "is_enabled": false
1060                    }
1061                }
1062            }"#
1063            .unindent(),
1064            cx,
1065        );
1066
1067        // weird formatting
1068        check_settings_update::<UserSettings>(
1069            &mut store,
1070            r#"{
1071                "user":   { "age": 36, "name": "Max", "staff": true }
1072            }"#
1073            .unindent(),
1074            |settings| settings.age = Some(37),
1075            r#"{
1076                "user":   { "age": 37, "name": "Max", "staff": true }
1077            }"#
1078            .unindent(),
1079            cx,
1080        );
1081
1082        // single-line formatting, other keys
1083        check_settings_update::<MultiKeySettings>(
1084            &mut store,
1085            r#"{ "one": 1, "two": 2 }"#.unindent(),
1086            |settings| settings.key1 = Some("x".into()),
1087            r#"{ "key1": "x", "one": 1, "two": 2 }"#.unindent(),
1088            cx,
1089        );
1090
1091        // empty object
1092        check_settings_update::<UserSettings>(
1093            &mut store,
1094            r#"{
1095                "user": {}
1096            }"#
1097            .unindent(),
1098            |settings| settings.age = Some(37),
1099            r#"{
1100                "user": {
1101                    "age": 37
1102                }
1103            }"#
1104            .unindent(),
1105            cx,
1106        );
1107
1108        // no content
1109        check_settings_update::<UserSettings>(
1110            &mut store,
1111            r#""#.unindent(),
1112            |settings| settings.age = Some(37),
1113            r#"{
1114                "user": {
1115                    "age": 37
1116                }
1117            }
1118            "#
1119            .unindent(),
1120            cx,
1121        );
1122    }
1123
1124    fn check_settings_update<T: Setting>(
1125        store: &mut SettingsStore,
1126        old_json: String,
1127        update: fn(&mut T::FileContent),
1128        expected_new_json: String,
1129        cx: &mut AppContext,
1130    ) {
1131        store.set_user_settings(&old_json, cx).ok();
1132        let edits = store.update::<T>(&old_json, update);
1133        let mut new_json = old_json;
1134        for (range, replacement) in edits.into_iter().rev() {
1135            new_json.replace_range(range, &replacement);
1136        }
1137        pretty_assertions::assert_eq!(new_json, expected_new_json);
1138    }
1139
1140    #[derive(Debug, PartialEq, Deserialize)]
1141    struct UserSettings {
1142        name: String,
1143        age: u32,
1144        staff: bool,
1145    }
1146
1147    #[derive(Clone, Serialize, Deserialize, JsonSchema)]
1148    struct UserSettingsJson {
1149        name: Option<String>,
1150        age: Option<u32>,
1151        staff: Option<bool>,
1152    }
1153
1154    impl Setting for UserSettings {
1155        const KEY: Option<&'static str> = Some("user");
1156        type FileContent = UserSettingsJson;
1157
1158        fn load(
1159            default_value: &UserSettingsJson,
1160            user_values: &[&UserSettingsJson],
1161            _: &AppContext,
1162        ) -> Self {
1163            Self::load_via_json_merge(default_value, user_values)
1164        }
1165    }
1166
1167    #[derive(Debug, Deserialize, PartialEq)]
1168    struct TurboSetting(bool);
1169
1170    impl Setting for TurboSetting {
1171        const KEY: Option<&'static str> = Some("turbo");
1172        type FileContent = Option<bool>;
1173
1174        fn load(
1175            default_value: &Option<bool>,
1176            user_values: &[&Option<bool>],
1177            _: &AppContext,
1178        ) -> Self {
1179            Self::load_via_json_merge(default_value, user_values)
1180        }
1181    }
1182
1183    #[derive(Clone, Debug, PartialEq, Deserialize)]
1184    struct MultiKeySettings {
1185        #[serde(default)]
1186        key1: String,
1187        #[serde(default)]
1188        key2: String,
1189    }
1190
1191    #[derive(Clone, Serialize, Deserialize, JsonSchema)]
1192    struct MultiKeySettingsJson {
1193        key1: Option<String>,
1194        key2: Option<String>,
1195    }
1196
1197    impl Setting for MultiKeySettings {
1198        const KEY: Option<&'static str> = None;
1199
1200        type FileContent = MultiKeySettingsJson;
1201
1202        fn load(
1203            default_value: &MultiKeySettingsJson,
1204            user_values: &[&MultiKeySettingsJson],
1205            _: &AppContext,
1206        ) -> Self {
1207            Self::load_via_json_merge(default_value, user_values)
1208        }
1209    }
1210
1211    #[derive(Debug, Deserialize)]
1212    struct JournalSettings {
1213        pub path: String,
1214        pub hour_format: HourFormat,
1215    }
1216
1217    #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1218    #[serde(rename_all = "snake_case")]
1219    enum HourFormat {
1220        Hour12,
1221        Hour24,
1222    }
1223
1224    #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1225    struct JournalSettingsJson {
1226        pub path: Option<String>,
1227        pub hour_format: Option<HourFormat>,
1228    }
1229
1230    impl Setting for JournalSettings {
1231        const KEY: Option<&'static str> = Some("journal");
1232
1233        type FileContent = JournalSettingsJson;
1234
1235        fn load(
1236            default_value: &JournalSettingsJson,
1237            user_values: &[&JournalSettingsJson],
1238            _: &AppContext,
1239        ) -> Self {
1240            Self::load_via_json_merge(default_value, user_values)
1241        }
1242    }
1243
1244    #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1245    struct LanguageSettings {
1246        #[serde(default)]
1247        languages: HashMap<String, LanguageSettingEntry>,
1248    }
1249
1250    #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1251    struct LanguageSettingEntry {
1252        is_enabled: bool,
1253    }
1254
1255    impl Setting for LanguageSettings {
1256        const KEY: Option<&'static str> = None;
1257
1258        type FileContent = Self;
1259
1260        fn load(default_value: &Self, user_values: &[&Self], _: &AppContext) -> Self {
1261            Self::load_via_json_merge(default_value, user_values)
1262        }
1263    }
1264}