Skip to main content

grug_ls/server/
completion.rs

1use lsp_server::{Connection, Message, RequestId, Response};
2use lsp_types::{CompletionItem, CompletionItemKind, CompletionParams, Documentation};
3
4use crate::server::{
5    Server,
6    document::Document,
7    utils::{get_nearest_node, get_spot_info},
8};
9
10use log::info;
11
12impl Server {
13    pub fn get_completion(
14        &self,
15        document: &Document,
16        node: &tree_sitter::Node<'_>,
17    ) -> Vec<CompletionItem> {
18        let mut items: Vec<CompletionItem> = Vec::new();
19
20        let spot_info = get_spot_info(document, node);
21
22        for var in spot_info.variables.iter() {
23            items.push(CompletionItem {
24                label: var.name.clone(),
25                detail: Some(var.format()),
26                documentation: None,
27                kind: Some(CompletionItemKind::VARIABLE),
28
29                ..Default::default()
30            });
31        }
32        for helper in document.helpers.iter() {
33            items.push(CompletionItem {
34                label: helper.name.clone(),
35                detail: Some(helper.format().clone()),
36                documentation: None,
37                kind: Some(CompletionItemKind::VARIABLE),
38
39                ..Default::default()
40            });
41        }
42
43        for (name, game_func) in self.mod_api.game_functions.iter() {
44            items.push(CompletionItem {
45                label: name.clone(),
46                detail: Some(format!("{}\n", game_func.format(name))),
47                documentation: Some(Documentation::String(game_func.description.clone())),
48                kind: Some(CompletionItemKind::FUNCTION),
49
50                ..Default::default()
51            });
52        }
53
54        if "source_file"
55            == node
56                .parent()
57                .map(|node| node.kind())
58                .unwrap_or("source_file")
59        {
60            info!("on root");
61            if let Some(entity) = self.mod_api.entities.get(&document.entity_type) {
62                info!("on entity");
63                for (func_name, func) in entity.on_functions.iter() {
64                    if !document
65                        .on_functions
66                        .iter()
67                        .any(|func| func.name == *func_name)
68                    {
69                        items.push(CompletionItem {
70                            label: func_name.clone(),
71                            detail: Some(func_name.clone()),
72                            documentation: Some(Documentation::String(func.description.clone())),
73                            kind: Some(CompletionItemKind::FUNCTION),
74
75                            ..Default::default()
76                        })
77                    }
78                }
79            }
80        }
81
82        items
83    }
84
85    pub fn handle_completion(
86        &self,
87        params: CompletionParams,
88        connection: &mut Connection,
89        id: RequestId,
90    ) {
91        let uri = params.text_document_position.text_document.uri.as_str();
92        let path = &uri["file.//".len()..];
93        let document = self.document_map.get(path).unwrap();
94
95        let node = get_nearest_node(document, params.text_document_position.position);
96
97        info!("{}", node.kind());
98
99        let completion = self.get_completion(document, &node);
100
101        info!("Sending this completion: {:?}", completion);
102        let response = Response::new_ok(id, completion);
103
104        connection.sender.send(Message::Response(response)).unwrap();
105    }
106}