diff --git a/doc/classes/EditorVCSInterface.xml b/doc/classes/EditorVCSInterface.xml
index afe2ada220d9..f0ed094cdee0 100644
--- a/doc/classes/EditorVCSInterface.xml
+++ b/doc/classes/EditorVCSInterface.xml
@@ -4,96 +4,301 @@
Version Control System (VCS) interface which reads and writes to the local VCS in use.
- 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 GDNative 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.
+ Used by the editor to display VCS extracted information in the editor. The implementation of this API is included in VCS plugins, which are essentially GDNative plugins. These VCS plugins are scripts that are attached (on demand) to the object instance of [code]EditorVCSInterface[/code]. All the virtual functions listed below, instead of performing the task themselves, call the internally defined functions in the VCS plugins to provide a plug-n-play experience. VCS plugin is supposed to override and implement them.
-
-
-
+
+
+
+
+
- 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.
+ called to checkout a [code]branch[/code] in the VCS.
-
-
-
+
+
+
+
+
- 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.
+ This method is called to commit staged changes.
-
-
+
+
+
+
+
- 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
+ Called to discards the changes made in file present at [code]file_path[/code].
-
-
+
+
+
- Returns the project name of the VCS working directory.
+ Fetches changes from the remote. Equivalent to [code]git fetch[/code].
-
-
+
+
+
- Returns the name of the VCS if the VCS has been initialized, else return an empty string.
+ Returns an Array of available branch names.
-
-
-
+
+
+
+
+
+
+
- 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].
+ Returns an Array of Dictionary objects (see [method create_diff_file] and [method add_diff_hunks_into_diff_file]) containing the changes in a file or a commit hash. The [code]identifier[/code] can be commit hash or file path based on value of area (see [enum TreeArea]).
-
-
+
+
+
+
+
+
+
- Returns [code]true[/code] if the addon is ready to respond to function calls, else returns [code]false[/code].
+ Returns an Array of Dictionary objects, each containing a line diff between file at [code]file_path[/code] and [code]text[/code]. Returns Array of Dictionary (see [method create_diff_hunk]).
+
+
+
+
+
+
+ Returns Array of Dictionary (see [method create_status_file]) objects, each containing the status data of a modified file. Equivalent to running plain [code]git status[/code].
+
+
+
+
+
+
+ Returns Array of Dictionary (see [method create_commit]) objects, each containing the data for a past commit.
+
+
+
+
+
+
+ Virtual function to get project name or path as name.
+
+
+
+
+
+
+ Virtual function to get name of VCS plugin.
+
+
+
+
+
+
+
+
+ Called when initializing the VCS plugin from the editor. Returns whether or not the plugin was successfully initialized.
+
+
+
+
+
+
+ Returns whether the VCS plugin has been initialized.
+
+
+
+
+
+
+ Pulls changes from the remote.
+
+
+
+
+
+
+ Pushes changes to the remote.
+
+
+
+
+
+
+
+
+
+
+ Called after initializing the plugin. The plugin should save the sent account credentials for future use while performing remote operations.
-
-
+
+
+
- Returns [code]true[/code] if the VCS addon has been initialized, 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.
-
-
+
+
+
+
+
- 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].
+ Stage file present at [code]file_path[/code] to the staged area.
-
-
-
+
+
+
+
+
- Stages the file which should be committed when [method EditorVCSInterface.commit] is called. Argument should contain the absolute path.
+ Unstage file present at [code]file_path[/code] from the staged area to the unstaged area.
-
-
-
+
+
+
+
+
+
+
- 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.
+ Helper function to add a diff hunk in a diff file. Appends [code]diff_hunk[/code] at the end in [code]diff_file[/code].
+
+
+
+
+
+
+
+
+
+
+ Helper function to add a diff line in a diff hunk. Appends [code]diff_line[/code] at the end in [code]diff_hunk[/code].
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Helper function to create a [code]Dictionary[/code] for commit data.
+
+
+
+
+
+
+
+
+
+
+ Helper function to create a [code]Dictionary[/code] for diff file data.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Helper function to create a [code]Dictionary[/code] for diff hunk data in diff file.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Helper function to create a [code]Dictionary[/code] for line diff.
+
+
+
+
+
+
+
+
+
+
+
+
+ Helper function to create a [code]Dictionary[/code] used by editor to read the status of a file.
+
+
+
+
+
+
+ Returns [code]true[/code] if the addon is ready to respond to function calls, else returns [code]false[/code].
+
+
+
+
+
+
+
+
+ shows an error message while performing a VCS operation.
+
+
+
+ Emitted when the stage area is refreshed by the editor.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/editor/editor_vcs_interface.cpp b/editor/editor_vcs_interface.cpp
index eaa8f891ec10..9eff83afd3cf 100644
--- a/editor/editor_vcs_interface.cpp
+++ b/editor/editor_vcs_interface.cpp
@@ -29,134 +29,287 @@
/*************************************************************************/
#include "editor_vcs_interface.h"
+#include "editor_node.h"
EditorVCSInterface *EditorVCSInterface::singleton = nullptr;
-void EditorVCSInterface::_bind_methods() {
- // Proxy end points that act as fallbacks to unavailability of a function in the VCS addon
- ClassDB::bind_method(D_METHOD("_initialize", "project_root_path"), &EditorVCSInterface::_initialize);
- ClassDB::bind_method(D_METHOD("_is_vcs_initialized"), &EditorVCSInterface::_is_vcs_initialized);
- ClassDB::bind_method(D_METHOD("_get_vcs_name"), &EditorVCSInterface::_get_vcs_name);
- ClassDB::bind_method(D_METHOD("_shut_down"), &EditorVCSInterface::_shut_down);
- ClassDB::bind_method(D_METHOD("_get_project_name"), &EditorVCSInterface::_get_project_name);
- ClassDB::bind_method(D_METHOD("_get_modified_files_data"), &EditorVCSInterface::_get_modified_files_data);
- ClassDB::bind_method(D_METHOD("_commit", "msg"), &EditorVCSInterface::_commit);
- ClassDB::bind_method(D_METHOD("_get_file_diff", "file_path"), &EditorVCSInterface::_get_file_diff);
- ClassDB::bind_method(D_METHOD("_stage_file", "file_path"), &EditorVCSInterface::_stage_file);
- ClassDB::bind_method(D_METHOD("_unstage_file", "file_path"), &EditorVCSInterface::_unstage_file);
-
- ClassDB::bind_method(D_METHOD("is_addon_ready"), &EditorVCSInterface::is_addon_ready);
-
- // API methods that redirect calls to the proxy end points
- ClassDB::bind_method(D_METHOD("initialize", "project_root_path"), &EditorVCSInterface::initialize);
- ClassDB::bind_method(D_METHOD("is_vcs_initialized"), &EditorVCSInterface::is_vcs_initialized);
- ClassDB::bind_method(D_METHOD("get_modified_files_data"), &EditorVCSInterface::get_modified_files_data);
- ClassDB::bind_method(D_METHOD("stage_file", "file_path"), &EditorVCSInterface::stage_file);
- ClassDB::bind_method(D_METHOD("unstage_file", "file_path"), &EditorVCSInterface::unstage_file);
- ClassDB::bind_method(D_METHOD("commit", "msg"), &EditorVCSInterface::commit);
- ClassDB::bind_method(D_METHOD("get_file_diff", "file_path"), &EditorVCSInterface::get_file_diff);
- ClassDB::bind_method(D_METHOD("shut_down"), &EditorVCSInterface::shut_down);
- ClassDB::bind_method(D_METHOD("get_project_name"), &EditorVCSInterface::get_project_name);
- ClassDB::bind_method(D_METHOD("get_vcs_name"), &EditorVCSInterface::get_vcs_name);
+void EditorVCSInterface::popup_error(String p_msg) {
+ EditorNode::get_singleton()->show_warning(p_msg.strip_edges(), get_vcs_name() + TTR(" Error"));
}
-bool EditorVCSInterface::_initialize(String p_project_root_path) {
- WARN_PRINT("Selected VCS addon does not implement an initialization function. This warning will be suppressed.");
- return true;
+bool EditorVCSInterface::initialize(String p_project_path) {
+ return call("_initialize", p_project_path);
}
-bool EditorVCSInterface::_is_vcs_initialized() {
- return false;
+List EditorVCSInterface::get_remotes() {
+ List remotes;
+
+ Array result = call("_get_remotes");
+ for (int i = 0; i < result.size(); i++) {
+ remotes.push_back(result[i]);
+ }
+
+ return remotes;
}
-Dictionary EditorVCSInterface::_get_modified_files_data() {
- return Dictionary();
+List EditorVCSInterface::get_modified_files_data() {
+ List status_files;
+
+ Array result = call("_get_modified_files_data");
+ for (int i = 0; i < result.size(); i++) {
+ status_files.push_back(_convert_status_file(result[i]));
+ }
+
+ return status_files;
}
-void EditorVCSInterface::_stage_file(String p_file_path) {
+void EditorVCSInterface::stage_file(String p_file_path) {
+ call("_stage_file", p_file_path);
}
-void EditorVCSInterface::_unstage_file(String p_file_path) {
+void EditorVCSInterface::unstage_file(String p_file_path) {
+ call("_unstage_file", p_file_path);
}
-void EditorVCSInterface::_commit(String p_msg) {
+void EditorVCSInterface::discard_file(String p_file_path) {
+ call("_discard_file", p_file_path);
}
-Array EditorVCSInterface::_get_file_diff(String p_file_path) {
- return Array();
+void EditorVCSInterface::commit(String p_msg) {
+ call("_commit", p_msg);
}
-bool EditorVCSInterface::_shut_down() {
- return false;
+List EditorVCSInterface::get_diff(String p_identifier, TreeArea p_area) {
+ List diff_files;
+
+ Array result = call("_get_diff", p_identifier, p_area);
+ for (int i = 0; i < result.size(); i++) {
+ diff_files.push_back(_convert_diff_file(result[i]));
+ }
+
+ return diff_files;
}
-String EditorVCSInterface::_get_project_name() {
- return String();
+List EditorVCSInterface::get_previous_commits(int p_max_commits) {
+ List commits;
+
+ Array result = call("_get_previous_commits", p_max_commits);
+ for (int i = 0; i < result.size(); i++) {
+ commits.push_back(_convert_commit(result[i]));
+ }
+
+ return commits;
}
-String EditorVCSInterface::_get_vcs_name() {
- return "";
+List EditorVCSInterface::get_branch_list() {
+ List branch_list;
+
+ Array result = call("_get_branch_list");
+ for (int i = 0; i < result.size(); i++) {
+ branch_list.push_back(result[i]);
+ }
+
+ return branch_list;
}
-bool EditorVCSInterface::initialize(String p_project_root_path) {
- is_initialized = call("_initialize", p_project_root_path);
- return is_initialized;
+void EditorVCSInterface::create_branch(String p_branch_name) {
+ call("_create_branch", p_branch_name);
}
-bool EditorVCSInterface::is_vcs_initialized() {
- return call("_is_vcs_initialized");
+void EditorVCSInterface::create_remote(String p_remote_name, String p_remote_url) {
+ call("_create_remote", p_remote_name, p_remote_url);
}
-Dictionary EditorVCSInterface::get_modified_files_data() {
- return call("_get_modified_files_data");
+String EditorVCSInterface::get_current_branch_name() {
+ return call("_get_current_branch_name");
}
-void EditorVCSInterface::stage_file(String p_file_path) {
- if (is_addon_ready()) {
- call("_stage_file", p_file_path);
- }
+bool EditorVCSInterface::checkout_branch(String p_branch_name) {
+ return call("_checkout_branch", p_branch_name);
}
-void EditorVCSInterface::unstage_file(String p_file_path) {
- if (is_addon_ready()) {
- call("_unstage_file", p_file_path);
- }
+void EditorVCSInterface::pull(String p_remote, String p_username, String p_password) {
+ call("_pull", p_remote, p_username, p_password);
}
-bool EditorVCSInterface::is_addon_ready() {
- return is_initialized;
+void EditorVCSInterface::push(String p_remote, String p_username, String p_password, bool p_force) {
+ call("_push", p_remote, p_username, p_password, p_force);
}
-void EditorVCSInterface::commit(String p_msg) {
- if (is_addon_ready()) {
- call("_commit", p_msg);
- }
+void EditorVCSInterface::fetch(String p_remote, String p_username, String p_password) {
+ call("_fetch", p_remote, p_username, p_password);
}
-Array EditorVCSInterface::get_file_diff(String p_file_path) {
- if (is_addon_ready()) {
- return call("_get_file_diff", p_file_path);
+List EditorVCSInterface::get_line_diff(String p_file_path, String p_text) {
+ List diff_hunks;
+
+ Array result = call("_get_line_diff", p_file_path, p_text);
+ for (int i = 0; i < result.size(); i++) {
+ diff_hunks.push_back(_convert_diff_hunk(result[i]));
}
- return Array();
+
+ return diff_hunks;
}
bool EditorVCSInterface::shut_down() {
return call("_shut_down");
}
-String EditorVCSInterface::get_project_name() {
- return call("_get_project_name");
-}
-
String EditorVCSInterface::get_vcs_name() {
return call("_get_vcs_name");
}
-EditorVCSInterface::EditorVCSInterface() {
- is_initialized = false;
+Dictionary EditorVCSInterface::create_diff_line(int p_new_line_no, int p_old_line_no, String p_content, String p_status) {
+ Dictionary diff_line;
+ diff_line["new_line_no"] = p_new_line_no;
+ diff_line["old_line_no"] = p_old_line_no;
+ diff_line["content"] = p_content;
+ diff_line["status"] = p_status;
+
+ return diff_line;
+}
+
+Dictionary EditorVCSInterface::create_diff_hunk(int p_old_start, int p_new_start, int p_old_lines, int p_new_lines) {
+ Dictionary diff_hunk;
+ diff_hunk["new_lines"] = p_new_lines;
+ diff_hunk["old_lines"] = p_old_lines;
+ diff_hunk["new_start"] = p_new_start;
+ diff_hunk["old_start"] = p_old_start;
+ diff_hunk["diff_lines"] = Array();
+ return diff_hunk;
+}
+
+Dictionary EditorVCSInterface::add_line_diffs_into_diff_hunk(Dictionary p_diff_hunk, Array p_line_diffs) {
+ p_diff_hunk["diff_lines"] = p_line_diffs;
+ return p_diff_hunk;
+}
+
+Dictionary EditorVCSInterface::create_diff_file(String p_new_file, String p_old_file) {
+ Dictionary file_diff;
+ file_diff["new_file"] = p_new_file;
+ file_diff["old_file"] = p_old_file;
+ file_diff["diff_hunks"] = Array();
+ return file_diff;
+}
+
+Dictionary EditorVCSInterface::create_commit(String p_msg, String p_author, String p_id, String p_date) {
+ Dictionary commit_info;
+ commit_info["message"] = p_msg;
+ commit_info["author"] = p_author;
+ commit_info["date"] = p_date;
+ commit_info["id"] = p_id;
+ return commit_info;
+}
+
+Dictionary EditorVCSInterface::add_diff_hunks_into_diff_file(Dictionary p_diff_file, Array p_diff_hunks) {
+ p_diff_file["diff_hunks"] = p_diff_hunks;
+ return p_diff_file;
+}
+
+Dictionary EditorVCSInterface::create_status_file(String p_file_path, ChangeType p_change, TreeArea p_area) {
+ Dictionary sf;
+ sf["file_path"] = p_file_path;
+ sf["change_type"] = p_change;
+ sf["area"] = p_area;
+ return sf;
+}
+
+EditorVCSInterface::DiffLine EditorVCSInterface::_convert_diff_line(Dictionary p_diff_line) {
+ DiffLine d;
+ d.new_line_no = p_diff_line["new_line_no"];
+ d.old_line_no = p_diff_line["old_line_no"];
+ d.content = p_diff_line["content"];
+ d.status = p_diff_line["status"];
+ return d;
}
-EditorVCSInterface::~EditorVCSInterface() {
+EditorVCSInterface::DiffHunk EditorVCSInterface::_convert_diff_hunk(Dictionary p_diff_hunk) {
+ DiffHunk dh;
+ dh.new_lines = p_diff_hunk["new_lines"];
+ dh.old_lines = p_diff_hunk["old_lines"];
+ dh.new_start = p_diff_hunk["new_start"];
+ dh.old_start = p_diff_hunk["old_start"];
+ Array diff_lines = p_diff_hunk["diff_lines"];
+ for (int i = 0; i < diff_lines.size(); i++) {
+ DiffLine dl = _convert_diff_line(diff_lines[i]);
+ dh.diff_lines.push_back(dl);
+ }
+ return dh;
+}
+
+EditorVCSInterface::DiffFile EditorVCSInterface::_convert_diff_file(Dictionary p_diff_file) {
+ DiffFile df;
+ df.new_file = p_diff_file["new_file"];
+ df.old_file = p_diff_file["old_file"];
+ Array diff_hunks = p_diff_file["diff_hunks"];
+ for (int i = 0; i < diff_hunks.size(); i++) {
+ DiffHunk dh = _convert_diff_hunk(diff_hunks[i]);
+ df.diff_hunks.push_back(dh);
+ }
+ return df;
+}
+
+EditorVCSInterface::Commit EditorVCSInterface::_convert_commit(Dictionary p_commit) {
+ EditorVCSInterface::Commit c;
+ c.msg = p_commit["message"];
+ c.author = p_commit["author"];
+ c.date = p_commit["date"];
+ c.id = p_commit["id"];
+ return c;
+}
+
+EditorVCSInterface::StatusFile EditorVCSInterface::_convert_status_file(Dictionary p_status_file) {
+ StatusFile sf;
+ sf.file_path = p_status_file["file_path"];
+ sf.change_type = (ChangeType)(int)p_status_file["change_type"];
+ sf.area = (TreeArea)(int)p_status_file["area"];
+ return sf;
+}
+
+void EditorVCSInterface::_bind_methods() {
+ // Proxy end points that implement the VCS specific operations that the editor demands
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "_initialize", PropertyInfo(Variant::STRING, "project_path")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::ARRAY, "_get_remotes"));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "_get_vcs_name"));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "_shut_down"));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::ARRAY, "_get_modified_files_data"));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo("_commit", PropertyInfo(Variant::STRING, "msg")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::ARRAY, "_get_diff", PropertyInfo(Variant::STRING, "identifier"), PropertyInfo(Variant::INT, "area")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo("_stage_file", PropertyInfo(Variant::STRING, "file_path")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo("_unstage_file", PropertyInfo(Variant::STRING, "file_path")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo("_discard_file", PropertyInfo(Variant::STRING, "file_path")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::ARRAY, "_get_previous_commits", PropertyInfo(Variant::INT, "max_commits")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::ARRAY, "_get_branch_list"));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo("_create_branch", PropertyInfo(Variant::STRING, "branch_name")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo("_create_remote", PropertyInfo(Variant::STRING, "remote_name"), PropertyInfo(Variant::STRING, "remote_url")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "_get_current_branch_name"));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "_checkout_branch", PropertyInfo(Variant::STRING, "branch_name")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo("_push", PropertyInfo(Variant::STRING, "remote"), PropertyInfo(Variant::STRING, "username"), PropertyInfo(Variant::STRING, "password"), PropertyInfo(Variant::BOOL, "force")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo("_pull", PropertyInfo(Variant::STRING, "remote"), PropertyInfo(Variant::STRING, "username"), PropertyInfo(Variant::STRING, "password")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo("_fetch", PropertyInfo(Variant::STRING, "remote"), PropertyInfo(Variant::STRING, "username"), PropertyInfo(Variant::STRING, "password")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::ARRAY, "_get_line_diff", PropertyInfo(Variant::STRING, "file_path"), PropertyInfo(Variant::STRING, "text")));
+
+ ClassDB::bind_method(D_METHOD("create_diff_line", "new_line_no", "old_line_no", "content", "status"), &EditorVCSInterface::create_diff_line);
+ ClassDB::bind_method(D_METHOD("create_diff_hunk", "old_start", "new_start", "old_lines", "new_lines"), &EditorVCSInterface::create_diff_hunk);
+ ClassDB::bind_method(D_METHOD("create_diff_file", "new_file", "old_file"), &EditorVCSInterface::create_diff_file);
+ ClassDB::bind_method(D_METHOD("create_commit", "msg", "author", "id", "date"), &EditorVCSInterface::create_commit);
+ ClassDB::bind_method(D_METHOD("create_status_file", "file_path", "change_type", "area"), &EditorVCSInterface::create_status_file);
+ ClassDB::bind_method(D_METHOD("add_diff_hunks_into_diff_file", "diff_hunk", "line_diffs"), &EditorVCSInterface::add_diff_hunks_into_diff_file);
+ ClassDB::bind_method(D_METHOD("add_line_diffs_into_diff_hunk", "diff_files", "diff_hunks"), &EditorVCSInterface::add_line_diffs_into_diff_hunk);
+ ClassDB::bind_method(D_METHOD("popup_error", "msg"), &EditorVCSInterface::popup_error);
+
+ ADD_SIGNAL(MethodInfo("stage_area_refreshed"));
+
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_NEW);
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_MODIFIED);
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_RENAMED);
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_DELETED);
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_TYPECHANGE);
+ BIND_ENUM_CONSTANT(CHANGE_TYPE_UNMERGED);
+
+ BIND_ENUM_CONSTANT(TREE_AREA_COMMIT);
+ BIND_ENUM_CONSTANT(TREE_AREA_STAGED);
+ BIND_ENUM_CONSTANT(TREE_AREA_UNSTAGED);
}
EditorVCSInterface *EditorVCSInterface::get_singleton() {
diff --git a/editor/editor_vcs_interface.h b/editor/editor_vcs_interface.h
index 7c1388c0932a..aba15d23a7d0 100644
--- a/editor/editor_vcs_interface.h
+++ b/editor/editor_vcs_interface.h
@@ -38,45 +38,109 @@
class EditorVCSInterface : public Object {
GDCLASS(EditorVCSInterface, Object)
- bool is_initialized;
+public:
+ enum ChangeType {
+ CHANGE_TYPE_NEW = 0,
+ CHANGE_TYPE_MODIFIED = 1,
+ CHANGE_TYPE_RENAMED = 2,
+ CHANGE_TYPE_DELETED = 3,
+ CHANGE_TYPE_TYPECHANGE = 4,
+ CHANGE_TYPE_UNMERGED = 5
+ };
+
+ enum TreeArea {
+ TREE_AREA_COMMIT = 0,
+ TREE_AREA_STAGED = 1,
+ TREE_AREA_UNSTAGED = 2
+ };
+
+ struct DiffLine {
+ int new_line_no;
+ int old_line_no;
+ String content;
+ String status;
+
+ String old_text;
+ String new_text;
+ };
+
+ struct DiffHunk {
+ int new_start;
+ int old_start;
+ int new_lines;
+ int old_lines;
+ List diff_lines;
+ };
+
+ struct DiffFile {
+ String new_file;
+ String old_file;
+ List diff_hunks;
+ };
+
+ struct Commit {
+ String author;
+ String msg;
+ String id;
+ String date;
+ };
+
+ struct StatusFile {
+ TreeArea area;
+ ChangeType change_type;
+ String file_path;
+ };
protected:
static EditorVCSInterface *singleton;
static void _bind_methods();
- // Implemented by addons as end points for the proxy functions
- virtual bool _initialize(String p_project_root_path);
- virtual bool _is_vcs_initialized();
- virtual Dictionary _get_modified_files_data();
- virtual void _stage_file(String p_file_path);
- virtual void _unstage_file(String p_file_path);
- virtual void _commit(String p_msg);
- virtual Array _get_file_diff(String p_file_path);
- virtual bool _shut_down();
- virtual String _get_project_name();
- virtual String _get_vcs_name();
+ DiffLine _convert_diff_line(Dictionary p_diff_line);
+ DiffHunk _convert_diff_hunk(Dictionary p_diff_hunk);
+ DiffFile _convert_diff_file(Dictionary p_diff_file);
+ Commit _convert_commit(Dictionary p_commit);
+ StatusFile _convert_status_file(Dictionary p_status_file);
public:
static EditorVCSInterface *get_singleton();
static void set_singleton(EditorVCSInterface *p_singleton);
- bool is_addon_ready();
-
// Proxy functions to the editor for use
- bool initialize(String p_project_root_path);
- bool is_vcs_initialized();
- Dictionary get_modified_files_data();
+ bool initialize(String p_project_path);
+ List get_modified_files_data();
void stage_file(String p_file_path);
void unstage_file(String p_file_path);
+ void discard_file(String p_file_path);
void commit(String p_msg);
- Array get_file_diff(String p_file_path);
+ List get_diff(String p_identifier, TreeArea p_area);
bool shut_down();
- String get_project_name();
String get_vcs_name();
+ List get_previous_commits(int p_max_commits);
+ List get_branch_list();
+ List get_remotes();
+ void create_branch(String p_branch_name);
+ void create_remote(String p_remote_name, String p_remote_url);
+ String get_current_branch_name();
+ bool checkout_branch(String p_branch_name);
+ void pull(String p_remote, String p_username, String p_password);
+ void push(String p_remote, String p_username, String p_password, bool p_force);
+ void fetch(String p_remote, String p_username, String p_password);
+ List get_line_diff(String p_file_path, String p_text);
- EditorVCSInterface();
- virtual ~EditorVCSInterface();
+ // Helper functions to create and convert Dictionary into data structures
+ Dictionary create_diff_line(int p_new_line_no, int p_old_line_no, String p_content, String p_status);
+ Dictionary create_diff_hunk(int p_old_start, int p_new_start, int p_old_lines, int p_new_lines);
+ Dictionary create_diff_file(String p_new_file, String p_old_file);
+ Dictionary create_commit(String p_msg, String p_author, String p_id, String p_date);
+ Dictionary create_status_file(String p_file_path, ChangeType p_change, TreeArea p_area);
+ Dictionary add_line_diffs_into_diff_hunk(Dictionary p_diff_hunk, Array p_line_diffs);
+ Dictionary add_diff_hunks_into_diff_file(Dictionary p_diff_file, Array p_diff_hunks);
+
+ void popup_error(String p_msg);
};
+VARIANT_ENUM_CAST(EditorVCSInterface::ChangeType);
+VARIANT_ENUM_CAST(EditorVCSInterface::TreeArea);
+
#endif // !EDITOR_VCS_INTERFACE_H
diff --git a/editor/icons/icon_open.svg b/editor/icons/icon_open.svg
new file mode 100644
index 000000000000..8cdcb1dc6eb5
--- /dev/null
+++ b/editor/icons/icon_open.svg
@@ -0,0 +1 @@
+
diff --git a/editor/icons/icon_refresh.svg b/editor/icons/icon_refresh.svg
new file mode 100644
index 000000000000..fb959f92cd4b
--- /dev/null
+++ b/editor/icons/icon_refresh.svg
@@ -0,0 +1 @@
+
diff --git a/editor/icons/icon_undo.svg b/editor/icons/icon_undo.svg
new file mode 100644
index 000000000000..bc100a555572
--- /dev/null
+++ b/editor/icons/icon_undo.svg
@@ -0,0 +1 @@
+
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 8833f4e8fcbb..e73ae59bbd34 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -719,7 +719,7 @@ void ScriptEditor::_resave_scripts(const String &p_str) {
disk_changed->hide();
}
-void ScriptEditor::_reload_scripts() {
+void ScriptEditor::reload_scripts() {
for (int i = 0; i < tab_container->get_child_count(); i++) {
ScriptEditorBase *se = Object::cast_to(tab_container->get_child(i));
if (!se) {
@@ -835,7 +835,7 @@ bool ScriptEditor::_test_script_times_on_disk(RES p_for_script) {
if (need_reload) {
if (!need_ask) {
- script_editor->_reload_scripts();
+ script_editor->reload_scripts();
need_reload = false;
} else {
disk_changed->call_deferred("popup_centered_ratio", 0.5);
@@ -3072,7 +3072,6 @@ void ScriptEditor::_bind_methods() {
ClassDB::bind_method("_editor_pause", &ScriptEditor::_editor_pause);
ClassDB::bind_method("_editor_stop", &ScriptEditor::_editor_stop);
ClassDB::bind_method("_add_callback", &ScriptEditor::_add_callback);
- ClassDB::bind_method("_reload_scripts", &ScriptEditor::_reload_scripts);
ClassDB::bind_method("_resave_scripts", &ScriptEditor::_resave_scripts);
ClassDB::bind_method("_res_saved_callback", &ScriptEditor::_res_saved_callback);
ClassDB::bind_method("_goto_script_line", &ScriptEditor::_goto_script_line);
@@ -3125,6 +3124,7 @@ void ScriptEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_current_script"), &ScriptEditor::_get_current_script);
ClassDB::bind_method(D_METHOD("get_open_scripts"), &ScriptEditor::_get_open_scripts);
ClassDB::bind_method(D_METHOD("open_script_create_dialog", "base_name", "base_path"), &ScriptEditor::open_script_create_dialog);
+ ClassDB::bind_method(D_METHOD("reload_scripts"), &ScriptEditor::reload_scripts);
ADD_SIGNAL(MethodInfo("editor_script_changed", PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script")));
ADD_SIGNAL(MethodInfo("script_close", PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script")));
@@ -3402,7 +3402,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
vbc->add_child(disk_changed_list);
disk_changed_list->set_v_size_flags(SIZE_EXPAND_FILL);
- disk_changed->connect("confirmed", this, "_reload_scripts");
+ disk_changed->connect("confirmed", this, "reload_scripts");
disk_changed->get_ok()->set_text(TTR("Reload"));
disk_changed->add_button(TTR("Resave"), !OS::get_singleton()->get_swap_ok_cancel(), "resave");
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 440d49b22133..c60ddec5fcab 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -278,7 +278,6 @@ class ScriptEditor : public PanelContainer {
String _get_debug_tooltip(const String &p_text, Node *_se);
void _resave_scripts(const String &p_str);
- void _reload_scripts();
bool _test_script_times_on_disk(RES p_for_script = Ref());
@@ -423,6 +422,7 @@ class ScriptEditor : public PanelContainer {
void ensure_focus_current();
void apply_scripts() const;
void open_script_create_dialog(const String &p_base_name, const String &p_base_path);
+ void reload_scripts();
void ensure_select_current();
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index b4631e98bf3d..2ef95513e4ad 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -30,47 +30,70 @@
#include "version_control_editor_plugin.h"
+#include "core/bind/core_bind.h"
#include "core/os/keyboard.h"
#include "core/script_language.h"
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/filesystem_dock.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.");
VersionControlEditorPlugin *VersionControlEditorPlugin::singleton = nullptr;
void VersionControlEditorPlugin::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_selected_a_vcs"), &VersionControlEditorPlugin::_selected_a_vcs);
ClassDB::bind_method(D_METHOD("_initialize_vcs"), &VersionControlEditorPlugin::_initialize_vcs);
- ClassDB::bind_method(D_METHOD("_send_commit_msg"), &VersionControlEditorPlugin::_send_commit_msg);
+ ClassDB::bind_method(D_METHOD("_update_set_up_warning"), &VersionControlEditorPlugin::_update_set_up_warning);
+ ClassDB::bind_method(D_METHOD("_commit"), &VersionControlEditorPlugin::_commit);
ClassDB::bind_method(D_METHOD("_refresh_stage_area"), &VersionControlEditorPlugin::_refresh_stage_area);
- ClassDB::bind_method(D_METHOD("_stage_all"), &VersionControlEditorPlugin::_stage_all);
- ClassDB::bind_method(D_METHOD("_stage_selected"), &VersionControlEditorPlugin::_stage_selected);
- ClassDB::bind_method(D_METHOD("_view_file_diff"), &VersionControlEditorPlugin::_view_file_diff);
- ClassDB::bind_method(D_METHOD("_refresh_file_diff"), &VersionControlEditorPlugin::_refresh_file_diff);
+ ClassDB::bind_method(D_METHOD("_move_all"), &VersionControlEditorPlugin::_move_all);
+ ClassDB::bind_method(D_METHOD("_load_diff"), &VersionControlEditorPlugin::_load_diff);
+ ClassDB::bind_method(D_METHOD("_display_diff"), &VersionControlEditorPlugin::_display_diff);
+ ClassDB::bind_method(D_METHOD("_item_activated"), &VersionControlEditorPlugin::_item_activated);
+ ClassDB::bind_method(D_METHOD("_update_branch_create_button"), &VersionControlEditorPlugin::_update_branch_create_button);
+ ClassDB::bind_method(D_METHOD("_update_remote_create_button"), &VersionControlEditorPlugin::_update_remote_create_button);
ClassDB::bind_method(D_METHOD("_update_commit_button"), &VersionControlEditorPlugin::_update_commit_button);
+ ClassDB::bind_method(D_METHOD("_refresh_branch_list"), &VersionControlEditorPlugin::_refresh_branch_list);
+ ClassDB::bind_method(D_METHOD("_refresh_commit_list"), &VersionControlEditorPlugin::_refresh_commit_list);
+ ClassDB::bind_method(D_METHOD("_refresh_remote_list"), &VersionControlEditorPlugin::_refresh_remote_list);
ClassDB::bind_method(D_METHOD("_commit_message_gui_input"), &VersionControlEditorPlugin::_commit_message_gui_input);
- ClassDB::bind_method(D_METHOD("popup_vcs_set_up_dialog"), &VersionControlEditorPlugin::popup_vcs_set_up_dialog);
+ ClassDB::bind_method(D_METHOD("_cell_button_pressed"), &VersionControlEditorPlugin::_cell_button_pressed);
+ ClassDB::bind_method(D_METHOD("_discard_all"), &VersionControlEditorPlugin::_discard_all);
+ ClassDB::bind_method(D_METHOD("_create_branch"), &VersionControlEditorPlugin::_create_branch);
+ ClassDB::bind_method(D_METHOD("_create_remote"), &VersionControlEditorPlugin::_create_remote);
+ ClassDB::bind_method(D_METHOD("_branch_item_selected"), &VersionControlEditorPlugin::_branch_item_selected);
+ ClassDB::bind_method(D_METHOD("_remote_selected"), &VersionControlEditorPlugin::_remote_selected);
+ ClassDB::bind_method(D_METHOD("_popup_create_branch"), &VersionControlEditorPlugin::_popup_create_branch);
+ ClassDB::bind_method(D_METHOD("_popup_create_remote"), &VersionControlEditorPlugin::_popup_create_remote);
+ ClassDB::bind_method(D_METHOD("_fetch"), &VersionControlEditorPlugin::_fetch);
+ ClassDB::bind_method(D_METHOD("_pull"), &VersionControlEditorPlugin::_pull);
+ ClassDB::bind_method(D_METHOD("_push"), &VersionControlEditorPlugin::_push);
- // Used to track the status of files in the staging area
- BIND_ENUM_CONSTANT(CHANGE_TYPE_NEW);
- BIND_ENUM_CONSTANT(CHANGE_TYPE_MODIFIED);
- BIND_ENUM_CONSTANT(CHANGE_TYPE_RENAMED);
- BIND_ENUM_CONSTANT(CHANGE_TYPE_DELETED);
- BIND_ENUM_CONSTANT(CHANGE_TYPE_TYPECHANGE);
+ ClassDB::bind_method(D_METHOD("popup_vcs_set_up_dialog"), &VersionControlEditorPlugin::popup_vcs_set_up_dialog);
}
-void VersionControlEditorPlugin::_selected_a_vcs(int p_id) {
- List available_addons = get_available_vcs_names();
- const StringName selected_vcs = set_up_choice->get_item_text(p_id);
+void VersionControlEditorPlugin::_notification(int p_what) {
+ if (p_what == NOTIFICATION_READY) {
+ String installed_plugin = GLOBAL_GET("version_control/plugin_name");
+ bool has_autoload_enable = GLOBAL_GET("version_control/autoload_on_startup");
+
+ if (installed_plugin != "" && has_autoload_enable) {
+ if (_load_plugin(installed_plugin)) {
+ _set_up();
+ }
+ }
+ }
}
void VersionControlEditorPlugin::_populate_available_vcs_names() {
static bool called = false;
if (!called) {
- List available_addons = get_available_vcs_names();
- for (int i = 0; i < available_addons.size(); i++) {
- set_up_choice->add_item(available_addons[i]);
+ List available_plugins = get_available_vcs_names();
+ for (int i = 0; i < available_plugins.size(); i++) {
+ set_up_choice->add_item(available_plugins[i]);
}
called = true;
@@ -82,9 +105,9 @@ VersionControlEditorPlugin *VersionControlEditorPlugin::get_singleton() {
}
void VersionControlEditorPlugin::popup_vcs_set_up_dialog(const Control *p_gui_base) {
- fetch_available_vcs_addon_names();
- List available_addons = get_available_vcs_names();
- if (available_addons.size() >= 1) {
+ fetch_available_vcs_plugin_names();
+ List available_plugins = get_available_vcs_names();
+ if (available_plugins.size() >= 1) {
Size2 popup_size = Size2(400, 100);
Size2 window_size = p_gui_base->get_viewport_rect().size;
popup_size.x = MIN(window_size.x * 0.5, popup_size.x);
@@ -94,213 +117,678 @@ 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 addons are available."), TTR("Error"));
+ EditorNode::get_singleton()->show_warning(TTR("No VCS plugins are available."), TTR("Error"));
}
}
void VersionControlEditorPlugin::_initialize_vcs() {
- register_editor();
-
- ERR_FAIL_COND_MSG(EditorVCSInterface::get_singleton(), EditorVCSInterface::get_singleton()->get_vcs_name() + " is already active");
+ ERR_FAIL_COND_MSG(EditorVCSInterface::get_singleton(), EditorVCSInterface::get_singleton()->get_vcs_name() + " is already active.");
const int id = set_up_choice->get_selected_id();
- String selected_addon = set_up_choice->get_item_text(id);
+ String selected_plugin = set_up_choice->get_item_text(id);
+
+ if (_load_plugin(selected_plugin)) {
+ _set_up();
+ ProjectSettings::get_singleton()->set("version_control/autoload_on_startup", true);
+ ProjectSettings::get_singleton()->set("version_control/plugin_name", selected_plugin);
+ ProjectSettings::get_singleton()->save();
+ }
+}
- String path = ScriptServer::get_global_class_path(selected_addon);
+bool VersionControlEditorPlugin::_load_plugin(String p_name) {
+ String path = ScriptServer::get_global_class_path(p_name);
Ref