summaryrefslogtreecommitdiffstats
path: root/editor/editor_help.cpp
diff options
context:
space:
mode:
authorYuri Sizov <11782833+YuriSizov@users.noreply.github.com>2023-04-26 16:54:25 +0200
committerGitHub <noreply@github.com>2023-04-26 16:54:25 +0200
commit26fb911f79d7b16c46ca476923fe1f32ab5d27ed (patch)
treef194bb48dea30dc8a18e3989b948f5f57d82232d /editor/editor_help.cpp
parente2e870c6118f6e9463c8907c947102f913f543de (diff)
parent6783ff69c06a5c6fcb0e22802fedcc1fa32ac25c (diff)
downloadredot-engine-26fb911f79d7b16c46ca476923fe1f32ab5d27ed.tar.gz
Merge pull request #72095 from anvilfolk/gd-docs
Improve GDScript documentation generation & behavior
Diffstat (limited to 'editor/editor_help.cpp')
-rw-r--r--editor/editor_help.cpp124
1 files changed, 86 insertions, 38 deletions
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index b9634a7e03..f2d852cc2b 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -32,6 +32,7 @@
#include "core/core_constants.h"
#include "core/input/input.h"
+#include "core/object/script_language.h"
#include "core/os/keyboard.h"
#include "core/version.h"
#include "doc_data_compressed.gen.h"
@@ -44,6 +45,8 @@
#define CONTRIBUTE_URL vformat("%s/contributing/documentation/updating_the_class_reference.html", VERSION_DOCS_URL)
+// TODO: this is sometimes used directly as doc->something, other times as EditorHelp::get_doc_data(), which is thread-safe.
+// Might this be a problem?
DocTools *EditorHelp::doc = nullptr;
class DocCache : public Resource {
@@ -73,6 +76,49 @@ public:
void set_classes(const Array &p_classes) { classes = p_classes; }
};
+static bool _attempt_doc_load(const String &p_class) {
+ // Docgen always happens in the outer-most class: it also generates docs for inner classes.
+ String outer_class = p_class.get_slice(".", 0);
+ if (!ScriptServer::is_global_class(outer_class)) {
+ return false;
+ }
+
+ // ResourceLoader is used in order to have a script-agnostic way to load scripts.
+ // This forces GDScript to compile the code, which is unnecessary for docgen, but it's a good compromise right now.
+ Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(outer_class), outer_class);
+ if (script.is_valid()) {
+ Vector<DocData::ClassDoc> docs = script->get_documentation();
+ for (int j = 0; j < docs.size(); j++) {
+ const DocData::ClassDoc &doc = docs.get(j);
+ EditorHelp::get_doc_data()->add_doc(doc);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+// Removes unnecessary prefix from p_class_specifier when within the p_edited_class context
+static String _contextualize_class_specifier(const String &p_class_specifier, const String &p_edited_class) {
+ // If this is a completely different context than the current class, then keep full path
+ if (!p_class_specifier.begins_with(p_edited_class)) {
+ return p_class_specifier;
+ }
+
+ // Here equal length + begins_with from above implies p_class_specifier == p_edited_class :)
+ if (p_class_specifier.length() == p_edited_class.length()) {
+ int rfind = p_class_specifier.rfind(".");
+ if (rfind == -1) { // Single identifier
+ return p_class_specifier;
+ }
+ // Multiple specifiers: keep last one only
+ return p_class_specifier.substr(rfind + 1);
+ }
+
+ // Remove prefix
+ return p_class_specifier.substr(p_edited_class.length() + 1);
+}
+
void EditorHelp::_update_theme_item_cache() {
VBoxContainer::_update_theme_item_cache();
@@ -130,12 +176,13 @@ void EditorHelp::_class_list_select(const String &p_select) {
}
void EditorHelp::_class_desc_select(const String &p_select) {
- if (p_select.begins_with("$")) { //enum
+ if (p_select.begins_with("$")) { // enum
String select = p_select.substr(1, p_select.length());
String class_name;
- if (select.contains(".")) {
- class_name = select.get_slice(".", 0);
- select = select.get_slice(".", 1);
+ int rfind = select.rfind(".");
+ if (rfind != -1) {
+ class_name = select.substr(0, rfind);
+ select = select.substr(rfind + 1);
} else {
class_name = "@GlobalScope";
}
@@ -253,35 +300,35 @@ void EditorHelp::_add_type(const String &p_type, const String &p_enum) {
bool is_enum_type = !p_enum.is_empty();
bool can_ref = !p_type.contains("*") || is_enum_type;
- String t = p_type;
+ String link_t = p_type; // For links in metadata
+ String display_t = link_t; // For display purposes
if (is_enum_type) {
- if (p_enum.get_slice_count(".") > 1) {
- t = p_enum.get_slice(".", 1);
- } else {
- t = p_enum.get_slice(".", 0);
- }
+ link_t = p_enum; // The link for enums is always the full enum description
+ display_t = _contextualize_class_specifier(p_enum, edited_class);
+ } else {
+ display_t = _contextualize_class_specifier(p_type, edited_class);
}
class_desc->push_color(theme_cache.type_color);
bool add_array = false;
if (can_ref) {
- if (t.ends_with("[]")) {
+ if (link_t.ends_with("[]")) {
add_array = true;
- t = t.replace("[]", "");
+ link_t = link_t.replace("[]", "");
- class_desc->push_meta("#Array"); //class
+ class_desc->push_meta("#Array"); // class
class_desc->add_text("Array");
class_desc->pop();
class_desc->add_text("[");
}
if (is_enum_type) {
- class_desc->push_meta("$" + p_enum); //class
+ class_desc->push_meta("$" + link_t); // enum
} else {
- class_desc->push_meta("#" + t); //class
+ class_desc->push_meta("#" + link_t); // class
}
}
- class_desc->add_text(t);
+ class_desc->add_text(display_t);
if (can_ref) {
class_desc->pop(); // Pushed meta above.
if (add_array) {
@@ -338,7 +385,7 @@ String EditorHelp::_fix_constant(const String &p_constant) const {
class_desc->pop();
void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview) {
- method_line[p_method.name] = class_desc->get_paragraph_count() - 2; //gets overridden if description
+ method_line[p_method.name] = class_desc->get_paragraph_count() - 2; // Gets overridden if description
const bool is_vararg = p_method.qualifiers.contains("vararg");
@@ -352,8 +399,8 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview
_add_type(p_method.return_type, p_method.return_enum);
if (p_overview) {
- class_desc->pop(); //align
- class_desc->pop(); //cell
+ class_desc->pop(); // align
+ class_desc->pop(); // cell
class_desc->push_cell();
} else {
class_desc->add_text(" ");
@@ -368,7 +415,7 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview
class_desc->pop();
if (p_overview && !p_method.description.strip_edges().is_empty()) {
- class_desc->pop(); //meta
+ class_desc->pop(); // meta
}
class_desc->push_color(theme_cache.symbol_color);
@@ -447,7 +494,7 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview
}
if (p_overview) {
- class_desc->pop(); //cell
+ class_desc->pop(); // cell
}
}
@@ -488,8 +535,9 @@ void EditorHelp::_pop_code_font() {
class_desc->pop();
}
-Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
- if (!doc->class_list.has(p_class)) {
+Error EditorHelp::_goto_desc(const String &p_class) {
+ // If class doesn't have docs listed, attempt on-demand docgen
+ if (!doc->class_list.has(p_class) && !_attempt_doc_load(p_class)) {
return ERR_DOES_NOT_EXIST;
}
@@ -529,9 +577,9 @@ void EditorHelp::_update_method_list(const Vector<DocData::MethodDoc> p_methods)
if (any_previous && !m.is_empty()) {
class_desc->push_cell();
- class_desc->pop(); //cell
+ class_desc->pop(); // cell
class_desc->push_cell();
- class_desc->pop(); //cell
+ class_desc->pop(); // cell
}
String group_prefix;
@@ -549,9 +597,9 @@ void EditorHelp::_update_method_list(const Vector<DocData::MethodDoc> p_methods)
if (is_new_group && pass == 1) {
class_desc->push_cell();
- class_desc->pop(); //cell
+ class_desc->pop(); // cell
class_desc->push_cell();
- class_desc->pop(); //cell
+ class_desc->pop(); // cell
}
_add_method(m[i], true);
@@ -560,7 +608,7 @@ void EditorHelp::_update_method_list(const Vector<DocData::MethodDoc> p_methods)
any_previous = !m.is_empty();
}
- class_desc->pop(); //table
+ class_desc->pop(); // table
class_desc->pop();
_pop_code_font();
@@ -1196,7 +1244,7 @@ void EditorHelp::_update_doc() {
_add_text(cd.signals[i].arguments[j].name);
class_desc->add_text(": ");
- _add_type(cd.signals[i].arguments[j].type);
+ _add_type(cd.signals[i].arguments[j].type, cd.signals[i].arguments[j].enumeration);
if (!cd.signals[i].arguments[j].default_value.is_empty()) {
class_desc->push_color(theme_cache.symbol_color);
class_desc->add_text(" = ");
@@ -1767,7 +1815,6 @@ void EditorHelp::_request_help(const String &p_string) {
if (err == OK) {
EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT);
}
- //100 palabras
}
void EditorHelp::_help_callback(const String &p_topic) {
@@ -2178,7 +2225,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt, Control
tag_stack.push_front("font");
} else {
- p_rt->add_text("["); //ignore
+ p_rt->add_text("["); // ignore
pos = brk_pos + 1;
}
}
@@ -2310,9 +2357,9 @@ void EditorHelp::go_to_help(const String &p_help) {
_help_callback(p_help);
}
-void EditorHelp::go_to_class(const String &p_class, int p_scroll) {
+void EditorHelp::go_to_class(const String &p_class) {
_wait_for_thread();
- _goto_desc(p_class, p_scroll);
+ _goto_desc(p_class);
}
void EditorHelp::update_doc() {
@@ -2443,14 +2490,15 @@ void EditorHelpBit::_go_to_help(String p_what) {
}
void EditorHelpBit::_meta_clicked(String p_select) {
- if (p_select.begins_with("$")) { //enum
-
+ if (p_select.begins_with("$")) { // enum
String select = p_select.substr(1, p_select.length());
String class_name;
- if (select.contains(".")) {
- class_name = select.get_slice(".", 0);
+ int rfind = select.rfind(".");
+ if (rfind != -1) {
+ class_name = select.substr(0, rfind);
+ select = select.substr(rfind + 1);
} else {
- class_name = "@Global";
+ class_name = "@GlobalScope";
}
_go_to_help("class_enum:" + class_name + ":" + select);
return;