summaryrefslogtreecommitdiffstats
path: root/scene/gui/text_edit.cpp
diff options
context:
space:
mode:
authorChristophe Andral <christophe@andral.fr>2024-02-02 23:10:55 +0100
committerChristophe Andral <christophe@andral.fr>2024-03-25 11:12:28 +0100
commitc988bec4b3dff7ac32a1940a3f5c3d97a46ca8cd (patch)
treec756bfd9c9d43eee0bbe59546de45c315e69e782 /scene/gui/text_edit.cpp
parent5d08c2631cadf29d80ca23c7d537e03c3e5edcc5 (diff)
downloadredot-engine-c988bec4b3dff7ac32a1940a3f5c3d97a46ca8cd.tar.gz
Add 'Skip to next (text) occurrence' feature to text editor
Adds `ui_text_skip_selection_for_next_occurrence` action and related implementation to text editor. This action is bound `Ctrl+Alt+D` shorcut. Used in conjonction with `ui_add_skip_selection_for_next_occurrence`, it gives the user the ability to select many occurrences of a selection and avoid some of them. Used without a previous selection, the action jumps to the next occurrence of the current word under the caret.
Diffstat (limited to 'scene/gui/text_edit.cpp')
-rw-r--r--scene/gui/text_edit.cpp56
1 files changed, 55 insertions, 1 deletions
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 2d7a66d4c0..29e4956588 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -2115,7 +2115,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
if (is_shortcut_keys_enabled()) {
- // SELECT ALL, SELECT WORD UNDER CARET, ADD SELECTION FOR NEXT OCCURRENCE,
+ // SELECT ALL, SELECT WORD UNDER CARET, ADD SELECTION FOR NEXT OCCURRENCE, SKIP SELECTION FOR NEXT OCCURRENCE,
// CLEAR CARETS AND SELECTIONS, CUT, COPY, PASTE.
if (k->is_action("ui_text_select_all", true)) {
select_all();
@@ -2132,6 +2132,11 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
accept_event();
return;
}
+ if (k->is_action("ui_text_skip_selection_for_next_occurrence", true)) {
+ skip_selection_for_next_occurrence();
+ accept_event();
+ return;
+ }
if (k->is_action("ui_text_clear_carets_and_selection", true)) {
// Since the default shortcut is ESC, accepts the event only if it's actually performed.
if (_clear_carets_and_selection()) {
@@ -5185,6 +5190,54 @@ void TextEdit::add_selection_for_next_occurrence() {
}
}
+void TextEdit::skip_selection_for_next_occurrence() {
+ if (!selecting_enabled) {
+ return;
+ }
+
+ if (text.size() == 1 && text[0].length() == 0) {
+ return;
+ }
+
+ // Always use the last caret, to correctly search for
+ // the next occurrence that comes after this caret.
+ int caret = get_caret_count() - 1;
+
+ // Supports getting the text under caret without selecting it.
+ // It allows to use this shortcut to simply jump to the next (under caret) word.
+ // Due to const and &(reference) presence, ternary operator is a way to avoid errors and warnings.
+ const String &searched_text = has_selection(caret) ? get_selected_text(caret) : get_word_under_caret(caret);
+
+ int column = (has_selection(caret) ? get_selection_from_column(caret) : get_caret_column(caret)) + 1;
+ int line = get_caret_line(caret);
+
+ const Point2i next_occurrence = search(searched_text, SEARCH_MATCH_CASE, line, column);
+
+ if (next_occurrence.x == -1 || next_occurrence.y == -1) {
+ return;
+ }
+
+ int to_column = (has_selection(caret) ? get_selection_to_column(caret) : get_caret_column(caret)) + 1;
+ int end = next_occurrence.x + (to_column - column);
+ int new_caret = add_caret(next_occurrence.y, end);
+
+ if (new_caret != -1) {
+ select(next_occurrence.y, next_occurrence.x, next_occurrence.y, end, new_caret);
+ adjust_viewport_to_caret(new_caret);
+ merge_overlapping_carets();
+ }
+
+ // Deselect word under previous caret.
+ if (has_selection(caret)) {
+ select_word_under_caret(caret);
+ }
+
+ // Remove previous caret.
+ if (get_caret_count() > 1) {
+ remove_caret(caret);
+ }
+}
+
void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_to_column, int p_caret) {
ERR_FAIL_INDEX(p_caret, carets.size());
if (!selecting_enabled) {
@@ -6351,6 +6404,7 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("select_all"), &TextEdit::select_all);
ClassDB::bind_method(D_METHOD("select_word_under_caret", "caret_index"), &TextEdit::select_word_under_caret, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("add_selection_for_next_occurrence"), &TextEdit::add_selection_for_next_occurrence);
+ ClassDB::bind_method(D_METHOD("skip_selection_for_next_occurrence"), &TextEdit::skip_selection_for_next_occurrence);
ClassDB::bind_method(D_METHOD("select", "from_line", "from_column", "to_line", "to_column", "caret_index"), &TextEdit::select, DEFVAL(0));
ClassDB::bind_method(D_METHOD("has_selection", "caret_index"), &TextEdit::has_selection, DEFVAL(-1));