diff --git a/Cargo.lock b/Cargo.lock index 934599122b1bc20f9aeeaaa2cdff02194f29c8f7..5dbdcd78d78e07a2373b591734ea04bd4a326eea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2681,6 +2681,7 @@ dependencies = [ "gpui", "language", "parking_lot 0.11.2", + "schemars", "serde", "serde_json", "theme", diff --git a/crates/extension/Cargo.toml b/crates/extension/Cargo.toml index 092f7b0bec7d6d7148855a2616da5e6fcf506c82..597bbf8f72a390acc0fa1a45d752570fb31a7ca8 100644 --- a/crates/extension/Cargo.toml +++ b/crates/extension/Cargo.toml @@ -8,6 +8,10 @@ license = "GPL-3.0-or-later" [lib] path = "src/extension_store.rs" +[[bin]] +name = "extension_json_schemas" +path = "src/extension_json_schemas.rs" + [dependencies] anyhow.workspace = true collections.workspace = true @@ -16,6 +20,7 @@ futures.workspace = true gpui.workspace = true language.workspace = true parking_lot.workspace = true +schemars.workspace = true serde.workspace = true serde_json.workspace = true theme.workspace = true diff --git a/crates/extension/src/extension_json_schemas.rs b/crates/extension/src/extension_json_schemas.rs new file mode 100644 index 0000000000000000000000000000000000000000..b46e72fce65bef2485354107166e8b9466d333d4 --- /dev/null +++ b/crates/extension/src/extension_json_schemas.rs @@ -0,0 +1,17 @@ +use language::LanguageConfig; +use schemars::schema_for; +use theme::ThemeFamilyContent; + +fn main() { + let theme_family_schema = schema_for!(ThemeFamilyContent); + let language_config_schema = schema_for!(LanguageConfig); + + println!( + "{}", + serde_json::to_string_pretty(&theme_family_schema).unwrap() + ); + println!( + "{}", + serde_json::to_string_pretty(&language_config_schema).unwrap() + ); +} diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 73db555b399ee253b163abb209cd3ea3d1ef0f7a..c3438f867e977fdee10e6396055770a1b5aa5d44 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -28,6 +28,11 @@ use lazy_static::lazy_static; use lsp::{CodeActionKind, LanguageServerBinary}; use parking_lot::Mutex; use regex::Regex; +use schemars::{ + gen::SchemaGenerator, + schema::{InstanceType, Schema, SchemaObject}, + JsonSchema, +}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use serde_json::Value; use std::{ @@ -363,7 +368,7 @@ pub struct CodeLabel { pub filter_range: Range, } -#[derive(Clone, Deserialize)] +#[derive(Clone, Deserialize, JsonSchema)] pub struct LanguageConfig { /// Human-readable name of the language. pub name: Arc, @@ -374,6 +379,7 @@ pub struct LanguageConfig { pub matcher: LanguageMatcher, /// List of bracket types in a language. #[serde(default)] + #[schemars(schema_with = "bracket_pair_config_json_schema")] pub brackets: BracketPairConfig, /// If set to true, auto indentation uses last non empty line to determine /// the indentation level for a new line. @@ -382,10 +388,12 @@ pub struct LanguageConfig { /// A regex that is used to determine whether the indentation level should be /// increased in the following line. #[serde(default, deserialize_with = "deserialize_regex")] + #[schemars(schema_with = "regex_json_schema")] pub increase_indent_pattern: Option, /// A regex that is used to determine whether the indentation level should be /// decreased in the following line. #[serde(default, deserialize_with = "deserialize_regex")] + #[schemars(schema_with = "regex_json_schema")] pub decrease_indent_pattern: Option, /// A list of characters that trigger the automatic insertion of a closing /// bracket when they immediately precede the point where an opening @@ -418,7 +426,7 @@ pub struct LanguageConfig { pub prettier_parser_name: Option, } -#[derive(Clone, Debug, Serialize, Deserialize, Default)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, JsonSchema)] pub struct LanguageMatcher { /// Given a list of `LanguageConfig`'s, the language of a file can be determined based on the path extension matching any of the `path_suffixes`. #[serde(default)] @@ -429,6 +437,7 @@ pub struct LanguageMatcher { serialize_with = "serialize_regex", deserialize_with = "deserialize_regex" )] + #[schemars(schema_with = "regex_json_schema")] pub first_line_pattern: Option, } @@ -441,13 +450,14 @@ pub struct LanguageScope { override_id: Option, } -#[derive(Clone, Deserialize, Default, Debug)] +#[derive(Clone, Deserialize, Default, Debug, JsonSchema)] pub struct LanguageConfigOverride { #[serde(default)] pub line_comments: Override>>, #[serde(default)] pub block_comment: Override<(Arc, Arc)>, #[serde(skip_deserializing)] + #[schemars(skip)] pub disabled_bracket_ixs: Vec, #[serde(default)] pub word_characters: Override>, @@ -455,7 +465,7 @@ pub struct LanguageConfigOverride { pub opt_into_language_servers: Vec, } -#[derive(Clone, Deserialize, Debug)] +#[derive(Clone, Deserialize, Debug, Serialize, JsonSchema)] #[serde(untagged)] pub enum Override { Remove { remove: bool }, @@ -513,6 +523,13 @@ fn deserialize_regex<'de, D: Deserializer<'de>>(d: D) -> Result, D } } +fn regex_json_schema(_: &mut SchemaGenerator) -> Schema { + Schema::Object(SchemaObject { + instance_type: Some(InstanceType::String.into()), + ..Default::default() + }) +} + fn serialize_regex(regex: &Option, serializer: S) -> Result where S: Serializer, @@ -539,29 +556,34 @@ pub struct FakeLspAdapter { /// /// This struct includes settings for defining which pairs of characters are considered brackets and /// also specifies any language-specific scopes where these pairs should be ignored for bracket matching purposes. -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, JsonSchema)] pub struct BracketPairConfig { /// A list of character pairs that should be treated as brackets in the context of a given language. pub pairs: Vec, /// A list of tree-sitter scopes for which a given bracket should not be active. /// N-th entry in `[Self::disabled_scopes_by_bracket_ix]` contains a list of disabled scopes for an n-th entry in `[Self::pairs]` + #[schemars(skip)] pub disabled_scopes_by_bracket_ix: Vec>, } +fn bracket_pair_config_json_schema(gen: &mut SchemaGenerator) -> Schema { + Option::>::json_schema(gen) +} + +#[derive(Deserialize, JsonSchema)] +pub struct BracketPairContent { + #[serde(flatten)] + pub bracket_pair: BracketPair, + #[serde(default)] + pub not_in: Vec, +} + impl<'de> Deserialize<'de> for BracketPairConfig { fn deserialize(deserializer: D) -> std::result::Result where D: Deserializer<'de>, { - #[derive(Deserialize)] - pub struct Entry { - #[serde(flatten)] - pub bracket_pair: BracketPair, - #[serde(default)] - pub not_in: Vec, - } - - let result = Vec::::deserialize(deserializer)?; + let result = Vec::::deserialize(deserializer)?; let mut brackets = Vec::with_capacity(result.len()); let mut disabled_scopes_by_bracket_ix = Vec::with_capacity(result.len()); for entry in result { @@ -578,7 +600,7 @@ impl<'de> Deserialize<'de> for BracketPairConfig { /// Describes a single bracket pair and how an editor should react to e.g. inserting /// an opening bracket or to a newline character insertion in between `start` and `end` characters. -#[derive(Clone, Debug, Default, Deserialize, PartialEq)] +#[derive(Clone, Debug, Default, Deserialize, PartialEq, JsonSchema)] pub struct BracketPair { /// Starting substring for a bracket. pub start: String,