Extract a common `match_index_for_direction` and `active_match_index`

Antonio Scandurra created

Change summary

crates/search/src/buffer_search.rs  | 91 +++++++++---------------------
crates/search/src/project_search.rs | 86 ++++++++---------------------
crates/search/src/search.rs         | 63 +++++++++++++++++++++
3 files changed, 115 insertions(+), 125 deletions(-)

Detailed changes

crates/search/src/buffer_search.rs 🔗

@@ -1,4 +1,4 @@
-use crate::{Direction, SearchOption, SelectMatch};
+use crate::{active_match_index, match_index_for_direction, Direction, SearchOption, SelectMatch};
 use collections::HashMap;
 use editor::{display_map::ToDisplayPoint, Anchor, Autoscroll, Bias, Editor};
 use gpui::{
@@ -8,10 +8,7 @@ use gpui::{
 use language::AnchorRangeExt;
 use postage::watch;
 use project::search::SearchQuery;
-use std::{
-    cmp::{self, Ordering},
-    ops::Range,
-};
+use std::ops::Range;
 use workspace::{ItemViewHandle, Pane, Settings, Toolbar, Workspace};
 
 action!(Deploy, bool);
@@ -334,43 +331,23 @@ impl SearchBar {
         cx.notify();
     }
 
-    fn select_match(&mut self, SelectMatch(direction): &SelectMatch, cx: &mut ViewContext<Self>) {
-        if let Some(mut index) = self.active_match_index {
+    fn select_match(&mut self, &SelectMatch(direction): &SelectMatch, cx: &mut ViewContext<Self>) {
+        if let Some(index) = self.active_match_index {
             if let Some(editor) = self.active_editor.as_ref() {
                 editor.update(cx, |editor, cx| {
-                    let newest_selection = editor.newest_anchor_selection().clone();
                     if let Some(ranges) = self.editors_with_matches.get(&cx.weak_handle()) {
-                        let position = newest_selection.head();
-                        let buffer = editor.buffer().read(cx).read(cx);
-                        if ranges[index].start.cmp(&position, &buffer).unwrap().is_gt() {
-                            if *direction == Direction::Prev {
-                                if index == 0 {
-                                    index = ranges.len() - 1;
-                                } else {
-                                    index -= 1;
-                                }
-                            }
-                        } else if ranges[index].end.cmp(&position, &buffer).unwrap().is_lt() {
-                            if *direction == Direction::Next {
-                                index = 0;
-                            }
-                        } else if *direction == Direction::Prev {
-                            if index == 0 {
-                                index = ranges.len() - 1;
-                            } else {
-                                index -= 1;
-                            }
-                        } else if *direction == Direction::Next {
-                            if index == ranges.len() - 1 {
-                                index = 0
-                            } else {
-                                index += 1;
-                            }
-                        }
-
-                        let range_to_select = ranges[index].clone();
-                        drop(buffer);
-                        editor.select_ranges([range_to_select], Some(Autoscroll::Fit), cx);
+                        let new_index = match_index_for_direction(
+                            ranges,
+                            &editor.newest_anchor_selection().head(),
+                            index,
+                            direction,
+                            &editor.buffer().read(cx).read(cx),
+                        );
+                        editor.select_ranges(
+                            [ranges[new_index].clone()],
+                            Some(Autoscroll::Fit),
+                            cx,
+                        );
                     }
                 });
             }
@@ -518,30 +495,18 @@ impl SearchBar {
     }
 
     fn update_match_index(&mut self, cx: &mut ViewContext<Self>) {
-        self.active_match_index = self.active_match_index(cx);
-        cx.notify();
-    }
-
-    fn active_match_index(&mut self, cx: &mut ViewContext<Self>) -> Option<usize> {
-        let editor = self.active_editor.as_ref()?;
-        let ranges = self.editors_with_matches.get(&editor.downgrade())?;
-        let editor = editor.read(cx);
-        let position = editor.newest_anchor_selection().head();
-        if ranges.is_empty() {
-            None
-        } else {
-            let buffer = editor.buffer().read(cx).read(cx);
-            match ranges.binary_search_by(|probe| {
-                if probe.end.cmp(&position, &*buffer).unwrap().is_lt() {
-                    Ordering::Less
-                } else if probe.start.cmp(&position, &*buffer).unwrap().is_gt() {
-                    Ordering::Greater
-                } else {
-                    Ordering::Equal
-                }
-            }) {
-                Ok(i) | Err(i) => Some(cmp::min(i, ranges.len() - 1)),
-            }
+        let new_index = self.active_editor.as_ref().and_then(|editor| {
+            let ranges = self.editors_with_matches.get(&editor.downgrade())?;
+            let editor = editor.read(cx);
+            active_match_index(
+                &ranges,
+                &editor.newest_anchor_selection().head(),
+                &editor.buffer().read(cx).read(cx),
+            )
+        });
+        if new_index != self.active_match_index {
+            self.active_match_index = new_index;
+            cx.notify();
         }
     }
 }

crates/search/src/project_search.rs 🔗

@@ -1,4 +1,7 @@
-use crate::{Direction, SearchOption, SelectMatch, ToggleSearchOption};
+use crate::{
+    active_match_index, match_index_for_direction, Direction, SearchOption, SelectMatch,
+    ToggleSearchOption,
+};
 use collections::HashMap;
 use editor::{Anchor, Autoscroll, Editor, MultiBuffer, SelectAll};
 use gpui::{
@@ -10,7 +13,6 @@ use postage::watch;
 use project::{search::SearchQuery, Project};
 use std::{
     any::{Any, TypeId},
-    cmp::{self, Ordering},
     ops::Range,
     path::PathBuf,
 };
@@ -496,42 +498,17 @@ impl ProjectSearchView {
     }
 
     fn select_match(&mut self, &SelectMatch(direction): &SelectMatch, cx: &mut ViewContext<Self>) {
-        if let Some(mut index) = self.active_match_index {
-            let range_to_select = {
-                let model = self.model.read(cx);
-                let results_editor = self.results_editor.read(cx);
-                let buffer = results_editor.buffer().read(cx).read(cx);
-                let cursor = results_editor.newest_anchor_selection().head();
-                let ranges = &model.match_ranges;
-
-                if ranges[index].start.cmp(&cursor, &buffer).unwrap().is_gt() {
-                    if direction == Direction::Prev {
-                        if index == 0 {
-                            index = ranges.len() - 1;
-                        } else {
-                            index -= 1;
-                        }
-                    }
-                } else if ranges[index].end.cmp(&cursor, &buffer).unwrap().is_lt() {
-                    if direction == Direction::Next {
-                        index = 0;
-                    }
-                } else if direction == Direction::Prev {
-                    if index == 0 {
-                        index = ranges.len() - 1;
-                    } else {
-                        index -= 1;
-                    }
-                } else if direction == Direction::Next {
-                    if index == ranges.len() - 1 {
-                        index = 0
-                    } else {
-                        index += 1;
-                    }
-                };
-                ranges[index].clone()
-            };
-
+        if let Some(index) = self.active_match_index {
+            let model = self.model.read(cx);
+            let results_editor = self.results_editor.read(cx);
+            let new_index = match_index_for_direction(
+                &model.match_ranges,
+                &results_editor.newest_anchor_selection().head(),
+                index,
+                direction,
+                &results_editor.buffer().read(cx).read(cx),
+            );
+            let range_to_select = model.match_ranges[new_index].clone();
             self.results_editor.update(cx, |editor, cx| {
                 editor.select_ranges([range_to_select], Some(Autoscroll::Fit), cx);
             });
@@ -595,30 +572,15 @@ impl ProjectSearchView {
     }
 
     fn update_match_index(&mut self, cx: &mut ViewContext<Self>) {
-        let match_ranges = self.model.read(cx).match_ranges.clone();
-        if match_ranges.is_empty() {
-            self.active_match_index = None;
-        } else {
-            let results_editor = &self.results_editor.read(cx);
-            let cursor = results_editor.newest_anchor_selection().head();
-            let new_index = {
-                let buffer = results_editor.buffer().read(cx).read(cx);
-                match match_ranges.binary_search_by(|probe| {
-                    if probe.end.cmp(&cursor, &*buffer).unwrap().is_lt() {
-                        Ordering::Less
-                    } else if probe.start.cmp(&cursor, &*buffer).unwrap().is_gt() {
-                        Ordering::Greater
-                    } else {
-                        Ordering::Equal
-                    }
-                }) {
-                    Ok(i) | Err(i) => Some(cmp::min(i, match_ranges.len() - 1)),
-                }
-            };
-            if self.active_match_index != new_index {
-                self.active_match_index = new_index;
-                cx.notify();
-            }
+        let results_editor = self.results_editor.read(cx);
+        let new_index = active_match_index(
+            &self.model.read(cx).match_ranges,
+            &results_editor.newest_anchor_selection().head(),
+            &results_editor.buffer().read(cx).read(cx),
+        );
+        if self.active_match_index != new_index {
+            self.active_match_index = new_index;
+            cx.notify();
         }
     }
 

crates/search/src/search.rs 🔗

@@ -1,3 +1,9 @@
+use std::{
+    cmp::{self, Ordering},
+    ops::Range,
+};
+
+use editor::{Anchor, MultiBufferSnapshot};
 use gpui::{action, MutableAppContext};
 
 mod buffer_search;
@@ -23,3 +29,60 @@ pub enum Direction {
     Prev,
     Next,
 }
+
+pub(crate) fn active_match_index(
+    ranges: &[Range<Anchor>],
+    cursor: &Anchor,
+    buffer: &MultiBufferSnapshot,
+) -> Option<usize> {
+    if ranges.is_empty() {
+        None
+    } else {
+        match ranges.binary_search_by(|probe| {
+            if probe.end.cmp(&cursor, &*buffer).unwrap().is_lt() {
+                Ordering::Less
+            } else if probe.start.cmp(&cursor, &*buffer).unwrap().is_gt() {
+                Ordering::Greater
+            } else {
+                Ordering::Equal
+            }
+        }) {
+            Ok(i) | Err(i) => Some(cmp::min(i, ranges.len() - 1)),
+        }
+    }
+}
+
+pub(crate) fn match_index_for_direction(
+    ranges: &[Range<Anchor>],
+    cursor: &Anchor,
+    mut index: usize,
+    direction: Direction,
+    buffer: &MultiBufferSnapshot,
+) -> usize {
+    if ranges[index].start.cmp(&cursor, &buffer).unwrap().is_gt() {
+        if direction == Direction::Prev {
+            if index == 0 {
+                index = ranges.len() - 1;
+            } else {
+                index -= 1;
+            }
+        }
+    } else if ranges[index].end.cmp(&cursor, &buffer).unwrap().is_lt() {
+        if direction == Direction::Next {
+            index = 0;
+        }
+    } else if direction == Direction::Prev {
+        if index == 0 {
+            index = ranges.len() - 1;
+        } else {
+            index -= 1;
+        }
+    } else if direction == Direction::Next {
+        if index == ranges.len() - 1 {
+            index = 0
+        } else {
+            index += 1;
+        }
+    };
+    index
+}