-
-
Notifications
You must be signed in to change notification settings - Fork 23.7k
Implement EditorExtensionSourceCodePlugin #110171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Implement EditorExtensionSourceCodePlugin #110171
Conversation
986d117 to
6ada699
Compare
6ada699 to
45fabe8
Compare
This comment was marked as resolved.
This comment was marked as resolved.
editor/docks/filesystem_dock.cpp
Outdated
| int item_idx = tree_popup->get_item_count() - 1; | ||
| tree_popup->set_item_disabled(item_idx, true); | ||
| tree_popup->set_item_tooltip(item_idx, "No extension source code plugins available."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| int item_idx = tree_popup->get_item_count() - 1; | |
| tree_popup->set_item_disabled(item_idx, true); | |
| tree_popup->set_item_tooltip(item_idx, "No extension source code plugins available."); | |
| tree_popup->set_item_disabled(-1, true); | |
| tree_popup->set_item_tooltip(-1, "No extension source code plugins available."); |
45fabe8 to
d53f65c
Compare
|
Sorry about that, I didn't put too much effort in handling errors in the demo and just assumed it would be tested in a project that follows the directory structure of the GDExtension template. I updated the demo (raulsntos@97b425b) to fix the issues you mentioned, I also pushed an update to the PR to apply the suggestions from the review. Thanks! |
|
I gave it a bit testing and managed to create a working class, although it wasn't easy. I encountered a few problems. They are probably related to the C++ plugin itself and out of scope, but some of them might be limitation of source plugins.
I don't know what plans are here exactly, but if EditorExtensionSourceCodePlugin is supposed to provide scripting-like experience to extensions, it's missing a few things:
Also I'm not sure about showing two script buttons. IMO the option to edit extension from Scene dock should only show in the context menu. It would also allow opening both cpp and h files in C++ (by providing 2 options). I'd be interested to test C# source plugin, as I imagine it will be more friendly to use than C++. |
| This method is only called if [method _overrides_external_editor] returns [code]true[/code]. | ||
| </description> | ||
| </method> | ||
| <method name="_overrides_external_editor" qualifiers="virtual const"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GDVIRTUAL_IS_OVERRIDDEN should be enough for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is to let the plugin indicate if it can handle it or not, even if it overrides the _open_in_external_editor method.
For example, in C# we implement custom logic to open IDEs but it depends on a custom setting which may be set to "None". In this case we want to use this method to let Godot know the plugin doesn't have a preference for how to open files, and should just fall back to the default editor.
| Returns the description for the given template ID. This description will be shown on the create new extension class dialog, and should provide more information about the template's purpose and usage. | ||
| </description> | ||
| </method> | ||
| <method name="_get_template_display_name" qualifiers="virtual const"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of multiple methods for getting template info, there could be one method _get_templates() expecting array of Dictionaries with template info (name, descriptions, files, options). Though it would be more friendly if we had structs support.
| Plugins that do not use templates should still implement [method _create_class_source] if they can create source files according to [method _can_create_class_source] but don't need to implement [method _create_class_source_from_template_id] or [method _create_class_source_from_template_file]. | ||
| </description> | ||
| </method> | ||
| <method name="_open_in_external_editor" qualifiers="virtual const"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The editor already has settings for configuring external editor. Why not just reuse them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say that different languages would have different settings for external editor. If you have multiple languages installed, you might want to open some in one editor and some in another (or not use an external editor).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This allows the plugin to provide their own implementation, which allows us to keep compatibility with the mono module's settings.
The mono module has a setting that allows to select an IDE from a dropdown. We provide custom integration for these IDEs, some of which can't be simply opened with a command (like Visual Studio which requires using the EnvDTE library).
Also, as @vnen said, since the mono module provides its own setting, it means you can select a different editor for C# than the general one that will be used for GDScript files.
| case NOTIFICATION_ENTER_TREE: { | ||
| // We use the same setting as the script templates intentionally, since it's the same feature | ||
| // just applied to extension classes so we want to remember the user's choice. | ||
| is_using_templates = EDITOR_DEF("_script_setup_use_script_templates", false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| is_using_templates = EDITOR_DEF("_script_setup_use_script_templates", false); | |
| is_using_templates = EDITOR_GET("_script_setup_use_script_templates", false); |
|
|
||
| /* Templates */ | ||
|
|
||
| gc->add_child(memnew(Label(TTR("Template:")))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Static strings should use TTRC.
| gc->add_child(memnew(Label(TTR("Template:")))); | |
| gc->add_child(memnew(Label(TTRC("Template:")))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should also go to extension folder.
editor/scene/connections_dialog.cpp
Outdated
| empty_tree_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD); | ||
|
|
||
| script_methods_only = memnew(CheckButton(TTR("Script Methods Only"))); | ||
| script_methods_only = memnew(CheckButton(TTR("Script/Class Methods Only"))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about "Class"; someone might understand it as built-in methods, making the option confusing.
Maybe "Script/Extension"?
I disagree, IMO the workflow for extensions should be the same as scripts. The dialogs and options should be the same (e.g. it should be As for opening headers, we can think of options. I think the easiest way is for the user to open the source and then use the editor to open the header. Of course it needs better source editor integration, but that would be required anyway if you plan to used the integrated editor. I also think C++ is an exception here, pretty much all languages will have 1 class = 1 file. |
d53f65c to
b6e3ac2
Compare
Since the FileSystem doesn't show non-Resource files, I don't know if there's much we can do here. Also, the C++ source files, at least when following the godot-cpp template directory structure, would be outside of the game project anyway. For C# we can add the
Yeah, it wasn't my intention to provide a fully functional plugin for C++ projects, so I think this is out of scope.
It should fall back to the default template, but that's up to the plugin implementation. I believe the current implementation for creating scripts falls back to the "Empty" template so that's what I'm planning to do for C#.
I don't know how to implement this properly, and it would probably be a lot of work. I think it's out of scope.
Oops. I guess we can use
Yeah, unfortunately for languages that allow defining classes in multiple files. I had to choose one and decided opening the In C# this is less of a problem, but it can still happen if you use
This should now be fixed.
In C# that's handled by our editor plugin, there's no additional setup. I think it's up to the language providers to add editor plugins as needed to handle this.
C# users want to see at a glance whether the node is one of their C# classes, for which the button provides a clear indication. It would also be a bit more inconvenient to open C# classes since it would now take 2 clicks instead of 1. In practice, I don't know how often users would attach scripts to extension classes. So there may not be many cases where we're showing 2 buttons for the same Node.
@vnen Although it may not be very common, you can have N class = M files in C#. You can define multiple classes in a single file. You can also define a single class across multiple files using the |
f6a1078 to
43b2965
Compare
EditorExtensionSourceCodePlugin could provide a list of extensions it manages and FileSystem dock would use them to show the files, similar to how |
| String EditorExtensionSourceCodePlugin::get_source_path(const StringName &p_class_name) const { | ||
| String path; | ||
| GDVIRTUAL_CALL(_get_source_path, p_class_name, path); | ||
| return path; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addition to this, I think we need to add something to the GDExtension interface to get information about the source code for a particular GDExtension. Like, it should be able to query the extension binding that was used (ex "godot-cpp"), the base path of the source code for that extension, and get the paths for classes that are already in the version that's loaded in the editor. I'll do some thinking about how I think this should look...
But that doesn't need to be in this PR, because I think we need what you already have here too, since we need to be able to find the source paths for new (or moved) classes, not just those that are already compiled into an extension
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addition to this, I think we need to add something to the GDExtension interface to get information about the source code for a particular GDExtension
I just posted draft PR #111922 with a quick sketch of how this could look
| virtual Error create_class_source(const String &p_class_name, const String &p_base_class_name, const PackedStringArray &p_paths) const; | ||
| virtual Error create_class_source_from_template_id(const String &p_class_name, const String &p_base_class_name, const PackedStringArray &p_paths, const String &p_template_id, const Dictionary &p_template_options) const; | ||
| virtual Error create_class_source_from_template_file(const String &p_class_name, const String &p_base_class_name, const PackedStringArray &p_paths, const String &p_template_path); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this meant to account for multiple GDExtensions from the same language?
Like, I'm envisioning that there would be one EditorExtensionSourceCodePlugin for godot-cpp, but you could have multiple GDExtensions using godot-cpp in your project.
I feel like these functions need to be able to "target" a specific extension. Or, did you have a different idea in mind for how this would work?
| #include "core/object/class_db.h" | ||
| #include "core/object/object.h" | ||
|
|
||
| class ValidationContext : public Object { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ValidationContext feels like an overly generic name, that could conflict with future Godot classes or classes in user projects.
Maybe SourceCodeValidationContext? Or, even throw Editor in there somewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a very generic class intended to be used with EditorValidationPanel.
EditorValidationContext makes sense probably.
| } | ||
|
|
||
| for (const Ref<EditorExtensionSourceCodePlugin> &plugin : plugins) { | ||
| if (plugin->can_handle_object(p_object)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this pass in the library to check if this one has source available? Not all GDExtensions in use will have their source as part of the project (some are just 3rd party stuff), and Object::get_extension_library() isn't exposed, so the plugins can't call that method themselves. (Another option would be to expose it?)
This plugin can provide source-code editing capabilities for GDExtension classes, such as: - Providing the path to source code files so they can be opened by the editor. - Opening source code files in external editors. - Creating class source code files. - Providing templates to use when creating source code files. - Editing class source code files to add callback methods when connecting signals to a non-existent method.
Adds support for the following capabilities: - Opening source code files in external editor when double-clicking in the FileSystem dock. - Replacing nodes in scene tree by drag-n-drop a source code file from FileSystem dock.
43b2965 to
032b78f
Compare
This plugin can provide source-code editing capabilities for GDExtension classes, such as:
I also made a C++ plugin demo to show how the plugin would be implemented, it's a mock up so it's not entirely functional:
Screenshots