Skip to content

Commit 24a69c5

Browse files
Riteoakien-mga
andcommitted
GDExtension: add an interface for loading extra documentation
Adds two new GDExtension interface methods: - `editor_help_load_xml_from_utf8_chars` - `editor_help_load_xml_from_utf8_chars_and_len` Both of these methods parse the XML passed into an extra documentation container which, when needed, is merged into the main doc container. Co-Authored-By: Rémi Verschelde <rverschelde@gmail.com>
1 parent f71f4b8 commit 24a69c5

9 files changed

+141
-0
lines changed

core/extension/gdextension.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,8 @@ void GDExtension::_unregister_extension_class(GDExtensionClassLibraryPtr p_libra
653653
if (!ext->is_reloading) {
654654
self->extension_classes.erase(class_name);
655655
}
656+
657+
GDExtensionEditorHelp::remove_class(class_name);
656658
#else
657659
self->extension_classes.erase(class_name);
658660
#endif
@@ -1183,4 +1185,17 @@ void GDExtensionEditorPlugins::remove_extension_class(const StringName &p_class_
11831185
extension_classes.erase(p_class_name);
11841186
}
11851187
}
1188+
1189+
GDExtensionEditorHelp::EditorHelpLoadXmlBufferFunc GDExtensionEditorHelp::editor_help_load_xml_buffer = nullptr;
1190+
GDExtensionEditorHelp::EditorHelpRemoveClassFunc GDExtensionEditorHelp::editor_help_remove_class = nullptr;
1191+
1192+
void GDExtensionEditorHelp::load_xml_buffer(const uint8_t *p_buffer, int p_size) {
1193+
ERR_FAIL_NULL(editor_help_load_xml_buffer);
1194+
editor_help_load_xml_buffer(p_buffer, p_size);
1195+
}
1196+
1197+
void GDExtensionEditorHelp::remove_class(const String &p_class) {
1198+
ERR_FAIL_NULL(editor_help_remove_class);
1199+
editor_help_remove_class(p_class);
1200+
}
11861201
#endif // TOOLS_ENABLED

core/extension/gdextension.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,26 @@ class GDExtensionEditorPlugins {
195195
return extension_classes;
196196
}
197197
};
198+
199+
class GDExtensionEditorHelp {
200+
protected:
201+
friend class EditorHelp;
202+
203+
// Similarly to EditorNode above, we need to be able to ask EditorHelp to parse
204+
// new documentation data. Note though that, differently from EditorHelp, this
205+
// is initialized even _before_ it gets instantiated, as we need to rely on
206+
// this method while initializing the engine.
207+
typedef void (*EditorHelpLoadXmlBufferFunc)(const uint8_t *p_buffer, int p_size);
208+
static EditorHelpLoadXmlBufferFunc editor_help_load_xml_buffer;
209+
210+
typedef void (*EditorHelpRemoveClassFunc)(const String &p_class);
211+
static EditorHelpRemoveClassFunc editor_help_remove_class;
212+
213+
public:
214+
static void load_xml_buffer(const uint8_t *p_buffer, int p_size);
215+
static void remove_class(const String &p_class);
216+
};
217+
198218
#endif // TOOLS_ENABLED
199219

200220
#endif // GDEXTENSION_H

core/extension/gdextension_interface.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
#include "core/variant/variant.h"
4343
#include "core/version.h"
4444

