format.rs

 1use collections::HashMap;
 2use schemars::{
 3    JsonSchema,
 4    r#gen::SchemaSettings,
 5    schema::{ObjectValidation, Schema, SchemaObject},
 6};
 7use serde::Deserialize;
 8use serde_json_lenient::Value;
 9
10#[derive(Deserialize)]
11pub struct VsSnippetsFile {
12    #[serde(flatten)]
13    pub(crate) snippets: HashMap<String, VsCodeSnippet>,
14}
15
16impl VsSnippetsFile {
17    pub fn generate_json_schema() -> Value {
18        let schema = SchemaSettings::draft07()
19            .with(|settings| settings.option_add_null_type = false)
20            .into_generator()
21            .into_root_schema_for::<Self>();
22
23        serde_json_lenient::to_value(schema).unwrap()
24    }
25}
26
27impl JsonSchema for VsSnippetsFile {
28    fn schema_name() -> String {
29        "VsSnippetsFile".into()
30    }
31
32    fn json_schema(r#gen: &mut schemars::r#gen::SchemaGenerator) -> Schema {
33        SchemaObject {
34            object: Some(Box::new(ObjectValidation {
35                additional_properties: Some(Box::new(r#gen.subschema_for::<VsCodeSnippet>())),
36                ..Default::default()
37            })),
38            ..Default::default()
39        }
40        .into()
41    }
42}
43
44#[derive(Deserialize, JsonSchema)]
45#[serde(untagged)]
46pub(crate) enum ListOrDirect {
47    Single(String),
48    List(Vec<String>),
49}
50
51impl From<ListOrDirect> for Vec<String> {
52    fn from(list: ListOrDirect) -> Self {
53        match list {
54            ListOrDirect::Single(entry) => vec![entry],
55            ListOrDirect::List(entries) => entries,
56        }
57    }
58}
59
60impl std::fmt::Display for ListOrDirect {
61    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
62        write!(
63            f,
64            "{}",
65            match self {
66                Self::Single(v) => v.to_owned(),
67                Self::List(v) => v.join("\n"),
68            }
69        )
70    }
71}
72
73#[derive(Deserialize, JsonSchema)]
74pub(crate) struct VsCodeSnippet {
75    /// The snippet prefix used to decide whether a completion menu should be shown.
76    pub(crate) prefix: Option<ListOrDirect>,
77
78    /// The snippet content. Use `$1` and `${1:defaultText}` to define cursor positions and `$0` for final cursor position.
79    pub(crate) body: ListOrDirect,
80
81    /// The snippet description displayed inside the completion menu.
82    pub(crate) description: Option<ListOrDirect>,
83}