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