1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
use serde::{Deserialize, Serialize};
use tracing::metadata::LevelFilter;

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct Config {
    #[serde(default)]
    pub client: LspClient,
    #[serde(default)]
    pub debug: DebugConfig,
    #[serde(default)]
    pub logging: LoggingConfig,
    #[serde(default)]
    pub inlay_hints: InlayHintsConfig,
    #[serde(default)]
    pub diagnostic: DiagnosticConfig,
    #[serde(default)]
    pub on_enter: OnEnterConfig,
    #[serde(default, skip_serializing)]
    trace: TraceConfig,
    #[serde(default)]
    pub garbage_collection: GarbageCollectionConfig,
}

#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum LspClient {
    VsCode,
    #[serde(other)]
    #[default]
    Other,
}

#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Default)]
struct TraceConfig {}

// Options for debugging various parts of the server.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DebugConfig {
    pub show_collected_tokens_as_warnings: Warnings,
}

impl Default for DebugConfig {
    fn default() -> Self {
        Self {
            show_collected_tokens_as_warnings: Warnings::Default,
        }
    }
}

// Options for displaying compiler diagnostics.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DiagnosticConfig {
    pub show_warnings: bool,
    pub show_errors: bool,
}

impl Default for DiagnosticConfig {
    fn default() -> Self {
        Self {
            show_warnings: true,
            show_errors: true,
        }
    }
}

// Options for configuring garbage collection.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GarbageCollectionConfig {
    pub gc_enabled: bool,
}

impl Default for GarbageCollectionConfig {
    fn default() -> Self {
        Self { gc_enabled: true }
    }
}

// Options for configuring server logging.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct LoggingConfig {
    #[serde(with = "LevelFilterDef")]
    pub level: LevelFilter,
}

impl Default for LoggingConfig {
    fn default() -> Self {
        Self {
            level: LevelFilter::OFF,
        }
    }
}

// This allows us to deserialize the enum that is defined in another crate.
#[derive(Deserialize, Serialize, Clone)]
#[serde(rename_all = "lowercase")]
#[serde(remote = "LevelFilter")]
#[allow(clippy::upper_case_acronyms)]
enum LevelFilterDef {
    OFF,
    ERROR,
    WARN,
    INFO,
    DEBUG,
    TRACE,
}

/// Instructs the client to draw squiggly lines
/// under all of the tokens that our server managed to parse.
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
pub enum Warnings {
    Default,
    Parsed,
    Typed,
}

// Options for configuring inlay hints.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct InlayHintsConfig {
    /// Whether to render leading colons for type hints, and trailing colons for parameter hints.
    pub render_colons: bool,
    /// Whether to show inlay type hints for variables.
    pub type_hints: bool,
    /// Maximum length for inlay hints. Set to null to have an unlimited length.
    pub max_length: Option<usize>,
}

impl Default for InlayHintsConfig {
    fn default() -> Self {
        Self {
            render_colons: true,
            type_hints: true,
            max_length: Some(25),
        }
    }
}

// Options for additional behavior when the user presses enter.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct OnEnterConfig {
    pub continue_doc_comments: Option<bool>,
    pub continue_comments: Option<bool>,
}

impl Default for OnEnterConfig {
    fn default() -> Self {
        Self {
            continue_doc_comments: Some(true),
            continue_comments: Some(false),
        }
    }
}

impl<'de> serde::Deserialize<'de> for Warnings {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct WarningsVisitor;

        impl<'de> serde::de::Visitor<'de> for WarningsVisitor {
            type Value = Warnings;

            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(formatter, "a string representing a Warnings")
            }

            fn visit_str<E: serde::de::Error>(self, s: &str) -> Result<Warnings, E> {
                Ok(match s {
                    "off" => Warnings::Default,
                    "parsed" => Warnings::Parsed,
                    "typed" => Warnings::Typed,
                    _ => return Err(E::invalid_value(serde::de::Unexpected::Str(s), &self)),
                })
            }
        }

        deserializer.deserialize_any(WarningsVisitor)
    }
}