corsa_client/api/
capabilities.rs1use corsa_core::fast::CompactString;
2use serde::{Deserialize, Serialize};
3
4#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
6#[serde(rename_all = "camelCase")]
7pub struct CapabilitiesResponse {
8 #[serde(default)]
10 pub runtime: RuntimeCapabilities,
11 #[serde(default)]
13 pub overlay: OverlayCapabilities,
14 #[serde(default)]
16 pub diagnostics: DiagnosticsCapabilities,
17 #[serde(default)]
19 pub editor: EditorCapabilities,
20}
21
22#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
24#[serde(rename_all = "camelCase")]
25pub struct RuntimeCapabilities {
26 #[serde(skip_serializing_if = "Option::is_none")]
28 pub kind: Option<CompactString>,
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub executable: Option<CompactString>,
32 #[serde(skip_serializing_if = "Option::is_none")]
34 pub transport: Option<CompactString>,
35 #[serde(default)]
37 pub capability_endpoint: bool,
38}
39
40#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
42#[serde(rename_all = "camelCase")]
43pub struct OverlayCapabilities {
44 #[serde(default)]
46 pub update_snapshot_overlay_changes: bool,
47}
48
49#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
51#[serde(rename_all = "camelCase")]
52pub struct DiagnosticsCapabilities {
53 #[serde(default)]
55 pub snapshot: bool,
56 #[serde(default)]
58 pub project: bool,
59 #[serde(default)]
61 pub file: bool,
62}
63
64#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
66#[serde(rename_all = "camelCase")]
67pub struct EditorCapabilities {
68 #[serde(default)]
70 pub hover: bool,
71 #[serde(default)]
73 pub definition: bool,
74 #[serde(default)]
76 pub references: bool,
77 #[serde(default)]
79 pub rename: bool,
80 #[serde(default)]
82 pub completion: bool,
83}
84
85impl CapabilitiesResponse {
86 pub(crate) fn fallback(runtime: RuntimeCapabilities) -> Self {
87 Self {
88 runtime,
89 overlay: OverlayCapabilities::default(),
90 diagnostics: DiagnosticsCapabilities::default(),
91 editor: EditorCapabilities::default(),
92 }
93 }
94}
95
96impl RuntimeCapabilities {
97 pub(crate) fn merge_with_local(mut self, local: RuntimeCapabilities) -> Self {
98 if self.kind.is_none() {
99 self.kind = local.kind;
100 }
101 if self.executable.is_none() {
102 self.executable = local.executable;
103 }
104 if self.transport.is_none() {
105 self.transport = local.transport;
106 }
107 self.capability_endpoint |= local.capability_endpoint;
108 self
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::{CapabilitiesResponse, RuntimeCapabilities};
115 use corsa_core::fast::CompactString;
116
117 #[test]
118 fn fallback_keeps_runtime_identity_and_disables_features() {
119 let response = CapabilitiesResponse::fallback(RuntimeCapabilities {
120 kind: Some(CompactString::from("tsgo")),
121 executable: Some(CompactString::from("/tmp/tsgo")),
122 transport: Some(CompactString::from("msgpack")),
123 capability_endpoint: false,
124 });
125
126 assert_eq!(response.runtime.kind.as_deref(), Some("tsgo"));
127 assert!(!response.overlay.update_snapshot_overlay_changes);
128 assert!(!response.diagnostics.snapshot);
129 assert!(!response.editor.hover);
130 }
131}