1use crate::{
2 AnyView, AnyWindowHandle, App, AppCell, AppContext, BackgroundExecutor, BorrowAppContext,
3 Entity, EntityId, EventEmitter, Focusable, ForegroundExecutor, Global, GpuiBorrow,
4 PromptButton, PromptLevel, Render, Reservation, Result, Subscription, Task, VisualContext,
5 Window, WindowHandle,
6};
7use anyhow::{Context as _, bail};
8use derive_more::{Deref, DerefMut};
9use futures::channel::oneshot;
10use futures::future::FutureExt;
11use std::{future::Future, rc::Weak};
12
13use super::{Context, WeakEntity};
14
15#[derive(Clone)]
22pub struct AsyncApp {
23 pub(crate) app: Weak<AppCell>,
24 pub(crate) background_executor: BackgroundExecutor,
25 pub(crate) foreground_executor: ForegroundExecutor,
26}
27
28impl AsyncApp {
29 fn app(&self) -> std::rc::Rc<AppCell> {
30 self.app
31 .upgrade()
32 .expect("app was released before async operation completed")
33 }
34}
35
36impl AppContext for AsyncApp {
37 fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
38 let app = self.app();
39 let mut app = app.borrow_mut();
40 app.new(build_entity)
41 }
42
43 fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {
44 let app = self.app();
45 let mut app = app.borrow_mut();
46 app.reserve_entity()
47 }
48
49 fn insert_entity<T: 'static>(
50 &mut self,
51 reservation: Reservation<T>,
52 build_entity: impl FnOnce(&mut Context<T>) -> T,
53 ) -> Entity<T> {
54 let app = self.app();
55 let mut app = app.borrow_mut();
56 app.insert_entity(reservation, build_entity)
57 }
58
59 #[inline(always)]
60 fn update_entity<T: 'static, R>(
61 &mut self,
62 handle: &Entity<T>,
63 update: impl FnOnce(&mut T, &mut Context<T>) -> R,
64 ) -> R {
65 let app = self.app();
66 let mut app = app.borrow_mut();
67 app.update_entity(handle, update)
68 }
69
70 fn as_mut<'a, T>(&'a mut self, _handle: &Entity<T>) -> GpuiBorrow<'a, T>
71 where
72 T: 'static,
73 {
74 panic!("Cannot as_mut with an async context. Try calling update() first")
75 }
76
77 #[inline(always)]
78 fn read_entity<T, R>(&self, handle: &Entity<T>, callback: impl FnOnce(&T, &App) -> R) -> R
79 where
80 T: 'static,
81 {
82 let app = self.app();
83 let lock = app.borrow();
84 lock.read_entity(handle, callback)
85 }
86
87 #[inline(always)]
88 fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Result<T>
89 where
90 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
91 {
92 let app = self.app.upgrade().context("app was released")?;
93 let mut lock = app.try_borrow_mut()?;
94 if lock.quitting {
95 bail!("app is quitting");
96 }
97 lock.update_window(window, f)
98 }
99
100 #[inline(always)]
101 fn with_window<R>(
102 &mut self,
103 entity_id: EntityId,
104 f: impl FnOnce(&mut Window, &mut App) -> R,
105 ) -> Option<R> {
106 let app = self.app.upgrade()?;
107 let mut lock = app.try_borrow_mut().ok()?;
108 if lock.quitting {
109 return None;
110 }
111 lock.with_window(entity_id, f)
112 }
113
114 fn read_window<T, R>(
115 &self,
116 window: &WindowHandle<T>,
117 read: impl FnOnce(Entity<T>, &App) -> R,
118 ) -> Result<R>
119 where
120 T: 'static,
121 {
122 let app = self.app.upgrade().context("app was released")?;
123 let lock = app.borrow();
124 if lock.quitting {
125 bail!("app is quitting");
126 }
127 lock.read_window(window, read)
128 }
129
130 #[track_caller]
131 fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
132 where
133 R: Send + 'static,
134 {
135 self.background_executor.spawn(future)
136 }
137
138 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
139 where
140 G: Global,
141 {
142 let app = self.app();
143 let mut lock = app.borrow_mut();
144 lock.update(|this| this.read_global(callback))
145 }
146}
147
148impl AsyncApp {
149 pub fn refresh(&self) {
151 let app = self.app();
152 let mut lock = app.borrow_mut();
153 lock.update(|cx| cx.refresh_windows());
156 }
157
158 pub fn background_executor(&self) -> &BackgroundExecutor {
160 &self.background_executor
161 }
162
163 pub fn is_test(&self) -> bool {
166 self.background_executor.is_test()
167 }
168
169 pub fn foreground_executor(&self) -> &ForegroundExecutor {
171 &self.foreground_executor
172 }
173
174 #[inline(always)]
176 pub fn update<R>(&self, f: impl FnOnce(&mut App) -> R) -> R {
177 let app = self.app();
178 let mut lock = app.borrow_mut();
179 lock.update(f)
180 }
181
182 pub fn subscribe<T, Event>(
185 &mut self,
186 entity: &Entity<T>,
187 on_event: impl FnMut(Entity<T>, &Event, &mut App) + 'static,
188 ) -> Subscription
189 where
190 T: 'static + EventEmitter<Event>,
191 Event: 'static,
192 {
193 let app = self.app();
194 let mut lock = app.borrow_mut();
195 lock.subscribe(entity, on_event)
196 }
197
198 pub fn open_window<V>(
200 &self,
201 options: crate::WindowOptions,
202 build_root_view: impl FnOnce(&mut Window, &mut App) -> Entity<V>,
203 ) -> Result<WindowHandle<V>>
204 where
205 V: 'static + Render,
206 {
207 let app = self.app();
208 let mut lock = app.borrow_mut();
209 if lock.quitting {
210 bail!("app is quitting");
211 }
212 lock.open_window(options, build_root_view)
213 }
214
215 #[track_caller]
217 #[inline(always)]
218 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
219 where
220 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
221 R: 'static,
222 {
223 let mut cx = self.clone();
224 self.foreground_executor
225 .spawn(async move { f(&mut cx).await }.boxed_local())
226 }
227
228 pub fn has_global<G: Global>(&self) -> bool {
230 let app = self.app();
231 let app = app.borrow_mut();
232 app.has_global::<G>()
233 }
234
235 #[inline(always)]
239 pub fn read_global<G: Global, R>(&self, read: impl FnOnce(&G, &App) -> R) -> R {
240 let app = self.app();
241 let app = app.borrow_mut();
242 read(app.global(), &app)
243 }
244
245 pub fn try_read_global<G: Global, R>(&self, read: impl FnOnce(&G, &App) -> R) -> Option<R> {
249 let app = self.app();
250 let app = app.borrow_mut();
251 if app.quitting {
252 return None;
253 }
254 Some(read(app.try_global()?, &app))
255 }
256
257 pub fn read_default_global<G: Global + Default, R>(
260 &self,
261 read: impl FnOnce(&G, &App) -> R,
262 ) -> R {
263 let app = self.app();
264 let mut app = app.borrow_mut();
265 app.update(|cx| {
266 cx.default_global::<G>();
267 });
268 read(app.global(), &app)
269 }
270
271 pub fn update_global<G: Global, R>(&self, update: impl FnOnce(&mut G, &mut App) -> R) -> R {
274 let app = self.app();
275 let mut app = app.borrow_mut();
276 app.update(|cx| cx.update_global(update))
277 }
278
279 pub fn on_drop<T: 'static, Callback: FnOnce(&mut T, &mut Context<T>) + 'static>(
281 &self,
282 entity: &WeakEntity<T>,
283 f: Callback,
284 ) -> gpui_util::Deferred<impl FnOnce() + use<T, Callback>> {
285 let entity = entity.clone();
286 let mut cx = self.clone();
287 gpui_util::defer(move || {
288 entity.update(&mut cx, f).ok();
289 })
290 }
291}
292
293#[derive(Clone, Deref, DerefMut)]
296pub struct AsyncWindowContext {
297 #[deref]
298 #[deref_mut]
299 app: AsyncApp,
300 window: AnyWindowHandle,
301}
302
303impl AsyncWindowContext {
304 pub(crate) fn new_context(app: AsyncApp, window: AnyWindowHandle) -> Self {
305 Self { app, window }
306 }
307
308 pub fn window_handle(&self) -> AnyWindowHandle {
310 self.window
311 }
312
313 #[inline(always)]
315 #[track_caller]
316 pub fn update<R>(&mut self, update: impl FnOnce(&mut Window, &mut App) -> R) -> Result<R> {
317 self.app
318 .update_window(self.window, |_, window, cx| update(window, cx))
319 }
320
321 #[inline(always)]
323 #[track_caller]
324 pub fn update_root<R>(
325 &mut self,
326 update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
327 ) -> Result<R> {
328 self.app.update_window(self.window, update)
329 }
330
331 pub fn on_next_frame(&mut self, f: impl FnOnce(&mut Window, &mut App) + 'static) {
333 self.app
334 .update_window(self.window, |_, window, _| window.on_next_frame(f))
335 .ok();
336 }
337
338 pub fn read_global<G: Global, R>(
340 &mut self,
341 read: impl FnOnce(&G, &Window, &App) -> R,
342 ) -> Result<R> {
343 self.app
344 .update_window(self.window, |_, window, cx| read(cx.global(), window, cx))
345 }
346
347 pub fn update_global<G, R>(
350 &mut self,
351 update: impl FnOnce(&mut G, &mut Window, &mut App) -> R,
352 ) -> Result<R>
353 where
354 G: Global,
355 {
356 self.app.update_window(self.window, |_, window, cx| {
357 cx.update_global(|global, cx| update(global, window, cx))
358 })
359 }
360
361 #[track_caller]
364 #[inline(always)]
365 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
366 where
367 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
368 R: 'static,
369 {
370 let mut cx = self.clone();
371 self.foreground_executor
372 .spawn(async move { f(&mut cx).await }.boxed_local())
373 }
374
375 pub fn prompt<T>(
379 &mut self,
380 level: PromptLevel,
381 message: &str,
382 detail: Option<&str>,
383 answers: &[T],
384 ) -> oneshot::Receiver<usize>
385 where
386 T: Clone + Into<PromptButton>,
387 {
388 self.app
389 .update_window(self.window, |_, window, cx| {
390 window.prompt(level, message, detail, answers, cx)
391 })
392 .unwrap_or_else(|_| oneshot::channel().1)
393 }
394}
395
396impl AppContext for AsyncWindowContext {
397 fn new<T>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T>
398 where
399 T: 'static,
400 {
401 let mut build_entity = Some(build_entity);
402 match self.app.update_window(self.window, |_, _, cx| {
403 cx.new(
404 build_entity
405 .take()
406 .expect("build_entity is taken exactly once"),
407 )
408 }) {
409 Ok(entity) => entity,
410 Err(_) => self.app.new(
411 build_entity
412 .take()
413 .expect("update_window returned Err without invoking the closure"),
414 ),
415 }
416 }
417
418 fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {
419 self.app.reserve_entity()
420 }
421
422 fn insert_entity<T: 'static>(
423 &mut self,
424 reservation: Reservation<T>,
425 build_entity: impl FnOnce(&mut Context<T>) -> T,
426 ) -> Entity<T> {
427 let mut args = Some((reservation, build_entity));
428 match self.app.update_window(self.window, |_, _, cx| {
429 let (reservation, build_entity) = args.take().expect("args are taken exactly once");
430 cx.insert_entity(reservation, build_entity)
431 }) {
432 Ok(entity) => entity,
433 Err(_) => {
434 let (reservation, build_entity) = args
435 .take()
436 .expect("update_window returned Err without invoking the closure");
437 self.app.insert_entity(reservation, build_entity)
438 }
439 }
440 }
441
442 #[inline(always)]
443 fn update_entity<T: 'static, R>(
444 &mut self,
445 handle: &Entity<T>,
446 update: impl FnOnce(&mut T, &mut Context<T>) -> R,
447 ) -> R {
448 self.app.update_entity(handle, update)
449 }
450
451 fn as_mut<'a, T>(&'a mut self, _: &Entity<T>) -> GpuiBorrow<'a, T>
452 where
453 T: 'static,
454 {
455 panic!("Cannot use as_mut() from an async context, call `update`")
456 }
457
458 #[inline(always)]
459 fn read_entity<T, R>(&self, handle: &Entity<T>, read: impl FnOnce(&T, &App) -> R) -> R
460 where
461 T: 'static,
462 {
463 self.app.read_entity(handle, read)
464 }
465
466 #[inline(always)]
467 fn update_window<T, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<T>
468 where
469 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
470 {
471 self.app.update_window(window, update)
472 }
473
474 #[inline(always)]
475 fn with_window<R>(
476 &mut self,
477 entity_id: EntityId,
478 f: impl FnOnce(&mut Window, &mut App) -> R,
479 ) -> Option<R> {
480 self.app.with_window(entity_id, f)
481 }
482
483 fn read_window<T, R>(
484 &self,
485 window: &WindowHandle<T>,
486 read: impl FnOnce(Entity<T>, &App) -> R,
487 ) -> Result<R>
488 where
489 T: 'static,
490 {
491 self.app.read_window(window, read)
492 }
493
494 #[track_caller]
495 fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
496 where
497 R: Send + 'static,
498 {
499 self.app.background_executor.spawn(future)
500 }
501
502 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
503 where
504 G: Global,
505 {
506 self.app.read_global(callback)
507 }
508}
509
510impl VisualContext for AsyncWindowContext {
511 type Result<T> = Result<T>;
512
513 fn window_handle(&self) -> AnyWindowHandle {
514 self.window
515 }
516
517 fn new_window_entity<T: 'static>(
518 &mut self,
519 build_entity: impl FnOnce(&mut Window, &mut Context<T>) -> T,
520 ) -> Result<Entity<T>> {
521 self.app.update_window(self.window, |_, window, cx| {
522 cx.new(|cx| build_entity(window, cx))
523 })
524 }
525
526 fn update_window_entity<T: 'static, R>(
527 &mut self,
528 view: &Entity<T>,
529 update: impl FnOnce(&mut T, &mut Window, &mut Context<T>) -> R,
530 ) -> Result<R> {
531 let view = view.clone();
532 self.app
533 .with_window(view.entity_id(), |window, app| {
534 view.update(app, |entity, cx| update(entity, window, cx))
535 })
536 .context("entity has no current window")
537 }
538
539 fn replace_root_view<V>(
540 &mut self,
541 build_view: impl FnOnce(&mut Window, &mut Context<V>) -> V,
542 ) -> Result<Entity<V>>
543 where
544 V: 'static + Render,
545 {
546 self.app.update_window(self.window, |_, window, cx| {
547 window.replace_root(cx, build_view)
548 })
549 }
550
551 fn focus<V>(&mut self, view: &Entity<V>) -> Result<()>
552 where
553 V: Focusable,
554 {
555 self.app.update_window(self.window, |_, window, cx| {
556 view.read(cx).focus_handle(cx).focus(window, cx);
557 })
558 }
559}