From 04bd9cc06c59e44c9458513fa39b38321311de92 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. (cherry picked from commit 676627e1d16367616c7022df8d12c836c201c5f4) --- 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 4c3d23aa631..a776e528e0a 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -367,6 +367,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); @@ -375,11 +378,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 3b2013f7ecf..1975482cf11 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -4131,6 +4131,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; @@ -4194,9 +4197,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; } } @@ -6990,6 +6993,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); @@ -7001,9 +7007,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 8cfb1893709..3fcb6cc83b9 100644 --- a/tests/scene/test_text_edit.h +++ b/tests/scene/test_text_edit.h @@ -3221,7 +3221,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)); @@ -3253,6 +3253,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));