use collections::HashMap; use schemars::{JsonSchema, json_schema}; use serde::Deserialize; use serde_json_lenient::Value; use std::borrow::Cow; use util::schemars::DefaultDenyUnknownFields; #[derive(Deserialize)] pub struct VsSnippetsFile { #[serde(flatten)] pub(crate) snippets: HashMap, } impl VsSnippetsFile { pub fn generate_json_schema() -> Value { let schema = schemars::generate::SchemaSettings::draft2019_09() .with_transform(DefaultDenyUnknownFields) .into_generator() .root_schema_for::(); serde_json_lenient::to_value(schema).unwrap() } } impl JsonSchema for VsSnippetsFile { fn schema_name() -> Cow<'static, str> { "VsSnippetsFile".into() } fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema { let snippet_schema = generator.subschema_for::(); json_schema!({ "type": "object", "additionalProperties": snippet_schema }) } } #[derive(Deserialize, JsonSchema)] #[serde(untagged)] pub(crate) enum ListOrDirect { Single(String), List(Vec), } impl From for Vec { fn from(list: ListOrDirect) -> Self { match list { ListOrDirect::Single(entry) => vec![entry], ListOrDirect::List(entries) => entries, } } } impl std::fmt::Display for ListOrDirect { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( f, "{}", match self { Self::Single(v) => v.to_owned(), Self::List(v) => v.join("\n"), } ) } } #[derive(Deserialize, JsonSchema)] pub(crate) struct VsCodeSnippet { /// The snippet prefix used to decide whether a completion menu should be shown. pub(crate) prefix: Option, /// The snippet content. Use `$1` and `${1:defaultText}` to define cursor positions and `$0` for final cursor position. pub(crate) body: ListOrDirect, /// The snippet description displayed inside the completion menu. pub(crate) description: Option, }