45+
#include <string.h>
46+
4547
class CallableCustomExtension : public CallableCustom {
4648
void *userdata;
4749
void *token;
@@ -1375,6 +1377,19 @@ static void gdextension_editor_remove_plugin(GDExtensionConstStringNamePtr p_cla
13751377
#endif
13761378
}
13771379

1380+
static void gdextension_editor_help_load_xml_from_utf8_chars_and_len(const char *p_data, GDExtensionInt p_size) {
1381+
#ifdef TOOLS_ENABLED
1382+
GDExtensionEditorHelp::load_xml_buffer((const uint8_t *)p_data, p_size);
1383+
#endif
1384+
}
1385+
1386+
static void gdextension_editor_help_load_xml_from_utf8_chars(const char *p_data) {
1387+
#ifdef TOOLS_ENABLED
1388+
size_t len = strlen(p_data);
1389+
gdextension_editor_help_load_xml_from_utf8_chars_and_len(p_data, len);
1390+
#endif
1391+
}
1392+
13781393
#define REGISTER_INTERFACE_FUNC(m_name) GDExtension::register_interface_function(#m_name, (GDExtensionInterfaceFunctionPtr)&gdextension_##m_name)
13791394

13801395
void gdextension_setup_interface() {
@@ -1518,6 +1533,8 @@ void gdextension_setup_interface() {
15181533
REGISTER_INTERFACE_FUNC(classdb_get_class_tag);
15191534
REGISTER_INTERFACE_FUNC(editor_add_plugin);
15201535
REGISTER_INTERFACE_FUNC(editor_remove_plugin);
1536+
REGISTER_INTERFACE_FUNC(editor_help_load_xml_from_utf8_chars);
1537+
REGISTER_INTERFACE_FUNC(editor_help_load_xml_from_utf8_chars_and_len);
15211538
}
15221539

15231540
#undef REGISTER_INTERFACE_FUNCTION

core/extension/gdextension_interface.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2617,6 +2617,31 @@ typedef void (*GDExtensionInterfaceEditorAddPlugin)(GDExtensionConstStringNamePt
26172617
*/
26182618
typedef void (*GDExtensionInterfaceEditorRemovePlugin)(GDExtensionConstStringNamePtr p_class_name);
26192619

2620+
/**
2621+
* @name editor_help_load_xml_from_utf8_chars
2622+
* @since 4.3
2623+
*
2624+
* Loads new XML-formatted documentation data in the editor.
2625+
*
2626+
* The provided pointer can be immediately freed once the function returns.
2627+
*
2628+
* @param p_data A pointer to an UTF-8 encoded C string (null terminated).
2629+
*/
2630+
typedef void (*GDExtensionsInterfaceEditorHelpLoadXML)(const char *p_data);
2631+
2632+
/**
2633+
* @name editor_help_load_xml_from_utf8_chars_and_len
2634+
* @since 4.3
2635+
*
2636+
* Loads new XML-formatted documentation data in the editor.
2637+
*
2638+
* The provided pointer can be immediately freed once the function returns.
2639+
*
2640+
* @param p_data A pointer to an UTF-8 encoded C string.
2641+
* @param p_size The number of bytes (not code units).
2642+
*/
2643+
typedef void (*GDExtensionsInterfaceEditorHelpLoadXMLAndLen)(const char *p_data, GDExtensionInt p_size);
2644+
26202645
#ifdef __cplusplus
26212646
}
26222647
#endif

editor/doc_tools.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1635,3 +1635,15 @@ Error DocTools::load_compressed(const uint8_t *p_data, int p_compressed_size, in
16351635

16361636
return OK;
16371637
}
1638+
1639+
Error DocTools::load_xml(const uint8_t *p_data, int p_size) {
1640+
Ref<XMLParser> parser = memnew(XMLParser);
1641+
Error err = parser->_open_buffer(p_data, p_size);
1642+
if (err) {
1643+
return err;
1644+
}
1645+
1646+
_load(parser);
1647+
1648+
return OK;
1649+
}

editor/doc_tools.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class DocTools {
5151

5252
Error _load(Ref<XMLParser> parser);
5353
Error load_compressed(const uint8_t *p_data, int p_compressed_size, int p_uncompressed_size);
54+
Error load_xml(const uint8_t *p_data, int p_size);
5455
};
5556

5657
#endif // DOC_TOOLS_H

editor/editor_help.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "editor_help.h"
3232

3333
#include "core/core_constants.h"
34+
#include "core/extension/gdextension.h"
3435
#include "core/input/input.h"
3536
#include "core/object/script_language.h"
3637
#include "core/os/keyboard.h"
@@ -83,6 +84,7 @@ const Vector<String> classes_with_csharp_differences = {
8384
// TODO: this is sometimes used directly as doc->something, other times as EditorHelp::get_doc_data(), which is thread-safe.
8485
// Might this be a problem?
8586
DocTools *EditorHelp::doc = nullptr;
87+
DocTools *EditorHelp::ext_doc = nullptr;
8688

8789
static bool _attempt_doc_load(const String &p_class) {
8890
// Docgen always happens in the outer-most class: it also generates docs for inner classes.
@@ -2372,6 +2374,28 @@ String EditorHelp::get_cache_full_path() {
23722374
return EditorPaths::get_singleton()->get_cache_dir().path_join("editor_doc_cache.res");
23732375
}
23742376

2377+
void EditorHelp::load_xml_buffer(const uint8_t *p_buffer, int p_size) {
2378+
if (!ext_doc) {
2379+
ext_doc = memnew(DocTools);
2380+
}
2381+
2382+
ext_doc->load_xml(p_buffer, p_size);
2383+
2384+
if (doc) {
2385+
doc->load_xml(p_buffer, p_size);
2386+
}
2387+
}
2388+
2389+
void EditorHelp::remove_class(const String &p_class) {
2390+
if (ext_doc && ext_doc->has_doc(p_class)) {
2391+
ext_doc->remove_doc(p_class);
2392+
}
2393+
2394+
if (doc && doc->has_doc(p_class)) {
2395+
doc->remove_doc(p_class);
2396+
}
2397+
}
2398+
23752399
static bool first_attempt = true;
23762400

23772401
static String _compute_doc_version_hash() {
@@ -2392,6 +2416,12 @@ void EditorHelp::_load_doc_thread(void *p_udata) {
23922416
first_attempt = false;
23932417
callable_mp_static(&EditorHelp::generate_doc).bind(true).call_deferred();
23942418
}
2419+
2420+
// Append extra doc data. This is needed because it would otherwise be wiped by
2421+
// the doc regeneration routine.
2422+
if (ext_doc) {
2423+
doc->merge_from(*ext_doc);
2424+
}
23952425
}
23962426

23972427
void EditorHelp::_gen_doc_thread(void *p_udata) {
@@ -2411,6 +2441,12 @@ void EditorHelp::_gen_doc_thread(void *p_udata) {
24112441
if (err) {
24122442
ERR_PRINT("Cannot save editor help cache (" + get_cache_full_path() + ").");
24132443
}
2444+
2445+
// Append extra doc data. This is needed because it would otherwise be wiped by
2446+
// the doc regeneration routine.
2447+
if (ext_doc) {
2448+
doc->merge_from(*ext_doc);
2449+
}
24142450
}
24152451

24162452
static bool doc_gen_use_threads = true;
@@ -2561,6 +2597,11 @@ void EditorHelp::_bind_methods() {
25612597
ADD_SIGNAL(MethodInfo("go_to_help"));
25622598
}
25632599

2600+
void EditorHelp::init_gdext_pointers() {
2601+
GDExtensionEditorHelp::editor_help_load_xml_buffer = &EditorHelp::load_xml_buffer;
2602+
GDExtensionEditorHelp::editor_help_remove_class = &EditorHelp::remove_class;
2603+
}
2604+
25642605
EditorHelp::EditorHelp() {
25652606
set_custom_minimum_size(Size2(150 * EDSCALE, 0));
25662607

editor/editor_help.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ class EditorHelp : public VBoxContainer {
113113
RichTextLabel *class_desc = nullptr;
114114
HSplitContainer *h_split = nullptr;
115115
static DocTools *doc;
116+
static DocTools *ext_doc;
116117

117118
ConfirmationDialog *search_dialog = nullptr;
118119
LineEdit *search = nullptr;
@@ -206,6 +207,9 @@ class EditorHelp : public VBoxContainer {
206207
static void cleanup_doc();
207208
static String get_cache_full_path();
208209

210+
static void load_xml_buffer(const uint8_t *p_buffer, int p_size);
211+
static void remove_class(const String &p_class);
212+
209213
void go_to_help(const String &p_help);
210214
void go_to_class(const String &p_class);
211215
void update_doc();
@@ -225,6 +229,8 @@ class EditorHelp : public VBoxContainer {
225229

226230
void update_toggle_scripts_button();
227231

232+
static void init_gdext_pointers();
233+
228234
EditorHelp();
229235
~EditorHelp();
230236
};

editor/register_editor_types.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,10 @@ void register_editor_types() {
282282
ei_singleton.editor_only = true;
283283
Engine::get_singleton()->add_singleton(ei_singleton);
284284

285+
// Required as GDExtensions can register docs at init time way before this
286+
// class is actually instantiated.
287+
EditorHelp::init_gdext_pointers();
288+
285289
OS::get_singleton()->benchmark_end_measure("register_editor_types");
286290
}
287291

0 commit comments

Comments
 (0)