Generalize settings JSON schema logic to work w/ arbitrary setting types
This commit is contained in:
parent
9a6a2d9d27
commit
b6b2c5d1d1
3 changed files with 179 additions and 75 deletions
|
@ -1,8 +1,8 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use collections::{hash_map, BTreeMap, HashMap, HashSet};
|
||||
use collections::{btree_map, hash_map, BTreeMap, HashMap, HashSet};
|
||||
use gpui::AppContext;
|
||||
use lazy_static::lazy_static;
|
||||
use schemars::JsonSchema;
|
||||
use schemars::{gen::SchemaGenerator, schema::RootSchema, JsonSchema};
|
||||
use serde::{de::DeserializeOwned, Deserialize as _, Serialize};
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
|
@ -39,6 +39,10 @@ pub trait Setting: 'static {
|
|||
cx: &AppContext,
|
||||
) -> Self;
|
||||
|
||||
fn json_schema(generator: &mut SchemaGenerator, _: &SettingsJsonSchemaParams) -> RootSchema {
|
||||
generator.root_schema_for::<Self::FileContent>()
|
||||
}
|
||||
|
||||
fn load_via_json_merge(
|
||||
default_value: &Self::FileContent,
|
||||
user_values: &[&Self::FileContent],
|
||||
|
@ -54,6 +58,11 @@ pub trait Setting: 'static {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct SettingsJsonSchemaParams<'a> {
|
||||
pub theme_names: &'a [String],
|
||||
pub language_names: &'a [String],
|
||||
}
|
||||
|
||||
/// A set of strongly-typed setting values defined via multiple JSON files.
|
||||
#[derive(Default)]
|
||||
pub struct SettingsStore {
|
||||
|
@ -84,6 +93,11 @@ trait AnySettingValue {
|
|||
fn value_for_path(&self, path: Option<&Path>) -> &dyn Any;
|
||||
fn set_global_value(&mut self, value: Box<dyn Any>);
|
||||
fn set_local_value(&mut self, path: Arc<Path>, value: Box<dyn Any>);
|
||||
fn json_schema(
|
||||
&self,
|
||||
generator: &mut SchemaGenerator,
|
||||
_: &SettingsJsonSchemaParams,
|
||||
) -> RootSchema;
|
||||
}
|
||||
|
||||
struct DeserializedSetting(Box<dyn Any>);
|
||||
|
@ -270,6 +284,79 @@ impl SettingsStore {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn json_schema(&self, schema_params: &SettingsJsonSchemaParams) -> serde_json::Value {
|
||||
use schemars::{
|
||||
gen::SchemaSettings,
|
||||
schema::{Schema, SchemaObject},
|
||||
};
|
||||
|
||||
let settings = SchemaSettings::draft07().with(|settings| {
|
||||
settings.option_add_null_type = false;
|
||||
});
|
||||
let mut generator = SchemaGenerator::new(settings);
|
||||
let mut combined_schema = RootSchema::default();
|
||||
|
||||
for setting_value in self.setting_values.values() {
|
||||
let setting_schema = setting_value.json_schema(&mut generator, schema_params);
|
||||
combined_schema
|
||||
.definitions
|
||||
.extend(setting_schema.definitions);
|
||||
|
||||
let target_schema = if let Some(key) = setting_value.key() {
|
||||
let key_schema = combined_schema
|
||||
.schema
|
||||
.object()
|
||||
.properties
|
||||
.entry(key.to_string())
|
||||
.or_insert_with(|| Schema::Object(SchemaObject::default()));
|
||||
if let Schema::Object(key_schema) = key_schema {
|
||||
key_schema
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
&mut combined_schema.schema
|
||||
};
|
||||
|
||||
merge_schema(target_schema, setting_schema.schema);
|
||||
}
|
||||
|
||||
fn merge_schema(target: &mut SchemaObject, source: SchemaObject) {
|
||||
if let Some(source) = source.object {
|
||||
let target_properties = &mut target.object().properties;
|
||||
for (key, value) in source.properties {
|
||||
match target_properties.entry(key) {
|
||||
btree_map::Entry::Vacant(e) => {
|
||||
e.insert(value);
|
||||
}
|
||||
btree_map::Entry::Occupied(e) => {
|
||||
if let (Schema::Object(target), Schema::Object(src)) =
|
||||
(e.into_mut(), value)
|
||||
{
|
||||
merge_schema(target, src);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
overwrite(&mut target.instance_type, source.instance_type);
|
||||
overwrite(&mut target.string, source.string);
|
||||
overwrite(&mut target.number, source.number);
|
||||
overwrite(&mut target.reference, source.reference);
|
||||
overwrite(&mut target.array, source.array);
|
||||
overwrite(&mut target.enum_values, source.enum_values);
|
||||
|
||||
fn overwrite<T>(target: &mut Option<T>, source: Option<T>) {
|
||||
if let Some(source) = source {
|
||||
*target = Some(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serde_json::to_value(&combined_schema).unwrap()
|
||||
}
|
||||
|
||||
fn recompute_values(
|
||||
&mut self,
|
||||
user_settings_changed: bool,
|
||||
|
@ -457,6 +544,14 @@ impl<T: Setting> AnySettingValue for SettingValue<T> {
|
|||
Err(ix) => self.local_values.insert(ix, (path, value)),
|
||||
}
|
||||
}
|
||||
|
||||
fn json_schema(
|
||||
&self,
|
||||
generator: &mut SchemaGenerator,
|
||||
params: &SettingsJsonSchemaParams,
|
||||
) -> RootSchema {
|
||||
T::json_schema(generator, params)
|
||||
}
|
||||
}
|
||||
|
||||
// impl Debug for SettingsStore {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue