summaryrefslogtreecommitdiffstats
path: root/editor/plugins/script_editor_plugin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins/script_editor_plugin.cpp')
-rw-r--r--editor/plugins/script_editor_plugin.cpp389
1 files changed, 257 insertions, 132 deletions
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index d457906d0c..2f479527f3 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -38,6 +38,7 @@
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/version.h"
+#include "editor/code_editor.h"
#include "editor/debugger/editor_debugger_node.h"
#include "editor/debugger/script_editor_debugger.h"
#include "editor/editor_command_palette.h"
@@ -45,12 +46,12 @@
#include "editor/editor_interface.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
-#include "editor/editor_scale.h"
#include "editor/editor_script.h"
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"
#include "editor/filesystem_dock.h"
#include "editor/find_in_files.h"
+#include "editor/gui/editor_bottom_panel.h"
#include "editor/gui/editor_file_dialog.h"
#include "editor/gui/editor_run_bar.h"
#include "editor/gui/editor_toaster.h"
@@ -58,6 +59,8 @@
#include "editor/node_dock.h"
#include "editor/plugins/shader_editor_plugin.h"
#include "editor/plugins/text_shader_editor.h"
+#include "editor/themes/editor_scale.h"
+#include "editor/themes/editor_theme_manager.h"
#include "editor/window_wrapper.h"
#include "scene/main/node.h"
#include "scene/main/window.h"
@@ -134,12 +137,22 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
}
}
- const Ref<Script> scr = _get_edited_resource();
- if (scr.is_valid()) {
+ const ScriptLanguage *scr_lang = script_language;
+ StringName instance_base;
+
+ if (scr_lang == nullptr) {
+ const Ref<Script> scr = _get_edited_resource();
+ if (scr.is_valid()) {
+ scr_lang = scr->get_language();
+ instance_base = scr->get_instance_base_type();
+ }
+ }
+
+ if (scr_lang != nullptr) {
/* Core types. */
const Color basetype_color = EDITOR_GET("text_editor/theme/highlighting/base_type_color");
List<String> core_types;
- scr->get_language()->get_core_type_words(&core_types);
+ scr_lang->get_core_type_words(&core_types);
for (const String &E : core_types) {
highlighter->add_keyword_color(E, basetype_color);
}
@@ -148,9 +161,9 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
const Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");
const Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color");
List<String> keywords;
- scr->get_language()->get_reserved_words(&keywords);
+ scr_lang->get_reserved_words(&keywords);
for (const String &E : keywords) {
- if (scr->get_language()->is_control_flow_keyword(E)) {
+ if (scr_lang->is_control_flow_keyword(E)) {
highlighter->add_keyword_color(E, control_flow_keyword_color);
} else {
highlighter->add_keyword_color(E, keyword_color);
@@ -159,7 +172,6 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
/* Member types. */
const Color member_variable_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color");
- StringName instance_base = scr->get_instance_base_type();
if (instance_base != StringName()) {
List<PropertyInfo> plist;
ClassDB::get_property_list(instance_base, &plist);
@@ -184,17 +196,27 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
/* Comments */
const Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
List<String> comments;
- scr->get_language()->get_comment_delimiters(&comments);
+ scr_lang->get_comment_delimiters(&comments);
for (const String &comment : comments) {
String beg = comment.get_slice(" ", 0);
String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String();
highlighter->add_color_region(beg, end, comment_color, end.is_empty());
}
+ /* Doc comments */
+ const Color doc_comment_color = EDITOR_GET("text_editor/theme/highlighting/doc_comment_color");
+ List<String> doc_comments;
+ scr_lang->get_doc_comment_delimiters(&doc_comments);
+ for (const String &doc_comment : doc_comments) {
+ String beg = doc_comment.get_slice(" ", 0);
+ String end = doc_comment.get_slice_count(" ") > 1 ? doc_comment.get_slice(" ", 1) : String();
+ highlighter->add_color_region(beg, end, doc_comment_color, end.is_empty());
+ }
+
/* Strings */
const Color string_color = EDITOR_GET("text_editor/theme/highlighting/string_color");
List<String> strings;
- scr->get_language()->get_string_delimiters(&strings);
+ scr_lang->get_string_delimiters(&strings);
for (const String &string : strings) {
String beg = string.get_slice(" ", 0);
String end = string.get_slice_count(" ") > 1 ? string.get_slice(" ", 1) : String();
@@ -251,6 +273,7 @@ void ScriptEditorBase::_bind_methods() {
ADD_SIGNAL(MethodInfo("request_help", PropertyInfo(Variant::STRING, "topic")));
ADD_SIGNAL(MethodInfo("request_open_script_at_line", PropertyInfo(Variant::OBJECT, "script"), PropertyInfo(Variant::INT, "line")));
ADD_SIGNAL(MethodInfo("request_save_history"));
+ ADD_SIGNAL(MethodInfo("request_save_previous_state", PropertyInfo(Variant::INT, "line")));
ADD_SIGNAL(MethodInfo("go_to_help", PropertyInfo(Variant::STRING, "what")));
ADD_SIGNAL(MethodInfo("search_in_files_requested", PropertyInfo(Variant::STRING, "text")));
ADD_SIGNAL(MethodInfo("replace_in_files_requested", PropertyInfo(Variant::STRING, "text")));
@@ -410,6 +433,7 @@ ScriptEditorQuickOpen::ScriptEditorQuickOpen() {
register_text_enter(search_box);
set_hide_on_ok(false);
search_options->connect("item_activated", callable_mp(this, &ScriptEditorQuickOpen::_confirmed));
+ search_options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
search_options->set_hide_root(true);
search_options->set_hide_folding(true);
search_options->add_theme_constant_override("draw_guides", 1);
@@ -423,7 +447,11 @@ ScriptEditor *ScriptEditor::script_editor = nullptr;
String ScriptEditor::_get_debug_tooltip(const String &p_text, Node *_se) {
String val = EditorDebuggerNode::get_singleton()->get_var_value(p_text);
+ const int display_limit = 300;
if (!val.is_empty()) {
+ if (val.size() > display_limit) {
+ val = val.left(display_limit) + " [...] truncated!";
+ }
return p_text + ": " + val;
} else {
return String();
@@ -431,7 +459,7 @@ String ScriptEditor::_get_debug_tooltip(const String &p_text, Node *_se) {
}
void ScriptEditor::_breaked(bool p_breaked, bool p_can_debug) {
- if (bool(EDITOR_GET("text_editor/external/use_external_editor"))) {
+ if (external_editor_active) {
return;
}
@@ -534,7 +562,7 @@ void ScriptEditor::_set_breakpoint(Ref<RefCounted> p_script, int p_line, bool p_
}
state["breakpoints"] = breakpoints;
script_editor_cache->set_value(scr->get_path(), "state", state);
- EditorDebuggerNode::get_singleton()->set_breakpoint(scr->get_path(), p_line + 1, false);
+ EditorDebuggerNode::get_singleton()->set_breakpoint(scr->get_path(), p_line + 1, p_enabled);
}
}
@@ -612,6 +640,32 @@ void ScriptEditor::_save_history() {
_update_history_arrows();
}
+void ScriptEditor::_save_previous_state(Dictionary p_state) {
+ if (lock_history) {
+ // Done as a result of a deferred call triggered by set_edit_state().
+ lock_history = false;
+ return;
+ }
+
+ if (history_pos >= 0 && history_pos < history.size() && history[history_pos].control == tab_container->get_current_tab_control()) {
+ Node *n = tab_container->get_current_tab_control();
+
+ if (Object::cast_to<ScriptTextEditor>(n)) {
+ history.write[history_pos].state = p_state;
+ }
+ }
+
+ history.resize(history_pos + 1);
+ ScriptHistory sh;
+ sh.control = tab_container->get_current_tab_control();
+ sh.state = Variant();
+
+ history.push_back(sh);
+ history_pos++;
+
+ _update_history_arrows();
+}
+
void ScriptEditor::_go_to_tab(int p_idx) {
ScriptEditorBase *current = _get_current_editor();
if (current) {
@@ -641,8 +695,10 @@ void ScriptEditor::_go_to_tab(int p_idx) {
sh.control = c;
sh.state = Variant();
- history.push_back(sh);
- history_pos++;
+ if (!lock_history && (history.is_empty() || history[history.size() - 1].control != sh.control)) {
+ history.push_back(sh);
+ history_pos++;
+ }
tab_container->set_current_tab(p_idx);
@@ -680,7 +736,7 @@ void ScriptEditor::_go_to_tab(int p_idx) {
_update_help_overview_visibility();
}
-void ScriptEditor::_add_recent_script(String p_path) {
+void ScriptEditor::_add_recent_script(const String &p_path) {
if (p_path.is_empty()) {
return;
}
@@ -719,7 +775,7 @@ void ScriptEditor::_open_recent_script(int p_idx) {
// clear button
if (p_idx == recent_scripts->get_item_count() - 1) {
EditorSettings::get_singleton()->set_project_metadata("recent_files", "scripts", Array());
- call_deferred(SNAME("_update_recent_scripts"));
+ callable_mp(this, &ScriptEditor::_update_recent_scripts).call_deferred();
return;
}
@@ -774,7 +830,7 @@ void ScriptEditor::_open_recent_script(int p_idx) {
_show_error_dialog(path);
}
-void ScriptEditor::_show_error_dialog(String p_path) {
+void ScriptEditor::_show_error_dialog(const String &p_path) {
error_dialog->set_text(vformat(TTR("Can't open '%s'. The file could have been moved or deleted."), p_path));
error_dialog->popup_centered();
}
@@ -836,33 +892,36 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
_save_editor_state(current);
}
memdelete(tselected);
- if (idx >= tab_container->get_tab_count()) {
- idx = tab_container->get_tab_count() - 1;
- }
- if (idx >= 0) {
- if (history_pos >= 0) {
- idx = tab_container->get_tab_idx_from_control(history[history_pos].control);
- }
- _go_to_tab(idx);
- } else {
- _update_selected_editor_menu();
- }
if (script_close_queue.is_empty()) {
+ if (idx >= tab_container->get_tab_count()) {
+ idx = tab_container->get_tab_count() - 1;
+ }
+ if (idx >= 0) {
+ if (history_pos >= 0) {
+ idx = tab_container->get_tab_idx_from_control(history[history_pos].control);
+ }
+ _go_to_tab(idx);
+ } else {
+ _update_selected_editor_menu();
+ }
+
_update_history_arrows();
_update_script_names();
- _update_members_overview_visibility();
- _update_help_overview_visibility();
_save_layout();
_update_find_replace_bar();
}
}
-void ScriptEditor::_close_current_tab(bool p_save) {
- _close_tab(tab_container->get_current_tab(), p_save);
+void ScriptEditor::_close_current_tab(bool p_save, bool p_history_back) {
+ _close_tab(tab_container->get_current_tab(), p_save, p_history_back);
}
void ScriptEditor::_close_discard_current_tab(const String &p_str) {
+ Ref<Script> scr = _get_current_script();
+ if (scr.is_valid()) {
+ scr->reload_from_file();
+ }
_close_tab(tab_container->get_current_tab(), false);
erase_tab_confirm->hide();
}
@@ -919,7 +978,7 @@ void ScriptEditor::_queue_close_tabs() {
}
}
- _close_current_tab(false);
+ _close_current_tab(false, false);
}
_update_find_replace_bar();
}
@@ -982,12 +1041,24 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) {
}
}
+ if (p_res.is_valid()) {
+ // In case the Resource has built-in scripts.
+ _mark_built_in_scripts_as_saved(p_res->get_path());
+ }
+
_update_script_names();
- _trigger_live_script_reload();
+ Ref<Script> scr = p_res;
+ if (scr.is_valid()) {
+ trigger_live_script_reload(scr->get_path());
+ }
}
void ScriptEditor::_scene_saved_callback(const String &p_path) {
// If scene was saved, mark all built-in scripts from that scene as saved.
+ _mark_built_in_scripts_as_saved(p_path);
+}
+
+void ScriptEditor::_mark_built_in_scripts_as_saved(const String &p_parent_path) {
for (int i = 0; i < tab_container->get_tab_count(); i++) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
@@ -1000,7 +1071,7 @@ void ScriptEditor::_scene_saved_callback(const String &p_path) {
continue; // External script, who cares.
}
- if (edited_res->get_path().get_slice("::", 0) == p_path) {
+ if (edited_res->get_path().get_slice("::", 0) == p_parent_path) {
se->tag_saved_version();
}
@@ -1011,16 +1082,33 @@ void ScriptEditor::_scene_saved_callback(const String &p_path) {
}
}
-void ScriptEditor::_trigger_live_script_reload() {
+void ScriptEditor::trigger_live_script_reload(const String &p_script_path) {
+ if (!script_paths_to_reload.has(p_script_path)) {
+ script_paths_to_reload.append(p_script_path);
+ }
+ if (!pending_auto_reload && auto_reload_running_scripts) {
+ callable_mp(this, &ScriptEditor::_live_auto_reload_running_scripts).call_deferred();
+ pending_auto_reload = true;
+ }
+}
+
+void ScriptEditor::trigger_live_script_reload_all() {
if (!pending_auto_reload && auto_reload_running_scripts) {
call_deferred(SNAME("_live_auto_reload_running_scripts"));
pending_auto_reload = true;
+ reload_all_scripts = true;
}
}
void ScriptEditor::_live_auto_reload_running_scripts() {
pending_auto_reload = false;
- EditorDebuggerNode::get_singleton()->reload_scripts();
+ if (reload_all_scripts) {
+ EditorDebuggerNode::get_singleton()->reload_all_scripts();
+ } else {
+ EditorDebuggerNode::get_singleton()->reload_scripts(script_paths_to_reload);
+ }
+ reload_all_scripts = false;
+ script_paths_to_reload.clear();
}
bool ScriptEditor::_test_script_times_on_disk(Ref<Resource> p_for_script) {
@@ -1064,14 +1152,14 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Resource> p_for_script) {
script_editor->reload_scripts();
need_reload = false;
} else {
- disk_changed->call_deferred(SNAME("popup_centered_ratio"), 0.3);
+ callable_mp((Window *)disk_changed, &Window::popup_centered_ratio).call_deferred(0.3);
}
}
return need_reload;
}
-void ScriptEditor::_file_dialog_action(String p_file) {
+void ScriptEditor::_file_dialog_action(const String &p_file) {
switch (file_dialog_option) {
case FILE_NEW_TEXTFILE: {
Error err;
@@ -1175,8 +1263,8 @@ void ScriptEditor::_menu_option(int p_option) {
for (const String &E : textfile_extensions) {
file_dialog->add_filter("*." + E, E.to_upper());
}
- file_dialog->popup_file_dialog();
file_dialog->set_title(TTR("New Text File..."));
+ file_dialog->popup_file_dialog();
open_textfile_after_create = true;
} break;
case FILE_OPEN: {
@@ -1187,16 +1275,16 @@ void ScriptEditor::_menu_option(int p_option) {
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("Script", &extensions);
file_dialog->clear_filters();
- for (int i = 0; i < extensions.size(); i++) {
- file_dialog->add_filter("*." + extensions[i], extensions[i].to_upper());
+ for (const String &extension : extensions) {
+ file_dialog->add_filter("*." + extension, extension.to_upper());
}
for (const String &E : textfile_extensions) {
file_dialog->add_filter("*." + E, E.to_upper());
}
- file_dialog->popup_file_dialog();
file_dialog->set_title(TTR("Open File"));
+ file_dialog->popup_file_dialog();
return;
} break;
case FILE_REOPEN_CLOSED: {
@@ -1319,8 +1407,8 @@ void ScriptEditor::_menu_option(int p_option) {
file_dialog->clear_filters();
file_dialog->set_current_dir(text_file->get_path().get_base_dir());
file_dialog->set_current_file(text_file->get_path().get_file());
- file_dialog->popup_file_dialog();
file_dialog->set_title(TTR("Save File As..."));
+ file_dialog->popup_file_dialog();
break;
}
@@ -1409,11 +1497,7 @@ void ScriptEditor::_menu_option(int p_option) {
path = path.get_slice("::", 0); // Show the scene instead.
}
- FileSystemDock *file_system_dock = FileSystemDock::get_singleton();
- file_system_dock->navigate_to_path(path);
- // Ensure that the FileSystem dock is visible.
- TabContainer *dock_tab_container = (TabContainer *)file_system_dock->get_parent_control();
- dock_tab_container->set_current_tab(dock_tab_container->get_tab_idx_from_control(file_system_dock));
+ FileSystemDock::get_singleton()->navigate_to_path(path);
}
} break;
case CLOSE_DOCS: {
@@ -1498,8 +1582,8 @@ void ScriptEditor::_theme_option(int p_option) {
file_dialog_option = THEME_IMPORT;
file_dialog->clear_filters();
file_dialog->add_filter("*.tet");
- file_dialog->popup_file_dialog();
file_dialog->set_title(TTR("Import Theme"));
+ file_dialog->popup_file_dialog();
} break;
case THEME_RELOAD: {
EditorSettings::get_singleton()->load_text_editor_theme();
@@ -1524,8 +1608,8 @@ void ScriptEditor::_show_save_theme_as_dialog() {
file_dialog->clear_filters();
file_dialog->add_filter("*.tet");
file_dialog->set_current_path(EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(EDITOR_GET("text_editor/theme/color_theme")));
- file_dialog->popup_file_dialog();
file_dialog->set_title(TTR("Save Theme As..."));
+ file_dialog->popup_file_dialog();
}
bool ScriptEditor::_has_docs_tab() const {
@@ -1605,7 +1689,7 @@ void ScriptEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
EditorRunBar::get_singleton()->connect("stop_pressed", callable_mp(this, &ScriptEditor::_editor_stop));
- _editor_settings_changed();
+ _apply_editor_settings();
[[fallthrough]];
}
@@ -1635,7 +1719,6 @@ void ScriptEditor::_notification(int p_what) {
recent_scripts->reset_size();
if (is_inside_tree()) {
- _update_script_colors();
_update_script_names();
}
} break;
@@ -1672,18 +1755,6 @@ void ScriptEditor::_notification(int p_what) {
_test_script_times_on_disk();
_update_modified_scripts_for_external_editor();
} break;
-
- case CanvasItem::NOTIFICATION_VISIBILITY_CHANGED: {
- if (is_visible()) {
- find_in_files_button->show();
- } else {
- if (find_in_files->is_visible_in_tree()) {
- EditorNode::get_singleton()->hide_bottom_panel();
- }
- find_in_files_button->hide();
- }
-
- } break;
}
}
@@ -1849,7 +1920,7 @@ struct _ScriptEditorItemData {
if (sort_key == id.sort_key) {
return index < id.index;
} else {
- return sort_key.naturalnocasecmp_to(id.sort_key) < 0;
+ return sort_key.filenocasecmp_to(id.sort_key) < 0;
}
} else {
return category < id.category;
@@ -2143,8 +2214,11 @@ void ScriptEditor::_update_script_names() {
sd.index = i;
sedata.set(i, sd);
}
+
+ lock_history = true;
_go_to_tab(new_prev_tab);
_go_to_tab(new_cur_tab);
+ lock_history = false;
_sort_list_on_update = false;
}
@@ -2260,7 +2334,7 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
// Don't open dominant script if using an external editor.
bool use_external_editor =
- EDITOR_GET("text_editor/external/use_external_editor") ||
+ external_editor_active ||
(scr.is_valid() && scr->get_language()->overrides_external_editor());
use_external_editor = use_external_editor && !(scr.is_valid() && scr->is_built_in()); // Ignore external editor for built-in scripts.
const bool open_dominant = EDITOR_GET("text_editor/behavior/files/open_dominant_script_on_scene_change");
@@ -2432,6 +2506,10 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
if (script_editor_cache->has_section(p_resource->get_path())) {
se->set_edit_state(script_editor_cache->get_value(p_resource->get_path(), "state"));
+ ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(se);
+ if (ste) {
+ ste->store_previous_state();
+ }
}
_sort_list_on_update = true;
@@ -2443,10 +2521,17 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
se->connect("request_open_script_at_line", callable_mp(this, &ScriptEditor::_goto_script_line));
se->connect("go_to_help", callable_mp(this, &ScriptEditor::_help_class_goto));
se->connect("request_save_history", callable_mp(this, &ScriptEditor::_save_history));
+ se->connect("request_save_previous_state", callable_mp(this, &ScriptEditor::_save_previous_state));
se->connect("search_in_files_requested", callable_mp(this, &ScriptEditor::_on_find_in_files_requested));
se->connect("replace_in_files_requested", callable_mp(this, &ScriptEditor::_on_replace_in_files_requested));
se->connect("go_to_method", callable_mp(this, &ScriptEditor::script_goto_method));
+ CodeTextEditor *cte = se->get_code_editor();
+ if (cte) {
+ cte->set_zoom_factor(zoom_factor);
+ cte->connect("zoomed", callable_mp(this, &ScriptEditor::_set_zoom_factor));
+ }
+
//test for modification, maybe the script was not edited but was loaded
_test_script_times_on_disk(p_resource);
@@ -2502,17 +2587,7 @@ void ScriptEditor::save_current_script() {
clear_docs_from_script(scr);
}
- if (resource->is_built_in()) {
- // If built-in script, save the scene instead.
- const String scene_path = resource->get_path().get_slice("::", 0);
- if (!scene_path.is_empty()) {
- Vector<String> scene_to_save;
- scene_to_save.push_back(scene_path);
- EditorNode::get_singleton()->save_scene_list(scene_to_save);
- }
- } else {
- EditorNode::get_singleton()->save_resource(resource);
- }
+ EditorNode::get_singleton()->save_resource(resource);
if (scr.is_valid()) {
update_docs_from_script(scr);
@@ -2520,7 +2595,7 @@ void ScriptEditor::save_current_script() {
}
void ScriptEditor::save_all_scripts() {
- Vector<String> scenes_to_save;
+ HashSet<String> scenes_to_save;
for (int i = 0; i < tab_container->get_tab_count(); i++) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
@@ -2569,7 +2644,7 @@ void ScriptEditor::save_all_scripts() {
// For built-in scripts, save their scenes instead.
const String scene_path = edited_res->get_path().get_slice("::", 0);
if (!scene_path.is_empty() && !scenes_to_save.has(scene_path)) {
- scenes_to_save.push_back(scene_path);
+ scenes_to_save.insert(scene_path);
}
}
}
@@ -2592,6 +2667,9 @@ void ScriptEditor::apply_scripts() const {
}
void ScriptEditor::reload_scripts(bool p_refresh_only) {
+ if (external_editor_active) {
+ return;
+ }
for (int i = 0; i < tab_container->get_tab_count(); i++) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
@@ -2699,6 +2777,10 @@ void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const
Ref<Script> scr = p_obj->get_script();
ERR_FAIL_COND(!scr.is_valid());
+ if (!scr->get_language()->can_make_function()) {
+ return;
+ }
+
EditorNode::get_singleton()->push_item(scr.ptr());
for (int i = 0; i < tab_container->get_tab_count(); i++) {
@@ -2748,6 +2830,17 @@ void ScriptEditor::_save_layout() {
}
void ScriptEditor::_editor_settings_changed() {
+ if (!EditorThemeManager::is_generated_theme_outdated() &&
+ !EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor") &&
+ !EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor") &&
+ !EditorSettings::get_singleton()->check_changed_settings_in_group("docks/filesystem")) {
+ return;
+ }
+
+ _apply_editor_settings();
+}
+
+void ScriptEditor::_apply_editor_settings() {
textfile_extensions.clear();
const Vector<String> textfile_ext = ((String)(EDITOR_GET("docks/filesystem/textfile_extensions"))).split(",", false);
for (const String &E : textfile_ext) {
@@ -2759,6 +2852,7 @@ void ScriptEditor::_editor_settings_changed() {
members_overview_enabled = EDITOR_GET("text_editor/script_list/show_members_overview");
help_overview_enabled = EDITOR_GET("text_editor/help/show_help_index");
+ external_editor_active = EDITOR_GET("text_editor/external/use_external_editor");
_update_members_overview_visibility();
_update_help_overview_visibility();
@@ -2771,6 +2865,10 @@ void ScriptEditor::_editor_settings_changed() {
EditorSettings::get_singleton()->load_text_editor_theme();
}
+ _update_script_names();
+
+ ScriptServer::set_reload_scripts_on_save(EDITOR_GET("text_editor/behavior/files/auto_reload_and_parse_scripts_on_save"));
+
for (int i = 0; i < tab_container->get_tab_count(); i++) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
@@ -2779,10 +2877,6 @@ void ScriptEditor::_editor_settings_changed() {
se->update_settings();
}
- _update_script_colors();
- _update_script_names();
-
- ScriptServer::set_reload_scripts_on_save(EDITOR_GET("text_editor/behavior/files/auto_reload_and_parse_scripts_on_save"));
}
void ScriptEditor::_filesystem_changed() {
@@ -2865,7 +2959,7 @@ void ScriptEditor::_tree_changed() {
}
waiting_update_names = true;
- call_deferred(SNAME("_update_script_names"));
+ callable_mp(this, &ScriptEditor::_update_script_names).call_deferred();
}
void ScriptEditor::_split_dragged(float) {
@@ -2955,7 +3049,7 @@ bool ScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data
}
for (int i = 0; i < files.size(); i++) {
- String file = files[i];
+ const String &file = files[i];
if (file.is_empty() || !FileAccess::exists(file)) {
continue;
}
@@ -3035,7 +3129,7 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
}
int num_tabs_before = tab_container->get_tab_count();
for (int i = 0; i < files.size(); i++) {
- String file = files[i];
+ const String &file = files[i];
if (file.is_empty() || !FileAccess::exists(file)) {
continue;
}
@@ -3285,6 +3379,8 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
}
}
+ _set_zoom_factor(p_layout->get_value("ScriptEditor", "zoom_factor", 1.0f));
+
restoring_layout = false;
_update_script_names();
@@ -3334,6 +3430,7 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
p_layout->set_value("ScriptEditor", "open_help", helps);
p_layout->set_value("ScriptEditor", "script_split_offset", script_split->get_split_offset());
p_layout->set_value("ScriptEditor", "list_split_offset", list_split->get_split_offset());
+ p_layout->set_value("ScriptEditor", "zoom_factor", zoom_factor);
// Save the cache.
script_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("script_editor_cache.cfg"));
@@ -3361,6 +3458,7 @@ void ScriptEditor::_help_class_open(const String &p_class) {
_go_to_tab(tab_container->get_tab_count() - 1);
eh->go_to_class(p_class);
eh->connect("go_to_help", callable_mp(this, &ScriptEditor::_help_class_goto));
+ eh->connect("request_save_history", callable_mp(this, &ScriptEditor::_save_history));
_add_recent_script(p_class);
_sort_list_on_update = true;
_update_script_names();
@@ -3378,7 +3476,6 @@ void ScriptEditor::_help_class_goto(const String &p_desc) {
eh->set_name(cname);
tab_container->add_child(eh);
- _go_to_tab(tab_container->get_tab_count() - 1);
eh->go_to_help(p_desc);
eh->connect("go_to_help", callable_mp(this, &ScriptEditor::_help_class_goto));
_add_recent_script(eh->get_class());
@@ -3386,7 +3483,7 @@ void ScriptEditor::_help_class_goto(const String &p_desc) {
_update_script_names();
_save_layout();
- call_deferred("_help_tab_goto", cname, p_desc);
+ callable_mp(this, &ScriptEditor::_help_tab_goto).call_deferred(cname, p_desc);
}
bool ScriptEditor::_help_tab_goto(const String &p_name, const String &p_desc) {
@@ -3490,6 +3587,7 @@ void ScriptEditor::_update_history_pos(int p_new_pos) {
ScriptEditorBase *seb = Object::cast_to<ScriptEditorBase>(n);
if (seb) {
+ lock_history = true;
seb->set_edit_state(history[history_pos].state);
seb->ensure_focus();
@@ -3499,9 +3597,10 @@ void ScriptEditor::_update_history_pos(int p_new_pos) {
}
}
- if (Object::cast_to<EditorHelp>(n)) {
- Object::cast_to<EditorHelp>(n)->set_scroll(history[history_pos].state);
- Object::cast_to<EditorHelp>(n)->set_focused();
+ EditorHelp *eh = Object::cast_to<EditorHelp>(n);
+ if (eh) {
+ eh->set_scroll(history[history_pos].state);
+ eh->set_focused();
}
n->set_meta("__editor_pass", ++edit_pass);
@@ -3555,7 +3654,7 @@ TypedArray<ScriptEditorBase> ScriptEditor::_get_open_script_editors() const {
void ScriptEditor::set_scene_root_script(Ref<Script> p_script) {
// Don't open dominant script if using an external editor.
bool use_external_editor =
- EDITOR_GET("text_editor/external/use_external_editor") ||
+ external_editor_active ||
(p_script.is_valid() && p_script->get_language()->overrides_external_editor());
use_external_editor = use_external_editor && !(p_script.is_valid() && p_script->is_built_in()); // Ignore external editor for built-in scripts.
const bool open_dominant = EDITOR_GET("text_editor/behavior/files/open_dominant_script_on_scene_change");
@@ -3579,7 +3678,7 @@ void ScriptEditor::set_live_auto_reload_running_scripts(bool p_enabled) {
auto_reload_running_scripts = p_enabled;
}
-void ScriptEditor::_help_search(String p_text) {
+void ScriptEditor::_help_search(const String &p_text) {
help_search_dialog->popup_dialog(p_text);
}
@@ -3630,20 +3729,20 @@ void ScriptEditor::_script_changed() {
NodeDock::get_singleton()->update_lists();
}
-void ScriptEditor::_on_find_in_files_requested(String text) {
+void ScriptEditor::_on_find_in_files_requested(const String &text) {
find_in_files_dialog->set_find_in_files_mode(FindInFilesDialog::SEARCH_MODE);
find_in_files_dialog->set_search_text(text);
find_in_files_dialog->popup_centered();
}
-void ScriptEditor::_on_replace_in_files_requested(String text) {
+void ScriptEditor::_on_replace_in_files_requested(const String &text) {
find_in_files_dialog->set_find_in_files_mode(FindInFilesDialog::REPLACE_MODE);
find_in_files_dialog->set_search_text(text);
find_in_files_dialog->set_replace_text("");
find_in_files_dialog->popup_centered();
}
-void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_number, int begin, int end) {
+void ScriptEditor::_on_find_in_files_result_selected(const String &fpath, int line_number, int begin, int end) {
if (ResourceLoader::exists(fpath)) {
Ref<Resource> res = ResourceLoader::load(fpath);
@@ -3715,6 +3814,7 @@ void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_numb
ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(_get_current_editor());
if (ste) {
+ EditorInterface::get_singleton()->set_main_screen_editor("Script");
ste->goto_line_selection(line_number, begin, end);
}
}
@@ -3729,6 +3829,7 @@ void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_numb
ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(_get_current_editor());
if (ste) {
+ EditorInterface::get_singleton()->set_main_screen_editor("Script");
ste->goto_line_selection(line_number - 1, begin, end);
}
return;
@@ -3762,14 +3863,44 @@ void ScriptEditor::_start_find_in_files(bool with_replace) {
find_in_files->set_replace_text(find_in_files_dialog->get_replace_text());
find_in_files->start_search();
- EditorNode::get_singleton()->make_bottom_panel_item_visible(find_in_files);
+ if (find_in_files_button->get_index() != find_in_files_button->get_parent()->get_child_count()) {
+ find_in_files_button->get_parent()->move_child(find_in_files_button, -1);
+ }
+ if (!find_in_files_button->is_visible()) {
+ find_in_files_button->show();
+ }
+
+ EditorNode::get_bottom_panel()->make_item_visible(find_in_files);
}
-void ScriptEditor::_on_find_in_files_modified_files(PackedStringArray paths) {
+void ScriptEditor::_on_find_in_files_modified_files(const PackedStringArray &paths) {
_test_script_times_on_disk();
_update_modified_scripts_for_external_editor();
}
+void ScriptEditor::_set_zoom_factor(float p_zoom_factor) {
+ if (zoom_factor == p_zoom_factor) {
+ return;
+ }
+ zoom_factor = p_zoom_factor;
+ for (int i = 0; i < tab_container->get_tab_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
+ if (se) {
+ CodeTextEditor *cte = se->get_code_editor();
+ if (cte) {
+ if (zoom_factor != cte->get_zoom_factor()) {
+ cte->set_zoom_factor(zoom_factor);
+ }
+ }
+ }
+ }
+}
+
+void ScriptEditor::_on_find_in_files_close_button_clicked() {
+ EditorNode::get_bottom_panel()->hide_bottom_panel();
+ find_in_files_button->hide();
+}
+
void ScriptEditor::_window_changed(bool p_visible) {
make_floating->set_visible(!p_visible);
is_floating = p_visible;
@@ -3784,18 +3915,7 @@ void ScriptEditor::_filter_methods_text_changed(const String &p_newtext) {
}
void ScriptEditor::_bind_methods() {
- ClassDB::bind_method("_close_docs_tab", &ScriptEditor::_close_docs_tab);
- ClassDB::bind_method("_close_all_tabs", &ScriptEditor::_close_all_tabs);
- ClassDB::bind_method("_close_other_tabs", &ScriptEditor::_close_other_tabs);
- ClassDB::bind_method("_goto_script_line2", &ScriptEditor::_goto_script_line2);
- ClassDB::bind_method("_copy_script_path", &ScriptEditor::_copy_script_path);
-
- ClassDB::bind_method("_help_class_open", &ScriptEditor::_help_class_open);
ClassDB::bind_method("_help_tab_goto", &ScriptEditor::_help_tab_goto);
- ClassDB::bind_method("_live_auto_reload_running_scripts", &ScriptEditor::_live_auto_reload_running_scripts);
- ClassDB::bind_method("_update_members_overview", &ScriptEditor::_update_members_overview);
- ClassDB::bind_method("_update_recent_scripts", &ScriptEditor::_update_recent_scripts);
-
ClassDB::bind_method("get_current_editor", &ScriptEditor::_get_current_editor);
ClassDB::bind_method("get_open_script_editors", &ScriptEditor::_get_open_script_editors);
@@ -3807,6 +3927,8 @@ void ScriptEditor::_bind_methods() {
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("goto_help", "topic"), &ScriptEditor::goto_help);
+
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")));
}
@@ -3823,6 +3945,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
waiting_update_names = false;
pending_auto_reload = false;
auto_reload_running_scripts = true;
+ external_editor_active = false;
members_overview_enabled = EDITOR_GET("text_editor/script_list/show_members_overview");
help_overview_enabled = EDITOR_GET("text_editor/help/show_help_index");
@@ -3851,6 +3974,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
scripts_vbox->add_child(filter_scripts);
script_list = memnew(ItemList);
+ script_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
scripts_vbox->add_child(script_list);
script_list->set_custom_minimum_size(Size2(150, 60) * EDSCALE); //need to give a bit of limit to avoid it from disappearing
script_list->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -3895,6 +4019,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
overview_vbox->add_child(filter_methods);
members_overview = memnew(ItemList);
+ members_overview->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
overview_vbox->add_child(members_overview);
members_overview->set_allow_reselect(true);
@@ -3903,6 +4028,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
members_overview->set_allow_rmb_select(true);
help_overview = memnew(ItemList);
+ help_overview->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
overview_vbox->add_child(help_overview);
help_overview->set_allow_reselect(true);
help_overview->set_custom_minimum_size(Size2(0, 60) * EDSCALE); //need to give a bit of limit to avoid it from disappearing
@@ -3941,17 +4067,16 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new_textfile", TTR("New Text File..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::N), FILE_NEW_TEXTFILE);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/open", TTR("Open...")), FILE_OPEN);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reopen_closed_script", TTR("Reopen Closed Script"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::T), FILE_REOPEN_CLOSED);
- file_menu->get_popup()->add_submenu_item(TTR("Open Recent"), "RecentScripts", FILE_OPEN_RECENT);
recent_scripts = memnew(PopupMenu);
- recent_scripts->set_name("RecentScripts");
- file_menu->get_popup()->add_child(recent_scripts);
+ file_menu->get_popup()->add_submenu_node_item(TTR("Open Recent"), recent_scripts, FILE_OPEN_RECENT);
recent_scripts->connect("id_pressed", callable_mp(this, &ScriptEditor::_open_recent_script));
+
_update_recent_scripts();
file_menu->get_popup()->add_separator();
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save", TTR("Save"), KeyModifierMask::CMD_OR_CTRL | Key::S), FILE_SAVE);
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_as", TTR("Save As..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::S), FILE_SAVE_AS);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save", TTR("Save"), KeyModifierMask::ALT | KeyModifierMask::CMD_OR_CTRL | Key::S), FILE_SAVE);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_as", TTR("Save As...")), FILE_SAVE_AS);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), KeyModifierMask::SHIFT | KeyModifierMask::ALT | Key::S), FILE_SAVE_ALL);
ED_SHORTCUT_OVERRIDE("script_editor/save_all", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::S);
file_menu->get_popup()->add_separator();
@@ -3964,14 +4089,11 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_next", TTR("History Next"), KeyModifierMask::ALT | Key::RIGHT), WINDOW_NEXT);
file_menu->get_popup()->add_separator();
- file_menu->get_popup()->add_submenu_item(TTR("Theme"), "Theme", FILE_THEME);
-
theme_submenu = memnew(PopupMenu);
- theme_submenu->set_name("Theme");
- file_menu->get_popup()->add_child(theme_submenu);
- theme_submenu->connect("id_pressed", callable_mp(this, &ScriptEditor::_theme_option));
theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/import_theme", TTR("Import Theme...")), THEME_IMPORT);
theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/reload_theme", TTR("Reload Theme")), THEME_RELOAD);
+ file_menu->get_popup()->add_submenu_node_item(TTR("Theme"), theme_submenu, FILE_THEME);
+ theme_submenu->connect("id_pressed", callable_mp(this, &ScriptEditor::_theme_option));
theme_submenu->add_separator();
theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/save_theme", TTR("Save Theme")), THEME_SAVE);
@@ -4009,8 +4131,8 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
debugger->connect("set_execution", callable_mp(this, &ScriptEditor::_set_execution));
debugger->connect("clear_execution", callable_mp(this, &ScriptEditor::_clear_execution));
debugger->connect("breaked", callable_mp(this, &ScriptEditor::_breaked));
- debugger->get_default_debugger()->connect("set_breakpoint", callable_mp(this, &ScriptEditor::_set_breakpoint));
- debugger->get_default_debugger()->connect("clear_breakpoints", callable_mp(this, &ScriptEditor::_clear_breakpoints));
+ debugger->connect("breakpoint_set_in_tree", callable_mp(this, &ScriptEditor::_set_breakpoint));
+ debugger->connect("breakpoints_cleared_in_tree", callable_mp(this, &ScriptEditor::_clear_breakpoints));
menu_hb->add_spacer();
@@ -4054,24 +4176,25 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
script_forward->set_disabled(true);
script_forward->set_tooltip_text(TTR("Go to next edited document."));
- if (p_wrapper->is_window_available()) {
- menu_hb->add_child(memnew(VSeparator));
+ menu_hb->add_child(memnew(VSeparator));
- make_floating = memnew(ScreenSelect);
- make_floating->set_flat(true);
+ make_floating = memnew(ScreenSelect);
+ make_floating->set_flat(true);
+ make_floating->connect("request_open_in_screen", callable_mp(window_wrapper, &WindowWrapper::enable_window_on_screen).bind(true));
+ if (!make_floating->is_disabled()) {
+ // Override default ScreenSelect tooltip if multi-window support is available.
make_floating->set_tooltip_text(TTR("Make the script editor floating."));
- make_floating->connect("request_open_in_screen", callable_mp(window_wrapper, &WindowWrapper::enable_window_on_screen).bind(true));
-
- menu_hb->add_child(make_floating);
- p_wrapper->connect("window_visibility_changed", callable_mp(this, &ScriptEditor::_window_changed));
}
+ menu_hb->add_child(make_floating);
+ p_wrapper->connect("window_visibility_changed", callable_mp(this, &ScriptEditor::_window_changed));
+
tab_container->connect("tab_changed", callable_mp(this, &ScriptEditor::_tab_changed));
erase_tab_confirm = memnew(ConfirmationDialog);
erase_tab_confirm->set_ok_button_text(TTR("Save"));
erase_tab_confirm->add_button(TTR("Discard"), DisplayServer::get_singleton()->get_swap_cancel_ok(), "discard");
- erase_tab_confirm->connect("confirmed", callable_mp(this, &ScriptEditor::_close_current_tab).bind(true));
+ erase_tab_confirm->connect("confirmed", callable_mp(this, &ScriptEditor::_close_current_tab).bind(true, true));
erase_tab_confirm->connect("custom_action", callable_mp(this, &ScriptEditor::_close_discard_current_tab));
add_child(erase_tab_confirm);
@@ -4099,6 +4222,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
disk_changed_list = memnew(Tree);
vbc->add_child(disk_changed_list);
+ disk_changed_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
disk_changed_list->set_v_size_flags(SIZE_EXPAND_FILL);
disk_changed->connect("confirmed", callable_mp(this, &ScriptEditor::reload_scripts).bind(false));
@@ -4129,10 +4253,11 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
find_in_files_dialog->connect(FindInFilesDialog::SIGNAL_REPLACE_REQUESTED, callable_mp(this, &ScriptEditor::_start_find_in_files).bind(true));
add_child(find_in_files_dialog);
find_in_files = memnew(FindInFilesPanel);
- find_in_files_button = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Search Results"), find_in_files);
+ find_in_files_button = EditorNode::get_bottom_panel()->add_item(TTR("Search Results"), find_in_files, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_search_results_bottom_panel", TTR("Toggle Search Results Bottom Panel")));
find_in_files->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
find_in_files->connect(FindInFilesPanel::SIGNAL_RESULT_SELECTED, callable_mp(this, &ScriptEditor::_on_find_in_files_result_selected));
find_in_files->connect(FindInFilesPanel::SIGNAL_FILES_MODIFIED, callable_mp(this, &ScriptEditor::_on_find_in_files_modified_files));
+ find_in_files->connect(FindInFilesPanel::SIGNAL_CLOSE_BUTTON_CLICKED, callable_mp(this, &ScriptEditor::_on_find_in_files_close_button_clicked));
find_in_files->hide();
find_in_files_button->hide();
@@ -4160,7 +4285,7 @@ void ScriptEditorPlugin::_focus_another_editor() {
}
}
-void ScriptEditorPlugin::_save_last_editor(String p_editor) {
+void ScriptEditorPlugin::_save_last_editor(const String &p_editor) {
if (p_editor != get_name()) {
last_editor = p_editor;
}