search.rs

  1pub use buffer_search::BufferSearchBar;
  2use editor::{display_map::ToDisplayPoint, Anchor, Bias, Editor, MultiBufferSnapshot};
  3use gpui::{actions, impl_internal_actions, MutableAppContext, ViewHandle};
  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, PartialEq)]
 19pub struct ToggleSearchOption(pub SearchOption);
 20
 21actions!(search, [SelectNextMatch, SelectPrevMatch]);
 22impl_internal_actions!(search, [ToggleSearchOption]);
 23
 24#[derive(Clone, Copy, PartialEq)]
 25pub enum SearchOption {
 26    WholeWord,
 27    CaseSensitive,
 28    Regex,
 29}
 30
 31#[derive(Clone, Copy, PartialEq, Eq)]
 32pub enum Direction {
 33    Prev,
 34    Next,
 35}
 36
 37pub(crate) fn active_match_index(
 38    ranges: &[Range<Anchor>],
 39    cursor: &Anchor,
 40    buffer: &MultiBufferSnapshot,
 41) -> Option<usize> {
 42    if ranges.is_empty() {
 43        None
 44    } else {
 45        match ranges.binary_search_by(|probe| {
 46            if probe.end.cmp(&cursor, &*buffer).is_lt() {
 47                Ordering::Less
 48            } else if probe.start.cmp(&cursor, &*buffer).is_gt() {
 49                Ordering::Greater
 50            } else {
 51                Ordering::Equal
 52            }
 53        }) {
 54            Ok(i) | Err(i) => Some(cmp::min(i, ranges.len() - 1)),
 55        }
 56    }
 57}
 58
 59pub(crate) fn match_index_for_direction(
 60    ranges: &[Range<Anchor>],
 61    cursor: &Anchor,
 62    mut index: usize,
 63    direction: Direction,
 64    buffer: &MultiBufferSnapshot,
 65) -> usize {
 66    if ranges[index].start.cmp(&cursor, &buffer).is_gt() {
 67        if direction == Direction::Prev {
 68            if index == 0 {
 69                index = ranges.len() - 1;
 70            } else {
 71                index -= 1;
 72            }
 73        }
 74    } else if ranges[index].end.cmp(&cursor, &buffer).is_lt() {
 75        if direction == Direction::Next {
 76            index = 0;
 77        }
 78    } else if direction == Direction::Prev {
 79        if index == 0 {
 80            index = ranges.len() - 1;
 81        } else {
 82            index -= 1;
 83        }
 84    } else if direction == Direction::Next {
 85        if index == ranges.len() - 1 {
 86            index = 0
 87        } else {
 88            index += 1;
 89        }
 90    };
 91    index
 92}
 93
 94pub(crate) fn query_suggestion_for_editor(
 95    editor: &ViewHandle<Editor>,
 96    cx: &mut MutableAppContext,
 97) -> String {
 98    let display_map = editor
 99        .update(cx, |editor, cx| editor.snapshot(cx))
100        .display_snapshot;
101    let selection = editor.read(cx).selections.newest::<usize>(cx);
102    if selection.start == selection.end {
103        let point = selection.start.to_display_point(&display_map);
104        let range = editor::movement::surrounding_word(&display_map, point);
105        let range = range.start.to_offset(&display_map, Bias::Left)
106            ..range.end.to_offset(&display_map, Bias::Right);
107        let text: String = display_map.buffer_snapshot.text_for_range(range).collect();
108        if text.trim().is_empty() {
109            String::new()
110        } else {
111            text
112        }
113    } else {
114        display_map
115            .buffer_snapshot
116            .text_for_range(selection.start..selection.end)
117            .collect()
118    }
119}