From 676627e1d16367616c7022df8d12c836c201c5f4 Mon Sep 17 00:00:00 2001 From: Brian MacIntosh Date: Mon, 2 Oct 2023 13:30:23 -0700 Subject: [PATCH] "Whole Words" search can detect word boundaries inside the search term. For example, searching for ".func" will now match in "a.func" even with Whole Words enabled. --- editor/code_editor.cpp | 7 +++++-- scene/gui/text_edit.cpp | 14 ++++++++++---- tests/scene/test_text_edit.h | 7 ++++++- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 56e405bfcfd..64467bc254e 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -368,6 +368,9 @@ void FindReplaceBar::_update_results_count() { int col_pos = 0; + bool searched_start_is_symbol = is_symbol(searched[0]); + bool searched_end_is_symbol = is_symbol(searched[searched.length() - 1]); + while (true) { col_pos = is_case_sensitive() ? line_text.find(searched, col_pos) : line_text.findn(searched, col_pos); @@ -376,11 +379,11 @@ void FindReplaceBar::_update_results_count() { } if (is_whole_words()) { - if (col_pos > 0 && !is_symbol(line_text[col_pos - 1])) { + if (!searched_start_is_symbol && col_pos > 0 && !is_symbol(line_text[col_pos - 1])) { col_pos += searched.length(); continue; } - if (col_pos + searched.length() < line_text.length() && !is_symbol(line_text[col_pos + searched.length()])) { + if (!searched_end_is_symbol && col_pos + searched.length() < line_text.length() && !is_symbol(line_text[col_pos + searched.length()])) { col_pos += searched.length(); continue; } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 9e159cd303c..f00fdb6896d 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -4112,6 +4112,9 @@ Point2i TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_fro int line = p_from_line; int pos = -1; + bool key_start_is_symbol = is_symbol(p_key[0]); + bool key_end_is_symbol = is_symbol(p_key[p_key.length() - 1]); + for (int i = 0; i < text.size() + 1; i++) { if (line < 0) { line = text.size() - 1; @@ -4175,9 +4178,9 @@ Point2i TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_fro if (pos != -1 && (p_search_flags & SEARCH_WHOLE_WORDS)) { // Validate for whole words. - if (pos > 0 && !is_symbol(text_line[pos - 1])) { + if (!key_start_is_symbol && pos > 0 && !is_symbol(text_line[pos - 1])) { is_match = false; - } else if (pos + p_key.length() < text_line.length() && !is_symbol(text_line[pos + p_key.length()])) { + } else if (!key_end_is_symbol && pos + p_key.length() < text_line.length() && !is_symbol(text_line[pos + p_key.length()])) { is_match = false; } } @@ -7020,6 +7023,9 @@ int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_searc p_from_column = 0; } + bool key_start_is_symbol = is_symbol(p_key[0]); + bool key_end_is_symbol = is_symbol(p_key[p_key.length() - 1]); + while (col == -1 && p_from_column <= p_search.length()) { if (p_search_flags & SEARCH_MATCH_CASE) { col = p_search.find(p_key, p_from_column); @@ -7036,9 +7042,9 @@ int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_searc if (col != -1 && p_search_flags & SEARCH_WHOLE_WORDS) { p_from_column = col; - if (col > 0 && !is_symbol(p_search[col - 1])) { + if (!key_start_is_symbol && col > 0 && !is_symbol(p_search[col - 1])) { col = -1; - } else if ((col + p_key.length()) < p_search.length() && !is_symbol(p_search[col + p_key.length()])) { + } else if (!key_end_is_symbol && (col + p_key.length()) < p_search.length() && !is_symbol(p_search[col + p_key.length()])) { col = -1; } } diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h index 7e9b472af1b..840a04becf0 100644 --- a/tests/scene/test_text_edit.h +++ b/tests/scene/test_text_edit.h @@ -3193,7 +3193,7 @@ TEST_CASE("[SceneTree][TextEdit] search") { TextEdit *text_edit = memnew(TextEdit); SceneTree::get_singleton()->get_root()->add_child(text_edit); - text_edit->set_text("hay needle, hay\nHAY NEEDLE, HAY"); + text_edit->set_text("hay needle, hay\nHAY NEEDLE, HAY\nwordword.word.word"); int length = text_edit->get_line(1).length(); CHECK(text_edit->search("test", 0, 0, 0) == Point2i(-1, -1)); @@ -3225,6 +3225,11 @@ TEST_CASE("[SceneTree][TextEdit] search") { CHECK(text_edit->search("need", TextEdit::SEARCH_WHOLE_WORDS | TextEdit::SEARCH_MATCH_CASE, 0, 0) == Point2i(-1, -1)); CHECK(text_edit->search("need", TextEdit::SEARCH_WHOLE_WORDS | TextEdit::SEARCH_MATCH_CASE | TextEdit::SEARCH_BACKWARDS, 0, 0) == Point2i(-1, -1)); + CHECK(text_edit->search("word", TextEdit::SEARCH_WHOLE_WORDS, 2, 0) == Point2i(9, 2)); + CHECK(text_edit->search("word", TextEdit::SEARCH_WHOLE_WORDS, 2, 10) == Point2i(14, 2)); + CHECK(text_edit->search(".word", TextEdit::SEARCH_WHOLE_WORDS, 2, 0) == Point2i(8, 2)); + CHECK(text_edit->search("word.", TextEdit::SEARCH_WHOLE_WORDS, 2, 0) == Point2i(9, 2)); + ERR_PRINT_OFF; CHECK(text_edit->search("", 0, 0, 0) == Point2i(-1, -1)); CHECK(text_edit->search("needle", 0, -1, 0) == Point2i(-1, -1));