lmntal-language-server 0.2.0

A language server for LMNtal.
Documentation
use lmntalc_ide::{SemanticKind, SemanticSpan};
use tower_lsp_server::ls_types::{SemanticToken, SemanticTokenType};

pub const LEGEND_TYPE: &[SemanticTokenType] = &[
    SemanticTokenType::FUNCTION,
    SemanticTokenType::NAMESPACE,
    SemanticTokenType::CLASS,
    SemanticTokenType::VARIABLE,
    SemanticTokenType::STRUCT,
    SemanticTokenType::PROPERTY,
    SemanticTokenType::KEYWORD,
    SemanticTokenType::OPERATOR,
    SemanticTokenType::STRING,
    SemanticTokenType::NUMBER,
];

pub fn to_semantic_tokens(spans: &[SemanticSpan]) -> Vec<SemanticToken> {
    let mut spans = spans.to_vec();
    spans.sort_by_key(|span| (span.span.low().line, span.span.low().column));

    let mut last_line = 0;
    let mut last_start = 0;
    spans
        .into_iter()
        .map(|span| {
            let line = span.span.low().line;
            let col = span.span.low().column;
            let delta_line = line - last_line;
            let delta_start = if delta_line == 0 {
                col - last_start
            } else {
                col
            };
            last_line = line;
            last_start = col;

            SemanticToken {
                delta_line,
                delta_start,
                length: span.span.len() as u32,
                token_type: token_type(span.kind),
                token_modifiers_bitset: 0,
            }
        })
        .collect()
}

fn token_type(kind: SemanticKind) -> u32 {
    match kind {
        SemanticKind::Rule => 0,
        SemanticKind::Membrane => 1,
        SemanticKind::Atom => 2,
        SemanticKind::Link => 3,
        SemanticKind::Hyperlink => 4,
        SemanticKind::Context => 5,
        SemanticKind::KeywordAtom => 6,
        SemanticKind::OperatorAtom => 7,
        SemanticKind::StringAtom => 8,
        SemanticKind::NumberAtom => 9,
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use lmntalc_ide::{Pos, Span};

    #[test]
    fn encodes_delta_sorted_semantic_tokens() {
        let spans = vec![
            SemanticSpan {
                span: Span::new(Pos::new(4, 1, 1), Pos::new(5, 1, 2)),
                kind: SemanticKind::Link,
            },
            SemanticSpan {
                span: Span::new(Pos::new(0, 0, 0), Pos::new(4, 0, 4)),
                kind: SemanticKind::Rule,
            },
        ];

        let tokens = to_semantic_tokens(&spans);
        assert_eq!(tokens.len(), 2);
        assert_eq!(tokens[0].delta_line, 0);
        assert_eq!(tokens[0].delta_start, 0);
        assert_eq!(tokens[0].token_type, 0);
        assert_eq!(tokens[1].delta_line, 1);
        assert_eq!(tokens[1].delta_start, 1);
        assert_eq!(tokens[1].token_type, 3);
    }
}