use anyhow::{anyhow, Context, Result};use collections::{btree_map, hash_map, BTreeMap, HashMap};use gpui::{AppContext, AsyncAppContext, BorrowAppContext, Global, UpdateGlobal};use lazy_static::lazy_static;use schemars::{gen::SchemaGenerator, schema::RootSchema, JsonSchema};use serde::{de::DeserializeOwned, Deserialize as _, Serialize};use smallvec::SmallVec;use std::{ any::{type_name, Any, TypeId}, fmt::Debug, ops::Range, path::Path, str, sync::Arc,};use util::{merge_non_null_json_value_into, RangeExt, ResultExt as _}; /// A value that can be defined as a user setting.////// Settings can be loaded from a combination of multiple JSON files.pub trait Settings: 'static + Send + Sync { /// The name of a key within the JSON file from which this setting should /// be deserialized. If this is `None`, then the setting will be deserialized /// from the root object. const KEY: Option<&'static str>; /// The type that is stored in an individual JSON file. type FileContent: Clone + Default + Serialize + DeserializeOwned + JsonSchema; /// The logic for combining together values from one or more JSON files into the /// final value for this setting. fn load(sources: SettingsSources<Self::FileContent>, cx: &mut AppContext) -> Result<Self> where Self: Sized; fn json_schema( generator: &mut SchemaGenerator, _: &SettingsJsonSchemaParams, _: &AppContext, ) -> RootSchema { generator.root_schema_for::<Self::FileContent>() } fn missing_default() -> anyhow::Error { anyhow::anyhow!("missing default") } fn register(cx: &mut AppContext) where Self: Sized, { SettingsStore::update_global(cx, |store, cx| { store.register_setting::<Self>(cx); }); } #[track_caller] fn get<'a>(path: Option<SettingsLocation>, cx: &'a AppContext) -> &'a Self where Self: Sized, { cx.global::<SettingsStore>().get(path) } #[track_caller] fn get_global(cx: &AppContext) -> &Self where Self: Sized, { cx.global::<SettingsStore>().get(None) } #[track_caller] fn try_read_global<R>(cx: &AsyncAppContext, f: impl FnOnce(&Self) -> R) -> Option<R> where Self: Sized, { cx.try_read_global(|s: &SettingsStore, _| f(s.get(None))) } #[track_caller] fn override_global(settings: Self, cx: &mut AppContext) where Self: Sized, { cx.global_mut::<SettingsStore>().override_global(settings) }} #[derive(Clone, Copy, Debug)]pub struct SettingsSources<'a, T> { /// The default Zed settings. pub default: &'a T, /// Settings provided by extensions. pub extensions: Option<&'a T>, /// The user settings. pub user: Option<&'a T>, /// The user settings for the current release channel. pub release_channel: Option<&'a T>, /// The project settings, ordered from least specific to most specific. pub project: &'a [&'a T],} impl<'a, T: Serialize> SettingsSources<'a, T> { /// Returns an iterator over the default settings as well as all settings customizations. pub fn defaults_and_customizations(&self) -> impl Iterator<Item = &T> { [self.default].into_iter().chain(self.customizations()) } /// Returns an iterator over all of the settings customizations. pub fn customizations(&self) -> impl Iterator<Item = &T> { self.extensions .into_iter() .chain(self.user) .chain(self.release_channel) .chain(self.project.iter().copied()) } /// Returns the settings after performing a JSON merge of the provided customizations. /// /// Customizations later in the iterator win out over the earlier ones. pub fn json_merge_with<O: DeserializeOwned>( customizations: impl Iterator<Item = &'a T>, ) -> Result<O> { let mut merged = serde_json::Value::Null; for value in customizations { merge_non_null_json_value_into(serde_json::to_value(value).unwrap(), &mut merged); } Ok(serde_json::from_value(merged)?) } /// Returns the settings after performing a JSON merge of the customizations into the /// default settings. /// /// More-specific customizations win out over the less-specific ones. pub fn json_merge<O: DeserializeOwned>(&'a self) -> Result<O> { Self::json_merge_with(self.defaults_and_customizations()) }} #[derive(Clone, Copy)]pub struct SettingsLocation<'a> { pub worktree_id: usize, pub path: &'a Path,} pub struct SettingsJsonSchemaParams<'a> { pub staff_mode: bool, pub language_names: &'a [String], pub font_names: &'a [String],} /// A set of strongly-typed setting values defined via multiple JSON files.pub struct SettingsStore { setting_values: HashMap<TypeId, Box<dyn AnySettingValue>>, raw_default_settings: serde_json::Value, raw_user_settings: serde_json::Value, raw_extension_settings: serde_json::Value, raw_local_settings: BTreeMap<(usize, Arc<Path>), serde_json::Value>, tab_size_callback: Option<( TypeId, Box<dyn Fn(&dyn Any) -> Option<usize> + Send + Sync + 'static>, )>,} impl Global for SettingsStore {} impl Default for SettingsStore { fn default() -> Self { SettingsStore { setting_values: Default::default(), raw_default_settings: serde_json::json!({}), raw_user_settings: serde_json::json!({}), raw_extension_settings: serde_json::json!({}), raw_local_settings: Default::default(), tab_size_callback: Default::default(), } }} #[derive(Debug)]struct SettingValue<T> { global_value: Option<T>, local_values: Vec<(usize, Arc<Path>, T)>,} trait AnySettingValue: 'static + Send + Sync { fn key(&self) -> Option<&'static str>; fn setting_type_name(&self) -> &'static str; fn deserialize_setting(&self, json: &serde_json::Value) -> Result<DeserializedSetting>; fn load_setting( &self, sources: SettingsSources<DeserializedSetting>, cx: &mut AppContext, ) -> Result<Box<dyn Any>>; fn value_for_path(&self, path: Option<SettingsLocation>) -> &dyn Any; fn set_global_value(&mut self, value: Box<dyn Any>); fn set_local_value(&mut self, root_id: usize, path: Arc<Path>, value: Box<dyn Any>); fn json_schema( &self, generator: &mut SchemaGenerator, _: &SettingsJsonSchemaParams, cx: &AppContext, ) -> RootSchema;} struct DeserializedSetting(Box<dyn Any>); impl SettingsStore { pub fn update<C, R>(cx: &mut C, f: impl FnOnce(&mut Self, &mut C) -> R) -> R where C: BorrowAppContext, { cx.update_global(f) } /// Add a new type of setting to the store. pub fn register_setting<T: Settings>(&mut self, cx: &mut AppContext) { let setting_type_id = TypeId::of::<T>(); let entry = self.setting_values.entry(setting_type_id); if matches!(entry, hash_map::Entry::Occupied(_)) { return; } let setting_value = entry.or_insert(Box::new(SettingValue::<T> { global_value: None, local_values: Vec::new(), })); if let Some(default_settings) = setting_value .deserialize_setting(&self.raw_default_settings) .log_err() { let user_value = setting_value .deserialize_setting(&self.raw_user_settings) .log_err(); let mut release_channel_value = None; if let Some(release_settings) = &self .raw_user_settings .get(release_channel::RELEASE_CHANNEL.dev_name()) { release_channel_value = setting_value .deserialize_setting(release_settings) .log_err(); } let extension_value = setting_value .deserialize_setting(&self.raw_extension_settings) .log_err(); if let Some(setting) = setting_value .load_setting( SettingsSources { default: &default_settings, release_channel: release_channel_value.as_ref(), extensions: extension_value.as_ref(), user: user_value.as_ref(), project: &[], }, cx, ) .context("A default setting must be added to the `default.json` file") .log_err() { setting_value.set_global_value(setting); } } } /// Get the value of a setting. /// /// Panics if the given setting type has not been registered, or if there is no /// value for this setting. pub fn get<T: Settings>(&self, path: Option<SettingsLocation>) -> &T { self.setting_values .get(&TypeId::of::<T>()) .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>())) .value_for_path(path) .downcast_ref::<T>() .expect("no default value for setting type") } /// Override the global value for a setting. /// /// The given value will be overwritten if the user settings file changes. pub fn override_global<T: Settings>(&mut self, value: T) { self.setting_values .get_mut(&TypeId::of::<T>()) .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>())) .set_global_value(Box::new(value)) } /// Get the user's settings as a raw JSON value. /// /// This is only for debugging and reporting. For user-facing functionality, /// use the typed setting interface. pub fn raw_user_settings(&self) -> &serde_json::Value { &self.raw_user_settings } #[cfg(any(test, feature = "test-support"))] pub fn test(cx: &mut AppContext) -> Self { let mut this = Self::default(); this.set_default_settings(&crate::test_settings(), cx) .unwrap(); this.set_user_settings("{}", cx).unwrap(); this } /// Updates the value of a setting in the user's global configuration. /// /// This is only for tests. Normally, settings are only loaded from /// JSON files. #[cfg(any(test, feature = "test-support"))] pub fn update_user_settings<T: Settings>( &mut self, cx: &mut AppContext, update: impl FnOnce(&mut T::FileContent), ) { let old_text = serde_json::to_string(&self.raw_user_settings).unwrap(); let new_text = self.new_text_for_update::<T>(old_text, update); self.set_user_settings(&new_text, cx).unwrap(); } /// Updates the value of a setting in a JSON file, returning the new text /// for that JSON file. pub fn new_text_for_update<T: Settings>( &self, old_text: String, update: impl FnOnce(&mut T::FileContent), ) -> String { let edits = self.edits_for_update::<T>(&old_text, update); let mut new_text = old_text; for (range, replacement) in edits.into_iter() { new_text.replace_range(range, &replacement); } new_text } /// Updates the value of a setting in a JSON file, returning a list /// of edits to apply to the JSON file. pub fn edits_for_update<T: Settings>( &self, text: &str, update: impl FnOnce(&mut T::FileContent), ) -> Vec<(Range<usize>, String)> { let setting_type_id = TypeId::of::<T>(); let setting = self .setting_values .get(&setting_type_id) .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>())); let raw_settings = parse_json_with_comments::<serde_json::Value>(text).unwrap_or_default(); let old_content = match setting.deserialize_setting(&raw_settings) { Ok(content) => content.0.downcast::<T::FileContent>().unwrap(), Err(_) => Box::<<T as Settings>::FileContent>::default(), }; let mut new_content = old_content.clone(); update(&mut new_content); let old_value = serde_json::to_value(&old_content).unwrap(); let new_value = serde_json::to_value(new_content).unwrap(); let mut key_path = Vec::new(); if let Some(key) = T::KEY { key_path.push(key); } let mut edits = Vec::new(); let tab_size = self.json_tab_size(); let mut text = text.to_string(); update_value_in_json_text( &mut text, &mut key_path, tab_size, &old_value, &new_value, &mut edits, ); edits } /// Configure the tab sized when updating JSON files. pub fn set_json_tab_size_callback<T: Settings>( &mut self, get_tab_size: fn(&T) -> Option<usize>, ) { self.tab_size_callback = Some(( TypeId::of::<T>(), Box::new(move |value| get_tab_size(value.downcast_ref::<T>().unwrap())), )); } fn json_tab_size(&self) -> usize { const DEFAULT_JSON_TAB_SIZE: usize = 2; if let Some((setting_type_id, callback)) = &self.tab_size_callback { let setting_value = self.setting_values.get(setting_type_id).unwrap(); let value = setting_value.value_for_path(None); if let Some(value) = callback(value) { return value; } } DEFAULT_JSON_TAB_SIZE } /// Sets the default settings via a JSON string. /// /// The string should contain a JSON object with a default value for every setting. pub fn set_default_settings( &mut self, default_settings_content: &str, cx: &mut AppContext, ) -> Result<()> { let settings: serde_json::Value = parse_json_with_comments(default_settings_content)?; if settings.is_object() { self.raw_default_settings = settings; self.recompute_values(None, cx)?; Ok(()) } else { Err(anyhow!("settings must be an object")) } } /// Sets the user settings via a JSON string. pub fn set_user_settings( &mut self, user_settings_content: &str, cx: &mut AppContext, ) -> Result<()> { let settings: serde_json::Value = if user_settings_content.is_empty() { parse_json_with_comments("{}")? } else { parse_json_with_comments(user_settings_content)? }; if settings.is_object() { self.raw_user_settings = settings; self.recompute_values(None, cx)?; Ok(()) } else { Err(anyhow!("settings must be an object")) } } /// Add or remove a set of local settings via a JSON string. pub fn set_local_settings( &mut self, root_id: usize, path: Arc<Path>, settings_content: Option<&str>, cx: &mut AppContext, ) -> Result<()> { if settings_content.is_some_and(|content| !content.is_empty()) { self.raw_local_settings.insert( (root_id, path.clone()), parse_json_with_comments(settings_content.unwrap())?, ); } else { self.raw_local_settings.remove(&(root_id, path.clone())); } self.recompute_values(Some((root_id, &path)), cx)?; Ok(()) } pub fn set_extension_settings<T: Serialize>( &mut self, content: T, cx: &mut AppContext, ) -> Result<()> { let settings: serde_json::Value = serde_json::to_value(content)?; if settings.is_object() { self.raw_extension_settings = settings; self.recompute_values(None, cx)?; Ok(()) } else { Err(anyhow!("settings must be an object")) } } /// Add or remove a set of local settings via a JSON string. pub fn clear_local_settings(&mut self, root_id: usize, cx: &mut AppContext) -> Result<()> { self.raw_local_settings.retain(|k, _| k.0 != root_id); self.recompute_values(Some((root_id, "".as_ref())), cx)?; Ok(()) } pub fn local_settings(&self, root_id: usize) -> impl '_ + Iterator<Item = (Arc<Path>, String)> { self.raw_local_settings .range((root_id, Path::new("").into())..(root_id + 1, Path::new("").into())) .map(|((_, path), content)| (path.clone(), serde_json::to_string(content).unwrap())) } pub fn json_schema( &self, schema_params: &SettingsJsonSchemaParams, cx: &AppContext, ) -> serde_json::Value { use schemars::{Lines 1–500 of 1456. Load more
use anyhow::{anyhow, Context, Result}; use collections::{btree_map, hash_map, BTreeMap, HashMap}; use gpui::{AppContext, AsyncAppContext, BorrowAppContext, Global, UpdateGlobal}; use lazy_static::lazy_static; use schemars::{gen::SchemaGenerator, schema::RootSchema, JsonSchema}; use serde::{de::DeserializeOwned, Deserialize as _, Serialize}; use smallvec::SmallVec; use std::{ any::{type_name, Any, TypeId}, fmt::Debug, ops::Range, path::Path, str, sync::Arc, }; use util::{merge_non_null_json_value_into, RangeExt, ResultExt as _}; /// A value that can be defined as a user setting. /// /// Settings can be loaded from a combination of multiple JSON files. pub trait Settings: 'static + Send + Sync { /// The name of a key within the JSON file from which this setting should /// be deserialized. If this is `None`, then the setting will be deserialized /// from the root object. const KEY: Option<&'static str>; /// The type that is stored in an individual JSON file. type FileContent: Clone + Default + Serialize + DeserializeOwned + JsonSchema; /// The logic for combining together values from one or more JSON files into the /// final value for this setting. fn load(sources: SettingsSources<Self::FileContent>, cx: &mut AppContext) -> Result<Self> where Self: Sized; fn json_schema( generator: &mut SchemaGenerator, _: &SettingsJsonSchemaParams, _: &AppContext, ) -> RootSchema { generator.root_schema_for::<Self::FileContent>() } fn missing_default() -> anyhow::Error { anyhow::anyhow!("missing default") } fn register(cx: &mut AppContext) where Self: Sized, { SettingsStore::update_global(cx, |store, cx| { store.register_setting::<Self>(cx); }); } #[track_caller] fn get<'a>(path: Option<SettingsLocation>, cx: &'a AppContext) -> &'a Self where Self: Sized, { cx.global::<SettingsStore>().get(path) } #[track_caller] fn get_global(cx: &AppContext) -> &Self where Self: Sized, { cx.global::<SettingsStore>().get(None) } #[track_caller] fn try_read_global<R>(cx: &AsyncAppContext, f: impl FnOnce(&Self) -> R) -> Option<R> where Self: Sized, { cx.try_read_global(|s: &SettingsStore, _| f(s.get(None))) } #[track_caller] fn override_global(settings: Self, cx: &mut AppContext) where Self: Sized, { cx.global_mut::<SettingsStore>().override_global(settings) } } #[derive(Clone, Copy, Debug)] pub struct SettingsSources<'a, T> { /// The default Zed settings. pub default: &'a T, /// Settings provided by extensions. pub extensions: Option<&'a T>, /// The user settings. pub user: Option<&'a T>, /// The user settings for the current release channel. pub release_channel: Option<&'a T>, /// The project settings, ordered from least specific to most specific. pub project: &'a [&'a T], } impl<'a, T: Serialize> SettingsSources<'a, T> { /// Returns an iterator over the default settings as well as all settings customizations. pub fn defaults_and_customizations(&self) -> impl Iterator<Item = &T> { [self.default].into_iter().chain(self.customizations()) } /// Returns an iterator over all of the settings customizations. pub fn customizations(&self) -> impl Iterator<Item = &T> { self.extensions .into_iter() .chain(self.user) .chain(self.release_channel) .chain(self.project.iter().copied()) } /// Returns the settings after performing a JSON merge of the provided customizations. /// /// Customizations later in the iterator win out over the earlier ones. pub fn json_merge_with<O: DeserializeOwned>( customizations: impl Iterator<Item = &'a T>, ) -> Result<O> { let mut merged = serde_json::Value::Null; for value in customizations { merge_non_null_json_value_into(serde_json::to_value(value).unwrap(), &mut merged); } Ok(serde_json::from_value(merged)?) } /// Returns the settings after performing a JSON merge of the customizations into the /// default settings. /// /// More-specific customizations win out over the less-specific ones. pub fn json_merge<O: DeserializeOwned>(&'a self) -> Result<O> { Self::json_merge_with(self.defaults_and_customizations()) } } #[derive(Clone, Copy)] pub struct SettingsLocation<'a> { pub worktree_id: usize, pub path: &'a Path, } pub struct SettingsJsonSchemaParams<'a> { pub staff_mode: bool, pub language_names: &'a [String], pub font_names: &'a [String], } /// A set of strongly-typed setting values defined via multiple JSON files. pub struct SettingsStore { setting_values: HashMap<TypeId, Box<dyn AnySettingValue>>, raw_default_settings: serde_json::Value, raw_user_settings: serde_json::Value, raw_extension_settings: serde_json::Value, raw_local_settings: BTreeMap<(usize, Arc<Path>), serde_json::Value>, tab_size_callback: Option<( TypeId, Box<dyn Fn(&dyn Any) -> Option<usize> + Send + Sync + 'static>, )>, } impl Global for SettingsStore {} impl Default for SettingsStore { fn default() -> Self { SettingsStore { setting_values: Default::default(), raw_default_settings: serde_json::json!({}), raw_user_settings: serde_json::json!({}), raw_extension_settings: serde_json::json!({}), raw_local_settings: Default::default(), tab_size_callback: Default::default(), } } } #[derive(Debug)] struct SettingValue<T> { global_value: Option<T>, local_values: Vec<(usize, Arc<Path>, T)>, } trait AnySettingValue: 'static + Send + Sync { fn key(&self) -> Option<&'static str>; fn setting_type_name(&self) -> &'static str; fn deserialize_setting(&self, json: &serde_json::Value) -> Result<DeserializedSetting>; fn load_setting( &self, sources: SettingsSources<DeserializedSetting>, cx: &mut AppContext, ) -> Result<Box<dyn Any>>; fn value_for_path(&self, path: Option<SettingsLocation>) -> &dyn Any; fn set_global_value(&mut self, value: Box<dyn Any>); fn set_local_value(&mut self, root_id: usize, path: Arc<Path>, value: Box<dyn Any>); fn json_schema( &self, generator: &mut SchemaGenerator, _: &SettingsJsonSchemaParams, cx: &AppContext, ) -> RootSchema; } struct DeserializedSetting(Box<dyn Any>); impl SettingsStore { pub fn update<C, R>(cx: &mut C, f: impl FnOnce(&mut Self, &mut C) -> R) -> R where C: BorrowAppContext, { cx.update_global(f) } /// Add a new type of setting to the store. pub fn register_setting<T: Settings>(&mut self, cx: &mut AppContext) { let setting_type_id = TypeId::of::<T>(); let entry = self.setting_values.entry(setting_type_id); if matches!(entry, hash_map::Entry::Occupied(_)) { return; } let setting_value = entry.or_insert(Box::new(SettingValue::<T> { global_value: None, local_values: Vec::new(), })); if let Some(default_settings) = setting_value .deserialize_setting(&self.raw_default_settings) .log_err() { let user_value = setting_value .deserialize_setting(&self.raw_user_settings) .log_err(); let mut release_channel_value = None; if let Some(release_settings) = &self .raw_user_settings .get(release_channel::RELEASE_CHANNEL.dev_name()) { release_channel_value = setting_value .deserialize_setting(release_settings) .log_err(); } let extension_value = setting_value .deserialize_setting(&self.raw_extension_settings) .log_err(); if let Some(setting) = setting_value .load_setting( SettingsSources { default: &default_settings, release_channel: release_channel_value.as_ref(), extensions: extension_value.as_ref(), user: user_value.as_ref(), project: &[], }, cx, ) .context("A default setting must be added to the `default.json` file") .log_err() { setting_value.set_global_value(setting); } } } /// Get the value of a setting. /// /// Panics if the given setting type has not been registered, or if there is no /// value for this setting. pub fn get<T: Settings>(&self, path: Option<SettingsLocation>) -> &T { self.setting_values .get(&TypeId::of::<T>()) .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>())) .value_for_path(path) .downcast_ref::<T>() .expect("no default value for setting type") } /// Override the global value for a setting. /// /// The given value will be overwritten if the user settings file changes. pub fn override_global<T: Settings>(&mut self, value: T) { self.setting_values .get_mut(&TypeId::of::<T>()) .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>())) .set_global_value(Box::new(value)) } /// Get the user's settings as a raw JSON value. /// /// This is only for debugging and reporting. For user-facing functionality, /// use the typed setting interface. pub fn raw_user_settings(&self) -> &serde_json::Value { &self.raw_user_settings } #[cfg(any(test, feature = "test-support"))] pub fn test(cx: &mut AppContext) -> Self { let mut this = Self::default(); this.set_default_settings(&crate::test_settings(), cx) .unwrap(); this.set_user_settings("{}", cx).unwrap(); this } /// Updates the value of a setting in the user's global configuration. /// /// This is only for tests. Normally, settings are only loaded from /// JSON files. #[cfg(any(test, feature = "test-support"))] pub fn update_user_settings<T: Settings>( &mut self, cx: &mut AppContext, update: impl FnOnce(&mut T::FileContent), ) { let old_text = serde_json::to_string(&self.raw_user_settings).unwrap(); let new_text = self.new_text_for_update::<T>(old_text, update); self.set_user_settings(&new_text, cx).unwrap(); } /// Updates the value of a setting in a JSON file, returning the new text /// for that JSON file. pub fn new_text_for_update<T: Settings>( &self, old_text: String, update: impl FnOnce(&mut T::FileContent), ) -> String { let edits = self.edits_for_update::<T>(&old_text, update); let mut new_text = old_text; for (range, replacement) in edits.into_iter() { new_text.replace_range(range, &replacement); } new_text } /// Updates the value of a setting in a JSON file, returning a list /// of edits to apply to the JSON file. pub fn edits_for_update<T: Settings>( &self, text: &str, update: impl FnOnce(&mut T::FileContent), ) -> Vec<(Range<usize>, String)> { let setting_type_id = TypeId::of::<T>(); let setting = self .setting_values .get(&setting_type_id) .unwrap_or_else(|| panic!("unregistered setting type {}", type_name::<T>())); let raw_settings = parse_json_with_comments::<serde_json::Value>(text).unwrap_or_default(); let old_content = match setting.deserialize_setting(&raw_settings) { Ok(content) => content.0.downcast::<T::FileContent>().unwrap(), Err(_) => Box::<<T as Settings>::FileContent>::default(), }; let mut new_content = old_content.clone(); update(&mut new_content); let old_value = serde_json::to_value(&old_content).unwrap(); let new_value = serde_json::to_value(new_content).unwrap(); let mut key_path = Vec::new(); if let Some(key) = T::KEY { key_path.push(key); } let mut edits = Vec::new(); let tab_size = self.json_tab_size(); let mut text = text.to_string(); update_value_in_json_text( &mut text, &mut key_path, tab_size, &old_value, &new_value, &mut edits, ); edits } /// Configure the tab sized when updating JSON files. pub fn set_json_tab_size_callback<T: Settings>( &mut self, get_tab_size: fn(&T) -> Option<usize>, ) { self.tab_size_callback = Some(( TypeId::of::<T>(), Box::new(move |value| get_tab_size(value.downcast_ref::<T>().unwrap())), )); } fn json_tab_size(&self) -> usize { const DEFAULT_JSON_TAB_SIZE: usize = 2; if let Some((setting_type_id, callback)) = &self.tab_size_callback { let setting_value = self.setting_values.get(setting_type_id).unwrap(); let value = setting_value.value_for_path(None); if let Some(value) = callback(value) { return value; } } DEFAULT_JSON_TAB_SIZE } /// Sets the default settings via a JSON string. /// /// The string should contain a JSON object with a default value for every setting. pub fn set_default_settings( &mut self, default_settings_content: &str, cx: &mut AppContext, ) -> Result<()> { let settings: serde_json::Value = parse_json_with_comments(default_settings_content)?; if settings.is_object() { self.raw_default_settings = settings; self.recompute_values(None, cx)?; Ok(()) } else { Err(anyhow!("settings must be an object")) } } /// Sets the user settings via a JSON string. pub fn set_user_settings( &mut self, user_settings_content: &str, cx: &mut AppContext, ) -> Result<()> { let settings: serde_json::Value = if user_settings_content.is_empty() { parse_json_with_comments("{}")? } else { parse_json_with_comments(user_settings_content)? }; if settings.is_object() { self.raw_user_settings = settings; self.recompute_values(None, cx)?; Ok(()) } else { Err(anyhow!("settings must be an object")) } } /// Add or remove a set of local settings via a JSON string. pub fn set_local_settings( &mut self, root_id: usize, path: Arc<Path>, settings_content: Option<&str>, cx: &mut AppContext, ) -> Result<()> { if settings_content.is_some_and(|content| !content.is_empty()) { self.raw_local_settings.insert( (root_id, path.clone()), parse_json_with_comments(settings_content.unwrap())?, ); } else { self.raw_local_settings.remove(&(root_id, path.clone())); } self.recompute_values(Some((root_id, &path)), cx)?; Ok(()) } pub fn set_extension_settings<T: Serialize>( &mut self, content: T, cx: &mut AppContext, ) -> Result<()> { let settings: serde_json::Value = serde_json::to_value(content)?; if settings.is_object() { self.raw_extension_settings = settings; self.recompute_values(None, cx)?; Ok(()) } else { Err(anyhow!("settings must be an object")) } } /// Add or remove a set of local settings via a JSON string. pub fn clear_local_settings(&mut self, root_id: usize, cx: &mut AppContext) -> Result<()> { self.raw_local_settings.retain(|k, _| k.0 != root_id); self.recompute_values(Some((root_id, "".as_ref())), cx)?; Ok(()) } pub fn local_settings(&self, root_id: usize) -> impl '_ + Iterator<Item = (Arc<Path>, String)> { self.raw_local_settings .range((root_id, Path::new("").into())..(root_id + 1, Path::new("").into())) .map(|((_, path), content)| (path.clone(), serde_json::to_string(content).unwrap())) } pub fn json_schema( &self, schema_params: &SettingsJsonSchemaParams, cx: &AppContext, ) -> serde_json::Value { use schemars::{