Browse Source

Add "Replace in Files" functionality to text editors

The Soft Reload Script shortcut was changed from Ctrl + Shift + R
to Ctrl + Alt + R to avoid conflicts.
Dominik 'dreamsComeTrue' Jasiński 5 years ago
parent
commit
7bd0eae635

+ 68 - 4
editor/find_in_files.cpp

@@ -325,6 +325,17 @@ FindInFilesDialog::FindInFilesDialog() {
 	_search_text_line_edit->connect("text_entered", this, "_on_search_text_entered");
 	gc->add_child(_search_text_line_edit);
 
+	_replace_label = memnew(Label);
+	_replace_label->set_text(TTR("Replace:"));
+	_replace_label->hide();
+	gc->add_child(_replace_label);
+
+	_replace_text_line_edit = memnew(LineEdit);
+	_replace_text_line_edit->set_h_size_flags(SIZE_EXPAND_FILL);
+	_replace_text_line_edit->connect("text_entered", this, "_on_replace_text_entered");
+	_replace_text_line_edit->hide();
+	gc->add_child(_replace_text_line_edit);
+
 	gc->add_child(memnew(Control)); // Space to maintain the grid aligned.
 
 	{
@@ -385,6 +396,8 @@ FindInFilesDialog::FindInFilesDialog() {
 
 	Button *cancel_button = get_ok();
 	cancel_button->set_text(TTR("Cancel"));
+
+	_mode = SEARCH_MODE;
 }
 
 void FindInFilesDialog::set_search_text(String text) {
@@ -392,11 +405,40 @@ void FindInFilesDialog::set_search_text(String text) {
 	_on_search_text_modified(text);
 }
 
+void FindInFilesDialog::set_replace_text(String text) {
+	_replace_text_line_edit->set_text(text);
+}
+
+void FindInFilesDialog::set_find_in_files_mode(FindInFilesMode p_mode) {
+	if (_mode == p_mode) {
+		return;
+	}
+
+	_mode = p_mode;
+
+	if (p_mode == SEARCH_MODE) {
+		set_title(TTR("Find in Files"));
+		_replace_label->hide();
+		_replace_text_line_edit->hide();
+	} else if (p_mode == REPLACE_MODE) {
+		set_title(TTR("Replace in Files"));
+		_replace_label->show();
+		_replace_text_line_edit->show();
+	}
+
+	// After hiding some child controls, recalculate proper dialog size.
+	set_size(Size2(get_size().x, 0));
+}
+
 String FindInFilesDialog::get_search_text() const {
 	String text = _search_text_line_edit->get_text();
 	return text.strip_edges();
 }
 
+String FindInFilesDialog::get_replace_text() const {
+	return _replace_text_line_edit->get_text();
+}
+
 bool FindInFilesDialog::is_match_case() const {
 	return _match_case_checkbox->is_pressed();
 }
@@ -473,9 +515,26 @@ void FindInFilesDialog::_on_search_text_modified(String text) {
 }
 
 void FindInFilesDialog::_on_search_text_entered(String text) {
-	// This allows to trigger a global search without leaving the keyboard
+	// This allows to trigger a global search without leaving the keyboard.
 	if (!_find_button->is_disabled()) {
-		custom_action("find");
+		if (_mode == SEARCH_MODE) {
+			custom_action("find");
+		}
+	}
+
+	if (!_replace_button->is_disabled()) {
+		if (_mode == REPLACE_MODE) {
+			custom_action("replace");
+		}
+	}
+}
+
+void FindInFilesDialog::_on_replace_text_entered(String text) {
+	// This allows to trigger a global search without leaving the keyboard.
+	if (!_replace_button->is_disabled()) {
+		if (_mode == REPLACE_MODE) {
+			custom_action("replace");
+		}
 	}
 }
 
@@ -492,6 +551,7 @@ void FindInFilesDialog::_bind_methods() {
 	ClassDB::bind_method("_on_folder_selected", &FindInFilesDialog::_on_folder_selected);
 	ClassDB::bind_method("_on_search_text_modified", &FindInFilesDialog::_on_search_text_modified);
 	ClassDB::bind_method("_on_search_text_entered", &FindInFilesDialog::_on_search_text_entered);
+	ClassDB::bind_method("_on_replace_text_entered", &FindInFilesDialog::_on_replace_text_entered);
 
 	ADD_SIGNAL(MethodInfo(SIGNAL_FIND_REQUESTED));
 	ADD_SIGNAL(MethodInfo(SIGNAL_REPLACE_REQUESTED));
@@ -575,7 +635,7 @@ FindInFilesPanel::FindInFilesPanel() {
 		_replace_container->add_child(_replace_line_edit);
 
 		_replace_all_button = memnew(Button);
-		_replace_all_button->set_text(TTR("Replace all (no undo)"));
+		_replace_all_button->set_text(TTR("Replace All (NO UNDO)"));
 		_replace_all_button->connect("pressed", this, "_on_replace_all_clicked");
 		_replace_container->add_child(_replace_all_button);
 
@@ -602,6 +662,10 @@ void FindInFilesPanel::set_with_replace(bool with_replace) {
 	}
 }
 
+void FindInFilesPanel::set_replace_text(String text) {
+	_replace_line_edit->set_text(text);
+}
+
 void FindInFilesPanel::clear() {
 	_file_items.clear();
 	_result_items.clear();
@@ -906,7 +970,7 @@ void FindInFilesPanel::apply_replaces_in_file(String fpath, const Vector<Result>
 }
 
 String FindInFilesPanel::get_replace_text() {
-	return _replace_line_edit->get_text().strip_edges();
+	return _replace_line_edit->get_text();
 }
 
 void FindInFilesPanel::update_replace_buttons() {

+ 16 - 0
editor/find_in_files.h

@@ -97,14 +97,23 @@ class FindInFilesDialog : public AcceptDialog {
 	GDCLASS(FindInFilesDialog, AcceptDialog);
 
 public:
+	enum FindInFilesMode {
+		SEARCH_MODE,
+		REPLACE_MODE
+	};
+
 	static const char *SIGNAL_FIND_REQUESTED;
 	static const char *SIGNAL_REPLACE_REQUESTED;
 
 	FindInFilesDialog();
 
 	void set_search_text(String text);
+	void set_replace_text(String text);
+
+	void set_find_in_files_mode(FindInFilesMode p_mode);
 
 	String get_search_text() const;
+	String get_replace_text() const;
 	bool is_match_case() const;
 	bool is_whole_words() const;
 	String get_folder() const;
@@ -121,8 +130,14 @@ private:
 	void _on_folder_selected(String path);
 	void _on_search_text_modified(String text);
 	void _on_search_text_entered(String text);
+	void _on_replace_text_entered(String text);
 
+	FindInFilesMode _mode;
 	LineEdit *_search_text_line_edit;
+
+	Label *_replace_label;
+	LineEdit *_replace_text_line_edit;
+
 	LineEdit *_folder_line_edit;
 	CheckBox *_match_case_checkbox;
 	CheckBox *_whole_words_checkbox;
@@ -151,6 +166,7 @@ public:
 	FindInFiles *get_finder() const { return _finder; }
 
 	void set_with_replace(bool with_replace);
+	void set_replace_text(String text);
 
 	void start_search();
 	void stop_search();

+ 18 - 1
editor/plugins/script_editor_plugin.cpp

@@ -61,6 +61,7 @@ void ScriptEditorBase::_bind_methods() {
 	ADD_SIGNAL(MethodInfo("go_to_help", PropertyInfo(Variant::STRING, "what")));
 	// TODO: This signal is no use for VisualScript.
 	ADD_SIGNAL(MethodInfo("search_in_files_requested", PropertyInfo(Variant::STRING, "text")));
+	ADD_SIGNAL(MethodInfo("replace_in_files_requested", PropertyInfo(Variant::STRING, "text")));
 }
 
 static bool _is_built_in_script(Script *p_script) {
@@ -1037,6 +1038,9 @@ void ScriptEditor::_menu_option(int p_option) {
 		case SEARCH_IN_FILES: {
 			_on_find_in_files_requested("");
 		} break;
+		case REPLACE_IN_FILES: {
+			_on_replace_in_files_requested("");
+		} break;
 		case SEARCH_HELP: {
 			help_search_dialog->popup_dialog();
 		} break;
@@ -2132,6 +2136,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
 	se->connect("go_to_help", this, "_help_class_goto");
 	se->connect("request_save_history", this, "_save_history");
 	se->connect("search_in_files_requested", this, "_on_find_in_files_requested");
+	se->connect("replace_in_files_requested", this, "_on_replace_in_files_requested");
 
 	//test for modification, maybe the script was not edited but was loaded
 
@@ -2842,10 +2847,12 @@ void ScriptEditor::_update_selected_editor_menu() {
 		script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_previous", TTR("Find Previous"), KEY_MASK_SHIFT | KEY_F3), HELP_SEARCH_FIND_PREVIOUS);
 		script_search_menu->get_popup()->add_separator();
 		script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F), SEARCH_IN_FILES);
+		script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/replace_in_files", TTR("Replace in Files"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_R), REPLACE_IN_FILES);
 		script_search_menu->show();
 	} else {
 		if (tab_container->get_child_count() == 0) {
 			script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F), SEARCH_IN_FILES);
+			script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/replace_in_files", TTR("Replace in Files"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_R), REPLACE_IN_FILES);
 			script_search_menu->show();
 		} else {
 			script_search_menu->hide();
@@ -2986,7 +2993,15 @@ void ScriptEditor::_script_changed() {
 }
 
 void ScriptEditor::_on_find_in_files_requested(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_minsize();
+}
+
+void ScriptEditor::_on_replace_in_files_requested(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_minsize();
 }
 
@@ -3040,6 +3055,7 @@ void ScriptEditor::_start_find_in_files(bool with_replace) {
 	f->set_filter(find_in_files_dialog->get_filter());
 
 	find_in_files->set_with_replace(with_replace);
+	find_in_files->set_replace_text(find_in_files_dialog->get_replace_text());
 	find_in_files->start_search();
 
 	editor->make_bottom_panel_item_visible(find_in_files);
@@ -3115,6 +3131,7 @@ void ScriptEditor::_bind_methods() {
 	ClassDB::bind_method("_filter_methods_text_changed", &ScriptEditor::_filter_methods_text_changed);
 	ClassDB::bind_method("_update_recent_scripts", &ScriptEditor::_update_recent_scripts);
 	ClassDB::bind_method("_on_find_in_files_requested", &ScriptEditor::_on_find_in_files_requested);
+	ClassDB::bind_method("_on_replace_in_files_requested", &ScriptEditor::_on_replace_in_files_requested);
 	ClassDB::bind_method("_start_find_in_files", &ScriptEditor::_start_find_in_files);
 	ClassDB::bind_method("_on_find_in_files_result_selected", &ScriptEditor::_on_find_in_files_result_selected);
 	ClassDB::bind_method("_on_find_in_files_modified_files", &ScriptEditor::_on_find_in_files_modified_files);
@@ -3263,7 +3280,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
 	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"), KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_S), FILE_SAVE_ALL);
 	file_menu->get_popup()->add_separator();
-	file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_R), FILE_TOOL_RELOAD_SOFT);
+	file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KEY_MASK_CMD | KEY_MASK_ALT | KEY_R), FILE_TOOL_RELOAD_SOFT);
 	file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/copy_path", TTR("Copy Script Path")), FILE_COPY_PATH);
 	file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/show_in_file_system", TTR("Show in FileSystem")), SHOW_IN_FILE_SYSTEM);
 	file_menu->get_popup()->add_separator();

+ 2 - 0
editor/plugins/script_editor_plugin.h

@@ -160,6 +160,7 @@ class ScriptEditor : public PanelContainer {
 		DEBUG_KEEP_DEBUGGER_OPEN,
 		DEBUG_WITH_EXTERNAL_EDITOR,
 		SEARCH_IN_FILES,
+		REPLACE_IN_FILES,
 		SEARCH_HELP,
 		SEARCH_WEBSITE,
 		HELP_SEARCH_FIND,
@@ -399,6 +400,7 @@ class ScriptEditor : public PanelContainer {
 	Error _save_text_file(Ref<TextFile> p_text_file, const String &p_path);
 
 	void _on_find_in_files_requested(String text);
+	void _on_replace_in_files_requested(String text);
 	void _on_find_in_files_result_selected(String fpath, int line_number, int begin, int end);
 	void _start_find_in_files(bool with_replace);
 	void _on_find_in_files_modified_files(PoolStringArray paths);

+ 7 - 0
editor/plugins/script_text_editor.cpp

@@ -1235,6 +1235,11 @@ void ScriptTextEditor::_edit_option(int p_op) {
 			// So this will be delegated to the ScriptEditor.
 			emit_signal("search_in_files_requested", selected_text);
 		} break;
+		case REPLACE_IN_FILES: {
+			String selected_text = code_editor->get_text_edit()->get_selection_text();
+
+			emit_signal("replace_in_files_requested", selected_text);
+		} break;
 		case SEARCH_LOCATE_FUNCTION: {
 			quick_open->popup_dialog(get_functions());
 			quick_open->set_title(TTR("Go to Function"));
@@ -1805,6 +1810,7 @@ void ScriptTextEditor::_enable_code_editor() {
 	search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE);
 	search_menu->get_popup()->add_separator();
 	search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES);
+	search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES);
 	search_menu->get_popup()->add_separator();
 	search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL);
 	search_menu->get_popup()->connect("id_pressed", this, "_edit_option");
@@ -2020,6 +2026,7 @@ void ScriptTextEditor::register_editor() {
 #endif
 
 	ED_SHORTCUT("script_text_editor/find_in_files", TTR("Find in Files..."), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F);
+	ED_SHORTCUT("script_text_editor/replace_in_files", TTR("Replace in Files..."), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_R);
 
 #ifdef OSX_ENABLED
 	ED_SHORTCUT("script_text_editor/contextual_help", TTR("Contextual Help"), KEY_MASK_ALT | KEY_MASK_SHIFT | KEY_SPACE);

+ 1 - 0
editor/plugins/script_text_editor.h

@@ -135,6 +135,7 @@ class ScriptTextEditor : public ScriptEditorBase {
 		SEARCH_LOCATE_FUNCTION,
 		SEARCH_GOTO_LINE,
 		SEARCH_IN_FILES,
+		REPLACE_IN_FILES,
 		BOOKMARK_TOGGLE,
 		BOOKMARK_GOTO_NEXT,
 		BOOKMARK_GOTO_PREV,

+ 6 - 0
editor/plugins/text_editor.cpp

@@ -450,6 +450,11 @@ void TextEditor::_edit_option(int p_op) {
 			// So this will be delegated to the ScriptEditor.
 			emit_signal("search_in_files_requested", selected_text);
 		} break;
+		case REPLACE_IN_FILES: {
+			String selected_text = code_editor->get_text_edit()->get_selection_text();
+
+			emit_signal("replace_in_files_requested", selected_text);
+		} break;
 		case SEARCH_GOTO_LINE: {
 			goto_line_dialog->popup_find_line(tx);
 		} break;
@@ -616,6 +621,7 @@ TextEditor::TextEditor() {
 	search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE);
 	search_menu->get_popup()->add_separator();
 	search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES);
+	search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES);
 
 	edit_menu = memnew(MenuButton);
 	edit_hb->add_child(edit_menu);

+ 1 - 0
editor/plugins/text_editor.h

@@ -89,6 +89,7 @@ private:
 		SEARCH_FIND_PREV,
 		SEARCH_REPLACE,
 		SEARCH_IN_FILES,
+		REPLACE_IN_FILES,
 		SEARCH_GOTO_LINE,
 		BOOKMARK_TOGGLE,
 		BOOKMARK_GOTO_NEXT,