C#: Bindings generator now translates BBCode docs to XML comments
(cherry picked from commit 1ad16b3d4a
)
This commit is contained in:
parent
3e0fc6906e
commit
e3e33daeb9
|
@ -38,6 +38,7 @@
|
||||||
#include "core/os/dir_access.h"
|
#include "core/os/dir_access.h"
|
||||||
#include "core/os/file_access.h"
|
#include "core/os/file_access.h"
|
||||||
#include "core/os/os.h"
|
#include "core/os/os.h"
|
||||||
|
#include "core/string_builder.h"
|
||||||
#include "core/ucaps.h"
|
#include "core/ucaps.h"
|
||||||
|
|
||||||
#include "../glue/cs_compressed.gen.h"
|
#include "../glue/cs_compressed.gen.h"
|
||||||
|
@ -105,6 +106,16 @@ bool BindingsGenerator::verbose_output = false;
|
||||||
|
|
||||||
BindingsGenerator *BindingsGenerator::singleton = NULL;
|
BindingsGenerator *BindingsGenerator::singleton = NULL;
|
||||||
|
|
||||||
|
static String fix_doc_description(const String &p_bbcode) {
|
||||||
|
|
||||||
|
// This seems to be the correct way to do this. It's the same EditorHelp does.
|
||||||
|
|
||||||
|
return p_bbcode.dedent()
|
||||||
|
.replace("\t", "")
|
||||||
|
.replace("\r", "")
|
||||||
|
.strip_edges();
|
||||||
|
}
|
||||||
|
|
||||||
static String snake_to_pascal_case(const String &p_identifier, bool p_input_is_upper = false) {
|
static String snake_to_pascal_case(const String &p_identifier, bool p_input_is_upper = false) {
|
||||||
|
|
||||||
String ret;
|
String ret;
|
||||||
|
@ -173,6 +184,366 @@ static String snake_to_camel_case(const String &p_identifier, bool p_input_is_up
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype) {
|
||||||
|
|
||||||
|
// Based on the version in EditorHelp
|
||||||
|
|
||||||
|
if (p_bbcode.empty())
|
||||||
|
return String();
|
||||||
|
|
||||||
|
DocData *doc = EditorHelp::get_doc_data();
|
||||||
|
|
||||||
|
String bbcode = p_bbcode;
|
||||||
|
|
||||||
|
StringBuilder xml_output;
|
||||||
|
|
||||||
|
xml_output.append("<para>");
|
||||||
|
|
||||||
|
List<String> tag_stack;
|
||||||
|
bool code_tag = false;
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
while (pos < bbcode.length()) {
|
||||||
|
int brk_pos = bbcode.find("[", pos);
|
||||||
|
|
||||||
|
if (brk_pos < 0)
|
||||||
|
brk_pos = bbcode.length();
|
||||||
|
|
||||||
|
if (brk_pos > pos) {
|
||||||
|
String text = bbcode.substr(pos, brk_pos - pos);
|
||||||
|
if (code_tag || tag_stack.size() > 0) {
|
||||||
|
xml_output.append(text.xml_escape());
|
||||||
|
} else {
|
||||||
|
Vector<String> lines = text.split("\n");
|
||||||
|
for (int i = 0; i < lines.size(); i++) {
|
||||||
|
if (i != 0)
|
||||||
|
xml_output.append("<para>");
|
||||||
|
|
||||||
|
xml_output.append(lines[i].xml_escape());
|
||||||
|
|
||||||
|
if (i != lines.size() - 1)
|
||||||
|
xml_output.append("</para>\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (brk_pos == bbcode.length())
|
||||||
|
break; // nothing else to add
|
||||||
|
|
||||||
|
int brk_end = bbcode.find("]", brk_pos + 1);
|
||||||
|
|
||||||
|
if (brk_end == -1) {
|
||||||
|
String text = bbcode.substr(brk_pos, bbcode.length() - brk_pos);
|
||||||
|
if (code_tag || tag_stack.size() > 0) {
|
||||||
|
xml_output.append(text.xml_escape());
|
||||||
|
} else {
|
||||||
|
Vector<String> lines = text.split("\n");
|
||||||
|
for (int i = 0; i < lines.size(); i++) {
|
||||||
|
if (i != 0)
|
||||||
|
xml_output.append("<para>");
|
||||||
|
|
||||||
|
xml_output.append(lines[i].xml_escape());
|
||||||
|
|
||||||
|
if (i != lines.size() - 1)
|
||||||
|
xml_output.append("</para>\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
String tag = bbcode.substr(brk_pos + 1, brk_end - brk_pos - 1);
|
||||||
|
|
||||||
|
if (tag.begins_with("/")) {
|
||||||
|
bool tag_ok = tag_stack.size() && tag_stack.front()->get() == tag.substr(1, tag.length());
|
||||||
|
|
||||||
|
if (!tag_ok) {
|
||||||
|
xml_output.append("[");
|
||||||
|
pos = brk_pos + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag_stack.pop_front();
|
||||||
|
pos = brk_end + 1;
|
||||||
|
code_tag = false;
|
||||||
|
|
||||||
|
if (tag == "/url") {
|
||||||
|
xml_output.append("</a>");
|
||||||
|
} else if (tag == "/code") {
|
||||||
|
xml_output.append("</c>");
|
||||||
|
} else if (tag == "/codeblock") {
|
||||||
|
xml_output.append("</code>");
|
||||||
|
}
|
||||||
|
} else if (code_tag) {
|
||||||
|
xml_output.append("[");
|
||||||
|
pos = brk_pos + 1;
|
||||||
|
} else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ")) {
|
||||||
|
String link_target = tag.substr(tag.find(" ") + 1, tag.length());
|
||||||
|
String link_tag = tag.substr(0, tag.find(" "));
|
||||||
|
|
||||||
|
Vector<String> link_target_parts = link_target.split(".");
|
||||||
|
|
||||||
|
if (link_target_parts.size() <= 0 || link_target_parts.size() > 2) {
|
||||||
|
ERR_PRINTS("Invalid reference format: " + tag);
|
||||||
|
|
||||||
|
xml_output.append("<c>");
|
||||||
|
xml_output.append(tag);
|
||||||
|
xml_output.append("</c>");
|
||||||
|
|
||||||
|
pos = brk_end + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TypeInterface *target_itype;
|
||||||
|
StringName target_cname;
|
||||||
|
|
||||||
|
if (link_target_parts.size() == 2) {
|
||||||
|
target_itype = _get_type_or_null(TypeReference(link_target_parts[0]));
|
||||||
|
if (!target_itype) {
|
||||||
|
target_itype = _get_type_or_null(TypeReference("_" + link_target_parts[0]));
|
||||||
|
}
|
||||||
|
target_cname = link_target_parts[1];
|
||||||
|
} else {
|
||||||
|
target_itype = p_itype;
|
||||||
|
target_cname = link_target_parts[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (link_tag == "method") {
|
||||||
|
if (!target_itype || !target_itype->is_object_type) {
|
||||||
|
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||||
|
if (target_itype) {
|
||||||
|
OS::get_singleton()->print("Cannot resolve method reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data());
|
||||||
|
} else {
|
||||||
|
OS::get_singleton()->print("Cannot resolve type from method reference in documentation: %s\n", link_target.utf8().get_data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Map what we can
|
||||||
|
xml_output.append("<c>");
|
||||||
|
xml_output.append(link_target);
|
||||||
|
xml_output.append("</c>");
|
||||||
|
} else {
|
||||||
|
const MethodInterface *target_imethod = target_itype->find_method_by_name(target_cname);
|
||||||
|
|
||||||
|
if (target_imethod) {
|
||||||
|
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
|
||||||
|
xml_output.append(target_itype->proxy_name);
|
||||||
|
xml_output.append(".");
|
||||||
|
xml_output.append(target_imethod->proxy_name);
|
||||||
|
xml_output.append("\"/>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (link_tag == "member") {
|
||||||
|
if (!target_itype || !target_itype->is_object_type) {
|
||||||
|
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||||
|
if (target_itype) {
|
||||||
|
OS::get_singleton()->print("Cannot resolve member reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data());
|
||||||
|
} else {
|
||||||
|
OS::get_singleton()->print("Cannot resolve type from member reference in documentation: %s\n", link_target.utf8().get_data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Map what we can
|
||||||
|
xml_output.append("<c>");
|
||||||
|
xml_output.append(link_target);
|
||||||
|
xml_output.append("</c>");
|
||||||
|
} else {
|
||||||
|
const PropertyInterface *target_iprop = target_itype->find_property_by_name(target_cname);
|
||||||
|
|
||||||
|
if (target_iprop) {
|
||||||
|
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
|
||||||
|
xml_output.append(target_itype->proxy_name);
|
||||||
|
xml_output.append(".");
|
||||||
|
xml_output.append(target_iprop->proxy_name);
|
||||||
|
xml_output.append("\"/>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (link_tag == "signal") {
|
||||||
|
// We do not declare signals in any way in C#, so there is nothing to reference
|
||||||
|
xml_output.append("<c>");
|
||||||
|
xml_output.append(link_target);
|
||||||
|
xml_output.append("</c>");
|
||||||
|
} else if (link_tag == "enum") {
|
||||||
|
StringName search_cname = !target_itype ? target_cname :
|
||||||
|
StringName(target_itype->name + "." + (String)target_cname);
|
||||||
|
|
||||||
|
const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(search_cname);
|
||||||
|
|
||||||
|
if (!enum_match && search_cname != target_cname) {
|
||||||
|
enum_match = enum_types.find(target_cname);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enum_match) {
|
||||||
|
const TypeInterface &target_enum_itype = enum_match->value();
|
||||||
|
|
||||||
|
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
|
||||||
|
xml_output.append(target_enum_itype.proxy_name); // Includes nesting class if any
|
||||||
|
xml_output.append("\"/>");
|
||||||
|
} else {
|
||||||
|
ERR_PRINTS("Cannot resolve enum reference in documentation: " + link_target);
|
||||||
|
|
||||||
|
xml_output.append("<c>");
|
||||||
|
xml_output.append(link_target);
|
||||||
|
xml_output.append("</c>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = brk_end + 1;
|
||||||
|
} else if (doc->class_list.has(tag)) {
|
||||||
|
if (tag == "Array" || tag == "Dictionary") {
|
||||||
|
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE_COLLECTIONS ".");
|
||||||
|
xml_output.append(tag);
|
||||||
|
xml_output.append("\"/>");
|
||||||
|
} else if (tag == "bool" || tag == "int") {
|
||||||
|
xml_output.append("<see cref=\"");
|
||||||
|
xml_output.append(tag);
|
||||||
|
xml_output.append("\"/>");
|
||||||
|
} else if (tag == "float") {
|
||||||
|
xml_output.append("<see cref=\""
|
||||||
|
#ifdef REAL_T_IS_DOUBLE
|
||||||
|
"double"
|
||||||
|
#else
|
||||||
|
"float"
|
||||||
|
#endif
|
||||||
|
"\"/>");
|
||||||
|
} else if (tag == "Variant") {
|
||||||
|
// We use System.Object for Variant, so there is no Variant type in C#
|
||||||
|
xml_output.append("<c>Variant</c>");
|
||||||
|
} else if (tag == "String") {
|
||||||
|
xml_output.append("<see cref=\"string\"/>");
|
||||||
|
} else if (tag == "Nil") {
|
||||||
|
xml_output.append("<see langword=\"null\"/>");
|
||||||
|
} else if (tag.begins_with("@")) {
|
||||||
|
// @Global Scope, @GDScript, etc
|
||||||
|
xml_output.append("<c>");
|
||||||
|
xml_output.append(tag);
|
||||||
|
xml_output.append("</c>");
|
||||||
|
} else if (tag == "PoolByteArray") {
|
||||||
|
xml_output.append("<see cref=\"byte\"/>");
|
||||||
|
} else if (tag == "PoolIntArray") {
|
||||||
|
xml_output.append("<see cref=\"int\"/>");
|
||||||
|
} else if (tag == "PoolRealArray") {
|
||||||
|
#ifdef REAL_T_IS_DOUBLE
|
||||||
|
xml_output.append("<see cref=\"double\"/>");
|
||||||
|
#else
|
||||||
|
xml_output.append("<see cref=\"float\"/>");
|
||||||
|
#endif
|
||||||
|
} else if (tag == "PoolStringArray") {
|
||||||
|
xml_output.append("<see cref=\"string\"/>");
|
||||||
|
} else if (tag == "PoolVector2Array") {
|
||||||
|
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector2\"/>");
|
||||||
|
} else if (tag == "PoolVector3Array") {
|
||||||
|
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector3\"/>");
|
||||||
|
} else if (tag == "PoolColorArray") {
|
||||||
|
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Color\"/>");
|
||||||
|
} else {
|
||||||
|
const TypeInterface *target_itype = _get_type_or_null(TypeReference(tag));
|
||||||
|
|
||||||
|
if (!target_itype) {
|
||||||
|
target_itype = _get_type_or_null(TypeReference("_" + tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_itype) {
|
||||||
|
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
|
||||||
|
xml_output.append(target_itype->proxy_name);
|
||||||
|
xml_output.append("\"/>");
|
||||||
|
} else {
|
||||||
|
ERR_PRINTS("Cannot resolve type reference in documentation: " + tag);
|
||||||
|
|
||||||
|
xml_output.append("<c>");
|
||||||
|
xml_output.append(tag);
|
||||||
|
xml_output.append("</c>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = brk_end + 1;
|
||||||
|
} else if (tag == "b") {
|
||||||
|
// bold is not supported in xml comments
|
||||||
|
pos = brk_end + 1;
|
||||||
|
tag_stack.push_front(tag);
|
||||||
|
} else if (tag == "i") {
|
||||||
|
// italics is not supported in xml comments
|
||||||
|
pos = brk_end + 1;
|
||||||
|
tag_stack.push_front(tag);
|
||||||
|
} else if (tag == "code") {
|
||||||
|
xml_output.append("<c>");
|
||||||
|
|
||||||
|
code_tag = true;
|
||||||
|
pos = brk_end + 1;
|
||||||
|
tag_stack.push_front(tag);
|
||||||
|
} else if (tag == "codeblock") {
|
||||||
|
xml_output.append("<code>");
|
||||||
|
|
||||||
|
code_tag = true;
|
||||||
|
pos = brk_end + 1;
|
||||||
|
tag_stack.push_front(tag);
|
||||||
|
} else if (tag == "center") {
|
||||||
|
// center is alignment not supported in xml comments
|
||||||
|
pos = brk_end + 1;
|
||||||
|
tag_stack.push_front(tag);
|
||||||
|
} else if (tag == "br") {
|
||||||
|
xml_output.append("\n"); // FIXME: Should use <para> instead. Luckily this tag isn't used for now.
|
||||||
|
pos = brk_end + 1;
|
||||||
|
} else if (tag == "u") {
|
||||||
|
// underline is not supported in xml comments
|
||||||
|
pos = brk_end + 1;
|
||||||
|
tag_stack.push_front(tag);
|
||||||
|
} else if (tag == "s") {
|
||||||
|
// strikethrough is not supported in xml comments
|
||||||
|
pos = brk_end + 1;
|
||||||
|
tag_stack.push_front(tag);
|
||||||
|
} else if (tag == "url") {
|
||||||
|
int end = bbcode.find("[", brk_end);
|
||||||
|
if (end == -1)
|
||||||
|
end = bbcode.length();
|
||||||
|
String url = bbcode.substr(brk_end + 1, end - brk_end - 1);
|
||||||
|
xml_output.append("<a href=\"");
|
||||||
|
xml_output.append(url);
|
||||||
|
xml_output.append("\">");
|
||||||
|
xml_output.append(url);
|
||||||
|
|
||||||
|
pos = brk_end + 1;
|
||||||
|
tag_stack.push_front(tag);
|
||||||
|
} else if (tag.begins_with("url=")) {
|
||||||
|
String url = tag.substr(4, tag.length());
|
||||||
|
xml_output.append("<a href=\"");
|
||||||
|
xml_output.append(url);
|
||||||
|
xml_output.append("\">");
|
||||||
|
|
||||||
|
pos = brk_end + 1;
|
||||||
|
tag_stack.push_front("url");
|
||||||
|
} else if (tag == "img") {
|
||||||
|
int end = bbcode.find("[", brk_end);
|
||||||
|
if (end == -1)
|
||||||
|
end = bbcode.length();
|
||||||
|
String image = bbcode.substr(brk_end + 1, end - brk_end - 1);
|
||||||
|
|
||||||
|
// Not supported. Just append the bbcode.
|
||||||
|
xml_output.append("[img]");
|
||||||
|
xml_output.append(image);
|
||||||
|
xml_output.append("[/img]");
|
||||||
|
|
||||||
|
pos = end;
|
||||||
|
tag_stack.push_front(tag);
|
||||||
|
} else if (tag.begins_with("color=")) {
|
||||||
|
// Not supported.
|
||||||
|
pos = brk_end + 1;
|
||||||
|
tag_stack.push_front("color");
|
||||||
|
} else if (tag.begins_with("font=")) {
|
||||||
|
// Not supported.
|
||||||
|
pos = brk_end + 1;
|
||||||
|
tag_stack.push_front("font");
|
||||||
|
} else {
|
||||||
|
xml_output.append("["); // ignore
|
||||||
|
pos = brk_pos + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xml_output.append("</para>");
|
||||||
|
|
||||||
|
return xml_output.as_string();
|
||||||
|
}
|
||||||
|
|
||||||
int BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) {
|
int BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) {
|
||||||
|
|
||||||
CRASH_COND(p_ienum.constants.empty());
|
CRASH_COND(p_ienum.constants.empty());
|
||||||
|
@ -299,6 +670,9 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
|
||||||
|
|
||||||
// Constants (in partial GD class)
|
// Constants (in partial GD class)
|
||||||
|
|
||||||
|
p_output.push_back("\n#pragma warning disable CS1591 // Disable warning: "
|
||||||
|
"'Missing XML comment for publicly visible type or member'\n");
|
||||||
|
|
||||||
p_output.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
|
p_output.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
|
||||||
p_output.push_back(INDENT1 "public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" INDENT1 "{");
|
p_output.push_back(INDENT1 "public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" INDENT1 "{");
|
||||||
|
|
||||||
|
@ -306,21 +680,21 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
|
||||||
const ConstantInterface &iconstant = E->get();
|
const ConstantInterface &iconstant = E->get();
|
||||||
|
|
||||||
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
|
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
|
||||||
|
String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), NULL);
|
||||||
|
Vector<String> summary_lines = xml_summary.split("\n");
|
||||||
|
|
||||||
|
if (summary_lines.size()) {
|
||||||
p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
||||||
|
|
||||||
Vector<String> description_lines = iconstant.const_doc->description.split("\n");
|
for (int i = 0; i < summary_lines.size(); i++) {
|
||||||
|
|
||||||
for (int i = 0; i < description_lines.size(); i++) {
|
|
||||||
String description_line = description_lines[i].strip_edges();
|
|
||||||
if (description_line.size()) {
|
|
||||||
p_output.push_back(INDENT2 "/// ");
|
p_output.push_back(INDENT2 "/// ");
|
||||||
p_output.push_back(description_line.xml_escape());
|
p_output.push_back(summary_lines[i]);
|
||||||
p_output.push_back("\n");
|
p_output.push_back("\n");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
p_output.push_back(INDENT2 "/// </summary>");
|
p_output.push_back(INDENT2 "/// </summary>");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
p_output.push_back(MEMBER_BEGIN "public const int ");
|
p_output.push_back(MEMBER_BEGIN "public const int ");
|
||||||
p_output.push_back(iconstant.proxy_name);
|
p_output.push_back(iconstant.proxy_name);
|
||||||
|
@ -369,21 +743,21 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
|
||||||
const ConstantInterface &iconstant = F->get();
|
const ConstantInterface &iconstant = F->get();
|
||||||
|
|
||||||
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
|
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
|
||||||
|
String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), NULL);
|
||||||
|
Vector<String> summary_lines = xml_summary.split("\n");
|
||||||
|
|
||||||
|
if (summary_lines.size()) {
|
||||||
p_output.push_back(INDENT2 "/// <summary>\n");
|
p_output.push_back(INDENT2 "/// <summary>\n");
|
||||||
|
|
||||||
Vector<String> description_lines = iconstant.const_doc->description.split("\n");
|
for (int i = 0; i < summary_lines.size(); i++) {
|
||||||
|
|
||||||
for (int i = 0; i < description_lines.size(); i++) {
|
|
||||||
String description_line = description_lines[i].strip_edges();
|
|
||||||
if (description_line.size()) {
|
|
||||||
p_output.push_back(INDENT2 "/// ");
|
p_output.push_back(INDENT2 "/// ");
|
||||||
p_output.push_back(description_line.xml_escape());
|
p_output.push_back(summary_lines[i]);
|
||||||
p_output.push_back("\n");
|
p_output.push_back("\n");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
p_output.push_back(INDENT2 "/// </summary>\n");
|
p_output.push_back(INDENT2 "/// </summary>\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
p_output.push_back(INDENT2);
|
p_output.push_back(INDENT2);
|
||||||
p_output.push_back(iconstant.proxy_name);
|
p_output.push_back(iconstant.proxy_name);
|
||||||
|
@ -399,6 +773,8 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
|
||||||
}
|
}
|
||||||
|
|
||||||
p_output.push_back(CLOSE_BLOCK); // end of namespace
|
p_output.push_back(CLOSE_BLOCK); // end of namespace
|
||||||
|
|
||||||
|
p_output.push_back("\n#pragma warning restore CS1591\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) {
|
Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) {
|
||||||
|
@ -712,29 +1088,32 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
||||||
output.push_back("using System;\n"); // IntPtr
|
output.push_back("using System;\n"); // IntPtr
|
||||||
output.push_back("using System.Diagnostics;\n"); // DebuggerBrowsable
|
output.push_back("using System.Diagnostics;\n"); // DebuggerBrowsable
|
||||||
|
|
||||||
output.push_back("\n#pragma warning disable CS1591 // Disable warning: "
|
output.push_back("\n"
|
||||||
"'Missing XML comment for publicly visible type or member'\n");
|
"#pragma warning disable CS1591 // Disable warning: "
|
||||||
|
"'Missing XML comment for publicly visible type or member'\n"
|
||||||
|
"#pragma warning disable CS1573 // Disable warning: "
|
||||||
|
"'Parameter has no matching param tag in the XML comment'\n");
|
||||||
|
|
||||||
output.push_back("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
|
output.push_back("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
|
||||||
|
|
||||||
const DocData::ClassDoc *class_doc = itype.class_doc;
|
const DocData::ClassDoc *class_doc = itype.class_doc;
|
||||||
|
|
||||||
if (class_doc && class_doc->description.size()) {
|
if (class_doc && class_doc->description.size()) {
|
||||||
|
String xml_summary = bbcode_to_xml(fix_doc_description(class_doc->description), &itype);
|
||||||
|
Vector<String> summary_lines = xml_summary.split("\n");
|
||||||
|
|
||||||
|
if (summary_lines.size()) {
|
||||||
output.push_back(INDENT1 "/// <summary>\n");
|
output.push_back(INDENT1 "/// <summary>\n");
|
||||||
|
|
||||||
Vector<String> description_lines = class_doc->description.split("\n");
|
for (int i = 0; i < summary_lines.size(); i++) {
|
||||||
|
|
||||||
for (int i = 0; i < description_lines.size(); i++) {
|
|
||||||
String description_line = description_lines[i].strip_edges();
|
|
||||||
if (description_line.size()) {
|
|
||||||
output.push_back(INDENT1 "/// ");
|
output.push_back(INDENT1 "/// ");
|
||||||
output.push_back(description_line.xml_escape());
|
output.push_back(summary_lines[i]);
|
||||||
output.push_back("\n");
|
output.push_back("\n");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
output.push_back(INDENT1 "/// </summary>\n");
|
output.push_back(INDENT1 "/// </summary>\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
output.push_back(INDENT1 "public ");
|
output.push_back(INDENT1 "public ");
|
||||||
if (itype.is_singleton) {
|
if (itype.is_singleton) {
|
||||||
|
@ -767,21 +1146,21 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
||||||
const ConstantInterface &iconstant = E->get();
|
const ConstantInterface &iconstant = E->get();
|
||||||
|
|
||||||
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
|
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
|
||||||
|
String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), &itype);
|
||||||
|
Vector<String> summary_lines = xml_summary.split("\n");
|
||||||
|
|
||||||
|
if (summary_lines.size()) {
|
||||||
output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
||||||
|
|
||||||
Vector<String> description_lines = iconstant.const_doc->description.split("\n");
|
for (int i = 0; i < summary_lines.size(); i++) {
|
||||||
|
|
||||||
for (int i = 0; i < description_lines.size(); i++) {
|
|
||||||
String description_line = description_lines[i].strip_edges();
|
|
||||||
if (description_line.size()) {
|
|
||||||
output.push_back(INDENT2 "/// ");
|
output.push_back(INDENT2 "/// ");
|
||||||
output.push_back(description_line.xml_escape());
|
output.push_back(summary_lines[i]);
|
||||||
output.push_back("\n");
|
output.push_back("\n");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
output.push_back(INDENT2 "/// </summary>");
|
output.push_back(INDENT2 "/// </summary>");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
output.push_back(MEMBER_BEGIN "public const int ");
|
output.push_back(MEMBER_BEGIN "public const int ");
|
||||||
output.push_back(iconstant.proxy_name);
|
output.push_back(iconstant.proxy_name);
|
||||||
|
@ -808,21 +1187,21 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
||||||
const ConstantInterface &iconstant = F->get();
|
const ConstantInterface &iconstant = F->get();
|
||||||
|
|
||||||
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
|
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
|
||||||
|
String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), &itype);
|
||||||
|
Vector<String> summary_lines = xml_summary.split("\n");
|
||||||
|
|
||||||
|
if (summary_lines.size()) {
|
||||||
output.push_back(INDENT3 "/// <summary>\n");
|
output.push_back(INDENT3 "/// <summary>\n");
|
||||||
|
|
||||||
Vector<String> description_lines = iconstant.const_doc->description.split("\n");
|
for (int i = 0; i < summary_lines.size(); i++) {
|
||||||
|
|
||||||
for (int i = 0; i < description_lines.size(); i++) {
|
|
||||||
String description_line = description_lines[i].strip_edges();
|
|
||||||
if (description_line.size()) {
|
|
||||||
output.push_back(INDENT3 "/// ");
|
output.push_back(INDENT3 "/// ");
|
||||||
output.push_back(description_line.xml_escape());
|
output.push_back(summary_lines[i]);
|
||||||
output.push_back("\n");
|
output.push_back("\n");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
output.push_back(INDENT3 "/// </summary>\n");
|
output.push_back(INDENT3 "/// </summary>\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
output.push_back(INDENT3);
|
output.push_back(INDENT3);
|
||||||
output.push_back(iconstant.proxy_name);
|
output.push_back(iconstant.proxy_name);
|
||||||
|
@ -928,7 +1307,9 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
||||||
output.push_back(INDENT1 CLOSE_BLOCK /* class */
|
output.push_back(INDENT1 CLOSE_BLOCK /* class */
|
||||||
CLOSE_BLOCK /* namespace */);
|
CLOSE_BLOCK /* namespace */);
|
||||||
|
|
||||||
output.push_back("\n#pragma warning restore CS1591\n");
|
output.push_back("\n"
|
||||||
|
"#pragma warning restore CS1591\n"
|
||||||
|
"#pragma warning restore CS1573\n");
|
||||||
|
|
||||||
return _save_file(p_output_file, output);
|
return _save_file(p_output_file, output);
|
||||||
}
|
}
|
||||||
|
@ -978,34 +1359,22 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
|
||||||
const TypeInterface *prop_itype = _get_type_or_null(proptype_name);
|
const TypeInterface *prop_itype = _get_type_or_null(proptype_name);
|
||||||
ERR_FAIL_NULL_V(prop_itype, ERR_BUG); // Property type not found
|
ERR_FAIL_NULL_V(prop_itype, ERR_BUG); // Property type not found
|
||||||
|
|
||||||
String prop_proxy_name = escape_csharp_keyword(snake_to_pascal_case(p_iprop.cname));
|
|
||||||
|
|
||||||
// Prevent property and enclosing type from sharing the same name
|
|
||||||
if (prop_proxy_name == p_itype.proxy_name) {
|
|
||||||
if (verbose_output) {
|
|
||||||
WARN_PRINTS("Name of property `" + prop_proxy_name + "` is ambiguous with the name of its class `" +
|
|
||||||
p_itype.proxy_name + "`. Renaming property to `" + prop_proxy_name + "_`");
|
|
||||||
}
|
|
||||||
|
|
||||||
prop_proxy_name += "_";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p_iprop.prop_doc && p_iprop.prop_doc->description.size()) {
|
if (p_iprop.prop_doc && p_iprop.prop_doc->description.size()) {
|
||||||
|
String xml_summary = bbcode_to_xml(fix_doc_description(p_iprop.prop_doc->description), &p_itype);
|
||||||
|
Vector<String> summary_lines = xml_summary.split("\n");
|
||||||
|
|
||||||
|
if (summary_lines.size()) {
|
||||||
p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
||||||
|
|
||||||
Vector<String> description_lines = p_iprop.prop_doc->description.split("\n");
|
for (int i = 0; i < summary_lines.size(); i++) {
|
||||||
|
|
||||||
for (int i = 0; i < description_lines.size(); i++) {
|
|
||||||
String description_line = description_lines[i].strip_edges();
|
|
||||||
if (description_line.size()) {
|
|
||||||
p_output.push_back(INDENT2 "/// ");
|
p_output.push_back(INDENT2 "/// ");
|
||||||
p_output.push_back(description_line.xml_escape());
|
p_output.push_back(summary_lines[i]);
|
||||||
p_output.push_back("\n");
|
p_output.push_back("\n");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
p_output.push_back(INDENT2 "/// </summary>");
|
p_output.push_back(INDENT2 "/// </summary>");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
p_output.push_back(MEMBER_BEGIN "public ");
|
p_output.push_back(MEMBER_BEGIN "public ");
|
||||||
|
|
||||||
|
@ -1014,7 +1383,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
|
||||||
|
|
||||||
p_output.push_back(prop_itype->cs_type);
|
p_output.push_back(prop_itype->cs_type);
|
||||||
p_output.push_back(" ");
|
p_output.push_back(" ");
|
||||||
p_output.push_back(prop_proxy_name.replace("/", "__"));
|
p_output.push_back(p_iprop.proxy_name);
|
||||||
p_output.push_back("\n" INDENT2 OPEN_BLOCK);
|
p_output.push_back("\n" INDENT2 OPEN_BLOCK);
|
||||||
|
|
||||||
if (getter) {
|
if (getter) {
|
||||||
|
@ -1135,7 +1504,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
|
||||||
|
|
||||||
icall_params += arg_type->cs_in.empty() ? arg_in : sformat(arg_type->cs_in, arg_in);
|
icall_params += arg_type->cs_in.empty() ? arg_in : sformat(arg_type->cs_in, arg_in);
|
||||||
|
|
||||||
default_args_doc.push_back(INDENT2 "/// <param name=\"" + iarg.name + "\">If the param is null, then the default value is " + def_arg + "</param>\n");
|
// Apparently the name attribute must not include the @
|
||||||
|
String param_tag_name = iarg.name.begins_with("@") ? iarg.name.substr(1, iarg.name.length()) : iarg.name;
|
||||||
|
|
||||||
|
default_args_doc.push_back(INDENT2 "/// <param name=\"" + param_tag_name + "\">If the parameter is null, then the default value is " + def_arg + "</param>\n");
|
||||||
} else {
|
} else {
|
||||||
icall_params += arg_type->cs_in.empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name);
|
icall_params += arg_type->cs_in.empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name);
|
||||||
}
|
}
|
||||||
|
@ -1151,25 +1523,25 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_imethod.method_doc && p_imethod.method_doc->description.size()) {
|
if (p_imethod.method_doc && p_imethod.method_doc->description.size()) {
|
||||||
|
String xml_summary = bbcode_to_xml(fix_doc_description(p_imethod.method_doc->description), &p_itype);
|
||||||
|
Vector<String> summary_lines = xml_summary.split("\n");
|
||||||
|
|
||||||
|
if (summary_lines.size() || default_args_doc.size()) {
|
||||||
p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
||||||
|
|
||||||
Vector<String> description_lines = p_imethod.method_doc->description.split("\n");
|
for (int i = 0; i < summary_lines.size(); i++) {
|
||||||
|
|
||||||
for (int i = 0; i < description_lines.size(); i++) {
|
|
||||||
String description_line = description_lines[i].strip_edges();
|
|
||||||
if (description_line.size()) {
|
|
||||||
p_output.push_back(INDENT2 "/// ");
|
p_output.push_back(INDENT2 "/// ");
|
||||||
p_output.push_back(description_line.xml_escape());
|
p_output.push_back(summary_lines[i]);
|
||||||
p_output.push_back("\n");
|
p_output.push_back("\n");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (List<String>::Element *E = default_args_doc.front(); E; E = E->next()) {
|
for (List<String>::Element *E = default_args_doc.front(); E; E = E->next()) {
|
||||||
p_output.push_back(E->get().xml_escape());
|
p_output.push_back(E->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
p_output.push_back(INDENT2 "/// </summary>");
|
p_output.push_back(INDENT2 "/// </summary>");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!p_imethod.is_internal) {
|
if (!p_imethod.is_internal) {
|
||||||
p_output.push_back(MEMBER_BEGIN "[GodotMethod(\"");
|
p_output.push_back(MEMBER_BEGIN "[GodotMethod(\"");
|
||||||
|
@ -1728,7 +2100,6 @@ void BindingsGenerator::_populate_object_type_interfaces() {
|
||||||
|
|
||||||
PropertyInterface iprop;
|
PropertyInterface iprop;
|
||||||
iprop.cname = property.name;
|
iprop.cname = property.name;
|
||||||
iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname));
|
|
||||||
iprop.setter = ClassDB::get_property_setter(type_cname, iprop.cname);
|
iprop.setter = ClassDB::get_property_setter(type_cname, iprop.cname);
|
||||||
iprop.getter = ClassDB::get_property_getter(type_cname, iprop.cname);
|
iprop.getter = ClassDB::get_property_getter(type_cname, iprop.cname);
|
||||||
|
|
||||||
|
@ -1736,6 +2107,8 @@ void BindingsGenerator::_populate_object_type_interfaces() {
|
||||||
iprop.index = ClassDB::get_property_index(type_cname, iprop.cname, &valid);
|
iprop.index = ClassDB::get_property_index(type_cname, iprop.cname, &valid);
|
||||||
ERR_FAIL_COND(!valid);
|
ERR_FAIL_COND(!valid);
|
||||||
|
|
||||||
|
iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname));
|
||||||
|
|
||||||
// Prevent property and enclosing type from sharing the same name
|
// Prevent property and enclosing type from sharing the same name
|
||||||
if (iprop.proxy_name == itype.proxy_name) {
|
if (iprop.proxy_name == itype.proxy_name) {
|
||||||
if (verbose_output) {
|
if (verbose_output) {
|
||||||
|
@ -1746,6 +2119,8 @@ void BindingsGenerator::_populate_object_type_interfaces() {
|
||||||
iprop.proxy_name += "_";
|
iprop.proxy_name += "_";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iprop.proxy_name = iprop.proxy_name.replace("/", "__"); // Some members have a slash...
|
||||||
|
|
||||||
iprop.prop_doc = NULL;
|
iprop.prop_doc = NULL;
|
||||||
|
|
||||||
for (int i = 0; i < itype.class_doc->properties.size(); i++) {
|
for (int i = 0; i < itype.class_doc->properties.size(); i++) {
|
||||||
|
|
|
@ -87,8 +87,13 @@ class BindingsGenerator {
|
||||||
StringName cname;
|
StringName cname;
|
||||||
bool is_enum;
|
bool is_enum;
|
||||||
|
|
||||||
TypeReference() {
|
TypeReference() :
|
||||||
is_enum = false;
|
is_enum(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeReference(const StringName &p_cname) :
|
||||||
|
cname(p_cname),
|
||||||
|
is_enum(false) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -321,6 +326,15 @@ class BindingsGenerator {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PropertyInterface *find_property_by_name(const StringName &p_cname) const {
|
||||||
|
for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) {
|
||||||
|
if (E->get().cname == p_cname)
|
||||||
|
return &E->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
const PropertyInterface *find_property_by_proxy_name(const String &p_proxy_name) const {
|
const PropertyInterface *find_property_by_proxy_name(const String &p_proxy_name) const {
|
||||||
for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) {
|
for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) {
|
||||||
if (E->get().proxy_name == p_proxy_name)
|
if (E->get().proxy_name == p_proxy_name)
|
||||||
|
@ -482,6 +496,7 @@ class BindingsGenerator {
|
||||||
StringName type_VarArg;
|
StringName type_VarArg;
|
||||||
StringName type_Object;
|
StringName type_Object;
|
||||||
StringName type_Reference;
|
StringName type_Reference;
|
||||||
|
StringName type_String;
|
||||||
StringName enum_Error;
|
StringName enum_Error;
|
||||||
|
|
||||||
NameCache() {
|
NameCache() {
|
||||||
|
@ -493,6 +508,7 @@ class BindingsGenerator {
|
||||||
type_VarArg = StaticCString::create("VarArg");
|
type_VarArg = StaticCString::create("VarArg");
|
||||||
type_Object = StaticCString::create("Object");
|
type_Object = StaticCString::create("Object");
|
||||||
type_Reference = StaticCString::create("Reference");
|
type_Reference = StaticCString::create("Reference");
|
||||||
|
type_String = StaticCString::create("String");
|
||||||
enum_Error = StaticCString::create("Error");
|
enum_Error = StaticCString::create("Error");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,6 +538,8 @@ class BindingsGenerator {
|
||||||
return p_type.name;
|
return p_type.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype);
|
||||||
|
|
||||||
int _determine_enum_prefix(const EnumInterface &p_ienum);
|
int _determine_enum_prefix(const EnumInterface &p_ienum);
|
||||||
void _apply_prefix_to_enum_constants(EnumInterface &p_ienum, int p_prefix_length);
|
void _apply_prefix_to_enum_constants(EnumInterface &p_ienum, int p_prefix_length);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue