format.rs

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