summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/EditorVCSInterface.xml263
-rw-r--r--editor/editor_node.cpp6
-rw-r--r--editor/editor_node.h1
-rw-r--r--editor/editor_vcs_interface.cpp6
-rw-r--r--editor/editor_vcs_interface.h2
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp201
-rw-r--r--editor/plugins/version_control_editor_plugin.h15
7 files changed, 360 insertions, 134 deletions
diff --git a/doc/classes/EditorVCSInterface.xml b/doc/classes/EditorVCSInterface.xml
index 89ba79f7d9..cca6a0591f 100644
--- a/doc/classes/EditorVCSInterface.xml
+++ b/doc/classes/EditorVCSInterface.xml
@@ -1,97 +1,276 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorVCSInterface" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Version Control System (VCS) interface which reads and writes to the local VCS in use.
+ Version Control System (VCS) interface, which reads and writes to the local VCS in use.
</brief_description>
<description>
- Used by the editor to display VCS extracted information in the editor. The implementation of this API is included in VCS addons, which are essentially GDExtension plugins that need to be put into the project folder. These VCS addons are scripts which are attached (on demand) to the object instance of [code]EditorVCSInterface[/code]. All the functions listed below, instead of performing the task themselves, they call the internally defined functions in the VCS addons to provide a plug-n-play experience.
+ Defines the API that the editor uses to extract information from the underlying VCS. The implementation of this API is included in VCS plugins, which are GDExtension plugins that inherit [EditorVCSInterface] and are attached (on demand) to the singleton instance of [EditorVCSInterface]. Instead of performing the task themselves, all the virtual functions listed below are calling the internally overridden functions in the VCS plugins to provide a plug-n-play experience. A custom VCS plugin is supposed to inherit from [EditorVCSInterface] and override each of these virtual functions.
</description>
<tutorials>
</tutorials>
<methods>
- <method name="commit">
+ <method name="_checkout_branch" qualifiers="virtual">
+ <return type="bool" />
+ <param index="0" name="branch_name" type="String" />
+ <description>
+ Checks out a [code]branch_name[/code] in the VCS.
+ </description>
+ </method>
+ <method name="_commit" qualifiers="virtual">
<return type="void" />
<param index="0" name="msg" type="String" />
<description>
- Creates a version commit if the addon is initialized, else returns without doing anything. Uses the files which have been staged previously, with the commit message set to a value as provided as in the argument.
+ Commits the currently staged changes and applies the commit [code]msg[/code] to the resulting commit.
</description>
</method>
- <method name="get_file_diff">
- <return type="Dictionary[]" />
+ <method name="_create_branch" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="branch_name" type="String" />
+ <description>
+ Creates a new branch named [code]branch_name[/code] in the VCS.
+ </description>
+ </method>
+ <method name="_create_remote" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="remote_name" type="String" />
+ <param index="1" name="remote_url" type="String" />
+ <description>
+ Creates a new remote destination with name [code]remote_name[/code] and points it to [code]remote_url[/code]. This can be an HTTPS remote or an SSH remote.
+ </description>
+ </method>
+ <method name="_discard_file" qualifiers="virtual">
+ <return type="void" />
<param index="0" name="file_path" type="String" />
<description>
- Returns an [Array] of [Dictionary] objects containing the diff output from the VCS in use, if a VCS addon is initialized, else returns an empty [Array] object. The diff contents also consist of some contextual lines which provide context to the observed line change in the file.
- Each [Dictionary] object has the line diff contents under the keys:
- - [code]"content"[/code] to store a [String] containing the line contents
- - [code]"status"[/code] to store a [String] which contains [code]"+"[/code] in case the content is a line addition but it stores a [code]"-"[/code] in case of deletion and an empty string in the case the line content is neither an addition nor a deletion.
- - [code]"new_line_number"[/code] to store an integer containing the new line number of the line content.
- - [code]"line_count"[/code] to store an integer containing the number of lines in the line content.
- - [code]"old_line_number"[/code] to store an integer containing the old line number of the line content.
- - [code]"offset"[/code] to store the offset of the line change since the first contextual line content.
+ Discards the changes made in a file present at [code]file_path[/code].
</description>
</method>
- <method name="get_modified_files_data">
- <return type="Dictionary" />
+ <method name="_fetch" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="remote" type="String" />
<description>
- Returns a [Dictionary] containing the path of the detected file change mapped to an integer signifying what kind of change the corresponding file has experienced.
- The following integer values are being used to signify that the detected file is:
- - [code]0[/code]: New to the VCS working directory
- - [code]1[/code]: Modified
- - [code]2[/code]: Renamed
- - [code]3[/code]: Deleted
- - [code]4[/code]: Typechanged
+ Fetches new changes from the remote, but doesn't write changes to the current working directory. Equivalent to [code]git fetch[/code].
</description>
</method>
- <method name="get_project_name">
+ <method name="_get_branch_list" qualifiers="virtual">
+ <return type="Array" />
+ <description>
+ Gets an instance of an [Array] of [String]s containing available branch names in the VCS.
+ </description>
+ </method>
+ <method name="_get_current_branch_name" qualifiers="virtual">
<return type="String" />
<description>
- Returns the project name of the VCS working directory.
+ Gets the current branch name defined in the VCS.
+ </description>
+ </method>
+ <method name="_get_diff" qualifiers="virtual">
+ <return type="Dictionary[]" />
+ <param index="0" name="identifier" type="String" />
+ <param index="1" name="area" type="int" />
+ <description>
+ Returns an array of [Dictionary] items (see [method create_diff_file], [method create_diff_hunk], [method create_diff_line], [method add_line_diffs_into_diff_hunk] and [method add_diff_hunks_into_diff_file]), each containing information about a diff. If [code]identifier[/code] is a file path, returns a file diff, and if it is a commit identifier, then returns a commit diff.
+ </description>
+ </method>
+ <method name="_get_line_diff" qualifiers="virtual">
+ <return type="Array" />
+ <param index="0" name="file_path" type="String" />
+ <param index="1" name="text" type="String" />
+ <description>
+ Returns an [Array] of [Dictionary] items (see [method create_diff_hunk]), each containing a line diff between a file at [code]file_path[/code] and the [code]text[/code] which is passed in.
+ </description>
+ </method>
+ <method name="_get_modified_files_data" qualifiers="virtual">
+ <return type="Array" />
+ <description>
+ Returns an [Array] of [Dictionary] items (see [method create_status_file]), each containing the status data of every modified file in the project folder.
+ </description>
+ </method>
+ <method name="_get_previous_commits" qualifiers="virtual">
+ <return type="Array" />
+ <param index="0" name="max_commits" type="int" />
+ <description>
+ Returns an [Array] of [Dictionary] items (see [method create_commit]), each containing the data for a past commit.
</description>
</method>
- <method name="get_vcs_name">
+ <method name="_get_remotes" qualifiers="virtual">
+ <return type="Array" />
+ <description>
+ Returns an [Array] of [String]s, each containing the name of a remote configured in the VCS.
+ </description>
+ </method>
+ <method name="_get_vcs_name" qualifiers="virtual">
<return type="String" />
<description>
- Returns the name of the VCS if the VCS has been initialized, else return an empty string.
+ Returns the name of the underlying VCS provider.
</description>
</method>
- <method name="initialize">
+ <method name="_initialize" qualifiers="virtual">
<return type="bool" />
- <param index="0" name="project_root_path" type="String" />
+ <param index="0" name="project_path" type="String" />
<description>
- Initializes the VCS addon if not already. Uses the argument value as the path to the working directory of the project. Creates the initial commit if required. Returns [code]true[/code] if no failure occurs, else returns [code]false[/code].
+ Initializes the VCS plugin when called from the editor. Returns whether or not the plugin was successfully initialized. A VCS project is initialized at [code]project_path[/code].
</description>
</method>
- <method name="is_addon_ready">
- <return type="bool" />
+ <method name="_pull" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="remote" type="String" />
<description>
- Returns [code]true[/code] if the addon is ready to respond to function calls, else returns [code]false[/code].
+ Pulls changes from the remote. This can give rise to merge conflicts.
</description>
</method>
- <method name="is_vcs_initialized">
- <return type="bool" />
+ <method name="_push" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="remote" type="String" />
+ <param index="1" name="force" type="bool" />
+ <description>
+ Pushes changes to the [code]remote[/code]. Optionally, if [code]force[/code] is set to true, a force push will override the change history already present on the remote.
+ </description>
+ </method>
+ <method name="_remove_branch" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="branch_name" type="String" />
<description>
- Returns [code]true[/code] if the VCS addon has been initialized, else returns [code]false[/code].
+ Remove a branch from the local VCS.
</description>
</method>
- <method name="shut_down">
+ <method name="_remove_remote" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="remote_name" type="String" />
+ <description>
+ Remove a remote from the local VCS.
+ </description>
+ </method>
+ <method name="_set_credentials" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="username" type="String" />
+ <param index="1" name="password" type="String" />
+ <param index="2" name="ssh_public_key_path" type="String" />
+ <param index="3" name="ssh_private_key_path" type="String" />
+ <param index="4" name="ssh_passphrase" type="String" />
+ <description>
+ Set user credentials in the underlying VCS. [code]username[/code] and [code]password[/code] are used only during HTTPS authentication unless not already mentioned in the remote URL. [code]ssh_public_key_path[/code], [code]ssh_private_key_path[/code], and [code]ssh_passphrase[/code] are only used during SSH authentication.
+ </description>
+ </method>
+ <method name="_shut_down" qualifiers="virtual">
<return type="bool" />
<description>
- Shuts down the VCS addon to allow cleanup code to run on call. Returns [code]true[/code] is no failure occurs, else returns [code]false[/code].
+ Shuts down VCS plugin instance. Called when the user either closes the editor or shuts down the VCS plugin through the editor UI.
</description>
</method>
- <method name="stage_file">
+ <method name="_stage_file" qualifiers="virtual">
<return type="void" />
<param index="0" name="file_path" type="String" />
<description>
- Stages the file which should be committed when [method EditorVCSInterface.commit] is called. Argument should contain the absolute path.
+ Stages the file present at [code]file_path[/code] to the staged area.
</description>
</method>
- <method name="unstage_file">
+ <method name="_unstage_file" qualifiers="virtual">
<return type="void" />
<param index="0" name="file_path" type="String" />
<description>
- Unstages the file which was staged previously to be committed, so that it is no longer committed when [method EditorVCSInterface.commit] is called. Argument should contain the absolute path.
+ Unstages the file present at [code]file_path[/code] from the staged area to the unstaged area.
+ </description>
+ </method>
+ <method name="add_diff_hunks_into_diff_file">
+ <return type="Dictionary" />
+ <param index="0" name="diff_file" type="Dictionary" />
+ <param index="1" name="diff_hunks" type="Array" />
+ <description>
+ Helper function to add an array of [code]diff_hunks[/code] into a [code]diff_file[/code].
+ </description>
+ </method>
+ <method name="add_line_diffs_into_diff_hunk">
+ <return type="Dictionary" />
+ <param index="0" name="diff_hunk" type="Dictionary" />
+ <param index="1" name="line_diffs" type="Array" />
+ <description>
+ Helper function to add an array of [code]line_diffs[/code] into a [code]diff_hunk[/code].
+ </description>
+ </method>
+ <method name="create_commit">
+ <return type="Dictionary" />
+ <param index="0" name="msg" type="String" />
+ <param index="1" name="author" type="String" />
+ <param index="2" name="id" type="String" />
+ <param index="3" name="unix_timestamp" type="int" />
+ <param index="4" name="offset_minutes" type="int" />
+ <description>
+ Helper function to create a commit [Dictionary] item. [code]msg[/code] is the commit message of the commit. [code]author[/code] is a single human-readable string containing all the author's details, e.g. the email and name configured in the VCS. [code]id[/code] is the identifier of the commit, in whichever format your VCS may provide an identifier to commits. [code]unix_timestamp[/code] is the UTC Unix timestamp of when the commit was created. [code]offset_minutes[/code] is the timezone offset in minutes, recorded from the system timezone where the commit was created.
+ </description>
+ </method>
+ <method name="create_diff_file">
+ <return type="Dictionary" />
+ <param index="0" name="new_file" type="String" />
+ <param index="1" name="old_file" type="String" />
+ <description>
+ Helper function to create a [code]Dictionary[/code] for storing old and new diff file paths.
+ </description>
+ </method>
+ <method name="create_diff_hunk">
+ <return type="Dictionary" />
+ <param index="0" name="old_start" type="int" />
+ <param index="1" name="new_start" type="int" />
+ <param index="2" name="old_lines" type="int" />
+ <param index="3" name="new_lines" type="int" />
+ <description>
+ Helper function to create a [code]Dictionary[/code] for storing diff hunk data. [code]old_start[/code] is the starting line number in old file. [code]new_start[/code] is the starting line number in new file. [code]old_lines[/code] is the number of lines in the old file. [code]new_lines[/code] is the number of lines in the new file.
+ </description>
+ </method>
+ <method name="create_diff_line">
+ <return type="Dictionary" />
+ <param index="0" name="new_line_no" type="int" />
+ <param index="1" name="old_line_no" type="int" />
+ <param index="2" name="content" type="String" />
+ <param index="3" name="status" type="String" />
+ <description>
+ Helper function to create a [code]Dictionary[/code] for storing a line diff. [code]new_line_no[/code] is the line number in the new file (can be [code]-1[/code] if the line is deleted). [code]old_line_no[/code] is the line number in the old file (can be [code]-1[/code] if the line is added). [code]content[/code] is the diff text. [code]status[/code] is a single character string which stores the line origin.
+ </description>
+ </method>
+ <method name="create_status_file">
+ <return type="Dictionary" />
+ <param index="0" name="file_path" type="String" />
+ <param index="1" name="change_type" type="int" enum="EditorVCSInterface.ChangeType" />
+ <param index="2" name="area" type="int" enum="EditorVCSInterface.TreeArea" />
+ <description>
+ Helper function to create a [code]Dictionary[/code] used by editor to read the status of a file.
+ </description>
+ </method>
+ <method name="popup_error">
+ <return type="void" />
+ <param index="0" name="msg" type="String" />
+ <description>
+ Pops up an error message in the edior which is shown as coming from the underlying VCS. Use this to show VCS specific error messages.
</description>
</method>
</methods>
+ <constants>
+ <constant name="CHANGE_TYPE_NEW" value="0" enum="ChangeType">
+ A new file has been added.
+ </constant>
+ <constant name="CHANGE_TYPE_MODIFIED" value="1" enum="ChangeType">
+ An earlier added file has been modified.
+ </constant>
+ <constant name="CHANGE_TYPE_RENAMED" value="2" enum="ChangeType">
+ An earlier added file has been renamed.
+ </constant>
+ <constant name="CHANGE_TYPE_DELETED" value="3" enum="ChangeType">
+ An earlier added file has been deleted.
+ </constant>
+ <constant name="CHANGE_TYPE_TYPECHANGE" value="4" enum="ChangeType">
+ An earlier added file has been typechanged.
+ </constant>
+ <constant name="CHANGE_TYPE_UNMERGED" value="5" enum="ChangeType">
+ A file is left unmerged.
+ </constant>
+ <constant name="TREE_AREA_COMMIT" value="0" enum="TreeArea">
+ A commit is encountered from the commit area.
+ </constant>
+ <constant name="TREE_AREA_STAGED" value="1" enum="TreeArea">
+ A file is encountered from the staged area.
+ </constant>
+ <constant name="TREE_AREA_UNSTAGED" value="2" enum="TreeArea">
+ A file is encountered from the unstaged area.
+ </constant>
+ </constants>
</class>
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index c95cbc4f96..c137e4aea4 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -420,9 +420,6 @@ void EditorNode::_version_control_menu_option(int p_idx) {
case RUN_VCS_SETTINGS: {
VersionControlEditorPlugin::get_singleton()->popup_vcs_set_up_dialog(gui_base);
} break;
- case RUN_VCS_SHUT_DOWN: {
- VersionControlEditorPlugin::get_singleton()->shut_down();
- } break;
}
}
@@ -6723,8 +6720,7 @@ EditorNode::EditorNode() {
project_menu->add_child(vcs_actions_menu);
project_menu->add_submenu_item(TTR("Version Control"), "Version Control");
vcs_actions_menu->add_item(TTR("Create Version Control Metadata"), RUN_VCS_METADATA);
- vcs_actions_menu->add_item(TTR("Set Up Version Control"), RUN_VCS_SETTINGS);
- vcs_actions_menu->add_item(TTR("Shut Down Version Control"), RUN_VCS_SHUT_DOWN);
+ vcs_actions_menu->add_item(TTR("Version Control Settings"), RUN_VCS_SETTINGS);
project_menu->add_separator();
project_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/export", TTR("Export..."), Key::NONE, TTR("Export")), FILE_EXPORT_PROJECT);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 7e66e14ce0..394370400d 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -185,7 +185,6 @@ private:
RUN_PROJECT_MANAGER,
RUN_VCS_METADATA,
RUN_VCS_SETTINGS,
- RUN_VCS_SHUT_DOWN,
SETTINGS_UPDATE_CONTINUOUSLY,
SETTINGS_UPDATE_WHEN_CHANGED,
SETTINGS_UPDATE_ALWAYS,
diff --git a/editor/editor_vcs_interface.cpp b/editor/editor_vcs_interface.cpp
index 521e23ee55..0c6c876b2f 100644
--- a/editor/editor_vcs_interface.cpp
+++ b/editor/editor_vcs_interface.cpp
@@ -32,7 +32,7 @@
#include "editor_node.h"
-#define UNIMPLEMENTED() ERR_PRINT(TTR("Unimplemented virtual function in EditorVCSInterface based node: ") + __func__)
+#define UNIMPLEMENTED() ERR_PRINT(vformat("Unimplemented virtual function in EditorVCSInterface based plugin: %s", __func__))
EditorVCSInterface *EditorVCSInterface::singleton = nullptr;
@@ -409,14 +409,14 @@ void EditorVCSInterface::create_vcs_metadata_files(VCSMetadata p_vcs_metadata_ty
if (p_vcs_metadata_type == VCSMetadata::GIT) {
Ref<FileAccess> f = FileAccess::open(p_dir.path_join(".gitignore"), FileAccess::WRITE);
if (f.is_null()) {
- ERR_FAIL_MSG(TTR("Couldn't create .gitignore in project path."));
+ ERR_FAIL_MSG("Couldn't create .gitignore in project path.");
} else {
f->store_line("# Godot 4+ specific ignores");
f->store_line(".godot/");
}
f = FileAccess::open(p_dir.path_join(".gitattributes"), FileAccess::WRITE);
if (f.is_null()) {
- ERR_FAIL_MSG(TTR("Couldn't create .gitattributes in project path."));
+ ERR_FAIL_MSG("Couldn't create .gitattributes in project path.");
} else {
f->store_line("# Normalize EOL for all files that Git considers text files.");
f->store_line("* text=auto eol=lf");
diff --git a/editor/editor_vcs_interface.h b/editor/editor_vcs_interface.h
index d9aee64adb..e23e032ab9 100644
--- a/editor/editor_vcs_interface.h
+++ b/editor/editor_vcs_interface.h
@@ -180,4 +180,4 @@ public:
VARIANT_ENUM_CAST(EditorVCSInterface::ChangeType);
VARIANT_ENUM_CAST(EditorVCSInterface::TreeArea);
-#endif // !EDITOR_VCS_INTERFACE_H
+#endif // EDITOR_VCS_INTERFACE_H
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index 23ef640137..fba760d57f 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -31,13 +31,14 @@
#include "version_control_editor_plugin.h"
#include "core/config/project_settings.h"
-#include "core/core_bind.h"
#include "core/os/keyboard.h"
#include "core/os/time.h"
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
#include "editor/filesystem_dock.h"
+#include "scene/gui/separator.h"
#define CHECK_PLUGIN_INITIALIZED() \
ERR_FAIL_COND_MSG(!EditorVCSInterface::get_singleton(), "No VCS plugin is initialized. Select a Version Control Plugin from Project menu.");
@@ -79,7 +80,7 @@ void VersionControlEditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_extra_options"), &VersionControlEditorPlugin::_update_extra_options);
ClassDB::bind_method(D_METHOD("_popup_branch_remove_confirm"), &VersionControlEditorPlugin::_popup_branch_remove_confirm);
ClassDB::bind_method(D_METHOD("_popup_remote_remove_confirm"), &VersionControlEditorPlugin::_popup_remote_remove_confirm);
- ClassDB::bind_method(D_METHOD("_popup_ssh_key_file_dialog"), &VersionControlEditorPlugin::_popup_ssh_key_file_dialog);
+ ClassDB::bind_method(D_METHOD("_popup_file_dialog"), &VersionControlEditorPlugin::_popup_file_dialog);
ClassDB::bind_method(D_METHOD("popup_vcs_set_up_dialog"), &VersionControlEditorPlugin::popup_vcs_set_up_dialog);
}
@@ -92,11 +93,12 @@ void VersionControlEditorPlugin::_create_vcs_metadata_files() {
void VersionControlEditorPlugin::_notification(int p_what) {
if (p_what == NOTIFICATION_READY) {
String installed_plugin = GLOBAL_DEF("editor/version_control/plugin_name", "");
+ String project_path = GLOBAL_DEF("editor/version_control/project_path", OS::get_singleton()->get_resource_dir());
+ project_path_input->set_text(project_path);
bool has_autoload_enable = GLOBAL_DEF("editor/version_control/autoload_on_startup", false);
if (installed_plugin != "" && has_autoload_enable) {
- if (_load_plugin(installed_plugin)) {
- _set_up();
+ if (_load_plugin(installed_plugin, project_path)) {
_set_credentials();
}
}
@@ -130,7 +132,8 @@ void VersionControlEditorPlugin::popup_vcs_set_up_dialog(const Control *p_gui_ba
set_up_dialog->popup_centered_clamped(popup_size * EDSCALE);
} else {
- EditorNode::get_singleton()->show_warning(TTR("No VCS plugins are available."), TTR("Error"));
+ // TODO: Give info to user on how to fix this error.
+ EditorNode::get_singleton()->show_warning(TTR("No VCS plugins are available in the project. Install a VCS plugin to use VCS integration features."), TTR("Error"));
}
}
@@ -140,15 +143,22 @@ void VersionControlEditorPlugin::_initialize_vcs() {
const int id = set_up_choice->get_selected_id();
String selected_plugin = set_up_choice->get_item_text(id);
- if (_load_plugin(selected_plugin)) {
- _set_up();
-
- ProjectSettings::get_singleton()->set(SNAME("editor/version_control/autoload_on_startup"), true);
- ProjectSettings::get_singleton()->set(SNAME("editor/version_control/plugin_name"), selected_plugin);
+ if (_load_plugin(selected_plugin, project_path_input->get_text())) {
+ ProjectSettings::get_singleton()->set("editor/version_control/autoload_on_startup", true);
+ ProjectSettings::get_singleton()->set("editor/version_control/plugin_name", selected_plugin);
+ ProjectSettings::get_singleton()->set("editor/version_control/project_path", project_path_input->get_text());
ProjectSettings::get_singleton()->save();
}
}
+void VersionControlEditorPlugin::_set_vcs_ui_state(bool p_enabled) {
+ select_project_path_button->set_disabled(p_enabled);
+ set_up_dialog->get_ok_button()->set_disabled(!p_enabled);
+ project_path_input->set_editable(!p_enabled);
+ set_up_choice->set_disabled(p_enabled);
+ toggle_vcs_choice->set_pressed_no_signal(p_enabled);
+}
+
void VersionControlEditorPlugin::_set_credentials() {
CHECK_PLUGIN_INITIALIZED();
@@ -170,30 +180,28 @@ void VersionControlEditorPlugin::_set_credentials() {
EditorSettings::get_singleton()->set_setting("version_control/ssh_private_key_path", ssh_private_key);
}
-bool VersionControlEditorPlugin::_load_plugin(String p_name) {
+bool VersionControlEditorPlugin::_load_plugin(String p_name, String p_project_path) {
Object *extension_instance = ClassDB::instantiate(p_name);
- ERR_FAIL_NULL_V_MSG(extension_instance, false, TTR("Received a nullptr VCS extension instance during construction."));
+ ERR_FAIL_NULL_V_MSG(extension_instance, false, "Received a nullptr VCS extension instance during construction.");
EditorVCSInterface *vcs_plugin = Object::cast_to<EditorVCSInterface>(extension_instance);
- ERR_FAIL_NULL_V_MSG(vcs_plugin, false, vformat(TTR("Could not cast VCS extension instance to %s."), EditorVCSInterface::get_class_static()));
+ ERR_FAIL_NULL_V_MSG(vcs_plugin, false, vformat("Could not cast VCS extension instance to %s.", EditorVCSInterface::get_class_static()));
+
+ String res_dir = project_path_input->get_text();
+
+ ERR_FAIL_COND_V_MSG(!vcs_plugin->initialize(res_dir), false, "Could not initialize " + p_name);
EditorVCSInterface::set_singleton(vcs_plugin);
- return true;
-}
-void VersionControlEditorPlugin::_set_up() {
register_editor();
EditorFileSystem::get_singleton()->connect(SNAME("filesystem_changed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
- // TODO: Take the project directory from the UI, defaulted to the project directory, of course.
- String res_dir = OS::get_singleton()->get_resource_dir();
-
- ERR_FAIL_COND_MSG(!EditorVCSInterface::get_singleton()->initialize(res_dir), "VCS was not initialized.");
-
_refresh_stage_area();
_refresh_commit_list();
_refresh_branch_list();
_refresh_remote_list();
+
+ return true;
}
void VersionControlEditorPlugin::_update_set_up_warning(String p_new_text) {
@@ -250,7 +258,7 @@ void VersionControlEditorPlugin::_refresh_commit_list() {
for (List<EditorVCSInterface::Commit>::Element *e = commit_info_list.front(); e; e = e->next()) {
EditorVCSInterface::Commit commit = e->get();
- TreeItem *item = commit_list->create_item(commit_list->get_root());
+ TreeItem *item = commit_list->create_item();
// Only display the first line of a commit message
int line_ending = commit.msg.find_char('\n');
@@ -296,7 +304,7 @@ void VersionControlEditorPlugin::_commit() {
String msg = commit_message->get_text().strip_edges();
- ERR_FAIL_COND_MSG(msg.is_empty(), TTR("No commit message was provided."));
+ ERR_FAIL_COND_MSG(msg.is_empty(), "No commit message was provided.");
EditorVCSInterface::get_singleton()->commit(msg);
@@ -341,7 +349,7 @@ void VersionControlEditorPlugin::_ssh_private_key_selected(String p_path) {
set_up_ssh_private_key_path->set_text(p_path);
}
-void VersionControlEditorPlugin::_popup_ssh_key_file_dialog(Variant p_file_dialog_variant) {
+void VersionControlEditorPlugin::_popup_file_dialog(Variant p_file_dialog_variant) {
FileDialog *file_dialog = Object::cast_to<FileDialog>(p_file_dialog_variant);
ERR_FAIL_NULL(file_dialog);
@@ -404,8 +412,8 @@ void VersionControlEditorPlugin::_refresh_stage_area() {
}
}
- staged_files->update();
- unstaged_files->update();
+ staged_files->queue_redraw();
+ unstaged_files->queue_redraw();
int total_changes = status_files.size();
String commit_tab_title = TTR("Commit") + (total_changes > 0 ? " (" + itos(total_changes) + ")" : "");
@@ -427,15 +435,13 @@ void VersionControlEditorPlugin::_discard_file(String p_file_path, EditorVCSInte
}
void VersionControlEditorPlugin::_discard_all() {
- TreeItem *root = unstaged_files->get_root();
- if (root) {
- Array file_entries = root->get_children();
- for (int i = 0; i < file_entries.size(); i++) {
- TreeItem *file_entry = root->get_child(i);
- String file_path = file_entry->get_meta(SNAME("file_path"));
- EditorVCSInterface::ChangeType change = (EditorVCSInterface::ChangeType)(int)file_entry->get_meta(SNAME("change_type"));
- _discard_file(file_path, change);
- }
+ TreeItem *file_entry = unstaged_files->get_root()->get_first_child();
+ while (file_entry) {
+ String file_path = file_entry->get_meta(SNAME("file_path"));
+ EditorVCSInterface::ChangeType change = (EditorVCSInterface::ChangeType)(int)file_entry->get_meta(SNAME("change_type"));
+ _discard_file(file_path, change);
+
+ file_entry = file_entry->get_next();
}
_refresh_stage_area();
}
@@ -443,7 +449,7 @@ void VersionControlEditorPlugin::_discard_all() {
void VersionControlEditorPlugin::_add_new_item(Tree *p_tree, String p_file_path, EditorVCSInterface::ChangeType p_change) {
String change_text = p_file_path + " (" + change_type_to_strings[p_change] + ")";
- TreeItem *new_item = p_tree->create_item(p_tree->get_root());
+ TreeItem *new_item = p_tree->create_item();
new_item->set_text(0, change_text);
new_item->set_icon(0, change_type_to_icon[p_change]);
new_item->set_meta(SNAME("file_path"), p_file_path);
@@ -499,13 +505,11 @@ void VersionControlEditorPlugin::_update_opened_tabs() {
void VersionControlEditorPlugin::_move_all(Object *p_tree) {
Tree *tree = Object::cast_to<Tree>(p_tree);
- TreeItem *root = tree->get_root();
- if (root) {
- Array file_entries = root->get_children();
- for (int i = 0; i < file_entries.size(); i++) {
- TreeItem *file_entry = root->get_child(i);
- _move_item(tree, file_entry);
- }
+ TreeItem *file_entry = tree->get_root()->get_first_child();
+ while (file_entry) {
+ _move_item(tree, file_entry);
+
+ file_entry = file_entry->get_next();
}
_refresh_stage_area();
}
@@ -553,11 +557,6 @@ void VersionControlEditorPlugin::_item_activated(Object *p_tree) {
void VersionControlEditorPlugin::_move_item(Tree *p_tree, TreeItem *p_item) {
CHECK_PLUGIN_INITIALIZED();
- if (!p_item->has_meta(SNAME("file_path"))) {
- // We only move items that are coming from files
- return;
- }
-
if (p_tree == staged_files) {
EditorVCSInterface::get_singleton()->unstage_file(p_item->get_meta(SNAME("file_path")));
} else {
@@ -908,7 +907,7 @@ void VersionControlEditorPlugin::_update_extra_options() {
}
bool VersionControlEditorPlugin::_is_staging_area_empty() {
- return staged_files->get_last_item() == staged_files->get_root();
+ return staged_files->get_root()->get_child_count() == 0;
}
void VersionControlEditorPlugin::_commit_message_gui_input(const Ref<InputEvent> &p_event) {
@@ -935,13 +934,16 @@ void VersionControlEditorPlugin::_commit_message_gui_input(const Ref<InputEvent>
}
}
-void VersionControlEditorPlugin::register_editor() {
- EditorNode::get_singleton()->add_control_to_dock(EditorNode::DOCK_SLOT_RIGHT_UL, version_commit_dock);
-
- version_control_dock_button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Version Control"), version_control_dock);
+void VersionControlEditorPlugin::_toggle_vcs_integration(bool p_toggled) {
+ if (p_toggled) {
+ _initialize_vcs();
+ } else {
+ shut_down();
+ }
+}
- set_up_choice->set_disabled(true);
- set_up_init_button->set_disabled(true);
+void VersionControlEditorPlugin::_project_path_selected(String p_project_path) {
+ project_path_input->set_text(p_project_path);
}
void VersionControlEditorPlugin::fetch_available_vcs_plugin_names() {
@@ -949,6 +951,14 @@ void VersionControlEditorPlugin::fetch_available_vcs_plugin_names() {
ClassDB::get_direct_inheriters_from_class(EditorVCSInterface::get_class_static(), &available_plugins);
}
+void VersionControlEditorPlugin::register_editor() {
+ EditorNode::get_singleton()->add_control_to_dock(EditorNode::DOCK_SLOT_RIGHT_UL, version_commit_dock);
+
+ version_control_dock_button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Version Control"), version_control_dock);
+
+ _set_vcs_ui_state(true);
+}
+
void VersionControlEditorPlugin::shut_down() {
if (!EditorVCSInterface::get_singleton()) {
return;
@@ -965,8 +975,7 @@ void VersionControlEditorPlugin::shut_down() {
EditorNode::get_singleton()->remove_control_from_dock(version_commit_dock);
EditorNode::get_singleton()->remove_bottom_panel_item(version_control_dock);
- set_up_choice->set_disabled(false);
- set_up_init_button->set_disabled(false);
+ _set_vcs_ui_state(false);
}
VersionControlEditorPlugin::VersionControlEditorPlugin() {
@@ -1003,8 +1012,9 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
metadata_vb->add_child(l);
set_up_dialog = memnew(AcceptDialog);
- set_up_dialog->set_title(TTR("Set Up Version Control"));
+ set_up_dialog->set_title(TTR("Local Settings"));
set_up_dialog->set_min_size(Size2(600, 100));
+ set_up_dialog->add_cancel_button("Cancel");
set_up_dialog->set_hide_on_ok(true);
version_control_actions->add_child(set_up_dialog);
@@ -1022,18 +1032,55 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
Label *set_up_vcs_label = memnew(Label);
set_up_vcs_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- set_up_vcs_label->set_text(TTR("Version Control System"));
+ set_up_vcs_label->set_text(TTR("VCS Provider"));
set_up_hbc->add_child(set_up_vcs_label);
set_up_choice = memnew(OptionButton);
set_up_choice->set_h_size_flags(Control::SIZE_EXPAND_FILL);
set_up_hbc->add_child(set_up_choice);
- set_up_init_button = memnew(Button);
- set_up_init_button->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- set_up_init_button->set_text(TTR("Initialize"));
- set_up_init_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_initialize_vcs));
- set_up_vbc->add_child(set_up_init_button);
+ HBoxContainer *project_path_hbc = memnew(HBoxContainer);
+ project_path_hbc->set_h_size_flags(Control::SIZE_FILL);
+ set_up_vbc->add_child(project_path_hbc);
+
+ Label *project_path_label = memnew(Label);
+ project_path_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ project_path_label->set_text(TTR("VCS Project Path"));
+ project_path_hbc->add_child(project_path_label);
+
+ project_path_input = memnew(LineEdit);
+ project_path_input->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ project_path_input->set_text(OS::get_singleton()->get_resource_dir());
+ project_path_hbc->add_child(project_path_input);
+
+ FileDialog *select_project_path_file_dialog = memnew(FileDialog);
+ select_project_path_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM);
+ select_project_path_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_DIR);
+ select_project_path_file_dialog->set_show_hidden_files(true);
+ select_project_path_file_dialog->set_current_dir(OS::get_singleton()->get_resource_dir());
+ select_project_path_file_dialog->connect(SNAME("dir_selected"), callable_mp(this, &VersionControlEditorPlugin::_project_path_selected));
+ project_path_hbc->add_child(select_project_path_file_dialog);
+
+ select_project_path_button = memnew(Button);
+ select_project_path_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Folder", "EditorIcons"));
+ select_project_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(select_project_path_file_dialog));
+ select_project_path_button->set_tooltip_text(TTR("Select VCS project path"));
+ project_path_hbc->add_child(select_project_path_button);
+
+ HBoxContainer *toggle_vcs_hbc = memnew(HBoxContainer);
+ toggle_vcs_hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ set_up_vbc->add_child(toggle_vcs_hbc);
+
+ Label *toggle_vcs_label = memnew(Label);
+ toggle_vcs_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ toggle_vcs_label->set_text(TTR("Connect to VCS"));
+ toggle_vcs_hbc->add_child(toggle_vcs_label);
+
+ toggle_vcs_choice = memnew(CheckButton);
+ toggle_vcs_choice->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ toggle_vcs_choice->set_pressed_no_signal(false);
+ toggle_vcs_choice->connect(SNAME("toggled"), callable_mp(this, &VersionControlEditorPlugin::_toggle_vcs_integration));
+ toggle_vcs_hbc->add_child(toggle_vcs_choice);
set_up_vbc->add_child(memnew(HSeparator));
@@ -1109,8 +1156,8 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
Button *select_public_path_button = memnew(Button);
select_public_path_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Folder", "EditorIcons"));
- select_public_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_ssh_key_file_dialog).bind(set_up_ssh_public_key_file_dialog));
- select_public_path_button->set_tooltip(TTR("Select SSH public key path"));
+ select_public_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(set_up_ssh_public_key_file_dialog));
+ select_public_path_button->set_tooltip_text(TTR("Select SSH public key path"));
set_up_ssh_public_key_input_hbc->add_child(select_public_path_button);
HBoxContainer *set_up_ssh_private_key_input = memnew(HBoxContainer);
@@ -1143,8 +1190,8 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
Button *select_private_path_button = memnew(Button);
select_private_path_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Folder", "EditorIcons"));
- select_private_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_ssh_key_file_dialog).bind(set_up_ssh_private_key_file_dialog));
- select_private_path_button->set_tooltip(TTR("Select SSH private key path"));
+ select_private_path_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_file_dialog).bind(set_up_ssh_private_key_file_dialog));
+ select_private_path_button->set_tooltip_text(TTR("Select SSH private key path"));
set_up_ssh_private_key_input_hbc->add_child(select_private_path_button);
HBoxContainer *set_up_ssh_passphrase_input = memnew(HBoxContainer);
@@ -1195,7 +1242,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
unstage_title->add_child(refresh_button);
discard_all_button = memnew(Button);
- discard_all_button->set_tooltip(TTR("Discard all changes"));
+ discard_all_button->set_tooltip_text(TTR("Discard all changes"));
discard_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Close"), SNAME("EditorIcons")));
discard_all_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_discard_all));
discard_all_button->set_flat(true);
@@ -1204,7 +1251,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
stage_all_button = memnew(Button);
stage_all_button->set_flat(true);
stage_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons")));
- stage_all_button->set_tooltip(TTR("Stage all changes"));
+ stage_all_button->set_tooltip_text(TTR("Stage all changes"));
unstage_title->add_child(stage_all_button);
unstaged_files = memnew(Tree);
@@ -1234,7 +1281,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
unstage_all_button = memnew(Button);
unstage_all_button->set_flat(true);
unstage_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")));
- unstage_all_button->set_tooltip(TTR("Unstage all changes"));
+ unstage_all_button->set_tooltip_text(TTR("Unstage all changes"));
stage_title->add_child(unstage_all_button);
staged_files = memnew(Tree);
@@ -1291,7 +1338,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
commit_list_hbc->add_child(commit_list_label);
commit_list_size_button = memnew(OptionButton);
- commit_list_size_button->set_tooltip(TTR("Commit list size"));
+ commit_list_size_button->set_tooltip_text(TTR("Commit list size"));
commit_list_size_button->add_item("10");
commit_list_size_button->set_item_metadata(0, 10);
commit_list_size_button->add_item("20");
@@ -1322,7 +1369,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
version_commit_dock->add_child(menu_bar);
branch_select = memnew(OptionButton);
- branch_select->set_tooltip(TTR("Branches"));
+ branch_select->set_tooltip_text(TTR("Branches"));
branch_select->set_h_size_flags(Control::SIZE_EXPAND_FILL);
branch_select->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_branch_item_selected));
branch_select->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_branch_list));
@@ -1367,7 +1414,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
branch_create_hbc->add_child(branch_create_name_input);
remote_select = memnew(OptionButton);
- remote_select->set_tooltip(TTR("Remotes"));
+ remote_select->set_tooltip_text(TTR("Remotes"));
remote_select->set_h_size_flags(Control::SIZE_EXPAND_FILL);
remote_select->connect(SNAME("item_selected"), callable_mp(this, &VersionControlEditorPlugin::_remote_selected));
remote_select->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_remote_list));
@@ -1427,21 +1474,21 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
fetch_button = memnew(Button);
fetch_button->set_flat(true);
- fetch_button->set_tooltip(TTR("Fetch"));
+ fetch_button->set_tooltip_text(TTR("Fetch"));
fetch_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
fetch_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_fetch));
menu_bar->add_child(fetch_button);
pull_button = memnew(Button);
pull_button->set_flat(true);
- pull_button->set_tooltip(TTR("Pull"));
+ pull_button->set_tooltip_text(TTR("Pull"));
pull_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveDown"), SNAME("EditorIcons")));
pull_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_pull));
menu_bar->add_child(pull_button);
push_button = memnew(Button);
push_button->set_flat(true);
- push_button->set_tooltip(TTR("Push"));
+ push_button->set_tooltip_text(TTR("Push"));
push_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")));
push_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_push));
menu_bar->add_child(push_button);
diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h
index eff00343be..3340384a92 100644
--- a/editor/plugins/version_control_editor_plugin.h
+++ b/editor/plugins/version_control_editor_plugin.h
@@ -33,6 +33,7 @@
#include "editor/editor_plugin.h"
#include "editor/editor_vcs_interface.h"
+#include "scene/gui/check_button.h"
#include "scene/gui/container.h"
#include "scene/gui/file_dialog.h"
#include "scene/gui/menu_button.h"
@@ -70,8 +71,10 @@ private:
ConfirmationDialog *metadata_dialog = nullptr;
OptionButton *metadata_selection = nullptr;
AcceptDialog *set_up_dialog = nullptr;
+ CheckButton *toggle_vcs_choice = nullptr;
OptionButton *set_up_choice = nullptr;
- Button *set_up_init_button = nullptr;
+ LineEdit *project_path_input = nullptr;
+ Button *select_project_path_button = nullptr;
VBoxContainer *set_up_vbc = nullptr;
VBoxContainer *set_up_settings_vbc = nullptr;
LineEdit *set_up_username = nullptr;
@@ -137,6 +140,7 @@ private:
void _notification(int p_what);
void _initialize_vcs();
+ void _set_vcs_ui_state(bool p_enabled);
void _set_credentials();
void _ssh_public_key_selected(String p_path);
void _ssh_private_key_selected(String p_path);
@@ -146,8 +150,7 @@ private:
void _update_opened_tabs();
void _update_extra_options();
- bool _load_plugin(String p_path);
- void _set_up();
+ bool _load_plugin(String p_name, String p_project_path);
void _pull();
void _push();
@@ -188,7 +191,9 @@ private:
bool _is_staging_area_empty();
String _get_date_string_from(int64_t p_unix_timestamp, int64_t p_offset_minutes) const;
void _create_vcs_metadata_files();
- void _popup_ssh_key_file_dialog(Variant p_file_dialog_variant);
+ void _popup_file_dialog(Variant p_file_dialog_variant);
+ void _toggle_vcs_integration(bool p_toggled);
+ void _project_path_selected(String p_project_path);
friend class EditorVCSInterface;
@@ -211,4 +216,4 @@ public:
~VersionControlEditorPlugin();
};
-#endif // !VERSION_CONTROL_EDITOR_PLUGIN_H
+#endif // VERSION_CONTROL_EDITOR_PLUGIN_H