@@ -234,6 +234,14 @@ impl LanguageRegistry {
.cloned()
}
+ pub fn language_names(&self) -> Vec<String> {
+ self.languages
+ .read()
+ .iter()
+ .map(|language| language.name().to_string())
+ .collect()
+ }
+
pub fn select_language(&self, path: impl AsRef<Path>) -> Option<Arc<Language>> {
let path = path.as_ref();
let filename = path.file_name().and_then(|name| name.to_str());
@@ -1,7 +1,14 @@
use anyhow::Result;
use gpui::font_cache::{FamilyId, FontCache};
-use schemars::{schema_for, JsonSchema};
+use schemars::{
+ gen::{SchemaGenerator, SchemaSettings},
+ schema::{
+ InstanceType, ObjectValidation, Schema, SchemaObject, SingleOrVec, SubschemaValidation,
+ },
+ JsonSchema,
+};
use serde::Deserialize;
+use serde_json::Value;
use std::{collections::HashMap, sync::Arc};
use theme::{Theme, ThemeRegistry};
use util::ResultExt as _;
@@ -67,8 +74,88 @@ impl Settings {
})
}
- pub fn file_json_schema() -> serde_json::Value {
- serde_json::to_value(schema_for!(SettingsFileContent)).unwrap()
+ pub fn file_json_schema(
+ theme_names: Vec<String>,
+ language_names: Vec<String>,
+ ) -> serde_json::Value {
+ let settings = SchemaSettings::draft07().with(|settings| {
+ settings.option_add_null_type = false;
+ });
+ let generator = SchemaGenerator::new(settings);
+ let mut root_schema = generator.into_root_schema_for::<SettingsFileContent>();
+
+ // Construct theme names reference type
+ let theme_names = theme_names
+ .into_iter()
+ .map(|name| Value::String(name))
+ .collect();
+ let theme_names_schema = Schema::Object(SchemaObject {
+ instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
+ enum_values: Some(theme_names),
+ ..Default::default()
+ });
+ root_schema
+ .definitions
+ .insert("ThemeName".to_owned(), theme_names_schema);
+
+ // Construct language overrides reference type
+ let language_override_schema_reference = Schema::Object(SchemaObject {
+ reference: Some("#/definitions/LanguageOverride".to_owned()),
+ ..Default::default()
+ });
+ let language_overrides_properties = language_names
+ .into_iter()
+ .map(|name| {
+ (
+ name,
+ Schema::Object(SchemaObject {
+ subschemas: Some(Box::new(SubschemaValidation {
+ all_of: Some(vec![language_override_schema_reference.clone()]),
+ ..Default::default()
+ })),
+ ..Default::default()
+ }),
+ )
+ })
+ .collect();
+ let language_overrides_schema = Schema::Object(SchemaObject {
+ instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Object))),
+ object: Some(Box::new(ObjectValidation {
+ properties: language_overrides_properties,
+ ..Default::default()
+ })),
+ ..Default::default()
+ });
+ root_schema
+ .definitions
+ .insert("LanguageOverrides".to_owned(), language_overrides_schema);
+
+ // Modify theme property to use new theme reference type
+ let settings_file_schema = root_schema.schema.object.as_mut().unwrap();
+ let language_overrides_schema_reference = Schema::Object(SchemaObject {
+ reference: Some("#/definitions/ThemeName".to_owned()),
+ ..Default::default()
+ });
+ settings_file_schema.properties.insert(
+ "theme".to_owned(),
+ Schema::Object(SchemaObject {
+ subschemas: Some(Box::new(SubschemaValidation {
+ all_of: Some(vec![language_overrides_schema_reference]),
+ ..Default::default()
+ })),
+ ..Default::default()
+ }),
+ );
+
+ // Modify language_overrides property to use LanguageOverrides reference
+ settings_file_schema.properties.insert(
+ "language_overrides".to_owned(),
+ Schema::Object(SchemaObject {
+ reference: Some("#/definitions/LanguageOverrides".to_owned()),
+ ..Default::default()
+ }),
+ );
+ serde_json::to_value(root_schema).unwrap()
}
pub fn with_overrides(
@@ -128,7 +215,7 @@ impl Settings {
}
}
if let Some(value) = &data.theme {
- if let Some(theme) = theme_registry.get(value).log_err() {
+ if let Some(theme) = theme_registry.get(&value.to_string()).log_err() {
self.theme = theme;
}
}
@@ -142,10 +229,10 @@ impl Settings {
data.editor.preferred_line_length,
);
- for (language_name, settings) in &data.language_overrides {
+ for (language_name, settings) in data.language_overrides.clone().into_iter() {
let target = self
.language_overrides
- .entry(language_name.clone())
+ .entry(language_name.into())
.or_default();
merge_option(&mut target.tab_size, settings.tab_size);
@@ -140,13 +140,16 @@ pub fn build_workspace(
let mut workspace = Workspace::new(&workspace_params, cx);
let project = workspace.project().clone();
+ let theme_names = app_state.themes.list().collect();
+ let language_names = app_state.languages.language_names();
+
project.update(cx, |project, _| {
project.set_language_server_settings(serde_json::json!({
"json": {
"schemas": [
{
"fileMatch": "**/.zed/settings.json",
- "schema": Settings::file_json_schema(),
+ "schema": Settings::file_json_schema(theme_names, language_names),
}
]
}