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