1use bitflags::bitflags;
2pub use buffer_search::BufferSearchBar;
3use gpui::{actions, Action, AppContext, IntoElement};
4pub use mode::SearchMode;
5use project::search::SearchQuery;
6pub use project_search::ProjectSearchView;
7use ui::{prelude::*, Tooltip};
8use ui::{ButtonStyle, IconButton};
9
10pub mod buffer_search;
11mod mode;
12pub mod project_search;
13pub(crate) mod search_bar;
14
15pub fn init(cx: &mut AppContext) {
16 menu::init();
17 buffer_search::init(cx);
18 project_search::init(cx);
19}
20
21actions!(
22 search,
23 [
24 CycleMode,
25 FocusSearch,
26 ToggleWholeWord,
27 ToggleCaseSensitive,
28 ToggleIncludeIgnored,
29 ToggleReplace,
30 SelectNextMatch,
31 SelectPrevMatch,
32 SelectAllMatches,
33 NextHistoryQuery,
34 PreviousHistoryQuery,
35 ActivateTextMode,
36 ActivateRegexMode,
37 ReplaceAll,
38 ReplaceNext,
39 ]
40);
41
42bitflags! {
43 #[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
44 pub struct SearchOptions: u8 {
45 const NONE = 0b000;
46 const WHOLE_WORD = 0b001;
47 const CASE_SENSITIVE = 0b010;
48 const INCLUDE_IGNORED = 0b100;
49 }
50}
51
52impl SearchOptions {
53 pub fn label(&self) -> &'static str {
54 match *self {
55 SearchOptions::WHOLE_WORD => "Match Whole Word",
56 SearchOptions::CASE_SENSITIVE => "Match Case",
57 SearchOptions::INCLUDE_IGNORED => "Include ignored",
58 _ => panic!("{:?} is not a named SearchOption", self),
59 }
60 }
61
62 pub fn icon(&self) -> ui::IconName {
63 match *self {
64 SearchOptions::WHOLE_WORD => ui::IconName::WholeWord,
65 SearchOptions::CASE_SENSITIVE => ui::IconName::CaseSensitive,
66 SearchOptions::INCLUDE_IGNORED => ui::IconName::FileGit,
67 _ => panic!("{:?} is not a named SearchOption", self),
68 }
69 }
70
71 pub fn to_toggle_action(&self) -> Box<dyn Action + Sync + Send + 'static> {
72 match *self {
73 SearchOptions::WHOLE_WORD => Box::new(ToggleWholeWord),
74 SearchOptions::CASE_SENSITIVE => Box::new(ToggleCaseSensitive),
75 SearchOptions::INCLUDE_IGNORED => Box::new(ToggleIncludeIgnored),
76 _ => panic!("{:?} is not a named SearchOption", self),
77 }
78 }
79
80 pub fn none() -> SearchOptions {
81 SearchOptions::NONE
82 }
83
84 pub fn from_query(query: &SearchQuery) -> SearchOptions {
85 let mut options = SearchOptions::NONE;
86 options.set(SearchOptions::WHOLE_WORD, query.whole_word());
87 options.set(SearchOptions::CASE_SENSITIVE, query.case_sensitive());
88 options.set(SearchOptions::INCLUDE_IGNORED, query.include_ignored());
89 options
90 }
91
92 pub fn as_button(
93 &self,
94 active: bool,
95 action: impl Fn(&gpui::ClickEvent, &mut WindowContext) + 'static,
96 ) -> impl IntoElement {
97 IconButton::new(self.label(), self.icon())
98 .on_click(action)
99 .style(ButtonStyle::Subtle)
100 .selected(active)
101 .tooltip({
102 let action = self.to_toggle_action();
103 let label: SharedString = format!("Toggle {}", self.label()).into();
104 move |cx| Tooltip::for_action(label.clone(), &*action, cx)
105 })
106 }
107}