glua_ls 1.0.27

Language server for Garry's Mod Lua (GLua).
Documentation
mod implementation_searcher;

use crate::context::ServerContextSnapshot;
use glua_code_analysis::{EmmyLuaAnalysis, FileId};
use glua_parser::LuaAstNode;
use implementation_searcher::search_implementations;
use lsp_types::{
    ClientCapabilities, GotoDefinitionResponse, ImplementationProviderCapability, Position,
    ServerCapabilities, request::GotoImplementationParams,
};
use rowan::TokenAtOffset;
use tokio_util::sync::CancellationToken;

use super::RegisterCapabilities;

pub async fn on_implementation_handler(
    context: ServerContextSnapshot,
    params: GotoImplementationParams,
    cancel_token: CancellationToken,
) -> Option<GotoDefinitionResponse> {
    if cancel_token.is_cancelled() {
        return None;
    }
    let uri = params.text_document_position_params.text_document.uri;
    let analysis = context.read_analysis(&cancel_token).await?;
    if cancel_token.is_cancelled() {
        return None;
    }
    let file_id = analysis.get_file_id(&uri)?;
    let position = params.text_document_position_params.position;

    implementation(&analysis, file_id, position, &cancel_token)
}

pub fn implementation(
    analysis: &EmmyLuaAnalysis,
    file_id: FileId,
    position: Position,
    cancel_token: &CancellationToken,
) -> Option<GotoDefinitionResponse> {
    let semantic_model = analysis.compilation.get_semantic_model(file_id)?;

    let root = semantic_model.get_root();
    let position_offset = {
        let document = semantic_model.get_document();
        document.get_offset(position.line as usize, position.character as usize)?
    };

    if position_offset > root.syntax().text_range().end() {
        return None;
    }

    let token = match root.syntax().token_at_offset(position_offset) {
        TokenAtOffset::None => return None,
        TokenAtOffset::Single(token) => token,
        TokenAtOffset::Between(token, _) => token,
    };

    let implementations =
        search_implementations(&semantic_model, &analysis.compilation, token, cancel_token)?;

    if implementations.is_empty() {
        return None;
    }

    Some(GotoDefinitionResponse::Array(implementations))
}

pub struct ImplementationCapabilities;

impl RegisterCapabilities for ImplementationCapabilities {
    fn register_capabilities(server_capabilities: &mut ServerCapabilities, _: &ClientCapabilities) {
        server_capabilities.implementation_provider =
            Some(ImplementationProviderCapability::Simple(true));
    }
}