Add inheriting classes to DocTools

This commit is contained in:
A Thousand Ships 2023-08-16 14:00:59 +02:00
parent 4b55c81eba
commit dc86483e3a
No known key found for this signature in database
GPG key ID: 2033189A662F8BD7
5 changed files with 93 additions and 62 deletions

View file

@ -307,21 +307,21 @@ void DocTools::merge_from(const DocTools &p_data) {
} }
} }
void DocTools::remove_from(const DocTools &p_data) {
for (const KeyValue<String, DocData::ClassDoc> &E : p_data.class_list) {
if (class_list.has(E.key)) {
class_list.erase(E.key);
}
}
}
void DocTools::add_doc(const DocData::ClassDoc &p_class_doc) { void DocTools::add_doc(const DocData::ClassDoc &p_class_doc) {
ERR_FAIL_COND(p_class_doc.name.is_empty()); ERR_FAIL_COND(p_class_doc.name.is_empty());
class_list[p_class_doc.name] = p_class_doc; class_list[p_class_doc.name] = p_class_doc;
inheriting[p_class_doc.inherits].insert(p_class_doc.name);
} }
void DocTools::remove_doc(const String &p_class_name) { void DocTools::remove_doc(const String &p_class_name) {
ERR_FAIL_COND(p_class_name.is_empty() || !class_list.has(p_class_name)); ERR_FAIL_COND(p_class_name.is_empty() || !class_list.has(p_class_name));
const String &inherits = class_list[p_class_name].inherits;
if (inheriting.has(inherits)) {
inheriting[inherits].erase(p_class_name);
if (inheriting[inherits].is_empty()) {
inheriting.erase(inherits);
}
}
class_list.erase(p_class_name); class_list.erase(p_class_name);
} }
@ -391,6 +391,8 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
c.name = cname; c.name = cname;
c.inherits = ClassDB::get_parent_class(name); c.inherits = ClassDB::get_parent_class(name);
inheriting[c.inherits].insert(cname);
List<PropertyInfo> properties; List<PropertyInfo> properties;
List<PropertyInfo> own_properties; List<PropertyInfo> own_properties;
@ -692,6 +694,7 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
// it's not a ClassDB-exposed class. // it's not a ClassDB-exposed class.
class_list["Variant"] = DocData::ClassDoc(); class_list["Variant"] = DocData::ClassDoc();
class_list["Variant"].name = "Variant"; class_list["Variant"].name = "Variant";
inheriting[""].insert("Variant");
} }
// Add Variant data types. // Add Variant data types.
@ -709,6 +712,8 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
DocData::ClassDoc &c = class_list[cname]; DocData::ClassDoc &c = class_list[cname];
c.name = cname; c.name = cname;
inheriting[""].insert(cname);
Callable::CallError cerror; Callable::CallError cerror;
Variant v; Variant v;
Variant::construct(Variant::Type(i), v, nullptr, 0, cerror); Variant::construct(Variant::Type(i), v, nullptr, 0, cerror);
@ -870,6 +875,8 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
DocData::ClassDoc &c = class_list[cname]; DocData::ClassDoc &c = class_list[cname];
c.name = cname; c.name = cname;
inheriting[""].insert(cname);
// Global constants. // Global constants.
for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) { for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) {
DocData::ConstantDoc cd; DocData::ConstantDoc cd;
@ -953,6 +960,8 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
DocData::ClassDoc c; DocData::ClassDoc c;
c.name = cname; c.name = cname;
inheriting[""].insert(cname);
// Get functions. // Get functions.
List<MethodInfo> minfo; List<MethodInfo> minfo;
lang->get_public_functions(&minfo); lang->get_public_functions(&minfo);
@ -1195,6 +1204,8 @@ Error DocTools::_load(Ref<XMLParser> parser) {
c.inherits = parser->get_named_attribute_value("inherits"); c.inherits = parser->get_named_attribute_value("inherits");
} }
inheriting[c.inherits].insert(name);
if (parser->has_attribute("is_deprecated")) { if (parser->has_attribute("is_deprecated")) {
c.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true"; c.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true";
} }

