diff options
Diffstat (limited to 'editor/doc_tools.cpp')
-rw-r--r-- | editor/doc_tools.cpp | 244 |
1 files changed, 177 insertions, 67 deletions
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index beead74c53..6acf654b04 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -37,11 +37,41 @@ #include "core/io/dir_access.h" #include "core/io/marshalls.h" #include "core/object/script_language.h" +#include "core/string/translation.h" #include "core/version.h" #include "scene/resources/theme.h" // Used for a hack preserving Mono properties on non-Mono builds. -#include "modules/modules_enabled.gen.h" +#include "modules/modules_enabled.gen.h" // For mono. + +static String _get_indent(const String &p_text) { + String indent; + bool has_text = false; + int line_start = 0; + + for (int i = 0; i < p_text.length(); i++) { + const char32_t c = p_text[i]; + if (c == '\n') { + line_start = i + 1; + } else if (c > 32) { + has_text = true; + indent = p_text.substr(line_start, i - line_start); + break; // Indentation of the first line that has text. + } + } + if (!has_text) { + return p_text; + } + return indent; +} + +static String _translate_doc_string(const String &p_text) { + const String indent = _get_indent(p_text); + const String message = p_text.dedent().strip_edges(); + const String translated = TranslationServer::get_singleton()->doc_translate(message, ""); + // No need to restore stripped edges because they'll be stripped again later. + return translated.indent(indent); +} void DocTools::merge_from(const DocTools &p_data) { for (KeyValue<String, DocData::ClassDoc> &E : class_list) { @@ -57,25 +87,21 @@ void DocTools::merge_from(const DocTools &p_data) { c.brief_description = cf.brief_description; c.tutorials = cf.tutorials; - for (int i = 0; i < c.methods.size(); i++) { - DocData::MethodDoc &m = c.methods.write[i]; + for (int i = 0; i < c.constructors.size(); i++) { + DocData::MethodDoc &m = c.constructors.write[i]; - for (int j = 0; j < cf.methods.size(); j++) { - if (cf.methods[j].name != m.name) { + for (int j = 0; j < cf.constructors.size(); j++) { + if (cf.constructors[j].name != m.name) { continue; } - const char *operator_prefix = "operator "; // Operators use a space at the end, making this prefix an invalid identifier (and differentiating from methods). - - if (cf.methods[j].name == c.name || cf.methods[j].name.begins_with(operator_prefix)) { - // Since constructors and operators can repeat, we need to check the type of + { + // Since constructors can repeat, we need to check the type of // the arguments so we make sure they are different. - - if (cf.methods[j].arguments.size() != m.arguments.size()) { + if (cf.constructors[j].arguments.size() != m.arguments.size()) { continue; } - - int arg_count = cf.methods[j].arguments.size(); + int arg_count = cf.constructors[j].arguments.size(); Vector<bool> arg_used; arg_used.resize(arg_count); for (int l = 0; l < arg_count; ++l) { @@ -85,7 +111,7 @@ void DocTools::merge_from(const DocTools &p_data) { // have to check one by one so we make sure we have an exact match for (int k = 0; k < arg_count; ++k) { for (int l = 0; l < arg_count; ++l) { - if (cf.methods[j].arguments[k].type == m.arguments[l].type && !arg_used[l]) { + if (cf.constructors[j].arguments[k].type == m.arguments[l].type && !arg_used[l]) { arg_used.write[l] = true; break; } @@ -102,6 +128,21 @@ void DocTools::merge_from(const DocTools &p_data) { } } + const DocData::MethodDoc &mf = cf.constructors[j]; + + m.description = mf.description; + break; + } + } + + for (int i = 0; i < c.methods.size(); i++) { + DocData::MethodDoc &m = c.methods.write[i]; + + for (int j = 0; j < cf.methods.size(); j++) { + if (cf.methods[j].name != m.name) { + continue; + } + const DocData::MethodDoc &mf = cf.methods[j]; m.description = mf.description; @@ -165,6 +206,54 @@ void DocTools::merge_from(const DocTools &p_data) { } } + for (int i = 0; i < c.operators.size(); i++) { + DocData::MethodDoc &m = c.operators.write[i]; + + for (int j = 0; j < cf.operators.size(); j++) { + if (cf.operators[j].name != m.name) { + continue; + } + + { + // Since operators can repeat, we need to check the type of + // the arguments so we make sure they are different. + if (cf.operators[j].arguments.size() != m.arguments.size()) { + continue; + } + int arg_count = cf.operators[j].arguments.size(); + Vector<bool> arg_used; + arg_used.resize(arg_count); + for (int l = 0; l < arg_count; ++l) { + arg_used.write[l] = false; + } + // also there is no guarantee that argument ordering will match, so we + // have to check one by one so we make sure we have an exact match + for (int k = 0; k < arg_count; ++k) { + for (int l = 0; l < arg_count; ++l) { + if (cf.operators[j].arguments[k].type == m.arguments[l].type && !arg_used[l]) { + arg_used.write[l] = true; + break; + } + } + } + bool not_the_same = false; + for (int l = 0; l < arg_count; ++l) { + if (!arg_used[l]) { // at least one of the arguments was different + not_the_same = true; + } + } + if (not_the_same) { + continue; + } + } + + const DocData::MethodDoc &mf = cf.operators[j]; + + m.description = mf.description; + break; + } + } + #ifndef MODULE_MONO_ENABLED // The Mono module defines some properties that we want to keep when // re-generating docs with a non-Mono build, to prevent pointless diffs @@ -193,17 +282,17 @@ void DocTools::remove_from(const DocTools &p_data) { } void DocTools::add_doc(const DocData::ClassDoc &p_class_doc) { - ERR_FAIL_COND(p_class_doc.name == ""); + ERR_FAIL_COND(p_class_doc.name.is_empty()); class_list[p_class_doc.name] = p_class_doc; } void DocTools::remove_doc(const String &p_class_name) { - ERR_FAIL_COND(p_class_name == "" || !class_list.has(p_class_name)); + ERR_FAIL_COND(p_class_name.is_empty() || !class_list.has(p_class_name)); class_list.erase(p_class_name); } bool DocTools::has_doc(const String &p_class_name) { - if (p_class_name == "") { + if (p_class_name.is_empty()) { return false; } return class_list.has(p_class_name); @@ -261,7 +350,7 @@ void DocTools::generate(bool p_basic_types) { List<PropertyInfo> properties; List<PropertyInfo> own_properties; if (name == "ProjectSettings") { - //special case for project settings, so settings can be documented + // Special case for project settings, so settings can be documented. ProjectSettings::get_singleton()->get_property_list(&properties); own_properties = properties; } else { @@ -269,9 +358,12 @@ void DocTools::generate(bool p_basic_types) { ClassDB::get_property_list(name, &own_properties, true); } + properties.sort(); + own_properties.sort(); + List<PropertyInfo>::Element *EO = own_properties.front(); for (const PropertyInfo &E : properties) { - bool inherited = EO == nullptr; + bool inherited = true; if (EO && EO->get() == E) { inherited = false; EO = EO->next(); @@ -282,11 +374,17 @@ void DocTools::generate(bool p_basic_types) { } DocData::PropertyDoc prop; - prop.name = E.name; - prop.overridden = inherited; + if (inherited) { + String parent = ClassDB::get_parent_class(c.name); + while (!ClassDB::has_property(parent, prop.name, true)) { + parent = ClassDB::get_parent_class(parent); + } + prop.overrides = parent; + } + bool default_value_valid = false; Variant default_value; @@ -315,7 +413,7 @@ void DocTools::generate(bool p_basic_types) { //used to track uninitialized values using valgrind //print_line("getting default value for " + String(name) + "." + String(E.name)); if (default_value_valid && default_value.get_type() != Variant::OBJECT) { - prop.default_value = default_value.get_construct_string().replace("\n", ""); + prop.default_value = default_value.get_construct_string().replace("\n", " "); } StringName setter = ClassDB::get_property_setter(name, E.name); @@ -372,7 +470,7 @@ void DocTools::generate(bool p_basic_types) { method_list.sort(); for (const MethodInfo &E : method_list) { - if (E.name == "" || (E.name[0] == '_' && !(E.flags & METHOD_FLAG_VIRTUAL))) { + if (E.name.is_empty() || (E.name[0] == '_' && !(E.flags & METHOD_FLAG_VIRTUAL))) { continue; //hidden, don't count } @@ -394,21 +492,21 @@ void DocTools::generate(bool p_basic_types) { } if (E.flags & METHOD_FLAG_CONST) { - if (method.qualifiers != "") { + if (!method.qualifiers.is_empty()) { method.qualifiers += " "; } method.qualifiers += "const"; } if (E.flags & METHOD_FLAG_VARARG) { - if (method.qualifiers != "") { + if (!method.qualifiers.is_empty()) { method.qualifiers += " "; } method.qualifiers += "vararg"; } if (E.flags & METHOD_FLAG_STATIC) { - if (method.qualifiers != "") { + if (!method.qualifiers.is_empty()) { method.qualifiers += " "; } method.qualifiers += "static"; @@ -427,7 +525,7 @@ void DocTools::generate(bool p_basic_types) { int darg_idx = i - (E.arguments.size() - E.default_arguments.size()); if (darg_idx >= 0) { Variant default_arg = E.default_arguments[darg_idx]; - argument.default_value = default_arg.get_construct_string(); + argument.default_value = default_arg.get_construct_string().replace("\n", " "); } method.arguments.push_back(argument); @@ -490,7 +588,7 @@ void DocTools::generate(bool p_basic_types) { tid.name = E; tid.type = "Color"; tid.data_type = "color"; - tid.default_value = Variant(Theme::get_default()->get_color(E, cname)).get_construct_string(); + tid.default_value = Variant(Theme::get_default()->get_color(E, cname)).get_construct_string().replace("\n", " "); c.theme_properties.push_back(tid); } @@ -544,6 +642,8 @@ void DocTools::generate(bool p_basic_types) { tid.data_type = "style"; c.theme_properties.push_back(tid); } + + c.theme_properties.sort(); } classes.pop_front(); @@ -650,11 +750,6 @@ void DocTools::generate(bool p_basic_types) { DocData::MethodDoc method; method.name = mi.name; - if (method.name == cname) { - method.qualifiers = "constructor"; - } else if (method.name.begins_with("operator")) { - method.qualifiers = "operator"; - } for (int j = 0; j < mi.arguments.size(); j++) { PropertyInfo arginfo = mi.arguments[j]; @@ -665,7 +760,7 @@ void DocTools::generate(bool p_basic_types) { int darg_idx = mi.default_arguments.size() - mi.arguments.size() + j; if (darg_idx >= 0) { Variant default_arg = mi.default_arguments[darg_idx]; - ad.default_value = default_arg.get_construct_string(); + ad.default_value = default_arg.get_construct_string().replace("\n", " "); } method.arguments.push_back(ad); @@ -674,27 +769,33 @@ void DocTools::generate(bool p_basic_types) { DocData::return_doc_from_retinfo(method, mi.return_val); if (mi.flags & METHOD_FLAG_VARARG) { - if (method.qualifiers != "") { + if (!method.qualifiers.is_empty()) { method.qualifiers += " "; } method.qualifiers += "vararg"; } if (mi.flags & METHOD_FLAG_CONST) { - if (method.qualifiers != "") { + if (!method.qualifiers.is_empty()) { method.qualifiers += " "; } method.qualifiers += "const"; } if (mi.flags & METHOD_FLAG_STATIC) { - if (method.qualifiers != "") { + if (!method.qualifiers.is_empty()) { method.qualifiers += " "; } method.qualifiers += "static"; } - c.methods.push_back(method); + if (method.name == cname) { + c.constructors.push_back(method); + } else if (method.name.begins_with("operator")) { + c.operators.push_back(method); + } else { + c.methods.push_back(method); + } } List<PropertyInfo> properties; @@ -703,7 +804,7 @@ void DocTools::generate(bool p_basic_types) { DocData::PropertyDoc property; property.name = pi.name; property.type = Variant::get_type_name(pi.type); - property.default_value = v.get(pi.name).get_construct_string(); + property.default_value = v.get(pi.name).get_construct_string().replace("\n", " "); c.properties.push_back(property); } @@ -715,7 +816,7 @@ void DocTools::generate(bool p_basic_types) { DocData::ConstantDoc constant; constant.name = E; Variant value = Variant::get_constant_value(Variant::Type(i), E); - constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string(); + constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string().replace("\n", " "); constant.is_value_valid = true; c.constants.push_back(constant); } @@ -817,7 +918,7 @@ void DocTools::generate(bool p_basic_types) { md.name = mi.name; if (mi.flags & METHOD_FLAG_VARARG) { - if (md.qualifiers != "") { + if (!md.qualifiers.is_empty()) { md.qualifiers += " "; } md.qualifiers += "vararg"; @@ -832,7 +933,7 @@ void DocTools::generate(bool p_basic_types) { int darg_idx = j - (mi.arguments.size() - mi.default_arguments.size()); if (darg_idx >= 0) { Variant default_arg = mi.default_arguments[darg_idx]; - ad.default_value = default_arg.get_construct_string(); + ad.default_value = default_arg.get_construct_string().replace("\n", " "); } md.arguments.push_back(ad); @@ -916,7 +1017,7 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> & methods.push_back(method); } else { - ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + parser->get_node_name() + "."); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + parser->get_node_name() + ", expected " + element + "."); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == section) { @@ -937,7 +1038,7 @@ Error DocTools::load_classes(const String &p_dir) { da->list_dir_begin(); String path; path = da->get_next(); - while (path != String()) { + while (!path.is_empty()) { if (!da->current_is_dir() && path.ends_with("xml")) { Ref<XMLParser> parser = memnew(XMLParser); Error err2 = parser->open(p_dir.plus_file(path)); @@ -967,7 +1068,7 @@ Error DocTools::erase_classes(const String &p_dir) { da->list_dir_begin(); String path; path = da->get_next(); - while (path != String()) { + while (!path.is_empty()) { if (!da->current_is_dir() && path.ends_with("xml")) { to_erase.push_back(path); } @@ -1044,10 +1145,15 @@ Error DocTools::_load(Ref<XMLParser> parser) { break; // End of <tutorials>. } } + } else if (name2 == "constructors") { + Error err2 = _parse_methods(parser, c.constructors); + ERR_FAIL_COND_V(err2, err2); } else if (name2 == "methods") { Error err2 = _parse_methods(parser, c.methods); ERR_FAIL_COND_V(err2, err2); - + } else if (name2 == "operators") { + Error err2 = _parse_methods(parser, c.operators); + ERR_FAIL_COND_V(err2, err2); } else if (name2 == "signals") { Error err2 = _parse_methods(parser, c.signals); ERR_FAIL_COND_V(err2, err2); @@ -1163,7 +1269,7 @@ Error DocTools::_load(Ref<XMLParser> parser) { } static void _write_string(FileAccess *f, int p_tablevel, const String &p_string) { - if (p_string == "") { + if (p_string.is_empty()) { return; } String tab; @@ -1181,15 +1287,15 @@ static void _write_method_doc(FileAccess *f, const String &p_name, Vector<DocDat const DocData::MethodDoc &m = p_method_docs[i]; String qualifiers; - if (m.qualifiers != "") { + if (!m.qualifiers.is_empty()) { qualifiers += " qualifiers=\"" + m.qualifiers.xml_escape() + "\""; } _write_string(f, 2, "<" + p_name + " name=\"" + m.name.xml_escape() + "\"" + qualifiers + ">"); - if (m.return_type != "") { + if (!m.return_type.is_empty()) { String enum_text; - if (m.return_enum != String()) { + if (!m.return_enum.is_empty()) { enum_text = " enum=\"" + m.return_enum + "\""; } _write_string(f, 3, "<return type=\"" + m.return_type + "\"" + enum_text + " />"); @@ -1204,11 +1310,11 @@ static void _write_method_doc(FileAccess *f, const String &p_name, Vector<DocDat const DocData::ArgumentDoc &a = m.arguments[j]; String enum_text; - if (a.enumeration != String()) { + if (!a.enumeration.is_empty()) { enum_text = " enum=\"" + a.enumeration + "\""; } - if (a.default_value != "") { + if (!a.default_value.is_empty()) { _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " default=\"" + a.default_value.xml_escape(true) + "\" />"); } else { _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " />"); @@ -1216,7 +1322,7 @@ static void _write_method_doc(FileAccess *f, const String &p_name, Vector<DocDat } _write_string(f, 3, "<description>"); - _write_string(f, 4, m.description.strip_edges().xml_escape()); + _write_string(f, 4, _translate_doc_string(m.description).strip_edges().xml_escape()); _write_string(f, 3, "</description>"); _write_string(f, 2, "</" + p_name + ">"); @@ -1246,7 +1352,7 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str _write_string(f, 0, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); String header = "<class name=\"" + c.name + "\""; - if (c.inherits != "") { + if (!c.inherits.is_empty()) { header += " inherits=\"" + c.inherits + "\""; } header += String(" version=\"") + VERSION_BRANCH + "\""; @@ -1254,11 +1360,11 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str _write_string(f, 0, header); _write_string(f, 1, "<brief_description>"); - _write_string(f, 2, c.brief_description.strip_edges().xml_escape()); + _write_string(f, 2, _translate_doc_string(c.brief_description).strip_edges().xml_escape()); _write_string(f, 1, "</brief_description>"); _write_string(f, 1, "<description>"); - _write_string(f, 2, c.description.strip_edges().xml_escape()); + _write_string(f, 2, _translate_doc_string(c.description).strip_edges().xml_escape()); _write_string(f, 1, "</description>"); _write_string(f, 1, "<tutorials>"); @@ -1269,6 +1375,8 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str } _write_string(f, 1, "</tutorials>"); + _write_method_doc(f, "constructor", c.constructors); + _write_method_doc(f, "method", c.methods); if (!c.properties.is_empty()) { @@ -1278,20 +1386,20 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str for (int i = 0; i < c.properties.size(); i++) { String additional_attributes; - if (c.properties[i].enumeration != String()) { + if (!c.properties[i].enumeration.is_empty()) { additional_attributes += " enum=\"" + c.properties[i].enumeration + "\""; } - if (c.properties[i].default_value != String()) { + if (!c.properties[i].default_value.is_empty()) { additional_attributes += " default=\"" + c.properties[i].default_value.xml_escape(true) + "\""; } const DocData::PropertyDoc &p = c.properties[i]; if (c.properties[i].overridden) { - _write_string(f, 2, "<member name=\"" + p.name + "\" type=\"" + p.type + "\" setter=\"" + p.setter + "\" getter=\"" + p.getter + "\" override=\"true\"" + additional_attributes + " />"); + _write_string(f, 2, "<member name=\"" + p.name + "\" type=\"" + p.type + "\" setter=\"" + p.setter + "\" getter=\"" + p.getter + "\" overrides=\"" + p.overrides + "\"" + additional_attributes + " />"); } else { _write_string(f, 2, "<member name=\"" + p.name + "\" type=\"" + p.type + "\" setter=\"" + p.setter + "\" getter=\"" + p.getter + "\"" + additional_attributes + ">"); - _write_string(f, 3, p.description.strip_edges().xml_escape()); + _write_string(f, 3, _translate_doc_string(p.description).strip_edges().xml_escape()); _write_string(f, 2, "</member>"); } } @@ -1305,19 +1413,19 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str for (int i = 0; i < c.constants.size(); i++) { const DocData::ConstantDoc &k = c.constants[i]; if (k.is_value_valid) { - if (k.enumeration != String()) { + if (!k.enumeration.is_empty()) { _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\">"); } else { _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\">"); } } else { - if (k.enumeration != String()) { + if (!k.enumeration.is_empty()) { _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"platform-dependent\" enum=\"" + k.enumeration + "\">"); } else { _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"platform-dependent\">"); } } - _write_string(f, 3, k.description.strip_edges().xml_escape()); + _write_string(f, 3, _translate_doc_string(k.description).strip_edges().xml_escape()); _write_string(f, 2, "</constant>"); } @@ -1331,19 +1439,21 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str for (int i = 0; i < c.theme_properties.size(); i++) { const DocData::ThemeItemDoc &ti = c.theme_properties[i]; - if (ti.default_value != "") { + if (!ti.default_value.is_empty()) { _write_string(f, 2, "<theme_item name=\"" + ti.name + "\" data_type=\"" + ti.data_type + "\" type=\"" + ti.type + "\" default=\"" + ti.default_value.xml_escape(true) + "\">"); } else { _write_string(f, 2, "<theme_item name=\"" + ti.name + "\" data_type=\"" + ti.data_type + "\" type=\"" + ti.type + "\">"); } - _write_string(f, 3, ti.description.strip_edges().xml_escape()); + _write_string(f, 3, _translate_doc_string(ti.description).strip_edges().xml_escape()); _write_string(f, 2, "</theme_item>"); } _write_string(f, 1, "</theme_items>"); } + _write_method_doc(f, "operator", c.operators); + _write_string(f, 0, "</class>"); } |