summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp108
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.h12
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp22
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp53
-rw-r--r--modules/gdscript/language_server/lsp.hpp8
5 files changed, 156 insertions, 47 deletions
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index a6fbfd3779..16f4324da8 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -91,6 +91,16 @@ void ExtendGDScriptParser::update_symbols() {
for (int i = 0; i < class_symbol.children.size(); i++) {
const lsp::DocumentSymbol &symbol = class_symbol.children[i];
members.set(symbol.name, &symbol);
+
+ // cache level one inner classes
+ if (symbol.kind == lsp::SymbolKind::Class) {
+ ClassMembers inner_class;
+ for (int j = 0; j < symbol.children.size(); j++) {
+ const lsp::DocumentSymbol &s = symbol.children[j];
+ inner_class.set(s.name, &s);
+ }
+ inner_classes.set(symbol.name, inner_class);
+ }
}
}
}
@@ -112,7 +122,8 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
r_symbol.range.end.line = LINE_NUMBER_TO_INDEX(p_class->end_line);
r_symbol.selectionRange.start.line = r_symbol.range.start.line;
r_symbol.detail = "class " + r_symbol.name;
- r_symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(p_class->line));
+ bool is_root_class = &r_symbol == &class_symbol;
+ r_symbol.documentation = parse_documentation(is_root_class ? 0 : LINE_NUMBER_TO_INDEX(p_class->line), is_root_class);
for (int i = 0; i < p_class->variables.size(); ++i) {
@@ -192,7 +203,26 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
if (c.type.kind != GDScriptParser::DataType::UNRESOLVED) {
symbol.detail += ": " + c.type.to_string();
}
- symbol.detail += " = " + String(node->value);
+
+ String value_text;
+ if (node->value.get_type() == Variant::OBJECT) {
+ RES res = node->value;
+ if (res.is_valid() && !res->get_path().empty()) {
+ value_text = "preload(\"" + res->get_path() + "\")";
+ if (symbol.documentation.empty()) {
+ if (Map<String, ExtendGDScriptParser *>::Element *S = GDScriptLanguageProtocol::get_singleton()->get_workspace().scripts.find(res->get_path())) {
+ symbol.documentation = S->get()->class_symbol.documentation;
+ }
+ }
+ } else {
+ value_text = JSON::print(node->value);
+ }
+ } else {
+ value_text = JSON::print(node->value);
+ }
+ if (!value_text.empty()) {
+ symbol.detail += " = " + value_text;
+ }
r_symbol.children.push_back(symbol);
}
@@ -296,29 +326,43 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN
}
}
-String ExtendGDScriptParser::parse_documentation(int p_line) {
+String ExtendGDScriptParser::parse_documentation(int p_line, bool p_docs_down) {
ERR_FAIL_INDEX_V(p_line, lines.size(), String());
List<String> doc_lines;
- // inline comment
- String inline_comment = lines[p_line];
- int comment_start = inline_comment.find("#");
- if (comment_start != -1) {
- inline_comment = inline_comment.substr(comment_start, inline_comment.length());
- if (inline_comment.length() > 1) {
- doc_lines.push_back(inline_comment.substr(1, inline_comment.length()));
+ if (!p_docs_down) { // inline comment
+ String inline_comment = lines[p_line];
+ int comment_start = inline_comment.find("#");
+ if (comment_start != -1) {
+ inline_comment = inline_comment.substr(comment_start, inline_comment.length());
+ if (inline_comment.length() > 1) {
+ doc_lines.push_back(inline_comment.substr(1, inline_comment.length()));
+ }
}
}
- // upper line comments
- for (int i = p_line - 1; i >= 0; --i) {
+ int step = p_docs_down ? 1 : -1;
+ int start_line = p_docs_down ? p_line : p_line - 1;
+ for (int i = start_line; true; i += step) {
+
+ if (i < 0 || i >= lines.size()) break;
+
String line_comment = lines[i].strip_edges(true, false);
if (line_comment.begins_with("#")) {
if (line_comment.length() > 1) {
- doc_lines.push_front(line_comment.substr(1, line_comment.length()));
+ line_comment = line_comment.substr(1, line_comment.length());
+ if (p_docs_down) {
+ doc_lines.push_back(line_comment);
+ } else {
+ doc_lines.push_front(line_comment);
+ }
} else {
- doc_lines.push_front("");
+ if (p_docs_down) {
+ doc_lines.push_back("");
+ } else {
+ doc_lines.push_front("");
+ }
}
} else {
break;
@@ -456,11 +500,20 @@ const lsp::DocumentSymbol *ExtendGDScriptParser::get_symbol_defined_at_line(int
return search_symbol_defined_at_line(p_line, class_symbol);
}
-const lsp::DocumentSymbol *ExtendGDScriptParser::get_member_symbol(const String &p_name) const {
+const lsp::DocumentSymbol *ExtendGDScriptParser::get_member_symbol(const String &p_name, const String &p_subclass) const {
- const lsp::DocumentSymbol *const *ptr = members.getptr(p_name);
- if (ptr) {
- return *ptr;
+ if (p_subclass.empty()) {
+ const lsp::DocumentSymbol *const *ptr = members.getptr(p_name);
+ if (ptr) {
+ return *ptr;
+ }
+ } else {
+ if (const ClassMembers *_class = inner_classes.getptr(p_subclass)) {
+ const lsp::DocumentSymbol *const *ptr = _class->getptr(p_name);
+ if (ptr) {
+ return *ptr;
+ }
+ }
}
return NULL;
@@ -474,12 +527,29 @@ const Array &ExtendGDScriptParser::get_member_completions() {
while (name) {
const lsp::DocumentSymbol *symbol = members.get(*name);
- lsp::CompletionItem item = symbol->make_completion_item(false);
+ lsp::CompletionItem item = symbol->make_completion_item();
item.data = JOIN_SYMBOLS(path, *name);
member_completions.push_back(item.to_json());
name = members.next(name);
}
+
+ const String *_class = inner_classes.next(NULL);
+ while (_class) {
+
+ const ClassMembers *inner_class = inner_classes.getptr(*_class);
+ const String *member_name = inner_class->next(NULL);
+ while (member_name) {
+ const lsp::DocumentSymbol *symbol = inner_class->get(*member_name);
+ lsp::CompletionItem item = symbol->make_completion_item();
+ item.data = JOIN_SYMBOLS(path, JOIN_SYMBOLS(*_class, *member_name));
+ member_completions.push_back(item.to_json());
+
+ member_name = inner_class->next(member_name);
+ }
+
+ _class = inner_classes.next(_class);
+ }
}
return member_completions;
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.h b/modules/gdscript/language_server/gdscript_extend_parser.h
index d20dca59cf..3710b92993 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.h
+++ b/modules/gdscript/language_server/gdscript_extend_parser.h
@@ -39,8 +39,12 @@
#define LINE_NUMBER_TO_INDEX(p_line) ((p_line)-1)
#endif
+#ifndef SYMBOL_SEPERATOR
+#define SYMBOL_SEPERATOR "::"
+#endif
+
#ifndef JOIN_SYMBOLS
-#define JOIN_SYMBOLS(p_path, name) ((p_path) + "." + (name))
+#define JOIN_SYMBOLS(p_path, name) ((p_path) + SYMBOL_SEPERATOR + (name))
#endif
typedef HashMap<String, const lsp::DocumentSymbol *> ClassMembers;
@@ -54,6 +58,7 @@ class ExtendGDScriptParser : public GDScriptParser {
lsp::DocumentSymbol class_symbol;
Vector<lsp::Diagnostic> diagnostics;
ClassMembers members;
+ HashMap<String, ClassMembers> inner_classes;
void update_diagnostics();
@@ -61,7 +66,7 @@ class ExtendGDScriptParser : public GDScriptParser {
void parse_class_symbol(const GDScriptParser::ClassNode *p_class, lsp::DocumentSymbol &r_symbol);
void parse_function_symbol(const GDScriptParser::FunctionNode *p_func, lsp::DocumentSymbol &r_symbol);
- String parse_documentation(int p_line);
+ String parse_documentation(int p_line, bool p_docs_down = false);
const lsp::DocumentSymbol *search_symbol_defined_at_line(int p_line, const lsp::DocumentSymbol &p_parent) const;
Array member_completions;
@@ -73,6 +78,7 @@ public:
_FORCE_INLINE_ const lsp::DocumentSymbol &get_symbols() const { return class_symbol; }
_FORCE_INLINE_ const Vector<lsp::Diagnostic> &get_diagnostics() const { return diagnostics; }
_FORCE_INLINE_ const ClassMembers &get_members() const { return members; }
+ _FORCE_INLINE_ const HashMap<String, ClassMembers> &get_inner_classes() const { return inner_classes; }
String get_text_for_completion(const lsp::Position &p_cursor) const;
String get_text_for_lookup_symbol(const lsp::Position &p_cursor, const String &p_symbol = "", bool p_func_requred = false) const;
@@ -80,7 +86,7 @@ public:
String get_uri() const;
const lsp::DocumentSymbol *get_symbol_defined_at_line(int p_line) const;
- const lsp::DocumentSymbol *get_member_symbol(const String &p_name) const;
+ const lsp::DocumentSymbol *get_member_symbol(const String &p_name, const String &p_subclass = "") const;
const Array &get_member_completions();
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index a5211fb0f1..cb42e31644 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -88,7 +88,7 @@ void GDScriptTextDocument::initialize() {
while (name) {
const lsp::DocumentSymbol *symbol = members.get(*name);
- lsp::CompletionItem item = symbol->make_completion_item(false);
+ lsp::CompletionItem item = symbol->make_completion_item();
item.data = JOIN_SYMBOLS(String(*class_ptr), *name);
native_member_completions.push_back(item.to_json());
@@ -171,7 +171,7 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) {
break;
}
- arr[i] = item.to_json(true);
+ arr[i] = item.to_json();
i++;
}
} else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) {
@@ -211,12 +211,18 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) {
} else if (data.get_type() == Variant::STRING) {
String query = data;
- int seperator_pos = query.find_last(".");
- if (seperator_pos >= 0 && seperator_pos < query.length() - 1) {
- String class_ = query.substr(0, seperator_pos);
+ Vector<String> param_symbols = query.split(SYMBOL_SEPERATOR, false);
+
+ if (param_symbols.size() >= 2) {
+
+ String class_ = param_symbols[0];
StringName class_name = class_;
- String member_name = query.substr(seperator_pos + 1, query.length());
+ String member_name = param_symbols[param_symbols.size() - 1];
+ String inner_class_name;
+ if (param_symbols.size() >= 3) {
+ inner_class_name = param_symbols[1];
+ }
if (const ClassMembers *members = GDScriptLanguageProtocol::get_singleton()->get_workspace().native_members.getptr(class_name)) {
if (const lsp::DocumentSymbol *const *member = members->getptr(member_name)) {
@@ -226,7 +232,7 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) {
if (!symbol) {
if (const Map<String, ExtendGDScriptParser *>::Element *E = GDScriptLanguageProtocol::get_singleton()->get_workspace().scripts.find(class_name)) {
- symbol = E->get()->get_member_symbol(member_name);
+ symbol = E->get()->get_member_symbol(member_name, inner_class_name);
}
}
}
@@ -248,7 +254,7 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) {
}
}
- return item.to_json();
+ return item.to_json(true);
}
Array GDScriptTextDocument::foldingRange(const Dictionary &p_params) {
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index 089c19e6a4..ec95ea5765 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -170,14 +170,6 @@ String GDScriptWorkspace::marked_documentation(const String &p_bbcode) {
markdown = "";
for (int i = 0; i < lines.size(); i++) {
String line = lines[i];
- line = line.replace("[code]", "`");
- line = line.replace("[/code]", "`");
- line = line.replace("[i]", "*");
- line = line.replace("[/i]", "*");
- line = line.replace("[b]", "**");
- line = line.replace("[/b]", "**");
- line = line.replace("[u]", "__");
- line = line.replace("[/u]", "__");
int block_start = line.find("[codeblock]");
if (block_start != -1) {
code_block_indent = block_start;
@@ -186,14 +178,31 @@ String GDScriptWorkspace::marked_documentation(const String &p_bbcode) {
line = "\n";
} else if (in_code_block) {
line = "\t" + line.substr(code_block_indent, line.length());
- } else {
- line = line.strip_edges();
}
+
if (in_code_block && line.find("[/codeblock]") != -1) {
line = "'''\n";
line = "\n";
in_code_block = false;
}
+
+ if (!in_code_block) {
+ line = line.strip_edges();
+ line = line.replace("[code]", "`");
+ line = line.replace("[/code]", "`");
+ line = line.replace("[i]", "*");
+ line = line.replace("[/i]", "*");
+ line = line.replace("[b]", "**");
+ line = line.replace("[/b]", "**");
+ line = line.replace("[u]", "__");
+ line = line.replace("[/u]", "__");
+ line = line.replace("[method ", "`");
+ line = line.replace("[member ", "`");
+ line = line.replace("[signal ", "`");
+ line = line.replace("[", "`");
+ line = line.replace("]", "`");
+ }
+
if (!in_code_block && i < lines.size() - 1) {
line += "\n";
}
@@ -310,6 +319,8 @@ Error GDScriptWorkspace::initialize() {
native_symbols.insert(class_name, class_symbol);
}
+ reload_all_workspace_scripts();
+
if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) {
for (Map<StringName, lsp::DocumentSymbol>::Element *E = native_symbols.front(); E; E = E->next()) {
ClassMembers members;
@@ -320,9 +331,12 @@ Error GDScriptWorkspace::initialize() {
}
native_members.set(E->key(), members);
}
- }
- reload_all_workspace_scripts();
+ // cache member completions
+ for (Map<String, ExtendGDScriptParser *>::Element *S = scripts.front(); S; S = S->next()) {
+ S->get()->get_member_completions();
+ }
+ }
return OK;
}
@@ -477,10 +491,23 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP
}
for (Map<String, ExtendGDScriptParser *>::Element *E = scripts.front(); E; E = E->next()) {
- const ClassMembers &members = E->get()->get_members();
+ const ExtendGDScriptParser *script = E->get();
+ const ClassMembers &members = script->get_members();
if (const lsp::DocumentSymbol *const *symbol = members.getptr(symbol_identifier)) {
r_list.push_back(*symbol);
}
+
+ const HashMap<String, ClassMembers> &inner_classes = script->get_inner_classes();
+ const String *_class = inner_classes.next(NULL);
+ while (_class) {
+
+ const ClassMembers *inner_class = inner_classes.getptr(*_class);
+ if (const lsp::DocumentSymbol *const *symbol = inner_class->getptr(symbol_identifier)) {
+ r_list.push_back(*symbol);
+ }
+
+ _class = inner_classes.next(_class);
+ }
}
}
}
diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp
index c208d5a198..065b8b65e8 100644
--- a/modules/gdscript/language_server/lsp.hpp
+++ b/modules/gdscript/language_server/lsp.hpp
@@ -886,12 +886,12 @@ struct CompletionItem {
*/
Variant data;
- _FORCE_INLINE_ Dictionary to_json(bool minimized = false) const {
+ _FORCE_INLINE_ Dictionary to_json(bool resolved = false) const {
Dictionary dict;
dict["label"] = label;
dict["kind"] = kind;
dict["data"] = data;
- if (!minimized) {
+ if (resolved) {
dict["insertText"] = insertText;
dict["detail"] = detail;
dict["documentation"] = documentation.to_json();
@@ -1145,12 +1145,12 @@ struct DocumentSymbol {
return markdown;
}
- _FORCE_INLINE_ CompletionItem make_completion_item(bool with_doc = false) const {
+ _FORCE_INLINE_ CompletionItem make_completion_item(bool resolved = false) const {
lsp::CompletionItem item;
item.label = name;
- if (with_doc) {
+ if (resolved) {
item.documentation = render();
}