View file

@ -32,16 +32,17 @@
#define DOC_TOOLS_H #define DOC_TOOLS_H
#include "core/doc_data.h" #include "core/doc_data.h"
#include "core/templates/rb_set.h"
class DocTools { class DocTools {
public: public:
String version; String version;
HashMap<String, DocData::ClassDoc> class_list; HashMap<String, DocData::ClassDoc> class_list;
HashMap<String, RBSet<String, NaturalNoCaseComparator>> inheriting;
static Error erase_classes(const String &p_dir); static Error erase_classes(const String &p_dir);
void merge_from(const DocTools &p_data); void merge_from(const DocTools &p_data);
void remove_from(const DocTools &p_data);
void add_doc(const DocData::ClassDoc &p_class_doc); void add_doc(const DocData::ClassDoc &p_class_doc);
void remove_doc(const String &p_class_name); void remove_doc(const String &p_class_name);
bool has_doc(const String &p_class_name); bool has_doc(const String &p_class_name);

View file

@ -812,36 +812,26 @@ void EditorHelp::_update_doc() {
class_desc->add_newline(); class_desc->add_newline();
} }
// Descendents // Descendants
if (cd.is_script_doc || ClassDB::class_exists(cd.name)) { if ((cd.is_script_doc || ClassDB::class_exists(cd.name)) && doc->inheriting.has(cd.name)) {
bool found = false;
bool prev = false;
_push_normal_font(); _push_normal_font();
for (const KeyValue<String, DocData::ClassDoc> &E : doc->class_list) {
if (E.value.inherits == cd.name) {
if (!found) {
class_desc->push_color(theme_cache.title_color); class_desc->push_color(theme_cache.title_color);
class_desc->add_text(TTR("Inherited by:") + " "); class_desc->add_text(TTR("Inherited by:") + " ");
found = true;
}
if (prev) { for (RBSet<String, NaturalNoCaseComparator>::Element *itr = doc->inheriting[cd.name].front(); itr; itr = itr->next()) {
if (itr->prev()) {
class_desc->add_text(" , "); class_desc->add_text(" , ");
} }
_add_type_icon(E.value.name, theme_cache.doc_font_size, "ArrowRight");
_add_type_icon(itr->get(), theme_cache.doc_font_size, "ArrowRight");
class_desc->add_text(non_breaking_space); // Otherwise icon borrows hyperlink from _add_type(). class_desc->add_text(non_breaking_space); // Otherwise icon borrows hyperlink from _add_type().
_add_type(E.value.name); _add_type(itr->get());
prev = true;
}
} }
_pop_normal_font(); _pop_normal_font();
if (found) {
class_desc->pop(); class_desc->pop();
class_desc->add_newline(); class_desc->add_newline();
} }
}
// Note if deprecated. // Note if deprecated.
if (cd.is_deprecated) { if (cd.is_deprecated) {

View file

@ -317,7 +317,13 @@ bool EditorHelpSearch::Runner::_slice() {
} }
bool EditorHelpSearch::Runner::_phase_match_classes_init() { bool EditorHelpSearch::Runner::_phase_match_classes_init() {
iterator_doc = nullptr;
iterator_stack.clear();
if (search_flags & SEARCH_SHOW_HIERARCHY) {
iterator_stack.push_back(EditorHelp::get_doc_data()->inheriting[""].front());
} else {
iterator_doc = EditorHelp::get_doc_data()->class_list.begin(); iterator_doc = EditorHelp::get_doc_data()->class_list.begin();
}
matches.clear(); matches.clear();
matched_item = nullptr; matched_item = nullptr;
match_highest_score = 0; match_highest_score = 0;
@ -331,81 +337,103 @@ bool EditorHelpSearch::Runner::_phase_match_classes_init() {
} }
bool EditorHelpSearch::Runner::_phase_match_classes() { bool EditorHelpSearch::Runner::_phase_match_classes() {
if (!iterator_doc) { if (!iterator_doc && iterator_stack.is_empty()) {
return true; return true;
} }
DocData::ClassDoc &class_doc = iterator_doc->value; DocData::ClassDoc *class_doc = nullptr;
if (class_doc.name.is_empty()) { if (iterator_doc) {
++iterator_doc; class_doc = &iterator_doc->value;
return false; } else if (!iterator_stack.is_empty() && iterator_stack[iterator_stack.size() - 1]) {
class_doc = EditorHelp::get_doc_data()->class_list.getptr(iterator_stack[iterator_stack.size() - 1]->get());
} }
if (!_is_class_disabled_by_feature_profile(class_doc.name)) { if (class_doc && class_doc->name.is_empty()) {
class_doc = nullptr;
}
if (class_doc && !_is_class_disabled_by_feature_profile(class_doc->name)) {
ClassMatch match; ClassMatch match;
match.doc = &class_doc; match.doc = class_doc;
// Match class name. // Match class name.
if (search_flags & SEARCH_CLASSES) { if (search_flags & SEARCH_CLASSES) {
// If the search term is empty, add any classes which are not script docs or which don't start with // If the search term is empty, add any classes which are not script docs or which don't start with
// a double-quotation. This will ensure that only C++ classes and explicitly named classes will // a double-quotation. This will ensure that only C++ classes and explicitly named classes will
// be added. // be added.
match.name = (term.is_empty() && (!class_doc.is_script_doc || class_doc.name[0] != '\"')) || _match_string(term, class_doc.name); match.name = (term.is_empty() && (!class_doc->is_script_doc || class_doc->name[0] != '\"')) || _match_string(term, class_doc->name);
} }
// Match members only if the term is long enough, to avoid slow performance from building a large tree. // Match members only if the term is long enough, to avoid slow performance from building a large tree.
// Make an exception for annotations, since there are not that many of them. // Make an exception for annotations, since there are not that many of them.
if (term.length() > 1 || term == "@") { if (term.length() > 1 || term == "@") {
if (search_flags & SEARCH_CONSTRUCTORS) { if (search_flags & SEARCH_CONSTRUCTORS) {
_match_method_name_and_push_back(class_doc.constructors, &match.constructors); _match_method_name_and_push_back(class_doc->constructors, &match.constructors);
} }
if (search_flags & SEARCH_METHODS) { if (search_flags & SEARCH_METHODS) {
_match_method_name_and_push_back(class_doc.methods, &match.methods); _match_method_name_and_push_back(class_doc->methods, &match.methods);
} }
if (search_flags & SEARCH_OPERATORS) { if (search_flags & SEARCH_OPERATORS) {
_match_method_name_and_push_back(class_doc.operators, &match.operators); _match_method_name_and_push_back(class_doc->operators, &match.operators);
} }
if (search_flags & SEARCH_SIGNALS) { if (search_flags & SEARCH_SIGNALS) {
for (int i = 0; i < class_doc.signals.size(); i++) { for (int i = 0; i < class_doc->signals.size(); i++) {
if (_all_terms_in_name(class_doc.signals[i].name)) { if (_all_terms_in_name(class_doc->signals[i].name)) {
match.signals.push_back(const_cast<DocData::MethodDoc *>(&class_doc.signals[i])); match.signals.push_back(const_cast<DocData::MethodDoc *>(&class_doc->signals[i]));
} }
} }
} }
if (search_flags & SEARCH_CONSTANTS) { if (search_flags & SEARCH_CONSTANTS) {
for (int i = 0; i < class_doc.constants.size(); i++) { for (int i = 0; i < class_doc->constants.size(); i++) {
if (_all_terms_in_name(class_doc.constants[i].name)) { if (_all_terms_in_name(class_doc->constants[i].name)) {
match.constants.push_back(const_cast<DocData::ConstantDoc *>(&class_doc.constants[i])); match.constants.push_back(const_cast<DocData::ConstantDoc *>(&class_doc->constants[i]));
} }
} }
} }
if (search_flags & SEARCH_PROPERTIES) { if (search_flags & SEARCH_PROPERTIES) {
for (int i = 0; i < class_doc.properties.size(); i++) { for (int i = 0; i < class_doc->properties.size(); i++) {
if (_all_terms_in_name(class_doc.properties[i].name)) { if (_all_terms_in_name(class_doc->properties[i].name)) {
match.properties.push_back(const_cast<DocData::PropertyDoc *>(&class_doc.properties[i])); match.properties.push_back(const_cast<DocData::PropertyDoc *>(&class_doc->properties[i]));
} }
} }
} }
if (search_flags & SEARCH_THEME_ITEMS) { if (search_flags & SEARCH_THEME_ITEMS) {
for (int i = 0; i < class_doc.theme_properties.size(); i++) { for (int i = 0; i < class_doc->theme_properties.size(); i++) {
if (_all_terms_in_name(class_doc.theme_properties[i].name)) { if (_all_terms_in_name(class_doc->theme_properties[i].name)) {
match.theme_properties.push_back(const_cast<DocData::ThemeItemDoc *>(&class_doc.theme_properties[i])); match.theme_properties.push_back(const_cast<DocData::ThemeItemDoc *>(&class_doc->theme_properties[i]));
} }
} }
} }
if (search_flags & SEARCH_ANNOTATIONS) { if (search_flags & SEARCH_ANNOTATIONS) {
for (int i = 0; i < class_doc.annotations.size(); i++) { for (int i = 0; i < class_doc->annotations.size(); i++) {
if (_match_string(term, class_doc.annotations[i].name)) { if (_match_string(term, class_doc->annotations[i].name)) {
match.annotations.push_back(const_cast<DocData::MethodDoc *>(&class_doc.annotations[i])); match.annotations.push_back(const_cast<DocData::MethodDoc *>(&class_doc->annotations[i]));
} }
} }
} }
} }
matches[class_doc.name] = match; matches[class_doc->name] = match;
} }
if (iterator_doc) {
++iterator_doc; ++iterator_doc;
return !iterator_doc; return !iterator_doc;
}
if (!iterator_stack.is_empty()) {
if (iterator_stack[iterator_stack.size() - 1]) {
iterator_stack[iterator_stack.size() - 1] = iterator_stack[iterator_stack.size() - 1]->next();
}
if (!iterator_stack[iterator_stack.size() - 1]) {
iterator_stack.resize(iterator_stack.size() - 1);
}
}
if (class_doc && EditorHelp::get_doc_data()->inheriting.has(class_doc->name)) {
iterator_stack.push_back(EditorHelp::get_doc_data()->inheriting[class_doc->name].front());
}
return iterator_stack.is_empty();
} }
bool EditorHelpSearch::Runner::_phase_class_items_init() { bool EditorHelpSearch::Runner::_phase_class_items_init() {

View file

@ -124,6 +124,7 @@ class EditorHelpSearch::Runner : public RefCounted {
Color disabled_color; Color disabled_color;
HashMap<String, DocData::ClassDoc>::Iterator iterator_doc; HashMap<String, DocData::ClassDoc>::Iterator iterator_doc;
LocalVector<RBSet<String, NaturalNoCaseComparator>::Element *> iterator_stack;
HashMap<String, ClassMatch> matches; HashMap<String, ClassMatch> matches;
HashMap<String, ClassMatch>::Iterator iterator_match; HashMap<String, ClassMatch>::Iterator iterator_match;
TreeItem *root_item = nullptr; TreeItem *root_item = nullptr;