omena-lsp-server 0.3.0

Rust LSP server boundary scaffold for Omena CSS Modules
Documentation
use omena_query::{
    OmenaQuerySourceSelectorOccurrenceV0, OmenaWorkspaceOccurrenceFamilyV0,
    OmenaWorkspaceOccurrenceKindV0, OmenaWorkspaceOccurrenceRoleV0,
    OmenaWorkspaceOccurrenceSurfaceV0, OmenaWorkspaceOccurrenceV0,
};

use crate::{
    file_uri_equivalent,
    state::{
        LspDocumentOrigin, LspStyleHoverCandidate, LspStyleSymbolOccurrenceV0, LspTextDocumentState,
    },
};

pub(super) fn workspace_occurrence_from_source_selector_occurrence_for_lsp(
    occurrence: &OmenaQuerySourceSelectorOccurrenceV0,
) -> OmenaWorkspaceOccurrenceV0 {
    OmenaWorkspaceOccurrenceV0 {
        moniker: occurrence.moniker.clone(),
        uri: occurrence.uri.clone(),
        name: occurrence.selector_name.clone(),
        range: occurrence.range,
        kind: occurrence.kind,
        role: occurrence.role,
        surface: occurrence.source,
        family: Some(OmenaWorkspaceOccurrenceFamilyV0::CssModuleSelector),
        namespace: None,
        target_style_uri: occurrence.target_style_uri.clone(),
        rename_target: occurrence.rename_target,
    }
}

pub(super) fn source_selector_occurrence_from_workspace_occurrence_for_lsp(
    occurrence: OmenaWorkspaceOccurrenceV0,
) -> Option<OmenaQuerySourceSelectorOccurrenceV0> {
    (occurrence.family == Some(OmenaWorkspaceOccurrenceFamilyV0::CssModuleSelector)).then_some(
        OmenaQuerySourceSelectorOccurrenceV0 {
            moniker: occurrence.moniker,
            uri: occurrence.uri,
            selector_name: occurrence.name,
            range: occurrence.range,
            kind: occurrence.kind,
            role: occurrence.role,
            source: occurrence.surface,
            target_style_uri: occurrence.target_style_uri,
            rename_target: occurrence.rename_target,
        },
    )
}

pub(super) fn workspace_occurrence_kind_from_source_reference_kind_for_lsp(
    kind: &str,
) -> OmenaWorkspaceOccurrenceKindV0 {
    match kind {
        "sourceSelectorPrefixReference" => {
            OmenaWorkspaceOccurrenceKindV0::SourceSelectorPrefixReference
        }
        _ => OmenaWorkspaceOccurrenceKindV0::SourceSelectorReference,
    }
}

pub(super) fn workspace_occurrence_matches_target_style(
    occurrence: &OmenaWorkspaceOccurrenceV0,
    target_style_uri: Option<&str>,
) -> bool {
    target_style_uri.is_none_or(|target_uri| {
        occurrence
            .target_style_uri
            .as_deref()
            .is_none_or(|candidate_target_uri| {
                file_uri_equivalent(candidate_target_uri, target_uri)
            })
    })
}

pub(super) fn style_symbol_occurrence_from_workspace_occurrence_for_lsp(
    occurrence: &OmenaWorkspaceOccurrenceV0,
) -> Option<LspStyleSymbolOccurrenceV0> {
    let family = occurrence.family?;
    if family == OmenaWorkspaceOccurrenceFamilyV0::CssModuleSelector {
        return None;
    }
    Some(LspStyleSymbolOccurrenceV0 {
        moniker: occurrence.moniker.clone(),
        uri: occurrence.uri.clone(),
        kind: occurrence.kind,
        family,
        name: occurrence.name.clone(),
        range: occurrence.range,
        role: occurrence.role,
        namespace: occurrence.namespace.clone(),
    })
}

pub(super) fn workspace_occurrence_from_style_symbol_occurrence(
    document: &LspTextDocumentState,
    occurrence: &LspStyleSymbolOccurrenceV0,
) -> OmenaWorkspaceOccurrenceV0 {
    OmenaWorkspaceOccurrenceV0 {
        moniker: occurrence.moniker.clone(),
        uri: occurrence.uri.clone(),
        name: occurrence.name.clone(),
        range: occurrence.range,
        kind: occurrence.kind,
        role: occurrence.role,
        surface: OmenaWorkspaceOccurrenceSurfaceV0::OmenaLspStyleIndex,
        family: Some(occurrence.family),
        namespace: occurrence.namespace.clone(),
        target_style_uri: None,
        rename_target: document.origin == LspDocumentOrigin::Local,
    }
}

pub(super) fn style_symbol_occurrence_for_candidate(
    moniker: String,
    uri: &str,
    candidate: &LspStyleHoverCandidate,
    family: &'static str,
    role: &'static str,
) -> LspStyleSymbolOccurrenceV0 {
    LspStyleSymbolOccurrenceV0 {
        moniker,
        uri: uri.to_string(),
        kind: workspace_occurrence_kind_from_style_symbol_kind(candidate.kind)
            .unwrap_or(OmenaWorkspaceOccurrenceKindV0::CustomPropertyReference),
        family: workspace_occurrence_family_from_style_symbol_family(family)
            .unwrap_or(OmenaWorkspaceOccurrenceFamilyV0::Symbol),
        name: candidate.name.clone(),
        range: candidate.range,
        role: workspace_occurrence_role_from_style_symbol_role(role),
        namespace: candidate.namespace.clone(),
    }
}

fn workspace_occurrence_kind_from_style_symbol_kind(
    kind: &str,
) -> Option<OmenaWorkspaceOccurrenceKindV0> {
    match kind {
        "customPropertyDeclaration" => {
            Some(OmenaWorkspaceOccurrenceKindV0::CustomPropertyDeclaration)
        }
        "customPropertyReference" => Some(OmenaWorkspaceOccurrenceKindV0::CustomPropertyReference),
        "sassVariableDeclaration" => Some(OmenaWorkspaceOccurrenceKindV0::SassVariableDeclaration),
        "sassVariableReference" => Some(OmenaWorkspaceOccurrenceKindV0::SassVariableReference),
        "sassMixinDeclaration" => Some(OmenaWorkspaceOccurrenceKindV0::SassMixinDeclaration),
        "sassMixinInclude" => Some(OmenaWorkspaceOccurrenceKindV0::SassMixinInclude),
        "sassFunctionDeclaration" => Some(OmenaWorkspaceOccurrenceKindV0::SassFunctionDeclaration),
        "sassFunctionCall" => Some(OmenaWorkspaceOccurrenceKindV0::SassFunctionCall),
        _ => None,
    }
}

fn workspace_occurrence_role_from_style_symbol_role(role: &str) -> OmenaWorkspaceOccurrenceRoleV0 {
    if role == "definition" {
        OmenaWorkspaceOccurrenceRoleV0::Definition
    } else {
        OmenaWorkspaceOccurrenceRoleV0::Reference
    }
}

fn workspace_occurrence_family_from_style_symbol_family(
    family: &str,
) -> Option<OmenaWorkspaceOccurrenceFamilyV0> {
    match family {
        "customProperty" => Some(OmenaWorkspaceOccurrenceFamilyV0::CustomProperty),
        "variable" => Some(OmenaWorkspaceOccurrenceFamilyV0::Variable),
        "mixin" => Some(OmenaWorkspaceOccurrenceFamilyV0::Mixin),
        "function" => Some(OmenaWorkspaceOccurrenceFamilyV0::Function),
        "symbol" => Some(OmenaWorkspaceOccurrenceFamilyV0::Symbol),
        _ => None,
    }
}