From dc86483e3aef2879f94457220f32bb973ee1c912 Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Wed, 16 Aug 2023 14:00:59 +0200 Subject: [PATCH] Add inheriting classes to `DocTools` --- editor/doc_tools.cpp | 27 +++++++---- editor/doc_tools.h | 3 +- editor/editor_help.cpp | 36 ++++++-------- editor/editor_help_search.cpp | 88 +++++++++++++++++++++++------------ editor/editor_help_search.h | 1 + 5 files changed, 93 insertions(+), 62 deletions(-) diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index 9c1fc2a8bf5f..44f6444a31d5 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -307,21 +307,21 @@ void DocTools::merge_from(const DocTools &p_data) { } } -void DocTools::remove_from(const DocTools &p_data) { - for (const KeyValue &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) { ERR_FAIL_COND(p_class_doc.name.is_empty()); 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) { 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); } @@ -391,6 +391,8 @@ void DocTools::generate(BitField p_flags) { c.name = cname; c.inherits = ClassDB::get_parent_class(name); + inheriting[c.inherits].insert(cname); + List properties; List own_properties; @@ -692,6 +694,7 @@ void DocTools::generate(BitField p_flags) { // it's not a ClassDB-exposed class. class_list["Variant"] = DocData::ClassDoc(); class_list["Variant"].name = "Variant"; + inheriting[""].insert("Variant"); } // Add Variant data types. @@ -709,6 +712,8 @@ void DocTools::generate(BitField p_flags) { DocData::ClassDoc &c = class_list[cname]; c.name = cname; + inheriting[""].insert(cname); + Callable::CallError cerror; Variant v; Variant::construct(Variant::Type(i), v, nullptr, 0, cerror); @@ -870,6 +875,8 @@ void DocTools::generate(BitField p_flags) { DocData::ClassDoc &c = class_list[cname]; c.name = cname; + inheriting[""].insert(cname); + // Global constants. for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) { DocData::ConstantDoc cd; @@ -953,6 +960,8 @@ void DocTools::generate(BitField p_flags) { DocData::ClassDoc c; c.name = cname; + inheriting[""].insert(cname); + // Get functions. List minfo; lang->get_public_functions(&minfo); @@ -1195,6 +1204,8 @@ Error DocTools::_load(Ref parser) { c.inherits = parser->get_named_attribute_value("inherits"); } + inheriting[c.inherits].insert(name); + if (parser->has_attribute("is_deprecated")) { c.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true"; } diff --git a/editor/doc_tools.h b/editor/doc_tools.h index 5fffb6be3821..7f29cc238a95 100644 --- a/editor/doc_tools.h +++ b/editor/doc_tools.h @@ -32,16 +32,17 @@ #define DOC_TOOLS_H #include "core/doc_data.h" +#include "core/templates/rb_set.h" class DocTools { public: String version; HashMap class_list; + HashMap> inheriting; static Error erase_classes(const String &p_dir); void merge_from(const DocTools &p_data); - void remove_from(const DocTools &p_data); void add_doc(const DocData::ClassDoc &p_class_doc); void remove_doc(const String &p_class_name); bool has_doc(const String &p_class_name); diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 74c0ef4e507a..f0f7f877111b 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -812,35 +812,25 @@ void EditorHelp::_update_doc() { class_desc->add_newline(); } - // Descendents - if (cd.is_script_doc || ClassDB::class_exists(cd.name)) { - bool found = false; - bool prev = false; - + // Descendants + if ((cd.is_script_doc || ClassDB::class_exists(cd.name)) && doc->inheriting.has(cd.name)) { _push_normal_font(); - for (const KeyValue &E : doc->class_list) { - if (E.value.inherits == cd.name) { - if (!found) { - class_desc->push_color(theme_cache.title_color); - class_desc->add_text(TTR("Inherited by:") + " "); - found = true; - } + class_desc->push_color(theme_cache.title_color); + class_desc->add_text(TTR("Inherited by:") + " "); - if (prev) { - class_desc->add_text(" , "); - } - _add_type_icon(E.value.name, theme_cache.doc_font_size, "ArrowRight"); - class_desc->add_text(non_breaking_space); // Otherwise icon borrows hyperlink from _add_type(). - _add_type(E.value.name); - prev = true; + for (RBSet::Element *itr = doc->inheriting[cd.name].front(); itr; itr = itr->next()) { + if (itr->prev()) { + class_desc->add_text(" , "); } + + _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(). + _add_type(itr->get()); } _pop_normal_font(); - if (found) { - class_desc->pop(); - class_desc->add_newline(); - } + class_desc->pop(); + class_desc->add_newline(); } // Note if deprecated. diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index b200154ec8c0..190e8c2445c6 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -317,7 +317,13 @@ bool EditorHelpSearch::Runner::_slice() { } bool EditorHelpSearch::Runner::_phase_match_classes_init() { - iterator_doc = EditorHelp::get_doc_data()->class_list.begin(); + 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(); + } matches.clear(); matched_item = nullptr; match_highest_score = 0; @@ -331,81 +337,103 @@ bool EditorHelpSearch::Runner::_phase_match_classes_init() { } bool EditorHelpSearch::Runner::_phase_match_classes() { - if (!iterator_doc) { + if (!iterator_doc && iterator_stack.is_empty()) { return true; } - DocData::ClassDoc &class_doc = iterator_doc->value; - if (class_doc.name.is_empty()) { - ++iterator_doc; - return false; + DocData::ClassDoc *class_doc = nullptr; + if (iterator_doc) { + class_doc = &iterator_doc->value; + } 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 (class_doc && class_doc->name.is_empty()) { + class_doc = nullptr; } - if (!_is_class_disabled_by_feature_profile(class_doc.name)) { + if (class_doc && !_is_class_disabled_by_feature_profile(class_doc->name)) { ClassMatch match; - match.doc = &class_doc; + match.doc = class_doc; // Match class name. 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 // a double-quotation. This will ensure that only C++ classes and explicitly named classes will // 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. // Make an exception for annotations, since there are not that many of them. if (term.length() > 1 || term == "@") { 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) { - _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) { - _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) { - for (int i = 0; i < class_doc.signals.size(); i++) { - if (_all_terms_in_name(class_doc.signals[i].name)) { - match.signals.push_back(const_cast(&class_doc.signals[i])); + for (int i = 0; i < class_doc->signals.size(); i++) { + if (_all_terms_in_name(class_doc->signals[i].name)) { + match.signals.push_back(const_cast(&class_doc->signals[i])); } } } if (search_flags & SEARCH_CONSTANTS) { - for (int i = 0; i < class_doc.constants.size(); i++) { - if (_all_terms_in_name(class_doc.constants[i].name)) { - match.constants.push_back(const_cast(&class_doc.constants[i])); + for (int i = 0; i < class_doc->constants.size(); i++) { + if (_all_terms_in_name(class_doc->constants[i].name)) { + match.constants.push_back(const_cast(&class_doc->constants[i])); } } } if (search_flags & SEARCH_PROPERTIES) { - for (int i = 0; i < class_doc.properties.size(); i++) { - if (_all_terms_in_name(class_doc.properties[i].name)) { - match.properties.push_back(const_cast(&class_doc.properties[i])); + for (int i = 0; i < class_doc->properties.size(); i++) { + if (_all_terms_in_name(class_doc->properties[i].name)) { + match.properties.push_back(const_cast(&class_doc->properties[i])); } } } if (search_flags & SEARCH_THEME_ITEMS) { - for (int i = 0; i < class_doc.theme_properties.size(); i++) { - if (_all_terms_in_name(class_doc.theme_properties[i].name)) { - match.theme_properties.push_back(const_cast(&class_doc.theme_properties[i])); + for (int i = 0; i < class_doc->theme_properties.size(); i++) { + if (_all_terms_in_name(class_doc->theme_properties[i].name)) { + match.theme_properties.push_back(const_cast(&class_doc->theme_properties[i])); } } } if (search_flags & SEARCH_ANNOTATIONS) { - for (int i = 0; i < class_doc.annotations.size(); i++) { - if (_match_string(term, class_doc.annotations[i].name)) { - match.annotations.push_back(const_cast(&class_doc.annotations[i])); + for (int i = 0; i < class_doc->annotations.size(); i++) { + if (_match_string(term, class_doc->annotations[i].name)) { + match.annotations.push_back(const_cast(&class_doc->annotations[i])); } } } } - matches[class_doc.name] = match; + matches[class_doc->name] = match; + } + + if (iterator_doc) { + ++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()); } - ++iterator_doc; - return !iterator_doc; + return iterator_stack.is_empty(); } bool EditorHelpSearch::Runner::_phase_class_items_init() { diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h index 30a783a628ca..1d7f2b81df8b 100644 --- a/editor/editor_help_search.h +++ b/editor/editor_help_search.h @@ -124,6 +124,7 @@ class EditorHelpSearch::Runner : public RefCounted { Color disabled_color; HashMap::Iterator iterator_doc; + LocalVector::Element *> iterator_stack; HashMap matches; HashMap::Iterator iterator_match; TreeItem *root_item = nullptr;