1use std::{
2 cmp::{self, Ordering},
3 ops::Range,
4};
5
6use editor::{Anchor, MultiBufferSnapshot};
7use gpui::{action, MutableAppContext};
8
9mod buffer_search;
10mod project_search;
11
12pub fn init(cx: &mut MutableAppContext) {
13 buffer_search::init(cx);
14 project_search::init(cx);
15}
16
17action!(ToggleSearchOption, SearchOption);
18action!(SelectMatch, Direction);
19
20#[derive(Clone, Copy)]
21pub enum SearchOption {
22 WholeWord,
23 CaseSensitive,
24 Regex,
25}
26
27#[derive(Clone, Copy, PartialEq, Eq)]
28pub enum Direction {
29 Prev,
30 Next,
31}
32
33pub(crate) fn active_match_index(
34 ranges: &[Range<Anchor>],
35 cursor: &Anchor,
36 buffer: &MultiBufferSnapshot,
37) -> Option<usize> {
38 if ranges.is_empty() {
39 None
40 } else {
41 match ranges.binary_search_by(|probe| {
42 if probe.end.cmp(&cursor, &*buffer).unwrap().is_lt() {
43 Ordering::Less
44 } else if probe.start.cmp(&cursor, &*buffer).unwrap().is_gt() {
45 Ordering::Greater
46 } else {
47 Ordering::Equal
48 }
49 }) {
50 Ok(i) | Err(i) => Some(cmp::min(i, ranges.len() - 1)),
51 }
52 }
53}
54
55pub(crate) fn match_index_for_direction(
56 ranges: &[Range<Anchor>],
57 cursor: &Anchor,
58 mut index: usize,
59 direction: Direction,
60 buffer: &MultiBufferSnapshot,
61) -> usize {
62 if ranges[index].start.cmp(&cursor, &buffer).unwrap().is_gt() {
63 if direction == Direction::Prev {
64 if index == 0 {
65 index = ranges.len() - 1;
66 } else {
67 index -= 1;
68 }
69 }
70 } else if ranges[index].end.cmp(&cursor, &buffer).unwrap().is_lt() {
71 if direction == Direction::Next {
72 index = 0;
73 }
74 } else if direction == Direction::Prev {
75 if index == 0 {
76 index = ranges.len() - 1;
77 } else {
78 index -= 1;
79 }
80 } else if direction == Direction::Next {
81 if index == ranges.len() - 1 {
82 index = 0
83 } else {
84 index += 1;
85 }
86 };
87 index
88}