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}