summaryrefslogtreecommitdiff
path: root/scene/gui
diff options
context:
space:
mode:
authorAlfred Reinold Baudisch <alfred@alfredbaudisch.com>2022-10-19 19:35:14 +0200
committerAlfred Reinold Baudisch <alfred@alfredbaudisch.com>2022-10-21 08:26:53 +0200
commit7d15ecc3affdee1ad89ef1a2eeaca6b894ae6548 (patch)
tree366b22fbd35f6e5c20048ba0f14926fa83091998 /scene/gui
parent431012e14845590249c1ade9d153c55b32c9cca7 (diff)
Add Selection and Caret for Next Occurrence of Selection
Adds the bind `add_selection_for_next_occurrence` to TextEdit, with CTRL+D as the default shortcut. When the bind is performed, ff a selection is currently active with the last caret in text fields, searches for the next occurrence of the selection, adds a caret and selects the next occurrence. If no selection is currently active with the last caret in text fields, selects the word currently under the caret. The action can be performed sequentially for all occurrences of the selection of the last caret and for all existing carets. The viewport is adjusted to the latest newly added caret. The bind and the behaviour is similar to VS Code's "Add Selection to Next Find Match" and JetBrains' "Add Selection for Next Occurrence". It takes advantage of the multi-caret API. The default shortcut for `select_word_under_caret` has been changed to ALT+G, in order to give priority to CTRL+D for `add_selection_for_next_occurrence` to better align with popular IDEs and editors.
Diffstat (limited to 'scene/gui')
-rw-r--r--scene/gui/text_edit.cpp47
-rw-r--r--scene/gui/text_edit.h1
2 files changed, 47 insertions, 1 deletions
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 90974e31df..49b53ea206 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -2051,7 +2051,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
if (is_shortcut_keys_enabled()) {
- // SELECT ALL, SELECT WORD UNDER CARET, CUT, COPY, PASTE.
+ // SELECT ALL, SELECT WORD UNDER CARET, ADD SELECTION FOR NEXT OCCURRENCE, CUT, COPY, PASTE.
if (k->is_action("ui_text_select_all", true)) {
select_all();
accept_event();
@@ -2062,6 +2062,11 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
accept_event();
return;
}
+ if (k->is_action("ui_text_add_selection_for_next_occurrence", true)) {
+ add_selection_for_next_occurrence();
+ accept_event();
+ return;
+ }
if (k->is_action("ui_cut", true)) {
cut();
accept_event();
@@ -4832,6 +4837,45 @@ void TextEdit::select_word_under_caret(int p_caret) {
merge_overlapping_carets();
}
+void TextEdit::add_selection_for_next_occurrence() {
+ if (!selecting_enabled || !is_multiple_carets_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;
+
+ if (!has_selection(caret)) {
+ select_word_under_caret(caret);
+ return;
+ }
+
+ const String &highlighted_text = get_selected_text(caret);
+ int column = get_selection_from_column(caret) + 1;
+ int line = get_caret_line(caret);
+
+ const Point2i next_occurrence = search(highlighted_text, SEARCH_MATCH_CASE, line, column);
+
+ if (next_occurrence.x == -1 || next_occurrence.y == -1) {
+ return;
+ }
+
+ int to_column = get_selection_to_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();
+ }
+}
+
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) {
@@ -6000,6 +6044,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("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));
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index e4af621b73..86b838e387 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -851,6 +851,7 @@ public:
void select_all();
void select_word_under_caret(int p_caret = -1);
+ void add_selection_for_next_occurrence();
void select(int p_from_line, int p_from_column, int p_to_line, int p_to_column, int p_caret = 0);
bool has_selection(int p_caret = -1) const;