Polish & fix editor help cache generation
- Isolated the generation of extensions's docs. They're now not cached and refreshed as needed. - Removed superfluous sorting of the class list. - Removed some superfluous/unused elements. - Renamed some items for clarity.
This commit is contained in:
parent
93cdacbb0a
commit
a1d8fc1af9
|
@ -98,9 +98,24 @@ void ClassDB::get_class_list(List<StringName> *p_classes) {
|
||||||
p_classes->push_back(E.key);
|
p_classes->push_back(E.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
p_classes->sort();
|
p_classes->sort_custom<StringName::AlphCompare>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
void ClassDB::get_extensions_class_list(List<StringName> *p_classes) {
|
||||||
|
OBJTYPE_RLOCK;
|
||||||
|
|
||||||
|
for (const KeyValue<StringName, ClassInfo> &E : classes) {
|
||||||
|
if (E.value.api != API_EXTENSION && E.value.api != API_EDITOR_EXTENSION) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
p_classes->push_back(E.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
p_classes->sort_custom<StringName::AlphCompare>();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void ClassDB::get_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes) {
|
void ClassDB::get_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes) {
|
||||||
OBJTYPE_RLOCK;
|
OBJTYPE_RLOCK;
|
||||||
|
|
||||||
|
|
|
@ -251,6 +251,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_class_list(List<StringName> *p_classes);
|
static void get_class_list(List<StringName> *p_classes);
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
static void get_extensions_class_list(List<StringName> *p_classes);
|
||||||
|
#endif
|
||||||
static void get_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes);
|
static void get_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes);
|
||||||
static void get_direct_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes);
|
static void get_direct_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes);
|
||||||
static StringName get_parent_class_nocheck(const StringName &p_class);
|
static StringName get_parent_class_nocheck(const StringName &p_class);
|
||||||
|
|
|
@ -355,20 +355,27 @@ static Variant get_documentation_default_value(const StringName &p_class_name, c
|
||||||
return default_value;
|
return default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocTools::generate(bool p_basic_types) {
|
void DocTools::generate(BitField<GenerateFlags> p_flags) {
|
||||||
|
// This may involve instantiating classes that are only usable from the main thread
|
||||||
|
// (which is in fact the case of the core API).
|
||||||
|
ERR_FAIL_COND(!Thread::is_main_thread());
|
||||||
|
|
||||||
// Add ClassDB-exposed classes.
|
// Add ClassDB-exposed classes.
|
||||||
{
|
{
|
||||||
List<StringName> classes;
|
List<StringName> classes;
|
||||||
ClassDB::get_class_list(&classes);
|
if (p_flags.has_flag(GENERATE_FLAG_EXTENSION_CLASSES_ONLY)) {
|
||||||
classes.sort_custom<StringName::AlphCompare>();
|
ClassDB::get_extensions_class_list(&classes);
|
||||||
// Move ProjectSettings, so that other classes can register properties there.
|
} else {
|
||||||
classes.move_to_back(classes.find("ProjectSettings"));
|
ClassDB::get_class_list(&classes);
|
||||||
|
// Move ProjectSettings, so that other classes can register properties there.
|
||||||
|
classes.move_to_back(classes.find("ProjectSettings"));
|
||||||
|
}
|
||||||
|
|
||||||
bool skip_setter_getter_methods = true;
|
bool skip_setter_getter_methods = true;
|
||||||
|
|
||||||
// Populate documentation data for each exposed class.
|
// Populate documentation data for each exposed class.
|
||||||
while (classes.size()) {
|
while (classes.size()) {
|
||||||
String name = classes.front()->get();
|
const String &name = classes.front()->get();
|
||||||
if (!ClassDB::is_class_exposed(name)) {
|
if (!ClassDB::is_class_exposed(name)) {
|
||||||
print_verbose(vformat("Class '%s' is not exposed, skipping.", name));
|
print_verbose(vformat("Class '%s' is not exposed, skipping.", name));
|
||||||
classes.pop_front();
|
classes.pop_front();
|
||||||
|
@ -675,6 +682,10 @@ void DocTools::generate(bool p_basic_types) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_flags.has_flag(GENERATE_FLAG_SKIP_BASIC_TYPES)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Add a dummy Variant entry.
|
// Add a dummy Variant entry.
|
||||||
{
|
{
|
||||||
// This allows us to document the concept of Variant even though
|
// This allows us to document the concept of Variant even though
|
||||||
|
@ -683,11 +694,6 @@ void DocTools::generate(bool p_basic_types) {
|
||||||
class_list["Variant"].name = "Variant";
|
class_list["Variant"].name = "Variant";
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't want to populate basic types, break here.
|
|
||||||
if (!p_basic_types) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add Variant data types.
|
// Add Variant data types.
|
||||||
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
|
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
|
||||||
if (i == Variant::NIL) {
|
if (i == Variant::NIL) {
|
||||||
|
|
|
@ -45,7 +45,11 @@ public:
|
||||||
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);
|
||||||
void generate(bool p_basic_types = false);
|
enum GenerateFlags {
|
||||||
|
GENERATE_FLAG_SKIP_BASIC_TYPES = (1 << 0),
|
||||||
|
GENERATE_FLAG_EXTENSION_CLASSES_ONLY = (1 << 1),
|
||||||
|
};
|
||||||
|
void generate(BitField<GenerateFlags> p_flags = {});
|
||||||
Error load_classes(const String &p_dir);
|
Error load_classes(const String &p_dir);
|
||||||
Error save_classes(const String &p_default_path, const HashMap<String, String> &p_class_path, bool p_include_xml_schema = true);
|
Error save_classes(const String &p_default_path, const HashMap<String, String> &p_class_path, bool p_include_xml_schema = true);
|
||||||
|
|
||||||
|
|
|
@ -2361,13 +2361,11 @@ void EditorHelp::_add_text(const String &p_bbcode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
String EditorHelp::doc_version_hash;
|
String EditorHelp::doc_version_hash;
|
||||||
bool EditorHelp::doc_gen_first_attempt = true;
|
Thread EditorHelp::worker_thread;
|
||||||
bool EditorHelp::doc_gen_use_threads = true;
|
|
||||||
Thread EditorHelp::gen_thread;
|
|
||||||
|
|
||||||
void EditorHelp::_wait_for_thread() {
|
void EditorHelp::_wait_for_thread() {
|
||||||
if (gen_thread.is_started()) {
|
if (worker_thread.is_started()) {
|
||||||
gen_thread.wait_to_finish();
|
worker_thread.wait_to_finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2381,18 +2379,18 @@ String EditorHelp::get_cache_full_path() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorHelp::_load_doc_thread(void *p_udata) {
|
void EditorHelp::_load_doc_thread(void *p_udata) {
|
||||||
DEV_ASSERT(doc_gen_first_attempt);
|
|
||||||
|
|
||||||
Ref<Resource> cache_res = ResourceLoader::load(get_cache_full_path());
|
Ref<Resource> cache_res = ResourceLoader::load(get_cache_full_path());
|
||||||
if (cache_res.is_valid() && cache_res->get_meta("version_hash", "") == doc_version_hash) {
|
if (cache_res.is_valid() && cache_res->get_meta("version_hash", "") == doc_version_hash) {
|
||||||
Array classes = cache_res->get_meta("classes", Array());
|
Array classes = cache_res->get_meta("classes", Array());
|
||||||
for (int i = 0; i < classes.size(); i++) {
|
for (int i = 0; i < classes.size(); i++) {
|
||||||
doc->add_doc(DocData::ClassDoc::from_dict(classes[i]));
|
doc->add_doc(DocData::ClassDoc::from_dict(classes[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extensions' docs are not cached. Generate them now (on the main thread).
|
||||||
|
callable_mp_static(&EditorHelp::_gen_extensions_docs).call_deferred();
|
||||||
} else {
|
} else {
|
||||||
// We have to go back to the main thread to start from scratch.
|
// We have to go back to the main thread to start from scratch, bypassing any possibly existing cache.
|
||||||
doc_gen_first_attempt = false;
|
callable_mp_static(&EditorHelp::generate_doc).bind(false).call_deferred();
|
||||||
callable_mp_static(&EditorHelp::generate_doc).bind(true).call_deferred();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2406,6 +2404,12 @@ void EditorHelp::_gen_doc_thread(void *p_udata) {
|
||||||
cache_res->set_meta("version_hash", doc_version_hash);
|
cache_res->set_meta("version_hash", doc_version_hash);
|
||||||
Array classes;
|
Array classes;
|
||||||
for (const KeyValue<String, DocData::ClassDoc> &E : doc->class_list) {
|
for (const KeyValue<String, DocData::ClassDoc> &E : doc->class_list) {
|
||||||
|
if (ClassDB::class_exists(E.value.name)) {
|
||||||
|
ClassDB::APIType api = ClassDB::get_api_type(E.value.name);
|
||||||
|
if (api == ClassDB::API_EXTENSION || api == ClassDB::API_EDITOR_EXTENSION) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
classes.push_back(DocData::ClassDoc::to_dict(E.value));
|
classes.push_back(DocData::ClassDoc::to_dict(E.value));
|
||||||
}
|
}
|
||||||
cache_res->set_meta("classes", classes);
|
cache_res->set_meta("classes", classes);
|
||||||
|
@ -2415,14 +2419,15 @@ void EditorHelp::_gen_doc_thread(void *p_udata) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorHelp::_gen_extensions_docs() {
|
||||||
|
doc->generate((DocTools::GENERATE_FLAG_SKIP_BASIC_TYPES | DocTools::GENERATE_FLAG_EXTENSION_CLASSES_ONLY));
|
||||||
|
}
|
||||||
|
|
||||||
void EditorHelp::generate_doc(bool p_use_cache) {
|
void EditorHelp::generate_doc(bool p_use_cache) {
|
||||||
OS::get_singleton()->benchmark_begin_measure("EditorHelp::generate_doc");
|
OS::get_singleton()->benchmark_begin_measure("EditorHelp::generate_doc");
|
||||||
if (doc_gen_use_threads) {
|
|
||||||
// In case not the first attempt.
|
|
||||||
_wait_for_thread();
|
|
||||||
}
|
|
||||||
|
|
||||||
DEV_ASSERT(doc_gen_first_attempt == (doc == nullptr));
|
// In case not the first attempt.
|
||||||
|
_wait_for_thread();
|
||||||
|
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
doc = memnew(DocTools);
|
doc = memnew(DocTools);
|
||||||
|
@ -2432,24 +2437,14 @@ void EditorHelp::generate_doc(bool p_use_cache) {
|
||||||
_compute_doc_version_hash();
|
_compute_doc_version_hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_use_cache && doc_gen_first_attempt && FileAccess::exists(get_cache_full_path())) {
|
if (p_use_cache && FileAccess::exists(get_cache_full_path())) {
|
||||||
if (doc_gen_use_threads) {
|
worker_thread.start(_load_doc_thread, nullptr);
|
||||||
gen_thread.start(_load_doc_thread, nullptr);
|
|
||||||
} else {
|
|
||||||
_load_doc_thread(nullptr);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
print_verbose("Regenerating editor help cache");
|
print_verbose("Regenerating editor help cache");
|
||||||
|
doc->generate();
|
||||||
// Not doable on threads unfortunately, since it instantiates all sorts of classes to get default values.
|
worker_thread.start(_gen_doc_thread, nullptr);
|
||||||
doc->generate(true);
|
|
||||||
|
|
||||||
if (doc_gen_use_threads) {
|
|
||||||
gen_thread.start(_gen_doc_thread, nullptr);
|
|
||||||
} else {
|
|
||||||
_gen_doc_thread(nullptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OS::get_singleton()->benchmark_end_measure("EditorHelp::generate_doc");
|
OS::get_singleton()->benchmark_end_measure("EditorHelp::generate_doc");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -188,13 +188,12 @@ class EditorHelp : public VBoxContainer {
|
||||||
void _toggle_scripts_pressed();
|
void _toggle_scripts_pressed();
|
||||||
|
|
||||||
static String doc_version_hash;
|
static String doc_version_hash;
|
||||||
static bool doc_gen_first_attempt;
|
static Thread worker_thread;
|
||||||
static bool doc_gen_use_threads;
|
|
||||||
static Thread gen_thread;
|
|
||||||
|
|
||||||
static void _wait_for_thread();
|
static void _wait_for_thread();
|
||||||
static void _load_doc_thread(void *p_udata);
|
static void _load_doc_thread(void *p_udata);
|
||||||
static void _gen_doc_thread(void *p_udata);
|
static void _gen_doc_thread(void *p_udata);
|
||||||
|
static void _gen_extensions_docs();
|
||||||
static void _compute_doc_version_hash();
|
static void _compute_doc_version_hash();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -2767,7 +2767,7 @@ bool Main::start() {
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
String doc_tool_path;
|
String doc_tool_path;
|
||||||
bool doc_base = true;
|
BitField<DocTools::GenerateFlags> gen_flags;
|
||||||
String _export_preset;
|
String _export_preset;
|
||||||
bool export_debug = false;
|
bool export_debug = false;
|
||||||
bool export_pack_only = false;
|
bool export_pack_only = false;
|
||||||
|
@ -2792,7 +2792,7 @@ bool Main::start() {
|
||||||
check_only = true;
|
check_only = true;
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
} else if (args[i] == "--no-docbase") {
|
} else if (args[i] == "--no-docbase") {
|
||||||
doc_base = false;
|
gen_flags.set_flag(DocTools::GENERATE_FLAG_SKIP_BASIC_TYPES);
|
||||||
#ifndef DISABLE_DEPRECATED
|
#ifndef DISABLE_DEPRECATED
|
||||||
} else if (args[i] == "--convert-3to4") {
|
} else if (args[i] == "--convert-3to4") {
|
||||||
converting_project = true;
|
converting_project = true;
|
||||||
|
@ -2903,7 +2903,7 @@ bool Main::start() {
|
||||||
|
|
||||||
Error err;
|
Error err;
|
||||||
DocTools doc;
|
DocTools doc;
|
||||||
doc.generate(doc_base);
|
doc.generate(gen_flags);
|
||||||
|
|
||||||
DocTools docsrc;
|
DocTools docsrc;
|
||||||
HashMap<String, String> doc_data_classes;
|
HashMap<String, String> doc_data_classes;
|
||||||
|
|
Loading…
Reference in New Issue