Determine active match index correctly when cursor is after last match

Antonio Scandurra created

Change summary

crates/find/src/find.rs | 96 ++++++++++++++++++++++++++++++++++++++----
1 file changed, 86 insertions(+), 10 deletions(-)

Detailed changes

crates/find/src/find.rs 🔗

@@ -288,21 +288,17 @@ impl FindBar {
                     {
                         let position = newest_selection.head();
                         let buffer = editor.buffer().read(cx).read(cx);
-                        if ranges[index].start.cmp(&position, &buffer).unwrap().is_le()
-                            && ranges[index].end.cmp(&position, &buffer).unwrap().is_ge()
-                        {
+                        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 index == ranges.len() - 1 {
-                                    index = 0
-                                } 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 {
@@ -310,6 +306,12 @@ impl FindBar {
                             } 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();
@@ -430,7 +432,7 @@ impl FindBar {
                 Ordering::Equal
             }
         }) {
-            Ok(i) | Err(i) => Some(i),
+            Ok(i) | Err(i) => Some(cmp::min(i, ranges.len() - 1)),
         }
     }
 }
@@ -680,7 +682,11 @@ mod tests {
             );
         });
 
+        editor.update(&mut cx, |editor, cx| {
+            editor.select_display_ranges(&[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], cx);
+        });
         find_bar.update(&mut cx, |find_bar, cx| {
+            assert_eq!(find_bar.active_match_index, Some(0));
             find_bar.go_to_match(&GoToMatch(Direction::Next), cx);
             assert_eq!(
                 editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
@@ -757,6 +763,8 @@ mod tests {
             assert_eq!(find_bar.active_match_index, Some(0));
         });
 
+        // Park the cursor in between matches and ensure that going to the previous match selects
+        // the closest match to the left.
         editor.update(&mut cx, |editor, cx| {
             editor.select_display_ranges(&[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)], cx);
         });
@@ -771,5 +779,73 @@ mod tests {
         find_bar.read_with(&cx, |find_bar, _| {
             assert_eq!(find_bar.active_match_index, Some(0));
         });
+
+        // Park the cursor in between matches and ensure that going to the next match selects the
+        // closest match to the right.
+        editor.update(&mut cx, |editor, cx| {
+            editor.select_display_ranges(&[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)], cx);
+        });
+        find_bar.update(&mut cx, |find_bar, cx| {
+            assert_eq!(find_bar.active_match_index, Some(1));
+            find_bar.go_to_match(&GoToMatch(Direction::Next), cx);
+            assert_eq!(
+                editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
+                [DisplayPoint::new(3, 11)..DisplayPoint::new(3, 13)]
+            );
+        });
+        find_bar.read_with(&cx, |find_bar, _| {
+            assert_eq!(find_bar.active_match_index, Some(1));
+        });
+
+        // Park the cursor after the last match and ensure that going to the previous match selects
+        // the last match.
+        editor.update(&mut cx, |editor, cx| {
+            editor.select_display_ranges(&[DisplayPoint::new(3, 60)..DisplayPoint::new(3, 60)], cx);
+        });
+        find_bar.update(&mut cx, |find_bar, cx| {
+            assert_eq!(find_bar.active_match_index, Some(2));
+            find_bar.go_to_match(&GoToMatch(Direction::Prev), cx);
+            assert_eq!(
+                editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
+                [DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)]
+            );
+        });
+        find_bar.read_with(&cx, |find_bar, _| {
+            assert_eq!(find_bar.active_match_index, Some(2));
+        });
+
+        // Park the cursor after the last match and ensure that going to the next match selects the
+        // first match.
+        editor.update(&mut cx, |editor, cx| {
+            editor.select_display_ranges(&[DisplayPoint::new(3, 60)..DisplayPoint::new(3, 60)], cx);
+        });
+        find_bar.update(&mut cx, |find_bar, cx| {
+            assert_eq!(find_bar.active_match_index, Some(2));
+            find_bar.go_to_match(&GoToMatch(Direction::Next), cx);
+            assert_eq!(
+                editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
+                [DisplayPoint::new(0, 41)..DisplayPoint::new(0, 43)]
+            );
+        });
+        find_bar.read_with(&cx, |find_bar, _| {
+            assert_eq!(find_bar.active_match_index, Some(0));
+        });
+
+        // Park the cursor before the first match and ensure that going to the previous match
+        // selects the last match.
+        editor.update(&mut cx, |editor, cx| {
+            editor.select_display_ranges(&[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], cx);
+        });
+        find_bar.update(&mut cx, |find_bar, cx| {
+            assert_eq!(find_bar.active_match_index, Some(0));
+            find_bar.go_to_match(&GoToMatch(Direction::Prev), cx);
+            assert_eq!(
+                editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)),
+                [DisplayPoint::new(3, 56)..DisplayPoint::new(3, 58)]
+            );
+        });
+        find_bar.read_with(&cx, |find_bar, _| {
+            assert_eq!(find_bar.active_match_index, Some(2));
+        });
     }
 }