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