qlue-ls 2.7.0

A language server for SPARQL
Documentation
use std::rc::Rc;

use crate::server::{
    Server,
    lsp::errors::{ErrorCode, LSPError},
    message_handler::misc::resolve_backend_at_token,
    sparql_operations::execute_query,
};
use futures::lock::Mutex;
use ll_sparql_parser::{
    SyntaxNode, SyntaxToken,
    ast::{AstNode, Iri, QueryUnit},
};
use tera::Context;

pub(super) async fn hover(
    server_rc: Rc<Mutex<Server>>,
    root: SyntaxNode,
    hovered_token: SyntaxToken,
) -> Result<Option<String>, LSPError> {
    let server = server_rc.lock().await;
    let iri = match hovered_token.parent_ancestors().find_map(Iri::cast) {
        Some(value) => value,
        None => return Ok(None),
    };
    let mut context = Context::new();
    context.insert("entity", &iri.text());
    let query_unit = QueryUnit::cast(root).ok_or(LSPError::new(
        ErrorCode::InternalError,
        "Hover is currently only supported for Query operations",
    ))?;
    let backend =
        resolve_backend_at_token(&server, &query_unit, &hovered_token).ok_or(LSPError::new(
            ErrorCode::InternalError,
            "Could not determine backend for hover location",
        ))?;
    if let Some(label) = server.state.label_memory.get(&iri.text()) {
        Ok(Some(label.clone()))
    } else {
        let converter = server
            .state
            .get_converter(&backend.name)
            .ok_or(LSPError::new(
                ErrorCode::InternalError,
                "Could not get uri converter",
            ))?;
        context.insert(
            "prefixes",
            &iri.prefixed_name()
                .and_then(|prefixed_name| converter.find_by_prefix(&prefixed_name.prefix()).ok())
                .map(|record| vec![(record.prefix.clone(), record.uri_prefix.clone())])
                .unwrap_or_default(),
        );
        let query = server
            .tools
            .tera
            .render(&format!("{}-hover", backend.name), &context)
            .map_err(|err| {
                tracing::error!("{}", err);
                LSPError::new(ErrorCode::InternalError, &err.to_string())
            })?;
        let method = server.state.get_backend_request_method(&backend.name);
        let sparql_response = execute_query(
            server_rc.clone(),
            backend.url,
            query,
            None,
            None,
            Some(server.settings.completion.timeout_ms),
            method,
            None,
            0,
            false,
        )
        .await
        .map_err(|_err| LSPError::new(ErrorCode::InternalError, "hover query failed"))?;
        match sparql_response
            .expect("Non-lazy request should always return a result.")
            .results
            .bindings
            .first()
        {
            Some(binding) => binding
                .get("qlue_ls_label")
                .ok_or(LSPError::new(
                    ErrorCode::InternalError,
                    "No RDF literal \"qlue_ls_entity\" in result",
                ))
                .map(|rdf_term| Some(rdf_term.value().to_string())),
            None => Ok(None),
        }
    }
}