39
39
#include " scene/gui/box_container.h"
40
40
#include " scene/gui/button.h"
41
41
#include " scene/gui/check_box.h"
42
+ #include " scene/gui/code_edit.h"
42
43
#include " scene/gui/file_dialog.h"
43
44
#include " scene/gui/grid_container.h"
44
45
#include " scene/gui/label.h"
47
48
#include " scene/gui/tree.h"
48
49
49
50
const char *FindInFiles::SIGNAL_RESULT_FOUND = " result_found" ;
51
+ CodeEdit *_dummy_code_edit = nullptr ;
50
52
51
53
// TODO: Would be nice in Vector and Vectors.
52
54
template <typename T>
53
55
inline void pop_back (T &container) {
54
56
container.resize (container.size () - 1 );
55
57
}
56
58
57
- static bool find_next (const String &line, const String &pattern, int from, bool match_case, bool whole_words, int &out_begin, int &out_end) {
59
+ static bool find_next (const String &line, const String &pattern, int from, bool match_case, bool whole_words, bool ignore_code, bool ignore_strings, bool ignore_comments, int line_number, int &out_begin, int &out_end) {
58
60
int end = from;
61
+ line_number -= 1 ; // Get the line index, since that's what we use it for.
59
62
60
63
while (true ) {
61
64
int begin = match_case ? line.find (pattern, end) : line.findn (pattern, end);
@@ -77,6 +80,20 @@ static bool find_next(const String &line, const String &pattern, int from, bool
77
80
}
78
81
}
79
82
83
+ // Graceful failure, so you still get search results? Maybe it's better to assume it's valid, and not do another if check...
84
+ if (_dummy_code_edit == nullptr ) {
85
+ return true ;
86
+ }
87
+ if (ignore_code && _dummy_code_edit->is_in_comment (line_number, begin) == -1 && _dummy_code_edit->is_in_string (line_number, begin) == -1 ) {
88
+ continue ;
89
+ }
90
+ if (ignore_strings && _dummy_code_edit->is_in_string (line_number, begin) != -1 ) {
91
+ continue ;
92
+ }
93
+ if (ignore_comments && _dummy_code_edit->is_in_comment (line_number, begin) != -1 ) {
94
+ continue ;
95
+ }
96
+
80
97
return true ;
81
98
}
82
99
}
@@ -87,6 +104,30 @@ void FindInFiles::set_search_text(const String &p_pattern) {
87
104
_pattern = p_pattern;
88
105
}
89
106
107
+ void FindInFiles::set_search_file_context (const Ref<FileAccess> &file) {
108
+ ERR_FAIL_NULL_MSG (_dummy_code_edit, " _dummy_code_edit is null, Find in Files cannot use 'Code, Strings, Comments' filters for search." );
109
+ _dummy_code_edit->set_text (file->get_as_text ());
110
+
111
+ bool gdscript_delimiters = false ;
112
+ String extension = file->get_path ().get_extension ();
113
+ if (extension == " gd" ) {
114
+ gdscript_delimiters = true ;
115
+ }
116
+
117
+ TypedArray<String> delimiters;
118
+ if (gdscript_delimiters) {
119
+ delimiters.append (" #" );
120
+ } else { // This is for gdshader, csharp, and other c like languages.
121
+ // We don't support other languages in editor do we? Otherwise we could expose a way to add more delimiters.
122
+ delimiters.append (" //" );
123
+ delimiters.append (" /* */" );
124
+ }
125
+
126
+ // Only change comment delimiters, default string delimiters should work with any language.
127
+ _dummy_code_edit->clear_comment_delimiters ();
128
+ _dummy_code_edit->set_comment_delimiters (delimiters);
129
+ }
130
+
90
131
void FindInFiles::set_whole_words (bool p_whole_word) {
91
132
_whole_words = p_whole_word;
92
133
}
@@ -95,6 +136,18 @@ void FindInFiles::set_match_case(bool p_match_case) {
95
136
_match_case = p_match_case;
96
137
}
97
138
139
+ void FindInFiles::set_ignore_code (bool p_ignore_code) {
140
+ _ignore_code = p_ignore_code;
141
+ }
142
+
143
+ void FindInFiles::set_ignore_strings (bool p_ignore_strings) {
144
+ _ignore_strings = p_ignore_strings;
145
+ }
146
+
147
+ void FindInFiles::set_ignore_comments (bool p_ignore_comments) {
148
+ _ignore_comments = p_ignore_comments;
149
+ }
150
+
98
151
void FindInFiles::set_folder (const String &folder) {
99
152
_root_dir = folder;
100
153
}
@@ -268,6 +321,10 @@ void FindInFiles::_scan_file(const String &fpath) {
268
321
269
322
int line_number = 0 ;
270
323
324
+ if (_ignore_code || _ignore_strings || _ignore_comments) {
325
+ set_search_file_context (f);
326
+ }
327
+
271
328
while (!f->eof_reached ()) {
272
329
// Line number starts at 1.
273
330
++line_number;
@@ -277,7 +334,7 @@ void FindInFiles::_scan_file(const String &fpath) {
277
334
278
335
String line = f->get_line ();
279
336
280
- while (find_next (line, _pattern, end, _match_case, _whole_words, begin, end)) {
337
+ while (find_next (line, _pattern, end, _match_case, _whole_words, _ignore_code, _ignore_strings, _ignore_comments, line_number, begin, end)) {
281
338
emit_signal (SNAME (SIGNAL_RESULT_FOUND), fpath, line_number, begin, end, line);
282
339
}
283
340
}
@@ -302,6 +359,9 @@ FindInFilesDialog::FindInFilesDialog() {
302
359
set_min_size (Size2 (500 * EDSCALE, 0 ));
303
360
set_title (TTR (" Find in Files" ));
304
361
362
+ // Intentionally not added as child.
363
+ _dummy_code_edit = memnew (CodeEdit);
364
+
305
365
VBoxContainer *vbc = memnew (VBoxContainer);
306
366
vbc->set_anchor_and_offset (SIDE_LEFT, Control::ANCHOR_BEGIN, 8 * EDSCALE);
307
367
vbc->set_anchor_and_offset (SIDE_TOP, Control::ANCHOR_BEGIN, 8 * EDSCALE);
@@ -350,6 +410,31 @@ FindInFilesDialog::FindInFilesDialog() {
350
410
gc->add_child (hbc);
351
411
}
352
412
413
+ Label *search_in_label = memnew (Label);
414
+ search_in_label->set_text (TTR (" Inside:" ));
415
+ gc->add_child (search_in_label);
416
+
417
+ {
418
+ HBoxContainer *hbc = memnew (HBoxContainer);
419
+
420
+ _include_code_checkbox = memnew (CheckBox);
421
+ _include_code_checkbox->set_text (TTR (" Code" ));
422
+ _include_code_checkbox->set_pressed (true );
423
+ hbc->add_child (_include_code_checkbox);
424
+
425
+ _include_strings_checkbox = memnew (CheckBox);
426
+ _include_strings_checkbox->set_text (TTR (" Strings" ));
427
+ _include_strings_checkbox->set_pressed (true );
428
+ hbc->add_child (_include_strings_checkbox);
429
+
430
+ _include_comments_checkbox = memnew (CheckBox);
431
+ _include_comments_checkbox->set_text (TTR (" Comments" ));
432
+ _include_comments_checkbox->set_pressed (true );
433
+ hbc->add_child (_include_comments_checkbox);
434
+
435
+ gc->add_child (hbc);
436
+ }
437
+
353
438
Label *folder_label = memnew (Label);
354
439
folder_label->set_text (TTR (" Folder:" ));
355
440
gc->add_child (folder_label);
@@ -460,6 +545,18 @@ bool FindInFilesDialog::is_whole_words() const {
460
545
return _whole_words_checkbox->is_pressed ();
461
546
}
462
547
548
+ bool FindInFilesDialog::is_ignore_code () const {
549
+ return !_include_code_checkbox->is_pressed ();
550
+ }
551
+
552
+ bool FindInFilesDialog::is_ignore_strings () const {
553
+ return !_include_strings_checkbox->is_pressed ();
554
+ }
555
+
556
+ bool FindInFilesDialog::is_ignore_comments () const {
557
+ return !_include_comments_checkbox->is_pressed ();
558
+ }
559
+
463
560
String FindInFilesDialog::get_folder () const {
464
561
String text = _folder_line_edit->get_text ();
465
562
return text.strip_edges ();
@@ -947,6 +1044,10 @@ void FindInFilesPanel::apply_replaces_in_file(const String &fpath, const Vector<
947
1044
Ref<FileAccess> f = FileAccess::open (fpath, FileAccess::READ);
948
1045
ERR_FAIL_COND_MSG (f.is_null (), " Cannot open file from path '" + fpath + " '." );
949
1046
1047
+ if (_finder->is_ignore_code () || _finder->is_ignore_strings () || _finder->is_ignore_comments ()) {
1048
+ _finder->set_search_file_context (f);
1049
+ }
1050
+
950
1051
String buffer;
951
1052
int current_line = 1 ;
952
1053
@@ -971,7 +1072,7 @@ void FindInFilesPanel::apply_replaces_in_file(const String &fpath, const Vector<
971
1072
int repl_end = locations[i].end + offset;
972
1073
973
1074
int _;
974
- if (!find_next (line, search_text, repl_begin, _finder->is_match_case (), _finder->is_whole_words (), _, _)) {
1075
+ if (!find_next (line, search_text, repl_begin, _finder->is_match_case (), _finder->is_whole_words (), _finder-> is_ignore_code (), _finder-> is_ignore_strings (), _finder-> is_ignore_comments (), repl_line_number, _, _)) {
975
1076
// Make sure the replace is still valid in case the file was tampered with.
976
1077
print_verbose (String (" Occurrence no longer matches, replace will be ignored in {0}: line {1}, col {2}" ).format (varray (fpath, repl_line_number, repl_begin)));
977
1078
continue ;
0 commit comments