Add new actions `editor::FindNextMatch` and `editor::FindPreviousMatch` (#28559)

João Marcos created

Closes #7903

Release Notes:

- Add new actions `editor::FindNextMatch` and
`editor::FindPreviousMatch` that are similar to `editor::SelectNext` and
`editor::SelectPrevious` with `"replace_newest": true`, but jumps to the
first or last selection when there are multiple selections.

Change summary

assets/keymaps/linux/sublime_text.json |  4 +
assets/keymaps/macos/sublime_text.json |  4 +
crates/editor/src/actions.rs           |  2 +
crates/editor/src/editor.rs            | 48 ++++++++++++++++++++++++++++
crates/editor/src/element.rs           |  6 +++
5 files changed, 62 insertions(+), 2 deletions(-)

Detailed changes

assets/keymaps/linux/sublime_text.json 🔗

@@ -49,7 +49,9 @@
       "ctrl-k ctrl-l": "editor::ConvertToLowerCase",
       "shift-alt-m": "markdown::OpenPreviewToTheSide",
       "ctrl-backspace": "editor::DeleteToPreviousWordStart",
-      "ctrl-delete": "editor::DeleteToNextWordEnd"
+      "ctrl-delete": "editor::DeleteToNextWordEnd",
+      "f3": "editor::FindNextMatch",
+      "shift-f3": "editor::FindPreviousMatch"
     }
   },
   {

assets/keymaps/macos/sublime_text.json 🔗

@@ -51,7 +51,9 @@
       "cmd-shift-j": "editor::JoinLines",
       "shift-alt-m": "markdown::OpenPreviewToTheSide",
       "ctrl-backspace": "editor::DeleteToPreviousWordStart",
-      "ctrl-delete": "editor::DeleteToNextWordEnd"
+      "ctrl-delete": "editor::DeleteToNextWordEnd",
+      "cmd-g": "editor::FindNextMatch",
+      "cmd-shift-g": "editor::FindPreviousMatch"
     }
   },
   {

crates/editor/src/actions.rs 🔗

@@ -283,6 +283,8 @@ actions!(
         DuplicateSelection,
         ExpandMacroRecursively,
         FindAllReferences,
+        FindNextMatch,
+        FindPreviousMatch,
         Fold,
         FoldAll,
         FoldFunctionBodies,

crates/editor/src/editor.rs 🔗

@@ -12020,6 +12020,54 @@ impl Editor {
         Ok(())
     }
 
+    pub fn find_next_match(
+        &mut self,
+        _: &FindNextMatch,
+        window: &mut Window,
+        cx: &mut Context<Self>,
+    ) -> Result<()> {
+        let selections = self.selections.disjoint_anchors();
+        match selections.first() {
+            Some(first) if selections.len() >= 2 => {
+                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
+                    s.select_ranges([first.range()]);
+                });
+            }
+            _ => self.select_next(
+                &SelectNext {
+                    replace_newest: true,
+                },
+                window,
+                cx,
+            )?,
+        }
+        Ok(())
+    }
+
+    pub fn find_previous_match(
+        &mut self,
+        _: &FindPreviousMatch,
+        window: &mut Window,
+        cx: &mut Context<Self>,
+    ) -> Result<()> {
+        let selections = self.selections.disjoint_anchors();
+        match selections.last() {
+            Some(last) if selections.len() >= 2 => {
+                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
+                    s.select_ranges([last.range()]);
+                });
+            }
+            _ => self.select_previous(
+                &SelectPrevious {
+                    replace_newest: true,
+                },
+                window,
+                cx,
+            )?,
+        }
+        Ok(())
+    }
+
     pub fn toggle_comments(
         &mut self,
         action: &ToggleComments,

crates/editor/src/element.rs 🔗

@@ -325,6 +325,12 @@ impl EditorElement {
         register_action(editor, window, |editor, action, window, cx| {
             editor.select_previous(action, window, cx).log_err();
         });
+        register_action(editor, window, |editor, action, window, cx| {
+            editor.find_next_match(action, window, cx).log_err();
+        });
+        register_action(editor, window, |editor, action, window, cx| {
+            editor.find_previous_match(action, window, cx).log_err();
+        });
         register_action(editor, window, Editor::toggle_comments);
         register_action(editor, window, Editor::select_larger_syntax_node);
         register_action(editor, window, Editor::select_smaller_syntax_node);