Merge pull request #113060 from kitbdev/refactor-fif

Clean up FindInFiles code
This commit is contained in:
Thaddeus Crews
2026-04-13 11:45:44 -05:00
4 changed files with 870 additions and 881 deletions
File diff suppressed because it is too large Load Diff
+165 -167
View File
@@ -34,61 +34,56 @@
#include "editor/docks/editor_dock.h"
#include "scene/gui/dialogs.h"
// Performs the actual search
class FindInFiles : public Node {
GDCLASS(FindInFiles, Node);
// Performs the actual search.
class FindInFilesSearch : public Node {
GDCLASS(FindInFilesSearch, Node);
// Config.
String pattern;
HashSet<String> extension_filter;
HashSet<String> include_wildcards;
HashSet<String> exclude_wildcards;
String root_dir;
bool whole_words = true;
bool match_case = true;
// State.
bool searching = false;
String current_dir;
Vector<PackedStringArray> folders_stack;
Vector<String> files_to_scan;
int initial_files_count = 0;
void _process();
void _iterate();
void _scan_dir(const String &p_path, PackedStringArray &r_out_folders, PackedStringArray &r_out_files_to_scan);
void _scan_file(const String &p_fpath);
bool _is_file_matched(const HashSet<String> &p_wildcards, const String &p_file_path, bool p_case_sensitive) const;
protected:
void _notification(int p_what);
static void _bind_methods();
public:
static const char *SIGNAL_RESULT_FOUND;
static const char *SIGNAL_FINISHED;
void set_search_text(const String &p_pattern);
void set_whole_words(bool p_whole_word);
void set_match_case(bool p_match_case);
void set_folder(const String &folder);
void set_filter(const HashSet<String> &exts);
void set_folder(const String &p_folder);
void set_filter(const HashSet<String> &p_exts);
void set_includes(const HashSet<String> &p_include_wildcards);
void set_excludes(const HashSet<String> &p_exclude_wildcards);
String get_search_text() const { return _pattern; }
String get_search_text() const { return pattern; }
bool is_whole_words() const { return _whole_words; }
bool is_match_case() const { return _match_case; }
bool is_whole_words() const { return whole_words; }
bool is_match_case() const { return match_case; }
void start();
void stop();
bool is_searching() const { return _searching; }
bool is_searching() const { return searching; }
float get_progress() const;
protected:
void _notification(int p_what);
static void _bind_methods();
private:
void _process();
void _iterate();
void _scan_dir(const String &path, PackedStringArray &out_folders, PackedStringArray &out_files_to_scan);
void _scan_file(const String &fpath);
bool _is_file_matched(const HashSet<String> &p_wildcards, const String &p_file_path, bool p_case_sensitive) const;
// Config
String _pattern;
HashSet<String> _extension_filter;
HashSet<String> _include_wildcards;
HashSet<String> _exclude_wildcards;
String _root_dir;
bool _whole_words = true;
bool _match_case = true;
// State
bool _searching = false;
String _current_dir;
Vector<PackedStringArray> _folders_stack;
Vector<String> _files_to_scan;
int _initial_files_count = 0;
};
class LineEdit;
@@ -96,25 +91,47 @@ class CheckBox;
class FileDialog;
class HBoxContainer;
// Prompts search parameters
// Prompts search parameters.
class FindInFilesDialog : public AcceptDialog {
GDCLASS(FindInFilesDialog, AcceptDialog);
void _on_folder_button_pressed();
void _on_folder_selected(String p_path);
void _on_search_text_modified(const String &p_text);
void _on_search_text_submitted(const String &p_text);
void _on_replace_text_submitted(const String &p_text);
String _validate_filter_wildcard(const String &p_expression) const;
bool replace_mode = false;
LineEdit *search_text_line_edit = nullptr;
Label *replace_label = nullptr;
LineEdit *replace_text_line_edit = nullptr;
LineEdit *folder_line_edit = nullptr;
CheckBox *match_case_checkbox = nullptr;
CheckBox *whole_words_checkbox = nullptr;
Button *find_button = nullptr;
Button *replace_button = nullptr;
FileDialog *folder_dialog = nullptr;
HBoxContainer *filters_container = nullptr;
LineEdit *includes_line_edit = nullptr;
LineEdit *excludes_line_edit = nullptr;
HashMap<String, bool> filters_preferences;
protected:
void _notification(int p_what);
virtual void custom_action(const String &p_action) override;
static void _bind_methods();
public:
enum FindInFilesMode {
SEARCH_MODE,
REPLACE_MODE
};
void set_search_text(const String &p_text);
void set_replace_text(const String &p_text);
static const char *SIGNAL_FIND_REQUESTED;
static const char *SIGNAL_REPLACE_REQUESTED;
FindInFilesDialog();
void set_search_text(const String &text);
void set_replace_text(const String &text);
void set_find_in_files_mode(FindInFilesMode p_mode);
void set_replace_mode(bool p_replace);
String get_search_text() const;
String get_replace_text() const;
@@ -125,39 +142,7 @@ public:
HashSet<String> get_includes() const;
HashSet<String> get_excludes() const;
protected:
void _notification(int p_what);
void _visibility_changed();
void custom_action(const String &p_action) override;
static void _bind_methods();
private:
void _on_folder_button_pressed();
void _on_folder_selected(String path);
void _on_search_text_modified(const String &text);
void _on_search_text_submitted(const String &text);
void _on_replace_text_submitted(const String &text);
String validate_filter_wildcard(const String &p_expression) const;
FindInFilesMode _mode;
LineEdit *_search_text_line_edit = nullptr;
Label *_replace_label = nullptr;
LineEdit *_replace_text_line_edit = nullptr;
LineEdit *_folder_line_edit = nullptr;
CheckBox *_match_case_checkbox = nullptr;
CheckBox *_whole_words_checkbox = nullptr;
Button *_find_button = nullptr;
Button *_replace_button = nullptr;
FileDialog *_folder_dialog = nullptr;
HBoxContainer *_filters_container = nullptr;
LineEdit *_includes_line_edit = nullptr;
LineEdit *_excludes_line_edit = nullptr;
HashMap<String, bool> _filters_preferences;
FindInFilesDialog();
};
class Button;
@@ -166,48 +151,11 @@ class Tree;
class TreeItem;
class ProgressBar;
// Display search results
// Display search results.
class FindInFilesPanel : public MarginContainer {
GDCLASS(FindInFilesPanel, MarginContainer);
public:
static const char *SIGNAL_RESULT_SELECTED;
static const char *SIGNAL_FILES_MODIFIED;
static const char *SIGNAL_CLOSE_BUTTON_CLICKED;
FindInFilesPanel();
FindInFiles *get_finder() const { return _finder; }
void set_with_replace(bool with_replace);
void set_replace_text(const String &text);
bool is_keep_results() const;
void set_search_labels_visibility(bool p_visible);
void start_search();
void stop_search();
void update_layout(EditorDock::DockLayout p_layout);
protected:
static void _bind_methods();
void _notification(int p_what);
private:
void _on_button_clicked(TreeItem *p_item, int p_column, int p_id, int p_mouse_button_index);
void _on_result_found(const String &fpath, int line_number, int begin, int end, String text);
void _on_theme_changed();
void _on_finished();
void _on_refresh_button_clicked();
void _on_cancel_button_clicked();
void _on_close_button_clicked();
void _on_result_selected();
void _on_item_edited();
void _on_replace_text_changed(const String &text);
void _on_replace_all_clicked();
enum {
enum FindButtons {
FIND_BUTTON_REPLACE,
FIND_BUTTON_REMOVE,
};
@@ -219,36 +167,67 @@ private:
int begin_trimmed = 0;
};
void apply_replaces_in_file(const String &fpath, const Vector<Result> &locations, const String &new_text);
void update_replace_buttons();
void update_matches_text();
String get_replace_text();
FindInFilesSearch *finder = nullptr;
Label *find_label = nullptr;
Label *search_text_label = nullptr;
Tree *results_display = nullptr;
Label *status_label = nullptr;
CheckButton *keep_results_button = nullptr;
Button *refresh_button = nullptr;
Button *cancel_button = nullptr;
Button *close_button = nullptr;
ProgressBar *progress_bar = nullptr;
HashMap<String, TreeItem *> file_items;
HashMap<TreeItem *, int> file_items_results_count;
HashMap<TreeItem *, Result> result_items;
bool with_replace = false;
void draw_result_text(Object *item_obj, Rect2 rect);
HBoxContainer *replace_container = nullptr;
LineEdit *replace_line_edit = nullptr;
Button *replace_all_button = nullptr;
void clear();
bool floating = false;
MarginContainer *results_mc = nullptr;
FindInFiles *_finder = nullptr;
Label *_find_label = nullptr;
Label *_search_text_label = nullptr;
Tree *_results_display = nullptr;
Label *_status_label = nullptr;
CheckButton *_keep_results_button = nullptr;
Button *_refresh_button = nullptr;
Button *_cancel_button = nullptr;
Button *_close_button = nullptr;
ProgressBar *_progress_bar = nullptr;
HashMap<String, TreeItem *> _file_items;
HashMap<TreeItem *, int> _file_items_results_count;
HashMap<TreeItem *, Result> _result_items;
bool _with_replace = false;
void _on_button_clicked(TreeItem *p_item, int p_column, int p_id, int p_mouse_button_index);
void _on_result_found(const String &p_fpath, int p_line_number, int p_begin, int p_end, const String &p_text);
void _on_theme_changed();
void _on_finished();
void _on_refresh_button_clicked();
void _on_cancel_button_clicked();
void _on_close_button_clicked();
void _on_result_selected();
void _on_item_edited();
void _on_replace_text_changed(const String &p_text);
void _on_replace_all_clicked();
HBoxContainer *_replace_container = nullptr;
LineEdit *_replace_line_edit = nullptr;
Button *_replace_all_button = nullptr;
void _apply_replaces_in_file(const String &p_fpath, const Vector<Result> &p_locations, const String &p_new_text);
void _update_replace_buttons();
void _update_matches_text();
String _get_replace_text();
bool _floating = false;
MarginContainer *_results_mc = nullptr;
void _draw_result_text(Object *p_item_obj, const Rect2 &p_rect);
void _clear();
protected:
void _notification(int p_what);
static void _bind_methods();
public:
FindInFilesSearch *get_finder() const { return finder; }
void set_with_replace(bool p_with_replace);
void set_replace_text(const String &p_text);
bool is_keep_results() const;
void set_search_labels_visibility(bool p_visible);
void start_search();
void stop_search();
void update_layout(EditorDock::DockLayout p_layout);
FindInFilesPanel();
};
class PopupMenu;
@@ -261,39 +240,58 @@ class TabContainer;
class FindInFilesContainer : public EditorDock {
GDCLASS(FindInFilesContainer, EditorDock);
enum {
enum PanelMenuOptions {
PANEL_CLOSE,
PANEL_CLOSE_OTHERS,
PANEL_CLOSE_RIGHT,
PANEL_CLOSE_ALL,
};
void _on_theme_changed();
TabContainer *tabs = nullptr;
bool update_bar = true;
PopupMenu *tabs_context_menu = nullptr;
void _on_tab_close_pressed(int p_tab);
void _update_bar_visibility();
void _bar_menu_option(int p_option);
void _bar_input(const Ref<InputEvent> &p_input);
void _on_dock_closed();
TabContainer *_tabs = nullptr;
bool _update_bar = true;
PopupMenu *_tabs_context_menu = nullptr;
void _on_theme_changed();
FindInFilesPanel *_create_new_panel();
FindInFilesPanel *_get_current_panel();
void _result_selected(const String &p_fpath, int p_line_number, int p_begin, int p_end);
void _files_modified();
void _close_panel(FindInFilesPanel *p_panel);
void _on_dock_closed();
protected:
static void _bind_methods();
void _notification(int p_what);
void _on_find_in_files_result_selected(const String &p_fpath, int p_line_number, int p_begin, int p_end);
void _on_find_in_files_modified_files(const PackedStringArray &p_paths);
void _on_find_in_files_close_button_clicked(FindInFilesPanel *p_panel);
virtual void update_layout(EditorDock::DockLayout p_layout) override;
static void _bind_methods();
public:
FindInFilesContainer();
virtual void update_layout(EditorDock::DockLayout p_layout) override;
FindInFilesPanel *get_panel_for_results(const String &p_label);
FindInFilesContainer();
};
class FindInFiles : public Object {
GDCLASS(FindInFiles, Object);
FindInFilesDialog *dialog = nullptr;
FindInFilesContainer *container = nullptr;
void _start_search(bool p_with_replace);
void _result_selected(const String &p_fpath, int p_line_number, int p_begin, int p_end);
void _files_modified();
protected:
static void _bind_methods();
public:
void open_dialog(const String &p_initial_text, bool p_replace = false);
FindInFiles();
};
+11 -43
View File
@@ -48,7 +48,6 @@
#include "editor/debugger/script_editor_debugger.h"
#include "editor/doc/editor_help.h"
#include "editor/doc/editor_help_search.h"
#include "editor/docks/editor_dock_manager.h"
#include "editor/docks/filesystem_dock.h"
#include "editor/docks/inspector_dock.h"
#include "editor/docks/signals_dock.h"
@@ -1103,7 +1102,7 @@ void ScriptEditor::_menu_option(int p_option) {
open_find_in_files_dialog("");
} break;
case REPLACE_IN_FILES: {
_on_replace_in_files_requested("");
open_find_in_files_dialog("", true);
} break;
case SEARCH_HELP: {
help_search_dialog->popup_dialog();
@@ -2349,8 +2348,8 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
teb->connect("go_to_help", callable_mp(this, &ScriptEditor::_help_class_goto));
teb->connect("request_save_history", callable_mp(this, &ScriptEditor::_save_history));
teb->connect("request_save_previous_state", callable_mp(this, &ScriptEditor::_save_previous_state));
teb->connect("search_in_files_requested", callable_mp(this, &ScriptEditor::open_find_in_files_dialog));
teb->connect("replace_in_files_requested", callable_mp(this, &ScriptEditor::_on_replace_in_files_requested));
teb->connect("search_in_files_requested", callable_mp(this, &ScriptEditor::open_find_in_files_dialog).bind(false));
teb->connect("replace_in_files_requested", callable_mp(this, &ScriptEditor::open_find_in_files_dialog).bind(true));
teb->connect("go_to_method", callable_mp(this, &ScriptEditor::script_goto_method));
if (script_editor_cache->has_section(p_resource->get_path())) {
@@ -2603,10 +2602,8 @@ void ScriptEditor::_auto_format_text(ScriptEditorBase *p_seb) {
}
}
void ScriptEditor::open_find_in_files_dialog(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::open_find_in_files_dialog(const String &p_initial_text, bool p_replace) {
find_in_files->open_dialog(p_initial_text, p_replace);
}
void ScriptEditor::open_script_create_dialog(const String &p_base_name, const String &p_base_path) {
@@ -3661,13 +3658,6 @@ void ScriptEditor::_script_changed() {
SignalsDock::get_singleton()->update_lists();
}
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(const String &fpath, int line_number, int begin, int end) {
if (ResourceLoader::exists(fpath)) {
Ref<Resource> res = ResourceLoader::load(fpath);
@@ -3754,26 +3744,7 @@ void ScriptEditor::_on_find_in_files_result_selected(const String &fpath, int li
}
}
void ScriptEditor::_start_find_in_files(bool with_replace) {
FindInFilesPanel *panel = find_in_files->get_panel_for_results(with_replace ? TTR("Replace:") + " " + find_in_files_dialog->get_search_text() : TTR("Find:") + " " + find_in_files_dialog->get_search_text());
FindInFiles *f = panel->get_finder();
f->set_search_text(find_in_files_dialog->get_search_text());
f->set_match_case(find_in_files_dialog->is_match_case());
f->set_whole_words(find_in_files_dialog->is_whole_words());
f->set_folder(find_in_files_dialog->get_folder());
f->set_filter(find_in_files_dialog->get_filter());
f->set_includes(find_in_files_dialog->get_includes());
f->set_excludes(find_in_files_dialog->get_excludes());
panel->set_with_replace(with_replace);
panel->set_replace_text(find_in_files_dialog->get_replace_text());
panel->start_search();
find_in_files->make_visible();
}
void ScriptEditor::_on_find_in_files_modified_files(const PackedStringArray &paths) {
void ScriptEditor::_on_find_in_files_modified_files() {
_test_script_times_on_disk();
_update_modified_scripts_for_external_editor();
}
@@ -4184,14 +4155,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
add_child(help_search_dialog);
help_search_dialog->connect("go_to_help", callable_mp(this, &ScriptEditor::_help_class_goto));
find_in_files_dialog = memnew(FindInFilesDialog);
find_in_files_dialog->connect(FindInFilesDialog::SIGNAL_FIND_REQUESTED, callable_mp(this, &ScriptEditor::_start_find_in_files).bind(false));
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(FindInFilesContainer);
EditorDockManager::get_singleton()->add_dock(find_in_files);
find_in_files->close();
find_in_files = memnew(FindInFiles);
find_in_files->connect("result_selected", callable_mp(this, &ScriptEditor::_on_find_in_files_result_selected));
find_in_files->connect("files_modified", callable_mp(this, &ScriptEditor::_on_find_in_files_modified_files));
@@ -4217,6 +4181,10 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
_update_online_doc();
}
ScriptEditor::~ScriptEditor() {
memdelete(find_in_files);
}
void ScriptEditorPlugin::_focus_another_editor() {
if (window_wrapper->get_window_enabled()) {
ERR_FAIL_COND(last_editor.is_empty());
+6 -9
View File
@@ -78,8 +78,7 @@ public:
};
class EditorScriptCodeCompletionCache;
class FindInFilesContainer;
class FindInFilesDialog;
class FindInFiles;
class ScriptEditor : public PanelContainer {
GDCLASS(ScriptEditor, PanelContainer);
@@ -197,8 +196,7 @@ class ScriptEditor : public PanelContainer {
Button *script_back = nullptr;
Button *script_forward = nullptr;
FindInFilesDialog *find_in_files_dialog = nullptr;
FindInFilesContainer *find_in_files = nullptr;
FindInFiles *find_in_files = nullptr;
WindowWrapper *window_wrapper = nullptr;
@@ -384,10 +382,8 @@ class ScriptEditor : public PanelContainer {
Ref<TextFile> _load_text_file(const String &p_path, Error *r_error) const;
Error _save_text_file(Ref<TextFile> p_text_file, const String &p_path);
void _on_replace_in_files_requested(const String &text);
void _on_find_in_files_result_selected(const String &fpath, int line_number, int begin, int end);
void _start_find_in_files(bool with_replace);
void _on_find_in_files_modified_files(const PackedStringArray &paths);
void _on_find_in_files_result_selected(const String &p_path, int p_line_number, int p_begin, int p_end);
void _on_find_in_files_modified_files();
void _set_script_zoom_factor(float p_zoom_factor);
void _update_code_editor_zoom_factor(CodeTextEditor *p_code_text_editor);
@@ -409,7 +405,7 @@ public:
bool is_files_panel_toggled();
void apply_scripts() const;
void reload_scripts(bool p_refresh_only = false);
void open_find_in_files_dialog(const String &text);
void open_find_in_files_dialog(const String &p_initial_text = "", bool p_replace = false);
void open_script_create_dialog(const String &p_base_name, const String &p_base_path);
void open_text_file_create_dialog(const String &p_base_path, const String &p_base_name = "");
Ref<Resource> open_file(const String &p_file);
@@ -464,6 +460,7 @@ public:
static void register_create_script_editor_function(CreateScriptEditorFunc p_func);
ScriptEditor(WindowWrapper *p_wrapper);
~ScriptEditor();
};
class ScriptEditorPlugin : public EditorPlugin {