1 | /**************************************************************************/ |
2 | /* gdscript_text_document.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 | |
31 | #include "gdscript_text_document.h" |
32 | |
33 | #include "../gdscript.h" |
34 | #include "gdscript_extend_parser.h" |
35 | #include "gdscript_language_protocol.h" |
36 | |
37 | #include "core/os/os.h" |
38 | #include "editor/editor_settings.h" |
39 | #include "editor/plugins/script_text_editor.h" |
40 | #include "servers/display_server.h" |
41 | |
42 | void GDScriptTextDocument::_bind_methods() { |
43 | ClassDB::bind_method(D_METHOD("didOpen" ), &GDScriptTextDocument::didOpen); |
44 | ClassDB::bind_method(D_METHOD("didClose" ), &GDScriptTextDocument::didClose); |
45 | ClassDB::bind_method(D_METHOD("didChange" ), &GDScriptTextDocument::didChange); |
46 | ClassDB::bind_method(D_METHOD("willSaveWaitUntil" ), &GDScriptTextDocument::willSaveWaitUntil); |
47 | ClassDB::bind_method(D_METHOD("didSave" ), &GDScriptTextDocument::didSave); |
48 | ClassDB::bind_method(D_METHOD("nativeSymbol" ), &GDScriptTextDocument::nativeSymbol); |
49 | ClassDB::bind_method(D_METHOD("documentSymbol" ), &GDScriptTextDocument::documentSymbol); |
50 | ClassDB::bind_method(D_METHOD("completion" ), &GDScriptTextDocument::completion); |
51 | ClassDB::bind_method(D_METHOD("resolve" ), &GDScriptTextDocument::resolve); |
52 | ClassDB::bind_method(D_METHOD("rename" ), &GDScriptTextDocument::rename); |
53 | ClassDB::bind_method(D_METHOD("prepareRename" ), &GDScriptTextDocument::prepareRename); |
54 | ClassDB::bind_method(D_METHOD("references" ), &GDScriptTextDocument::references); |
55 | ClassDB::bind_method(D_METHOD("foldingRange" ), &GDScriptTextDocument::foldingRange); |
56 | ClassDB::bind_method(D_METHOD("codeLens" ), &GDScriptTextDocument::codeLens); |
57 | ClassDB::bind_method(D_METHOD("documentLink" ), &GDScriptTextDocument::documentLink); |
58 | ClassDB::bind_method(D_METHOD("colorPresentation" ), &GDScriptTextDocument::colorPresentation); |
59 | ClassDB::bind_method(D_METHOD("hover" ), &GDScriptTextDocument::hover); |
60 | ClassDB::bind_method(D_METHOD("definition" ), &GDScriptTextDocument::definition); |
61 | ClassDB::bind_method(D_METHOD("declaration" ), &GDScriptTextDocument::declaration); |
62 | ClassDB::bind_method(D_METHOD("signatureHelp" ), &GDScriptTextDocument::signatureHelp); |
63 | ClassDB::bind_method(D_METHOD("show_native_symbol_in_editor" ), &GDScriptTextDocument::show_native_symbol_in_editor); |
64 | } |
65 | |
66 | void GDScriptTextDocument::didOpen(const Variant &p_param) { |
67 | lsp::TextDocumentItem doc = load_document_item(p_param); |
68 | sync_script_content(doc.uri, doc.text); |
69 | } |
70 | |
71 | void GDScriptTextDocument::didClose(const Variant &p_param) { |
72 | // Left empty on purpose. Godot does nothing special on closing a document, |
73 | // but it satisfies LSP clients that require didClose be implemented. |
74 | } |
75 | |
76 | void GDScriptTextDocument::didChange(const Variant &p_param) { |
77 | lsp::TextDocumentItem doc = load_document_item(p_param); |
78 | Dictionary dict = p_param; |
79 | Array contentChanges = dict["contentChanges" ]; |
80 | for (int i = 0; i < contentChanges.size(); ++i) { |
81 | lsp::TextDocumentContentChangeEvent evt; |
82 | evt.load(contentChanges[i]); |
83 | doc.text = evt.text; |
84 | } |
85 | sync_script_content(doc.uri, doc.text); |
86 | } |
87 | |
88 | void GDScriptTextDocument::willSaveWaitUntil(const Variant &p_param) { |
89 | lsp::TextDocumentItem doc = load_document_item(p_param); |
90 | |
91 | String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(doc.uri); |
92 | Ref<Script> scr = ResourceLoader::load(path); |
93 | if (scr.is_valid()) { |
94 | ScriptEditor::get_singleton()->clear_docs_from_script(scr); |
95 | } |
96 | } |
97 | |
98 | void GDScriptTextDocument::didSave(const Variant &p_param) { |
99 | lsp::TextDocumentItem doc = load_document_item(p_param); |
100 | Dictionary dict = p_param; |
101 | String text = dict["text" ]; |
102 | |
103 | sync_script_content(doc.uri, text); |
104 | |
105 | String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(doc.uri); |
106 | Ref<GDScript> scr = ResourceLoader::load(path); |
107 | if (scr.is_valid() && (scr->load_source_code(path) == OK)) { |
108 | if (scr->is_tool()) { |
109 | scr->get_language()->reload_tool_script(scr, true); |
110 | } else { |
111 | scr->reload(true); |
112 | } |
113 | scr->update_exports(); |
114 | ScriptEditor::get_singleton()->reload_scripts(true); |
115 | ScriptEditor::get_singleton()->update_docs_from_script(scr); |
116 | } |
117 | } |
118 | |
119 | lsp::TextDocumentItem GDScriptTextDocument::load_document_item(const Variant &p_param) { |
120 | lsp::TextDocumentItem doc; |
121 | Dictionary params = p_param; |
122 | doc.load(params["textDocument" ]); |
123 | return doc; |
124 | } |
125 | |
126 | void GDScriptTextDocument::notify_client_show_symbol(const lsp::DocumentSymbol *symbol) { |
127 | ERR_FAIL_NULL(symbol); |
128 | GDScriptLanguageProtocol::get_singleton()->notify_client("gdscript/show_native_symbol" , symbol->to_json(true)); |
129 | } |
130 | |
131 | void GDScriptTextDocument::initialize() { |
132 | if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) { |
133 | for (const KeyValue<StringName, ClassMembers> &E : GDScriptLanguageProtocol::get_singleton()->get_workspace()->native_members) { |
134 | const ClassMembers &members = E.value; |
135 | |
136 | for (const KeyValue<String, const lsp::DocumentSymbol *> &F : members) { |
137 | const lsp::DocumentSymbol *symbol = members.get(F.key); |
138 | lsp::CompletionItem item = symbol->make_completion_item(); |
139 | item.data = JOIN_SYMBOLS(String(E.key), F.key); |
140 | native_member_completions.push_back(item.to_json()); |
141 | } |
142 | } |
143 | } |
144 | } |
145 | |
146 | Variant GDScriptTextDocument::nativeSymbol(const Dictionary &p_params) { |
147 | Variant ret; |
148 | |
149 | lsp::NativeSymbolInspectParams params; |
150 | params.load(p_params); |
151 | |
152 | if (const lsp::DocumentSymbol *symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_native_symbol(params)) { |
153 | ret = symbol->to_json(true); |
154 | notify_client_show_symbol(symbol); |
155 | } |
156 | |
157 | return ret; |
158 | } |
159 | |
160 | Array GDScriptTextDocument::documentSymbol(const Dictionary &p_params) { |
161 | Dictionary params = p_params["textDocument" ]; |
162 | String uri = params["uri" ]; |
163 | String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(uri); |
164 | Array arr; |
165 | if (HashMap<String, ExtendGDScriptParser *>::ConstIterator parser = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(path)) { |
166 | lsp::DocumentSymbol symbol = parser->value->get_symbols(); |
167 | arr.push_back(symbol.to_json(true)); |
168 | } |
169 | return arr; |
170 | } |
171 | |
172 | Array GDScriptTextDocument::completion(const Dictionary &p_params) { |
173 | Array arr; |
174 | |
175 | lsp::CompletionParams params; |
176 | params.load(p_params); |
177 | Dictionary request_data = params.to_json(); |
178 | |
179 | List<ScriptLanguage::CodeCompletionOption> options; |
180 | GDScriptLanguageProtocol::get_singleton()->get_workspace()->completion(params, &options); |
181 | |
182 | if (!options.is_empty()) { |
183 | int i = 0; |
184 | arr.resize(options.size()); |
185 | |
186 | for (const ScriptLanguage::CodeCompletionOption &option : options) { |
187 | lsp::CompletionItem item; |
188 | item.label = option.display; |
189 | item.data = request_data; |
190 | item.insertText = option.insert_text; |
191 | |
192 | switch (option.kind) { |
193 | case ScriptLanguage::CODE_COMPLETION_KIND_ENUM: |
194 | item.kind = lsp::CompletionItemKind::Enum; |
195 | break; |
196 | case ScriptLanguage::CODE_COMPLETION_KIND_CLASS: |
197 | item.kind = lsp::CompletionItemKind::Class; |
198 | break; |
199 | case ScriptLanguage::CODE_COMPLETION_KIND_MEMBER: |
200 | item.kind = lsp::CompletionItemKind::Property; |
201 | break; |
202 | case ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION: |
203 | item.kind = lsp::CompletionItemKind::Method; |
204 | break; |
205 | case ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL: |
206 | item.kind = lsp::CompletionItemKind::Event; |
207 | break; |
208 | case ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT: |
209 | item.kind = lsp::CompletionItemKind::Constant; |
210 | break; |
211 | case ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE: |
212 | item.kind = lsp::CompletionItemKind::Variable; |
213 | break; |
214 | case ScriptLanguage::CODE_COMPLETION_KIND_FILE_PATH: |
215 | item.kind = lsp::CompletionItemKind::File; |
216 | break; |
217 | case ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH: |
218 | item.kind = lsp::CompletionItemKind::Snippet; |
219 | break; |
220 | case ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT: |
221 | item.kind = lsp::CompletionItemKind::Text; |
222 | break; |
223 | default: { |
224 | } |
225 | } |
226 | |
227 | arr[i] = item.to_json(); |
228 | i++; |
229 | } |
230 | } else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) { |
231 | arr = native_member_completions.duplicate(); |
232 | |
233 | for (KeyValue<String, ExtendGDScriptParser *> &E : GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts) { |
234 | ExtendGDScriptParser *scr = E.value; |
235 | const Array &items = scr->get_member_completions(); |
236 | |
237 | const int start_size = arr.size(); |
238 | arr.resize(start_size + items.size()); |
239 | for (int i = start_size; i < arr.size(); i++) { |
240 | arr[i] = items[i - start_size]; |
241 | } |
242 | } |
243 | } |
244 | return arr; |
245 | } |
246 | |
247 | Dictionary GDScriptTextDocument::rename(const Dictionary &p_params) { |
248 | lsp::TextDocumentPositionParams params; |
249 | params.load(p_params); |
250 | String new_name = p_params["newName" ]; |
251 | |
252 | return GDScriptLanguageProtocol::get_singleton()->get_workspace()->rename(params, new_name); |
253 | } |
254 | |
255 | Variant GDScriptTextDocument::prepareRename(const Dictionary &p_params) { |
256 | lsp::TextDocumentPositionParams params; |
257 | params.load(p_params); |
258 | |
259 | lsp::DocumentSymbol symbol; |
260 | lsp::Range range; |
261 | if (GDScriptLanguageProtocol::get_singleton()->get_workspace()->can_rename(params, symbol, range)) { |
262 | return Variant(range.to_json()); |
263 | } |
264 | |
265 | // `null` -> rename not valid at current location. |
266 | return Variant(); |
267 | } |
268 | |
269 | Array GDScriptTextDocument::references(const Dictionary &p_params) { |
270 | Array res; |
271 | |
272 | lsp::ReferenceParams params; |
273 | params.load(p_params); |
274 | |
275 | const lsp::DocumentSymbol *symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_symbol(params); |
276 | if (symbol) { |
277 | Vector<lsp::Location> usages = GDScriptLanguageProtocol::get_singleton()->get_workspace()->find_all_usages(*symbol); |
278 | res.resize(usages.size()); |
279 | int declaration_adjustment = 0; |
280 | for (int i = 0; i < usages.size(); i++) { |
281 | lsp::Location usage = usages[i]; |
282 | if (!params.context.includeDeclaration && usage.range == symbol->range) { |
283 | declaration_adjustment++; |
284 | continue; |
285 | } |
286 | res[i - declaration_adjustment] = usages[i].to_json(); |
287 | } |
288 | |
289 | if (declaration_adjustment > 0) { |
290 | res.resize(res.size() - declaration_adjustment); |
291 | } |
292 | } |
293 | |
294 | return res; |
295 | } |
296 | |
297 | Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) { |
298 | lsp::CompletionItem item; |
299 | item.load(p_params); |
300 | |
301 | lsp::CompletionParams params; |
302 | Variant data = p_params["data" ]; |
303 | |
304 | const lsp::DocumentSymbol *symbol = nullptr; |
305 | |
306 | if (data.get_type() == Variant::DICTIONARY) { |
307 | params.load(p_params["data" ]); |
308 | symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_symbol(params, item.label, item.kind == lsp::CompletionItemKind::Method || item.kind == lsp::CompletionItemKind::Function); |
309 | |
310 | } else if (data.get_type() == Variant::STRING) { |
311 | String query = data; |
312 | |
313 | Vector<String> param_symbols = query.split(SYMBOL_SEPERATOR, false); |
314 | |
315 | if (param_symbols.size() >= 2) { |
316 | String class_ = param_symbols[0]; |
317 | StringName class_name = class_; |
318 | String member_name = param_symbols[param_symbols.size() - 1]; |
319 | String inner_class_name; |
320 | if (param_symbols.size() >= 3) { |
321 | inner_class_name = param_symbols[1]; |
322 | } |
323 | |
324 | if (const ClassMembers *members = GDScriptLanguageProtocol::get_singleton()->get_workspace()->native_members.getptr(class_name)) { |
325 | if (const lsp::DocumentSymbol *const *member = members->getptr(member_name)) { |
326 | symbol = *member; |
327 | } |
328 | } |
329 | |
330 | if (!symbol) { |
331 | if (HashMap<String, ExtendGDScriptParser *>::ConstIterator E = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(class_name)) { |
332 | symbol = E->value->get_member_symbol(member_name, inner_class_name); |
333 | } |
334 | } |
335 | } |
336 | } |
337 | |
338 | if (symbol) { |
339 | item.documentation = symbol->render(); |
340 | } |
341 | |
342 | if (item.kind == lsp::CompletionItemKind::Event) { |
343 | if (params.context.triggerKind == lsp::CompletionTriggerKind::TriggerCharacter && (params.context.triggerCharacter == "(" )) { |
344 | const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes" ) ? "'" : "\"" ; |
345 | item.insertText = item.label.quote(quote_style); |
346 | } |
347 | } |
348 | |
349 | return item.to_json(true); |
350 | } |
351 | |
352 | Array GDScriptTextDocument::foldingRange(const Dictionary &p_params) { |
353 | Array arr; |
354 | return arr; |
355 | } |
356 | |
357 | Array GDScriptTextDocument::codeLens(const Dictionary &p_params) { |
358 | Array arr; |
359 | return arr; |
360 | } |
361 | |
362 | Array GDScriptTextDocument::documentLink(const Dictionary &p_params) { |
363 | Array ret; |
364 | |
365 | lsp::DocumentLinkParams params; |
366 | params.load(p_params); |
367 | |
368 | List<lsp::DocumentLink> links; |
369 | GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_document_links(params.textDocument.uri, links); |
370 | for (const lsp::DocumentLink &E : links) { |
371 | ret.push_back(E.to_json()); |
372 | } |
373 | return ret; |
374 | } |
375 | |
376 | Array GDScriptTextDocument::colorPresentation(const Dictionary &p_params) { |
377 | Array arr; |
378 | return arr; |
379 | } |
380 | |
381 | Variant GDScriptTextDocument::hover(const Dictionary &p_params) { |
382 | lsp::TextDocumentPositionParams params; |
383 | params.load(p_params); |
384 | |
385 | const lsp::DocumentSymbol *symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_symbol(params); |
386 | if (symbol) { |
387 | lsp::Hover hover; |
388 | hover.contents = symbol->render(); |
389 | hover.range.start = params.position; |
390 | hover.range.end = params.position; |
391 | return hover.to_json(); |
392 | |
393 | } else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) { |
394 | Dictionary ret; |
395 | Array contents; |
396 | List<const lsp::DocumentSymbol *> list; |
397 | GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_related_symbols(params, list); |
398 | for (const lsp::DocumentSymbol *&E : list) { |
399 | if (const lsp::DocumentSymbol *s = E) { |
400 | contents.push_back(s->render().value); |
401 | } |
402 | } |
403 | ret["contents" ] = contents; |
404 | return ret; |
405 | } |
406 | |
407 | return Variant(); |
408 | } |
409 | |
410 | Array GDScriptTextDocument::definition(const Dictionary &p_params) { |
411 | lsp::TextDocumentPositionParams params; |
412 | params.load(p_params); |
413 | List<const lsp::DocumentSymbol *> symbols; |
414 | Array arr = this->find_symbols(params, symbols); |
415 | return arr; |
416 | } |
417 | |
418 | Variant GDScriptTextDocument::declaration(const Dictionary &p_params) { |
419 | lsp::TextDocumentPositionParams params; |
420 | params.load(p_params); |
421 | List<const lsp::DocumentSymbol *> symbols; |
422 | Array arr = this->find_symbols(params, symbols); |
423 | if (arr.is_empty() && !symbols.is_empty() && !symbols.front()->get()->native_class.is_empty()) { // Find a native symbol |
424 | const lsp::DocumentSymbol *symbol = symbols.front()->get(); |
425 | if (GDScriptLanguageProtocol::get_singleton()->is_goto_native_symbols_enabled()) { |
426 | String id; |
427 | switch (symbol->kind) { |
428 | case lsp::SymbolKind::Class: |
429 | id = "class_name:" + symbol->name; |
430 | break; |
431 | case lsp::SymbolKind::Constant: |
432 | id = "class_constant:" + symbol->native_class + ":" + symbol->name; |
433 | break; |
434 | case lsp::SymbolKind::Property: |
435 | case lsp::SymbolKind::Variable: |
436 | id = "class_property:" + symbol->native_class + ":" + symbol->name; |
437 | break; |
438 | case lsp::SymbolKind::Enum: |
439 | id = "class_enum:" + symbol->native_class + ":" + symbol->name; |
440 | break; |
441 | case lsp::SymbolKind::Method: |
442 | case lsp::SymbolKind::Function: |
443 | id = "class_method:" + symbol->native_class + ":" + symbol->name; |
444 | break; |
445 | default: |
446 | id = "class_global:" + symbol->native_class + ":" + symbol->name; |
447 | break; |
448 | } |
449 | call_deferred(SNAME("show_native_symbol_in_editor" ), id); |
450 | } else { |
451 | notify_client_show_symbol(symbol); |
452 | } |
453 | } |
454 | return arr; |
455 | } |
456 | |
457 | Variant GDScriptTextDocument::signatureHelp(const Dictionary &p_params) { |
458 | Variant ret; |
459 | |
460 | lsp::TextDocumentPositionParams params; |
461 | params.load(p_params); |
462 | |
463 | lsp::SignatureHelp s; |
464 | if (OK == GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_signature(params, s)) { |
465 | ret = s.to_json(); |
466 | } |
467 | |
468 | return ret; |
469 | } |
470 | |
471 | GDScriptTextDocument::GDScriptTextDocument() { |
472 | file_checker = FileAccess::create(FileAccess::ACCESS_RESOURCES); |
473 | } |
474 | |
475 | void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) { |
476 | String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path); |
477 | GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content); |
478 | |
479 | EditorFileSystem::get_singleton()->update_file(path); |
480 | } |
481 | |
482 | void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) { |
483 | ScriptEditor::get_singleton()->call_deferred(SNAME("_help_class_goto" ), p_symbol_id); |
484 | |
485 | DisplayServer::get_singleton()->window_move_to_foreground(); |
486 | } |
487 | |
488 | Array GDScriptTextDocument::find_symbols(const lsp::TextDocumentPositionParams &p_location, List<const lsp::DocumentSymbol *> &r_list) { |
489 | Array arr; |
490 | const lsp::DocumentSymbol *symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_symbol(p_location); |
491 | if (symbol) { |
492 | lsp::Location location; |
493 | location.uri = symbol->uri; |
494 | location.range = symbol->selectionRange; |
495 | const String &path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(symbol->uri); |
496 | if (file_checker->file_exists(path)) { |
497 | arr.push_back(location.to_json()); |
498 | } |
499 | r_list.push_back(symbol); |
500 | } else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) { |
501 | List<const lsp::DocumentSymbol *> list; |
502 | GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_related_symbols(p_location, list); |
503 | for (const lsp::DocumentSymbol *&E : list) { |
504 | if (const lsp::DocumentSymbol *s = E) { |
505 | if (!s->uri.is_empty()) { |
506 | lsp::Location location; |
507 | location.uri = s->uri; |
508 | location.range = s->selectionRange; |
509 | arr.push_back(location.to_json()); |
510 | r_list.push_back(s); |
511 | } |
512 | } |
513 | } |
514 | } |
515 | return arr; |
516 | } |
517 | |