use corsa_core::fast::CompactString;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CapabilitiesResponse {
#[serde(default)]
pub runtime: RuntimeCapabilities,
#[serde(default)]
pub overlay: OverlayCapabilities,
#[serde(default)]
pub diagnostics: DiagnosticsCapabilities,
#[serde(default)]
pub editor: EditorCapabilities,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RuntimeCapabilities {
#[serde(skip_serializing_if = "Option::is_none")]
pub kind: Option<CompactString>,
#[serde(skip_serializing_if = "Option::is_none")]
pub executable: Option<CompactString>,
#[serde(skip_serializing_if = "Option::is_none")]
pub transport: Option<CompactString>,
#[serde(default)]
pub capability_endpoint: bool,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct OverlayCapabilities {
#[serde(default)]
pub update_snapshot_overlay_changes: bool,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DiagnosticsCapabilities {
#[serde(default)]
pub snapshot: bool,
#[serde(default)]
pub project: bool,
#[serde(default)]
pub file: bool,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct EditorCapabilities {
#[serde(default)]
pub hover: bool,
#[serde(default)]
pub definition: bool,
#[serde(default)]
pub references: bool,
#[serde(default)]
pub rename: bool,
#[serde(default)]
pub completion: bool,
}
impl CapabilitiesResponse {
pub(crate) fn fallback(runtime: RuntimeCapabilities) -> Self {
Self {
runtime,
overlay: OverlayCapabilities::default(),
diagnostics: DiagnosticsCapabilities::default(),
editor: EditorCapabilities::default(),
}
}
}
impl RuntimeCapabilities {
pub(crate) fn merge_with_local(mut self, local: RuntimeCapabilities) -> Self {
if self.kind.is_none() {
self.kind = local.kind;
}
if self.executable.is_none() {
self.executable = local.executable;
}
if self.transport.is_none() {
self.transport = local.transport;
}
self.capability_endpoint |= local.capability_endpoint;
self
}
}
#[cfg(test)]
mod tests {
use super::{CapabilitiesResponse, RuntimeCapabilities};
use corsa_core::fast::CompactString;
#[test]
fn fallback_keeps_runtime_identity_and_disables_features() {
let response = CapabilitiesResponse::fallback(RuntimeCapabilities {
kind: Some(CompactString::from("tsgo")),
executable: Some(CompactString::from("/tmp/tsgo")),
transport: Some(CompactString::from("msgpack")),
capability_endpoint: false,
});
assert_eq!(response.runtime.kind.as_deref(), Some("tsgo"));
assert!(!response.overlay.update_snapshot_overlay_changes);
assert!(!response.diagnostics.snapshot);
assert!(!response.editor.hover);
}
}