junolsp 0.1.7

Language Server for JunoLang
use tower_lsp::lsp_types::{
    Diagnostic,
    DiagnosticSeverity,
    Position,
    Range,
    Url,
};

use libjuno::{
    pest::{
        error::LineColLocation,
        Parser,
    },
    JunoParser,
    Rule,
};

use crate::backend::Backend;

pub async fn publish(
    backend: &Backend,
    uri: Url,
) {
    let Some(source) = backend.workspace.source(&uri) else {
        return;
    };

    let diagnostics = match JunoParser::parse(Rule::program, &source) {
        Ok(_) => Vec::new(),
        Err(error) => {
            vec![pest_error_to_diagnostic(error)]
        }
    };

    backend
        .client
        .publish_diagnostics(uri, diagnostics, None)
        .await;
}

fn pest_error_to_diagnostic(
    error: libjuno::pest::error::Error<Rule>,
) -> Diagnostic {

    let range = match error.line_col {

        LineColLocation::Pos((line, column)) => {
            Range {
                start: Position {
                    line: (line - 1) as u32,
                    character: (column - 1) as u32,
                },
                end: Position {
                    line: (line - 1) as u32,
                    character: column as u32,
                },
            }
        }

        LineColLocation::Span((start_line, start_column), (end_line, end_column)) => {
            Range {
                start: Position {
                    line: (start_line - 1) as u32,
                    character: (start_column - 1) as u32,
                },
                end: Position {
                    line: (end_line - 1) as u32,
                    character: (end_column - 1) as u32,
                },
            }
        }
    };

    Diagnostic {
        range,
        severity: Some(DiagnosticSeverity::ERROR),
        source: Some("junolsp".into()),
        message: error.to_string(),
        ..Default::default()
    }
}