search.rs

  1use bitflags::bitflags;
  2pub use buffer_search::BufferSearchBar;
  3use gpui::{actions, Action, AppContext, RenderOnce};
  4pub use mode::SearchMode;
  5use project::search::SearchQuery;
  6use ui::ButtonVariant;
  7//pub use project_search::{ProjectSearchBar, ProjectSearchView};
  8// use theme::components::{
  9//     action_button::Button, svg::Svg, ComponentExt, IconButtonStyle, ToggleIconButtonStyle,
 10// };
 11
 12pub mod buffer_search;
 13mod history;
 14mod mode;
 15//pub mod project_search;
 16pub(crate) mod search_bar;
 17
 18pub fn init(cx: &mut AppContext) {
 19    buffer_search::init(cx);
 20    //project_search::init(cx);
 21}
 22
 23actions!(
 24    CycleMode,
 25    ToggleWholeWord,
 26    ToggleCaseSensitive,
 27    ToggleReplace,
 28    SelectNextMatch,
 29    SelectPrevMatch,
 30    SelectAllMatches,
 31    NextHistoryQuery,
 32    PreviousHistoryQuery,
 33    ActivateTextMode,
 34    ActivateSemanticMode,
 35    ActivateRegexMode,
 36    ReplaceAll,
 37    ReplaceNext,
 38);
 39
 40bitflags! {
 41    #[derive(Default)]
 42    pub struct SearchOptions: u8 {
 43        const NONE = 0b000;
 44        const WHOLE_WORD = 0b001;
 45        const CASE_SENSITIVE = 0b010;
 46    }
 47}
 48
 49impl SearchOptions {
 50    pub fn label(&self) -> &'static str {
 51        match *self {
 52            SearchOptions::WHOLE_WORD => "Match Whole Word",
 53            SearchOptions::CASE_SENSITIVE => "Match Case",
 54            _ => panic!("{:?} is not a named SearchOption", self),
 55        }
 56    }
 57
 58    pub fn icon(&self) -> ui::Icon {
 59        match *self {
 60            SearchOptions::WHOLE_WORD => ui::Icon::WholeWord,
 61            SearchOptions::CASE_SENSITIVE => ui::Icon::CaseSensitive,
 62            _ => panic!("{:?} is not a named SearchOption", self),
 63        }
 64    }
 65
 66    pub fn to_toggle_action(&self) -> Box<dyn Action + Sync + Send + 'static> {
 67        match *self {
 68            SearchOptions::WHOLE_WORD => Box::new(ToggleWholeWord),
 69            SearchOptions::CASE_SENSITIVE => Box::new(ToggleCaseSensitive),
 70            _ => panic!("{:?} is not a named SearchOption", self),
 71        }
 72    }
 73
 74    pub fn none() -> SearchOptions {
 75        SearchOptions::NONE
 76    }
 77
 78    pub fn from_query(query: &SearchQuery) -> SearchOptions {
 79        let mut options = SearchOptions::NONE;
 80        options.set(SearchOptions::WHOLE_WORD, query.whole_word());
 81        options.set(SearchOptions::CASE_SENSITIVE, query.case_sensitive());
 82        options
 83    }
 84
 85    pub fn as_button(&self, active: bool) -> impl RenderOnce {
 86        ui::IconButton::new(0, self.icon())
 87            .on_click({
 88                let action = self.to_toggle_action();
 89                move |_, cx| {
 90                    cx.dispatch_action(action.boxed_clone());
 91                }
 92            })
 93            .variant(ui::ButtonVariant::Ghost)
 94            .when(active, |button| button.variant(ButtonVariant::Filled))
 95    }
 96}
 97
 98fn toggle_replace_button(active: bool) -> impl RenderOnce {
 99    // todo: add toggle_replace button
100    ui::IconButton::new(0, ui::Icon::Replace)
101        .on_click(|_, cx| {
102            cx.dispatch_action(Box::new(ToggleReplace));
103            cx.notify();
104        })
105        .variant(ui::ButtonVariant::Ghost)
106        .when(active, |button| button.variant(ButtonVariant::Filled))
107}
108
109fn render_replace_button(
110    action: impl Action + 'static + Send + Sync,
111    icon: ui::Icon,
112) -> impl RenderOnce {
113    // todo: add tooltip
114    ui::IconButton::new(0, icon).on_click(move |_, cx| {
115        cx.dispatch_action(action.boxed_clone());
116    })
117}