1use lsp_server::{Connection, ErrorCode, Message, RequestId, Response};
2use lsp_types::{Hover, HoverContents, HoverParams, MarkupContent, MarkupKind, Position, Range};
3use vfs::FileSystem;
4
5use crate::{
6 server::{
7 Server,
8 document::Document,
9 mod_api::ModApi,
10 utils::get_spot_info,
11 },
12};
13
14impl Server {
15 fn get_hover(
16 mod_api: &ModApi,
17 document: &Document,
18 node: &tree_sitter::Node<'_>,
19 ) -> Option<String> {
20 let range = node.byte_range();
21 if node.kind() == "identifier" {
22 let name = &document.content[range];
23 let spot_info = get_spot_info(document, node);
24 for var in spot_info.variables.into_iter() {
25 if var.name.as_bytes() == name {
26 return Some(format!("{}: {}", var.name, var.r#type.as_str()));
27 }
28 }
29
30 let name = String::from_utf8(name.to_vec()).ok()?;
31
32 if let Some(func) = mod_api.game_functions.get(&name) {
33 let mut text = func.format(&name);
34 text.push_str("\n\n");
35
36 text.push_str(&func.description);
37
38 return Some(text);
39 }
40 } else if node.kind() == "helper_identifier" {
41 let name = &document.content[range];
42
43 if let Some(helper) = document.helpers.iter().find(|helper| helper.name.as_bytes() == name) {
44 return Some(helper.format());
45 }
46 } else if node.kind() == "on_identifier" {
47 let name = String::from_utf8(document.content[range].to_vec()).ok()?;
48 if let Some(entity) = mod_api.entities.get(&document.entity_type) {
49 if let Some(on_func) = entity.on_functions.get(&name) {
50 let mut text = name;
51 text.push_str("\n\n");
52
53 text.push_str(&on_func.description);
54 return Some(text);
55 }
56 }
57 }
58
59 None
60 }
61 pub fn handle_hover(&self, params: HoverParams, connection: &mut Connection, id: RequestId) {
62 let uri = params.text_document_position_params.text_document.uri.as_str();
63
64 assert!(uri.starts_with("file://"));
66
67 let path = &uri["file.//".len()..];
68
69 if !self.file_system.exists(path).unwrap_or(false) {
70 connection.sender.send(Message::Response(Response::new_err(id, ErrorCode::InvalidRequest as i32, format!("File doesnt exist: {}", path)))).unwrap();
71 return;
72 }
73
74 let document = &self.document_map.get(path).unwrap();
75
76 let ast = &document.tree;
77
78 let point = tree_sitter::Point {
79 column: params.text_document_position_params.position.character as usize,
80 row: params.text_document_position_params.position.line as usize,
81 };
82
83 let node = ast
84 .root_node()
85 .named_descendant_for_point_range(point, point)
86 .unwrap();
87
88 let range = node.range();
89
90 let content = Self::get_hover(&self.mod_api, document, &node);
91 if content.is_none() {
92 connection.sender.send(Message::Response(Response::new_ok(id, serde_json::Value::Null))).unwrap();
93 return;
94 }
95 let mut content = content.unwrap().as_bytes().to_vec();
96
97 let var = document
98 .global_vars
99 .iter()
100 .find(|var| var.name.as_bytes() == &content);
101 if let Some(var) = var {
102 content = format!("{}: {}", var.name, var.r#type.as_str())
103 .as_bytes()
104 .to_vec();
105 }
106
107 let res = Response::new_ok(id, Hover {
108 contents: HoverContents::Markup(MarkupContent {
109 kind: MarkupKind::PlainText,
110 value: String::from_utf8(content).unwrap(),
111 }),
112 range: Some(Range {
113 start: Position {
114 line: range.start_point.row as u32,
115 character: range.start_point.column as u32,
116 },
117 end: Position {
118 line: range.end_point.row as u32,
119 character: range.end_point.column as u32,
120 },
121 }),
122 });
123
124 connection.sender.send(Message::Response(res)).unwrap();
125 }
126}