From 92e718f070935f275213431a38598456b43019d3 Mon Sep 17 00:00:00 2001 From: David Snopek Date: Thu, 25 Jan 2024 08:54:58 -0600 Subject: [PATCH] Allow submitting documentation to the Godot editor --- gdextension/gdextension_interface.h | 25 +++++++++++++++++++++ include/godot_cpp/godot.hpp | 2 ++ src/godot.cpp | 4 ++++ test/SConstruct | 5 ++++- test/doc_classes/Example.xml | 25 +++++++++++++++++++++ test/project/project.godot | 2 +- test/src/register_types.cpp | 10 +++++++++ tools/godotcpp.py | 35 ++++++++++++++++++++++++++++- 8 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 test/doc_classes/Example.xml diff --git a/gdextension/gdextension_interface.h b/gdextension/gdextension_interface.h index 60ec8d4175..c8a8dd75f5 100644 --- a/gdextension/gdextension_interface.h +++ b/gdextension/gdextension_interface.h @@ -2835,6 +2835,31 @@ typedef void (*GDExtensionInterfaceEditorAddPlugin)(GDExtensionConstStringNamePt */ typedef void (*GDExtensionInterfaceEditorRemovePlugin)(GDExtensionConstStringNamePtr p_class_name); +/** + * @name editor_help_load_xml_from_utf8_chars + * @since 4.3 + * + * Loads new XML-formatted documentation data in the editor. + * + * The provided pointer can be immediately freed once the function returns. + * + * @param p_data A pointer to an UTF-8 encoded C string (null terminated). + */ +typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars)(const char *p_data); + +/** + * @name editor_help_load_xml_from_utf8_chars_and_len + * @since 4.3 + * + * Loads new XML-formatted documentation data in the editor. + * + * The provided pointer can be immediately freed once the function returns. + * + * @param p_data A pointer to an UTF-8 encoded C string. + * @param p_size The number of bytes (not code units). + */ +typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen)(const char *p_data, GDExtensionInt p_size); + #ifdef __cplusplus } #endif diff --git a/include/godot_cpp/godot.hpp b/include/godot_cpp/godot.hpp index 5a6293027e..bdbc1a4232 100644 --- a/include/godot_cpp/godot.hpp +++ b/include/godot_cpp/godot.hpp @@ -190,6 +190,8 @@ extern "C" GDExtensionInterfaceClassdbUnregisterExtensionClass gdextension_inter extern "C" GDExtensionInterfaceGetLibraryPath gdextension_interface_get_library_path; extern "C" GDExtensionInterfaceEditorAddPlugin gdextension_interface_editor_add_plugin; extern "C" GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugin; +extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars gdextension_interface_editor_help_load_xml_from_utf8_chars; +extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len; } // namespace internal diff --git a/src/godot.cpp b/src/godot.cpp index 8a031be23b..73b70f4699 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -196,6 +196,8 @@ GDExtensionInterfaceClassdbUnregisterExtensionClass gdextension_interface_classd GDExtensionInterfaceGetLibraryPath gdextension_interface_get_library_path = nullptr; GDExtensionInterfaceEditorAddPlugin gdextension_interface_editor_add_plugin = nullptr; GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugin = nullptr; +GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars gdextension_interface_editor_help_load_xml_from_utf8_chars = nullptr; +GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len = nullptr; } // namespace internal @@ -436,6 +438,8 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge LOAD_PROC_ADDRESS(get_library_path, GDExtensionInterfaceGetLibraryPath); LOAD_PROC_ADDRESS(editor_add_plugin, GDExtensionInterfaceEditorAddPlugin); LOAD_PROC_ADDRESS(editor_remove_plugin, GDExtensionInterfaceEditorRemovePlugin); + LOAD_PROC_ADDRESS(editor_help_load_xml_from_utf8_chars, GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars); + LOAD_PROC_ADDRESS(editor_help_load_xml_from_utf8_chars_and_len, GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen); r_initialization->initialize = initialize_level; r_initialization->deinitialize = deinitialize_level; diff --git a/test/SConstruct b/test/SConstruct index 9c25917bb4..95d8b4d5f0 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -16,6 +16,9 @@ env = SConscript("../SConstruct") env.Append(CPPPATH=["src/"]) sources = Glob("src/*.cpp") +doc_header = env.GodotCPPDocHeader("src/doc_data.gen.h", source=Glob("doc_classes/*.xml")) +#sources.append(doc_header) + if env["platform"] == "macos": library = env.SharedLibrary( "project/bin/libgdexample.{}.{}.framework/libgdexample.{}.{}".format( @@ -40,4 +43,4 @@ else: source=sources, ) -Default(library) +Default(doc_header, library) diff --git a/test/doc_classes/Example.xml b/test/doc_classes/Example.xml new file mode 100644 index 0000000000..2a28f2c983 --- /dev/null +++ b/test/doc_classes/Example.xml @@ -0,0 +1,25 @@ + + + + A test control defined in GDExtension. + + + A control used for the automated GDExtension tests. + + + + + + + + Tests a simple function call. + + + + + + + + + + diff --git a/test/project/project.godot b/test/project/project.godot index 4f51c07f60..df3dd70f74 100644 --- a/test/project/project.godot +++ b/test/project/project.godot @@ -12,7 +12,7 @@ config_version=5 config/name="GDExtension Test Project" run/main_scene="res://main.tscn" -config/features=PackedStringArray("4.2") +config/features=PackedStringArray("4.3") config/icon="res://icon.png" [native_extensions] diff --git a/test/src/register_types.cpp b/test/src/register_types.cpp index 7cfe689e0e..71d3847c82 100644 --- a/test/src/register_types.cpp +++ b/test/src/register_types.cpp @@ -14,9 +14,19 @@ #include "example.h" #include "tests.h" +#if defined(TOOLS_ENABLED) || defined(DEBUG_ENABLED) +#include "doc_data.gen.h" +#endif + using namespace godot; void initialize_example_module(ModuleInitializationLevel p_level) { +#if defined(TOOLS_ENABLED) || defined(DEBUG_ENABLED) + if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) { + internal::gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len(reinterpret_cast(_doc_data_uncompressed), _doc_data_uncompressed_size); + } +#endif + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { return; } diff --git a/tools/godotcpp.py b/tools/godotcpp.py index 13a57e96d3..c2786750d3 100644 --- a/tools/godotcpp.py +++ b/tools/godotcpp.py @@ -325,6 +325,38 @@ def options(opts, env): tool.options(opts) +def make_doc_header(target, source, env): + dst = str(target[0]) + g = open(dst, "w", encoding="utf-8") + buf = "" + docbegin = "" + docend = "" + for src in source: + src_path = str(src) + if not src_path.endswith(".xml"): + continue + with open(src_path, "r", encoding="utf-8") as f: + content = f.read() + buf += content + + buf = (docbegin + buf + docend).encode("utf-8") + decomp_size = len(buf) + + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("#ifndef _GODOT_CPP_DOC_DATA_RAW_H\n") + g.write("#define _GODOT_CPP_DOC_DATA_RAW_H\n") + g.write('static const char *_doc_data_hash = "' + str(hash(buf)) + '";\n') + g.write("static const int _doc_data_uncompressed_size = " + str(decomp_size) + ";\n") + g.write("static const unsigned char _doc_data_uncompressed[] = {\n") + for i in range(len(buf)): + g.write("\t" + str(buf[i]) + ",\n") + g.write("};\n") + + g.write("#endif") + + g.close() + + def generate(env): # Default num_jobs to local cpu count if not user specified. # SCons has a peculiarity where user-specified options won't be overridden @@ -451,7 +483,8 @@ def generate(env): # Builders env.Append( BUILDERS={ - "GodotCPPBindings": Builder(action=Action(scons_generate_bindings, "$GENCOMSTR"), emitter=scons_emit_files) + "GodotCPPBindings": Builder(action=Action(scons_generate_bindings, "$GENCOMSTR"), emitter=scons_emit_files), + "GodotCPPDocHeader": Builder(action=make_doc_header), } ) env.AddMethod(_godot_cpp, "GodotCPP")