Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T06:34:39.289Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

registrar.rs

234 lines · 7.5 KB · rust
1use gpui::{Action, App, Context, Div, Entity, InteractiveElement, Window, div};
2use workspace::{Pane, Workspace};
3
4use crate::BufferSearchBar;
5
6/// Registrar inverts the dependency between search and its downstream user, allowing said downstream user to register search action without knowing exactly what those actions are.
7pub trait SearchActionsRegistrar {
8    fn register_handler<A: Action>(&mut self, callback: impl ActionExecutor<A>);
9}
10
11type SearchBarActionCallback<A> =
12    fn(&mut BufferSearchBar, &A, &mut Window, &mut Context<BufferSearchBar>);
13
14type GetSearchBar<T> =
15    for<'a, 'b> fn(&'a T, &'a mut Window, &mut Context<'b, T>) -> Option<Entity<BufferSearchBar>>;
16
17/// Registers search actions on a div that can be taken out.
18pub struct DivRegistrar<'a, 'b, T: 'static> {
19    div: Option<Div>,
20    cx: &'a mut Context<'b, T>,
21    search_getter: GetSearchBar<T>,
22}
23
24impl<'a, 'b, T: 'static> DivRegistrar<'a, 'b, T> {
25    pub fn new(search_getter: GetSearchBar<T>, cx: &'a mut Context<'b, T>) -> Self {
26        Self {
27            div: Some(div()),
28            cx,
29            search_getter,
30        }
31    }
32    pub fn into_div(self) -> Div {
33        // This option is always Some; it's an option in the first place because we want to call methods
34        // on div that require ownership.
35        self.div.unwrap()
36    }
37}
38
39impl<T: 'static> SearchActionsRegistrar for DivRegistrar<'_, '_, T> {
40    fn register_handler<A: Action>(&mut self, callback: impl ActionExecutor<A>) {
41        let getter = self.search_getter;
42        self.div = self.div.take().map(|div| {
43            div.on_action(self.cx.listener(move |this, action, window, cx| {
44                let should_notify = (getter)(this, window, cx)
45                    .map(|search_bar| {
46                        search_bar.update(cx, |search_bar, cx| {
47                            callback.execute(search_bar, action, window, cx)
48                        })
49                    })
50                    .unwrap_or(false);
51                if should_notify {
52                    cx.notify();
53                } else {
54                    cx.propagate();
55                }
56            }))
57        });
58    }
59}
60
61pub struct PaneDivRegistrar {
62    div: Option<Div>,
63    pane: Entity<Pane>,
64}
65
66impl PaneDivRegistrar {
67    pub fn new(div: Div, pane: Entity<Pane>) -> Self {
68        Self {
69            div: Some(div),
70            pane,
71        }
72    }
73
74    pub fn into_div(self) -> Div {
75        self.div.unwrap()
76    }
77}
78
79impl SearchActionsRegistrar for PaneDivRegistrar {
80    fn register_handler<A: Action>(&mut self, callback: impl ActionExecutor<A>) {
81        let pane = self.pane.clone();
82        self.div = self.div.take().map(|div| {
83            div.on_action(move |action: &A, window: &mut Window, cx: &mut App| {
84                let search_bar = pane
85                    .read(cx)
86                    .toolbar()
87                    .read(cx)
88                    .item_of_type::<BufferSearchBar>();
89                let should_notify = search_bar
90                    .map(|search_bar| {
91                        search_bar.update(cx, |search_bar, cx| {
92                            callback.execute(search_bar, action, window, cx)
93                        })
94                    })
95                    .unwrap_or(false);
96                if should_notify {
97                    pane.update(cx, |_, cx| cx.notify());
98                } else {
99                    cx.propagate();
100                }
101            })
102        });
103    }
104}
105
106pub fn register_pane_search_actions(div: Div, pane: Entity<Pane>) -> Div {
107    let mut registrar = PaneDivRegistrar::new(div, pane);
108    BufferSearchBar::register(&mut registrar);
109    registrar.into_div()
110}
111
112/// Register actions for an active pane.
113impl SearchActionsRegistrar for Workspace {
114    fn register_handler<A: Action>(&mut self, callback: impl ActionExecutor<A>) {
115        self.register_action(move |workspace, action: &A, window, cx| {
116            if workspace.has_active_modal(window, cx) && !workspace.hide_modal(window, cx) {
117                cx.propagate();
118                return;
119            }
120
121            let pane = workspace.active_pane();
122            let callback = callback.clone();
123            pane.update(cx, |this, cx| {
124                this.toolbar().update(cx, move |this, cx| {
125                    if let Some(search_bar) = this.item_of_type::<BufferSearchBar>() {
126                        let should_notify = search_bar.update(cx, move |search_bar, cx| {
127                            callback.execute(search_bar, action, window, cx)
128                        });
129                        if should_notify {
130                            cx.notify();
131                        } else {
132                            cx.propagate();
133                        }
134                    }
135                })
136            });
137        });
138    }
139}
140
141type DidHandleAction = bool;
142/// Potentially executes the underlying action if some preconditions are met (e.g. buffer search bar is visible)
143pub trait ActionExecutor<A: Action>: 'static + Clone {
144    fn execute(
145        &self,
146        search_bar: &mut BufferSearchBar,
147        action: &A,
148        window: &mut Window,
149        cx: &mut Context<BufferSearchBar>,
150    ) -> DidHandleAction;
151}
152
153/// Run an action when the search bar has been dismissed from the panel.
154pub struct ForDismissed<A>(pub(super) SearchBarActionCallback<A>);
155impl<A> Clone for ForDismissed<A> {
156    fn clone(&self) -> Self {
157        Self(self.0)
158    }
159}
160
161impl<A: Action> ActionExecutor<A> for ForDismissed<A> {
162    fn execute(
163        &self,
164        search_bar: &mut BufferSearchBar,
165        action: &A,
166        window: &mut Window,
167        cx: &mut Context<BufferSearchBar>,
168    ) -> DidHandleAction {
169        if search_bar.is_dismissed() {
170            self.0(search_bar, action, window, cx);
171            true
172        } else {
173            false
174        }
175    }
176}
177
178/// Run an action when the search bar is deployed.
179pub struct ForDeployed<A>(pub(super) SearchBarActionCallback<A>);
180impl<A> Clone for ForDeployed<A> {
181    fn clone(&self) -> Self {
182        Self(self.0)
183    }
184}
185
186impl<A: Action> ActionExecutor<A> for ForDeployed<A> {
187    fn execute(
188        &self,
189        search_bar: &mut BufferSearchBar,
190        action: &A,
191        window: &mut Window,
192        cx: &mut Context<BufferSearchBar>,
193    ) -> DidHandleAction {
194        if search_bar.is_dismissed() || search_bar.active_searchable_item.is_none() {
195            false
196        } else {
197            self.0(search_bar, action, window, cx);
198            true
199        }
200    }
201}
202
203/// Run an action when the search bar has any matches or a pending external query,
204/// regardless of whether it is visible or not.
205pub struct WithResultsOrExternalQuery<A>(pub(super) SearchBarActionCallback<A>);
206impl<A> Clone for WithResultsOrExternalQuery<A> {
207    fn clone(&self) -> Self {
208        Self(self.0)
209    }
210}
211
212impl<A: Action> ActionExecutor<A> for WithResultsOrExternalQuery<A> {
213    fn execute(
214        &self,
215        search_bar: &mut BufferSearchBar,
216        action: &A,
217        window: &mut Window,
218        cx: &mut Context<BufferSearchBar>,
219    ) -> DidHandleAction {
220        #[cfg(not(target_os = "macos"))]
221        let has_external_query = false;
222
223        #[cfg(target_os = "macos")]
224        let has_external_query = search_bar.pending_external_query.is_some();
225
226        if has_external_query || search_bar.active_match_index.is_some() {
227            self.0(search_bar, action, window, cx);
228            true
229        } else {
230            false
231        }
232    }
233}
234
Served at tenant.openagents/omega Member data and write actions are omitted.