grug-ls 0.1.2

A Language Server for the grug language
Documentation
use lsp_server::{Connection, Message, RequestId, Response};
use lsp_types::{CompletionItem, CompletionItemKind, CompletionParams, Documentation};

use crate::server::{
    Server,
    document::Document,
    utils::{get_nearest_node, get_spot_info},
};

use log::info;

impl Server {
    pub fn get_completion(
        &self,
        document: &Document,
        node: &tree_sitter::Node<'_>,
    ) -> Vec<CompletionItem> {
        let mut items: Vec<CompletionItem> = Vec::new();

        let spot_info = get_spot_info(document, node);

        for var in spot_info.variables.iter() {
            items.push(CompletionItem {
                label: var.name.clone(),
                detail: Some(var.format()),
                documentation: None,
                kind: Some(CompletionItemKind::VARIABLE),

                ..Default::default()
            });
        }
        for helper in document.helpers.iter() {
            items.push(CompletionItem {
                label: helper.name.clone(),
                detail: Some(helper.format().clone()),
                documentation: None,
                kind: Some(CompletionItemKind::VARIABLE),

                ..Default::default()
            });
        }

        for (name, game_func) in self.mod_api.game_functions.iter() {
            items.push(CompletionItem {
                label: name.clone(),
                detail: Some(format!("{}\n", game_func.format(name))),
                documentation: Some(Documentation::String(game_func.description.clone())),
                kind: Some(CompletionItemKind::FUNCTION),

                ..Default::default()
            });
        }

        if "source_file"
            == node
                .parent()
                .map(|node| node.kind())
                .unwrap_or("source_file")
        {
            info!("on root");
            if let Some(entity) = self.mod_api.entities.get(&document.entity_type) {
                info!("on entity");
                for (func_name, func) in entity.on_functions.iter() {
                    if !document
                        .on_functions
                        .iter()
                        .any(|func| func.name == *func_name)
                    {
                        items.push(CompletionItem {
                            label: func_name.clone(),
                            detail: Some(func_name.clone()),
                            documentation: Some(Documentation::String(func.description.clone())),
                            kind: Some(CompletionItemKind::FUNCTION),

                            ..Default::default()
                        })
                    }
                }
            }
        }

        items
    }

    pub fn handle_completion(
        &self,
        params: CompletionParams,
        connection: &mut Connection,
        id: RequestId,
    ) {
        let uri = params.text_document_position.text_document.uri.as_str();
        let path = &uri["file.//".len()..];
        let document = self.document_map.get(path).unwrap();

        let node = get_nearest_node(document, params.text_document_position.position);

        info!("{}", node.kind());

        let completion = self.get_completion(document, &node);

        info!("Sending this completion: {:?}", completion);
        let response = Response::new_ok(id, completion);

        connection.sender.send(Message::Response(response)).unwrap();
    }
}