From 221f1f4401530c3eb4aa08b74e64b2a4cafda0d1 Mon Sep 17 00:00:00 2001 From: arkology <43543909+arkology@users.noreply.github.com> Date: Sat, 5 Jul 2025 22:07:31 +0300 Subject: [PATCH] `FindInFiles`: Allow replace individual results --- editor/icons/ReplaceText.svg | 1 + editor/script/find_in_files.cpp | 42 ++++++++++++++++++++++++++++----- editor/script/find_in_files.h | 5 ++++ 3 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 editor/icons/ReplaceText.svg diff --git a/editor/icons/ReplaceText.svg b/editor/icons/ReplaceText.svg new file mode 100644 index 00000000000..cd6af62c873 --- /dev/null +++ b/editor/icons/ReplaceText.svg @@ -0,0 +1 @@ + diff --git a/editor/script/find_in_files.cpp b/editor/script/find_in_files.cpp index 26ced16cf5b..bcf678e12d2 100644 --- a/editor/script/find_in_files.cpp +++ b/editor/script/find_in_files.cpp @@ -860,11 +860,13 @@ void FindInFilesPanel::_notification(int p_what) { TreeItem *file_item = _results_display->get_root()->get_first_child(); while (file_item) { - file_item->set_button_tooltip_text(0, 0, TTR("Remove result")); + file_item->set_button_tooltip_text(0, FIND_BUTTON_REPLACE, TTR("Replace all matches in file")); + file_item->set_button_tooltip_text(0, FIND_BUTTON_REMOVE, TTR("Remove result")); TreeItem *result_item = file_item->get_first_child(); while (result_item) { - result_item->set_button_tooltip_text(_with_replace ? 1 : 0, 0, TTR("Remove result")); + result_item->set_button_tooltip_text(_with_replace ? 1 : 0, FIND_BUTTON_REPLACE, TTR("Replace")); + result_item->set_button_tooltip_text(_with_replace ? 1 : 0, FIND_BUTTON_REMOVE, TTR("Remove result")); result_item = result_item->get_next(); } @@ -880,13 +882,18 @@ void FindInFilesPanel::_notification(int p_what) { void FindInFilesPanel::_on_result_found(const String &fpath, int line_number, int begin, int end, String text) { TreeItem *file_item; Ref remove_texture = get_editor_theme_icon(SNAME("Close")); + Ref replace_texture = get_editor_theme_icon(SNAME("ReplaceText")); HashMap::Iterator E = _file_items.find(fpath); if (!E) { file_item = _results_display->create_item(); file_item->set_text(0, fpath); file_item->set_metadata(0, fpath); - file_item->add_button(0, remove_texture, 0, false, TTR("Remove result")); + + if (_with_replace) { + file_item->add_button(0, replace_texture, FIND_BUTTON_REPLACE, false, TTR("Replace all matches in file")); + } + file_item->add_button(0, remove_texture, FIND_BUTTON_REMOVE, false, TTR("Remove result")); // The width of this column is restrained to checkboxes, // but that doesn't make sense for the parent items, @@ -931,9 +938,10 @@ void FindInFilesPanel::_on_result_found(const String &fpath, int line_number, in item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); item->set_checked(0, true); item->set_editable(0, true); - item->add_button(1, remove_texture, 0, false, TTR("Remove result")); + item->add_button(1, replace_texture, FIND_BUTTON_REPLACE, false, TTR("Replace")); + item->add_button(1, remove_texture, FIND_BUTTON_REMOVE, false, TTR("Remove result")); } else { - item->add_button(0, remove_texture, 0, false, TTR("Remove result")); + item->add_button(0, remove_texture, FIND_BUTTON_REMOVE, false, TTR("Remove result")); } } @@ -1048,9 +1056,31 @@ void FindInFilesPanel::_on_replace_all_clicked() { } void FindInFilesPanel::_on_button_clicked(TreeItem *p_item, int p_column, int p_id, int p_mouse_button_index) { + const String file_path = p_item->get_metadata(0); + + if (p_id == FIND_BUTTON_REPLACE) { + const String replace_text = get_replace_text(); + Vector locations; + PackedStringArray modified_files; + if (_file_items.has(file_path)) { + for (TreeItem *item = p_item->get_first_child(); item; item = item->get_next()) { + HashMap::Iterator F = _result_items.find(item); + ERR_FAIL_COND(!F); + locations.push_back(F->value); + } + apply_replaces_in_file(file_path, locations, replace_text); + modified_files.push_back(file_path); + } else { + locations.push_back(_result_items.find(p_item)->value); + const String path = p_item->get_parent()->get_metadata(0); + apply_replaces_in_file(path, locations, replace_text); + modified_files.push_back(path); + } + emit_signal(SNAME(SIGNAL_FILES_MODIFIED), modified_files); + } + _result_items.erase(p_item); if (_file_items_results_count.has(p_item)) { - const String file_path = p_item->get_metadata(0); int match_count = p_item->get_child_count(); for (int i = 0; i < match_count; i++) { diff --git a/editor/script/find_in_files.h b/editor/script/find_in_files.h index 03720e13dee..74a4d56a342 100644 --- a/editor/script/find_in_files.h +++ b/editor/script/find_in_files.h @@ -201,6 +201,11 @@ private: void _on_replace_text_changed(const String &text); void _on_replace_all_clicked(); + enum { + FIND_BUTTON_REPLACE, + FIND_BUTTON_REMOVE, + }; + struct Result { int line_number = 0; int begin = 0;