gdscript_language_protocol.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. /**************************************************************************/
  2. /* gdscript_language_protocol.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "gdscript_language_protocol.h"
  31. #include "core/config/project_settings.h"
  32. #include "editor/doc/doc_tools.h"
  33. #include "editor/doc/editor_help.h"
  34. #include "editor/editor_log.h"
  35. #include "editor/editor_node.h"
  36. #include "editor/settings/editor_settings.h"
  37. #include "modules/gdscript/language_server/godot_lsp.h"
  38. #define LSP_CLIENT_V(m_ret_val) \
  39. ERR_FAIL_COND_V(latest_client_id == LSP_NO_CLIENT, m_ret_val); \
  40. ERR_FAIL_COND_V(!clients.has(latest_client_id), m_ret_val); \
  41. Ref<LSPeer> client = clients.get(latest_client_id); \
  42. ERR_FAIL_COND_V(!client.is_valid(), m_ret_val);
  43. #define LSP_CLIENT \
  44. ERR_FAIL_COND(latest_client_id == LSP_NO_CLIENT); \
  45. ERR_FAIL_COND(!clients.has(latest_client_id)); \
  46. Ref<LSPeer> client = clients.get(latest_client_id); \
  47. ERR_FAIL_COND(!client.is_valid());
  48. GDScriptLanguageProtocol *GDScriptLanguageProtocol::singleton = nullptr;
  49. Error GDScriptLanguageProtocol::LSPeer::handle_data() {
  50. int read = 0;
  51. // Read headers
  52. if (!has_header) {
  53. while (true) {
  54. if (req_pos >= LSP_MAX_BUFFER_SIZE) {
  55. req_pos = 0;
  56. ERR_FAIL_V_MSG(ERR_OUT_OF_MEMORY, "Response header too big");
  57. }
  58. Error err = connection->get_partial_data(&req_buf[req_pos], 1, read);
  59. if (err != OK) {
  60. return FAILED;
  61. } else if (read != 1) { // Busy, wait until next poll
  62. return ERR_BUSY;
  63. }
  64. char *r = (char *)req_buf;
  65. int l = req_pos;
  66. // End of headers
  67. if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {
  68. r[l - 3] = '\0'; // Null terminate to read string
  69. String header = String::utf8(r);
  70. content_length = header.substr(16).to_int();
  71. has_header = true;
  72. req_pos = 0;
  73. break;
  74. }
  75. req_pos++;
  76. }
  77. }
  78. if (has_header) {
  79. while (req_pos < content_length) {
  80. if (req_pos >= LSP_MAX_BUFFER_SIZE) {
  81. req_pos = 0;
  82. has_header = false;
  83. ERR_FAIL_COND_V_MSG(req_pos >= LSP_MAX_BUFFER_SIZE, ERR_OUT_OF_MEMORY, "Response content too big");
  84. }
  85. Error err = connection->get_partial_data(&req_buf[req_pos], 1, read);
  86. if (err != OK) {
  87. return FAILED;
  88. } else if (read != 1) {
  89. return ERR_BUSY;
  90. }
  91. req_pos++;
  92. }
  93. // Parse data
  94. String msg = String::utf8((const char *)req_buf, req_pos);
  95. // Reset to read again
  96. req_pos = 0;
  97. has_header = false;
  98. // Response
  99. String output = GDScriptLanguageProtocol::get_singleton()->process_message(msg);
  100. clear_stale_parsers();
  101. if (!output.is_empty()) {
  102. res_queue.push_back(output.utf8());
  103. }
  104. }
  105. return OK;
  106. }
  107. Error GDScriptLanguageProtocol::LSPeer::send_data() {
  108. int sent = 0;
  109. while (!res_queue.is_empty()) {
  110. CharString c_res = res_queue[0];
  111. if (res_sent < c_res.size()) {
  112. Error err = connection->put_partial_data((const uint8_t *)c_res.get_data() + res_sent, c_res.size() - res_sent - 1, sent);
  113. if (err != OK) {
  114. return err;
  115. }
  116. res_sent += sent;
  117. }
  118. // Response sent
  119. if (res_sent >= c_res.size() - 1) {
  120. res_sent = 0;
  121. res_queue.remove_at(0);
  122. }
  123. }
  124. return OK;
  125. }
  126. Error GDScriptLanguageProtocol::on_client_connected() {
  127. Ref<StreamPeerTCP> tcp_peer = server->take_connection();
  128. ERR_FAIL_COND_V_MSG(clients.size() >= LSP_MAX_CLIENTS, FAILED, "Max client limits reached");
  129. Ref<LSPeer> peer = memnew(LSPeer);
  130. peer->connection = tcp_peer;
  131. clients.insert(next_client_id, peer);
  132. next_client_id++;
  133. EditorNode::get_log()->add_message("[LSP] Connection Taken", EditorLog::MSG_TYPE_EDITOR);
  134. return OK;
  135. }
  136. void GDScriptLanguageProtocol::on_client_disconnected(const int &p_client_id) {
  137. clients.erase(p_client_id);
  138. EditorNode::get_log()->add_message("[LSP] Disconnected", EditorLog::MSG_TYPE_EDITOR);
  139. }
  140. String GDScriptLanguageProtocol::process_message(const String &p_text) {
  141. String ret = process_string(p_text);
  142. if (ret.is_empty()) {
  143. return ret;
  144. } else {
  145. return format_output(ret);
  146. }
  147. }
  148. String GDScriptLanguageProtocol::format_output(const String &p_text) {
  149. String header = "Content-Length: ";
  150. CharString charstr = p_text.utf8();
  151. size_t len = charstr.length();
  152. header += itos(len);
  153. header += "\r\n\r\n";
  154. return header + p_text;
  155. }
  156. void GDScriptLanguageProtocol::_bind_methods() {
  157. ClassDB::bind_method(D_METHOD("initialize", "params"), &GDScriptLanguageProtocol::initialize);
  158. ClassDB::bind_method(D_METHOD("initialized", "params"), &GDScriptLanguageProtocol::initialized);
  159. ClassDB::bind_method(D_METHOD("on_client_connected"), &GDScriptLanguageProtocol::on_client_connected);
  160. ClassDB::bind_method(D_METHOD("on_client_disconnected"), &GDScriptLanguageProtocol::on_client_disconnected);
  161. ClassDB::bind_method(D_METHOD("notify_client", "method", "params", "client_id"), &GDScriptLanguageProtocol::notify_client, DEFVAL(Variant()), DEFVAL(-1));
  162. ClassDB::bind_method(D_METHOD("is_smart_resolve_enabled"), &GDScriptLanguageProtocol::is_smart_resolve_enabled);
  163. ClassDB::bind_method(D_METHOD("get_text_document"), &GDScriptLanguageProtocol::get_text_document);
  164. ClassDB::bind_method(D_METHOD("get_workspace"), &GDScriptLanguageProtocol::get_workspace);
  165. ClassDB::bind_method(D_METHOD("is_initialized"), &GDScriptLanguageProtocol::is_initialized);
  166. }
  167. Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) {
  168. LSP::InitializeResult ret;
  169. {
  170. // Warn if the workspace root does not match with the project that is currently open in Godot,
  171. // since it might lead to unexpected behavior, like wrong warnings about duplicate class names.
  172. String root;
  173. Variant root_uri_var = p_params["rootUri"];
  174. Variant root_var = p_params.get("rootPath", Variant());
  175. if (root_uri_var.is_string()) {
  176. root = get_workspace()->get_file_path(root_uri_var);
  177. } else if (root_var.is_string()) {
  178. root = root_var;
  179. }
  180. if (ProjectSettings::get_singleton()->localize_path(root) != "res://") {
  181. LSP::ShowMessageParams params{
  182. LSP::MessageType::Warning,
  183. "The GDScript Language Server might not work correctly with other projects than the one opened in Godot."
  184. };
  185. notify_client("window/showMessage", params.to_json());
  186. }
  187. }
  188. String root_uri = p_params["rootUri"];
  189. String root = p_params.get("rootPath", "");
  190. bool is_same_workspace;
  191. #ifndef WINDOWS_ENABLED
  192. is_same_workspace = root.to_lower() == workspace->root.to_lower();
  193. #else
  194. is_same_workspace = root.replace_char('\\', '/').to_lower() == workspace->root.to_lower();
  195. #endif
  196. if (root_uri.length() && is_same_workspace) {
  197. workspace->root_uri = root_uri;
  198. } else {
  199. String r_root = workspace->root;
  200. r_root = r_root.lstrip("/");
  201. workspace->root_uri = "file:///" + r_root;
  202. Dictionary params;
  203. params["path"] = workspace->root;
  204. Dictionary request = make_notification("gdscript_client/changeWorkspace", params);
  205. ERR_FAIL_COND_V_MSG(!clients.has(latest_client_id), ret.to_json(),
  206. vformat("GDScriptLanguageProtocol: Can't initialize invalid peer '%d'.", latest_client_id));
  207. Ref<LSPeer> peer = clients.get(latest_client_id);
  208. if (peer.is_valid()) {
  209. String msg = Variant(request).to_json_string();
  210. msg = format_output(msg);
  211. (*peer)->res_queue.push_back(msg.utf8());
  212. }
  213. }
  214. if (!_initialized) {
  215. workspace->initialize();
  216. text_document->initialize();
  217. _initialized = true;
  218. }
  219. return ret.to_json();
  220. }
  221. void GDScriptLanguageProtocol::initialized(const Variant &p_params) {
  222. LSP::GodotCapabilities capabilities;
  223. DocTools *doc = EditorHelp::get_doc_data();
  224. for (const KeyValue<String, DocData::ClassDoc> &E : doc->class_list) {
  225. LSP::GodotNativeClassInfo gdclass;
  226. gdclass.name = E.value.name;
  227. gdclass.class_doc = &(E.value);
  228. if (ClassDB::ClassInfo *ptr = ClassDB::classes.getptr(StringName(E.value.name))) {
  229. gdclass.class_info = ptr;
  230. }
  231. capabilities.native_classes.push_back(gdclass);
  232. }
  233. notify_client("gdscript/capabilities", capabilities.to_json());
  234. }
  235. void GDScriptLanguageProtocol::poll(int p_limit_usec) {
  236. uint64_t target_ticks = OS::get_singleton()->get_ticks_usec() + p_limit_usec;
  237. if (server->is_connection_available()) {
  238. on_client_connected();
  239. }
  240. HashMap<int, Ref<LSPeer>>::Iterator E = clients.begin();
  241. while (E != clients.end()) {
  242. Ref<LSPeer> peer = E->value;
  243. peer->connection->poll();
  244. StreamPeerTCP::Status status = peer->connection->get_status();
  245. if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) {
  246. on_client_disconnected(E->key);
  247. E = clients.begin();
  248. continue;
  249. } else {
  250. Error err = OK;
  251. while (peer->connection->get_available_bytes() > 0) {
  252. latest_client_id = E->key;
  253. err = peer->handle_data();
  254. if (err != OK || OS::get_singleton()->get_ticks_usec() >= target_ticks) {
  255. break;
  256. }
  257. }
  258. if (err != OK && err != ERR_BUSY) {
  259. on_client_disconnected(E->key);
  260. E = clients.begin();
  261. continue;
  262. }
  263. err = peer->send_data();
  264. if (err != OK && err != ERR_BUSY) {
  265. on_client_disconnected(E->key);
  266. E = clients.begin();
  267. continue;
  268. }
  269. }
  270. ++E;
  271. }
  272. }
  273. Error GDScriptLanguageProtocol::start(int p_port, const IPAddress &p_bind_ip) {
  274. return server->listen(p_port, p_bind_ip);
  275. }
  276. void GDScriptLanguageProtocol::stop() {
  277. for (const KeyValue<int, Ref<LSPeer>> &E : clients) {
  278. Ref<LSPeer> peer = clients.get(E.key);
  279. peer->connection->disconnect_from_host();
  280. }
  281. server->stop();
  282. }
  283. void GDScriptLanguageProtocol::notify_client(const String &p_method, const Variant &p_params, int p_client_id) {
  284. #ifdef TESTS_ENABLED
  285. if (clients.is_empty()) {
  286. return;
  287. }
  288. #endif
  289. if (p_client_id == -1) {
  290. ERR_FAIL_COND_MSG(latest_client_id == LSP_NO_CLIENT, "GDScript LSP: Can't notify client as none was connected.");
  291. p_client_id = latest_client_id;
  292. }
  293. ERR_FAIL_COND(!clients.has(p_client_id));
  294. Ref<LSPeer> peer = clients.get(p_client_id);
  295. ERR_FAIL_COND(peer.is_null());
  296. Dictionary message = make_notification(p_method, p_params);
  297. String msg = Variant(message).to_json_string();
  298. msg = format_output(msg);
  299. peer->res_queue.push_back(msg.utf8());
  300. }
  301. void GDScriptLanguageProtocol::request_client(const String &p_method, const Variant &p_params, int p_client_id) {
  302. #ifdef TESTS_ENABLED
  303. if (clients.is_empty()) {
  304. return;
  305. }
  306. #endif
  307. if (p_client_id == -1) {
  308. ERR_FAIL_COND_MSG(latest_client_id == LSP_NO_CLIENT, "GDScript LSP: Can't notify client as none was connected.");
  309. p_client_id = latest_client_id;
  310. }
  311. ERR_FAIL_COND(!clients.has(p_client_id));
  312. Ref<LSPeer> peer = clients.get(p_client_id);
  313. ERR_FAIL_COND(peer.is_null());
  314. Dictionary message = make_request(p_method, p_params, next_server_id);
  315. next_server_id++;
  316. String msg = Variant(message).to_json_string();
  317. msg = format_output(msg);
  318. peer->res_queue.push_back(msg.utf8());
  319. }
  320. bool GDScriptLanguageProtocol::is_smart_resolve_enabled() const {
  321. return bool(_EDITOR_GET("network/language_server/enable_smart_resolve"));
  322. }
  323. bool GDScriptLanguageProtocol::is_goto_native_symbols_enabled() const {
  324. return bool(_EDITOR_GET("network/language_server/show_native_symbols_in_editor"));
  325. }
  326. ExtendGDScriptParser *GDScriptLanguageProtocol::LSPeer::parse_script(const String &p_path) {
  327. remove_cached_parser(p_path);
  328. String content;
  329. const LSP::TextDocumentItem *document = managed_files.getptr(p_path);
  330. if (document == nullptr) {
  331. if (!p_path.has_extension("gd")) {
  332. return nullptr;
  333. }
  334. Error err;
  335. content = FileAccess::get_file_as_string(p_path, &err);
  336. if (err != OK) {
  337. return nullptr;
  338. }
  339. } else {
  340. if (document->languageId != LSP::LanguageId::GDSCRIPT) {
  341. return nullptr;
  342. }
  343. content = document->text;
  344. }
  345. ExtendGDScriptParser *parser = memnew(ExtendGDScriptParser);
  346. parse_results[p_path] = parser;
  347. parser->parse(content, p_path);
  348. if (document != nullptr) {
  349. GDScriptLanguageProtocol::get_singleton()->get_workspace()->publish_diagnostics(p_path);
  350. } else {
  351. // Don't keep cached for further requests since we can't invalidate the cache properly.
  352. stale_parsers.insert(p_path);
  353. }
  354. return parser;
  355. }
  356. void GDScriptLanguageProtocol::LSPeer::clear_stale_parsers() {
  357. while (!stale_parsers.is_empty()) {
  358. remove_cached_parser(*stale_parsers.begin());
  359. }
  360. }
  361. void GDScriptLanguageProtocol::LSPeer::remove_cached_parser(const String &p_path) {
  362. HashMap<String, ExtendGDScriptParser *>::Iterator cached = parse_results.find(p_path);
  363. if (cached) {
  364. memdelete(cached->value);
  365. parse_results.remove(cached);
  366. }
  367. stale_parsers.erase(p_path);
  368. }
  369. ExtendGDScriptParser *GDScriptLanguageProtocol::get_parse_result(const String &p_path) {
  370. LSP_CLIENT_V(nullptr);
  371. ExtendGDScriptParser **cached_parser = client->parse_results.getptr(p_path);
  372. if (cached_parser == nullptr) {
  373. return client->parse_script(p_path);
  374. }
  375. return *cached_parser;
  376. }
  377. void GDScriptLanguageProtocol::lsp_did_open(const Dictionary &p_params) {
  378. LSP_CLIENT;
  379. LSP::TextDocumentItem document;
  380. document.load(p_params["textDocument"]);
  381. // We keep track of non GDScript files that the client owns, but we are not interested in the content.
  382. if (document.languageId != LSP::LanguageId::GDSCRIPT) {
  383. document.text = "";
  384. }
  385. String path = get_workspace()->get_file_path(document.uri);
  386. /// An open notification must not be sent more than once without a corresponding close notification send before.
  387. ERR_FAIL_COND_MSG(client->managed_files.has(path), "LSP: Client is opening already opened file.");
  388. client->managed_files[path] = document;
  389. client->parse_script(path);
  390. }
  391. void GDScriptLanguageProtocol::lsp_did_change(const Dictionary &p_params) {
  392. LSP_CLIENT;
  393. LSP::TextDocumentIdentifier identifier;
  394. identifier.load(p_params["textDocument"]);
  395. String path = get_workspace()->get_file_path(identifier.uri);
  396. LSP::TextDocumentItem *document = client->managed_files.getptr(path);
  397. /// Before a client can change a text document it must claim ownership of its content using the textDocument/didOpen notification.
  398. ERR_FAIL_COND_MSG(document == nullptr, "LSP: Client is changing file without opening it.");
  399. if (document->languageId != LSP::LanguageId::GDSCRIPT) {
  400. return;
  401. }
  402. Array contentChanges = p_params["contentChanges"];
  403. if (contentChanges.is_empty()) {
  404. return;
  405. }
  406. // We only support TextDocumentSyncKind::Full. So only the last full text is relevant.
  407. LSP::TextDocumentContentChangeEvent event;
  408. event.load(contentChanges.back());
  409. document->text = event.text;
  410. client->parse_script(path);
  411. }
  412. void GDScriptLanguageProtocol::lsp_did_close(const Dictionary &p_params) {
  413. LSP_CLIENT;
  414. LSP::TextDocumentIdentifier identifier;
  415. identifier.load(p_params["textDocument"]);
  416. String path = get_workspace()->get_file_path(identifier.uri);
  417. bool was_opened = client->managed_files.erase(path);
  418. client->remove_cached_parser(path);
  419. /// A close notification requires a previous open notification to be sent.
  420. ERR_FAIL_COND_MSG(!was_opened, "LSP: Client is closing file without opening it.");
  421. }
  422. void GDScriptLanguageProtocol::resolve_related_symbols(const LSP::TextDocumentPositionParams &p_doc_pos, List<const LSP::DocumentSymbol *> &r_list) {
  423. LSP_CLIENT;
  424. String path = workspace->get_file_path(p_doc_pos.textDocument.uri);
  425. const ExtendGDScriptParser *parser = get_parse_result(path);
  426. if (!parser) {
  427. return;
  428. }
  429. String symbol_identifier;
  430. LSP::Range range;
  431. symbol_identifier = parser->get_identifier_under_position(p_doc_pos.position, range);
  432. for (const KeyValue<StringName, ClassMembers> &E : workspace->native_members) {
  433. if (const LSP::DocumentSymbol *const *symbol = E.value.getptr(symbol_identifier)) {
  434. r_list.push_back(*symbol);
  435. }
  436. }
  437. for (const KeyValue<String, ExtendGDScriptParser *> &E : client->parse_results) {
  438. const ExtendGDScriptParser *scr = E.value;
  439. const ClassMembers &members = scr->get_members();
  440. if (const LSP::DocumentSymbol *const *symbol = members.getptr(symbol_identifier)) {
  441. r_list.push_back(*symbol);
  442. }
  443. for (const KeyValue<String, ClassMembers> &F : scr->get_inner_classes()) {
  444. const ClassMembers *inner_class = &F.value;
  445. if (const LSP::DocumentSymbol *const *symbol = inner_class->getptr(symbol_identifier)) {
  446. r_list.push_back(*symbol);
  447. }
  448. }
  449. }
  450. }
  451. GDScriptLanguageProtocol::LSPeer::~LSPeer() {
  452. while (!parse_results.is_empty()) {
  453. String path = parse_results.begin()->key;
  454. remove_cached_parser(path);
  455. }
  456. stale_parsers.clear();
  457. }
  458. // clang-format off
  459. #define SET_DOCUMENT_METHOD(m_method) set_method(_STR(textDocument/m_method), callable_mp(text_document.ptr(), &GDScriptTextDocument::m_method))
  460. #define SET_COMPLETION_METHOD(m_method) set_method(_STR(completionItem/m_method), callable_mp(text_document.ptr(), &GDScriptTextDocument::m_method))
  461. #define SET_WORKSPACE_METHOD(m_method) set_method(_STR(workspace/m_method), callable_mp(workspace.ptr(), &GDScriptWorkspace::m_method))
  462. // clang-format on
  463. GDScriptLanguageProtocol::GDScriptLanguageProtocol() {
  464. server.instantiate();
  465. singleton = this;
  466. workspace.instantiate();
  467. text_document.instantiate();
  468. SET_DOCUMENT_METHOD(didOpen);
  469. SET_DOCUMENT_METHOD(didClose);
  470. SET_DOCUMENT_METHOD(didChange);
  471. SET_DOCUMENT_METHOD(willSaveWaitUntil);
  472. SET_DOCUMENT_METHOD(didSave);
  473. SET_DOCUMENT_METHOD(documentSymbol);
  474. SET_DOCUMENT_METHOD(completion);
  475. SET_DOCUMENT_METHOD(rename);
  476. SET_DOCUMENT_METHOD(prepareRename);
  477. SET_DOCUMENT_METHOD(references);
  478. SET_DOCUMENT_METHOD(foldingRange);
  479. SET_DOCUMENT_METHOD(codeLens);
  480. SET_DOCUMENT_METHOD(documentLink);
  481. SET_DOCUMENT_METHOD(colorPresentation);
  482. SET_DOCUMENT_METHOD(hover);
  483. SET_DOCUMENT_METHOD(definition);
  484. SET_DOCUMENT_METHOD(declaration);
  485. SET_DOCUMENT_METHOD(signatureHelp);
  486. SET_DOCUMENT_METHOD(nativeSymbol); // Custom method.
  487. SET_COMPLETION_METHOD(resolve);
  488. set_method("initialize", callable_mp(this, &GDScriptLanguageProtocol::initialize));
  489. set_method("initialized", callable_mp(this, &GDScriptLanguageProtocol::initialized));
  490. workspace->root = ProjectSettings::get_singleton()->get_resource_path();
  491. }
  492. #undef SET_DOCUMENT_METHOD
  493. #undef SET_COMPLETION_METHOD
  494. #undef SET_WORKSPACE_METHOD
  495. #undef LSP_CLIENT
  496. #undef LSP_CLIENT_V