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