merman-analysis 0.8.0-alpha.3

Diagnostics-first analysis contracts and source mapping for Merman.
Documentation
use super::{
    ByteSpan, EditorSymbolKind, FenceExpectedSyntax, FenceExpectedSyntaxKind, FenceReferenceGroup,
    FenceSemanticItem, FenceSemanticRole, FenceTextIndex, FenceTextIndexSource,
    is_class_definition_detail,
};

pub(super) fn from_core_facts(facts: merman_core::EditorSemanticFacts) -> FenceTextIndex {
    let mut index = FenceTextIndex::default();
    let source_mapped_spans = facts.span_coordinate_space.is_original_source();

    index.source = match (facts.completeness, source_mapped_spans) {
        (merman_core::EditorSemanticCompleteness::Complete, true) => {
            FenceTextIndexSource::ParserComplete
        }
        (merman_core::EditorSemanticCompleteness::Complete, false) => {
            FenceTextIndexSource::ParserCompleteDegradedSpans
        }
        (merman_core::EditorSemanticCompleteness::Recovered, true) => {
            FenceTextIndexSource::ParserRecovered
        }
        (merman_core::EditorSemanticCompleteness::Recovered, false) => {
            FenceTextIndexSource::ParserRecoveredDegradedSpans
        }
    };
    index.directive_prefixes.extend(facts.directive_prefixes);
    if source_mapped_spans {
        index
            .expected_syntax
            .extend(
                facts
                    .expected_syntax
                    .into_iter()
                    .map(|expected| FenceExpectedSyntax {
                        kind: expected_syntax_kind_from_core(expected.kind),
                        span: ByteSpan {
                            start: expected.span.start,
                            end: expected.span.end,
                        },
                    }),
            );
    }

    for symbol in facts.symbols {
        let role = symbol.role;
        let kind = editor_kind_from_core(symbol.kind);
        let is_class_definition = is_class_definition_detail(symbol.detail.as_deref());
        if is_class_definition {
            index.class_names.insert(symbol.name.clone());
        }
        if role.contributes_completion() && !is_class_definition {
            index.node_ids.insert(symbol.name.clone());
        }
        if !source_mapped_spans {
            continue;
        }

        let item = FenceSemanticItem {
            name: symbol.name,
            detail: symbol.detail,
            kind,
            role: semantic_role_from_core(role),
            span: ByteSpan {
                start: symbol.span.start,
                end: symbol.span.end,
            },
            selection: ByteSpan {
                start: symbol.selection.start,
                end: symbol.selection.end,
            },
        };
        if role.contributes_references() {
            index
                .references
                .entry(FenceReferenceGroup::from_semantic_item(&item))
                .or_default()
                .push(item.selection);
        }
        if role.contributes_outline() {
            index.outline_items.push(item.to_line_item());
        }
        index.semantic_items.push(item);
    }

    index.outline_items.sort_by(|left, right| {
        (
            left.span.start,
            left.span.end,
            left.name.as_str(),
            left.selection.start,
            left.selection.end,
        )
            .cmp(&(
                right.span.start,
                right.span.end,
                right.name.as_str(),
                right.selection.start,
                right.selection.end,
            ))
    });
    index.semantic_items.sort_by(|left, right| {
        (
            left.span.start,
            left.span.end,
            left.name.as_str(),
            left.selection.start,
            left.selection.end,
        )
            .cmp(&(
                right.span.start,
                right.span.end,
                right.name.as_str(),
                right.selection.start,
                right.selection.end,
            ))
    });
    index
}

fn editor_kind_from_core(kind: merman_core::EditorSemanticKind) -> EditorSymbolKind {
    match kind {
        merman_core::EditorSemanticKind::Class => EditorSymbolKind::Class,
        merman_core::EditorSemanticKind::Event => EditorSymbolKind::Event,
        merman_core::EditorSemanticKind::Function => EditorSymbolKind::Function,
        merman_core::EditorSemanticKind::Module => EditorSymbolKind::Module,
        merman_core::EditorSemanticKind::Namespace => EditorSymbolKind::Namespace,
        merman_core::EditorSemanticKind::Object => EditorSymbolKind::Object,
        merman_core::EditorSemanticKind::Package => EditorSymbolKind::Package,
        merman_core::EditorSemanticKind::Property => EditorSymbolKind::Property,
        merman_core::EditorSemanticKind::String => EditorSymbolKind::String,
        merman_core::EditorSemanticKind::Struct => EditorSymbolKind::Struct,
        merman_core::EditorSemanticKind::Variable => EditorSymbolKind::Variable,
    }
}

fn semantic_role_from_core(role: merman_core::EditorSemanticRole) -> FenceSemanticRole {
    match role {
        merman_core::EditorSemanticRole::Entity => FenceSemanticRole::Entity,
        merman_core::EditorSemanticRole::Outline => FenceSemanticRole::Outline,
        merman_core::EditorSemanticRole::Payload => FenceSemanticRole::Payload,
    }
}

fn expected_syntax_kind_from_core(
    kind: merman_core::EditorExpectedSyntaxKind,
) -> FenceExpectedSyntaxKind {
    match kind {
        merman_core::EditorExpectedSyntaxKind::IdList => FenceExpectedSyntaxKind::IdList,
        merman_core::EditorExpectedSyntaxKind::NodeIdentifier => {
            FenceExpectedSyntaxKind::NodeIdentifier
        }
        merman_core::EditorExpectedSyntaxKind::ShapeValue => FenceExpectedSyntaxKind::Shape,
        merman_core::EditorExpectedSyntaxKind::ShapeTrigger => {
            FenceExpectedSyntaxKind::ShapeTrigger
        }
        merman_core::EditorExpectedSyntaxKind::DirectionValue => FenceExpectedSyntaxKind::Direction,
        merman_core::EditorExpectedSyntaxKind::Payload => FenceExpectedSyntaxKind::Payload,
    }
}