Detailed changes
@@ -22,9 +22,9 @@ use slotmap::SlotMap;
pub use async_context::*;
use collections::{FxHashMap, FxHashSet, HashMap, VecDeque};
+pub use context::*;
pub use entity_map::*;
use http_client::HttpClient;
-pub use model_context::*;
#[cfg(any(test, feature = "test-support"))]
pub use test_context::*;
use util::ResultExt;
@@ -41,8 +41,8 @@ use crate::{
};
mod async_context;
+mod context;
mod entity_map;
-mod model_context;
#[cfg(any(test, feature = "test-support"))]
mod test_context;
@@ -1667,6 +1667,21 @@ impl AppContext for App {
Ok(read(view, self))
}
+
+ fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
+ where
+ R: Send + 'static,
+ {
+ self.background_executor.spawn(future)
+ }
+
+ fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
+ where
+ G: Global,
+ {
+ let mut g = self.global::<G>();
+ callback(&g, self)
+ }
}
/// These effects are processed at the end of each application update cycle.
@@ -104,6 +104,22 @@ impl AppContext for AsyncApp {
let lock = app.borrow();
lock.read_window(window, read)
}
+
+ fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
+ where
+ R: Send + 'static,
+ {
+ self.background_executor.spawn(future)
+ }
+
+ fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
+ where
+ G: Global,
+ {
+ let app = self.app.upgrade().context("app was released")?;
+ let mut lock = app.borrow_mut();
+ Ok(lock.update(|this| this.read_global(callback)))
+ }
}
impl AsyncApp {
@@ -367,6 +383,20 @@ impl AppContext for AsyncWindowContext {
{
self.app.read_window(window, read)
}
+
+ fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
+ where
+ R: Send + 'static,
+ {
+ self.app.background_executor.spawn(future)
+ }
+
+ fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Result<R>
+ where
+ G: Global,
+ {
+ self.app.read_global(callback)
+ }
}
impl VisualContext for AsyncWindowContext {
@@ -1,7 +1,7 @@
use crate::{
- AnyView, AnyWindowHandle, App, AppContext, AsyncApp, DispatchPhase, Effect, EntityId,
- EventEmitter, FocusHandle, FocusOutEvent, Focusable, Global, KeystrokeObserver, Reservation,
- SubscriberSet, Subscription, Task, WeakEntity, WeakFocusHandle, Window, WindowHandle,
+ AnyView, AnyWindowHandle, AppContext, AsyncApp, DispatchPhase, Effect, EntityId, EventEmitter,
+ FocusHandle, FocusOutEvent, Focusable, Global, KeystrokeObserver, Reservation, SubscriberSet,
+ Subscription, Task, WeakEntity, WeakFocusHandle, Window, WindowHandle,
};
use anyhow::Result;
use derive_more::{Deref, DerefMut};
@@ -13,7 +13,7 @@ use std::{
sync::Arc,
};
-use super::{AsyncWindowContext, Entity, KeystrokeEvent};
+use super::{App, AsyncWindowContext, Entity, KeystrokeEvent};
/// The app context, with specialized behavior for the given model.
#[derive(Deref, DerefMut)]
@@ -717,6 +717,20 @@ impl<'a, T> AppContext for Context<'a, T> {
{
self.app.read_window(window, read)
}
+
+ fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
+ where
+ R: Send + 'static,
+ {
+ self.app.background_executor.spawn(future)
+ }
+
+ fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
+ where
+ G: Global,
+ {
+ self.app.read_global(callback)
+ }
}
impl<T> Borrow<App> for Context<'_, T> {
@@ -94,6 +94,21 @@ impl AppContext for TestAppContext {
let app = self.app.borrow();
app.read_window(window, read)
}
+
+ fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
+ where
+ R: Send + 'static,
+ {
+ self.background_executor.spawn(future)
+ }
+
+ fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
+ where
+ G: Global,
+ {
+ let app = self.app.borrow();
+ app.read_global(callback)
+ }
}
impl TestAppContext {
@@ -906,6 +921,20 @@ impl AppContext for VisualTestContext {
{
self.cx.read_window(window, read)
}
+
+ fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
+ where
+ R: Send + 'static,
+ {
+ self.cx.background_spawn(future)
+ }
+
+ fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
+ where
+ G: Global,
+ {
+ self.cx.read_global(callback)
+ }
}
impl VisualContext for VisualTestContext {
@@ -155,7 +155,7 @@ pub use util::arc_cow::ArcCow;
pub use view::*;
pub use window::*;
-use std::{any::Any, borrow::BorrowMut};
+use std::{any::Any, borrow::BorrowMut, future::Future};
use taffy::TaffyLayoutEngine;
/// The context trait, allows the different contexts in GPUI to be used
@@ -215,6 +215,16 @@ pub trait AppContext {
) -> Result<R>
where
T: 'static;
+
+ /// Spawn a future on a background thread
+ fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
+ where
+ R: Send + 'static;
+
+ /// Read a global from this app context
+ fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
+ where
+ G: Global;
}
/// Returned by [Context::reserve_entity] to later be passed to [Context::insert_model].
@@ -81,6 +81,20 @@ pub fn derive_app_context(input: TokenStream) -> TokenStream {
{
self.#app_variable.read_window(window, read)
}
+
+ fn background_spawn<R>(&self, future: impl std::future::Future<Output = R> + Send + 'static) -> gpui::Task<R>
+ where
+ R: Send + 'static,
+ {
+ self.#app_variable.background_spawn(future)
+ }
+
+ fn read_global<G, R>(&self, callback: impl FnOnce(&G, &gpui::App) -> R) -> Self::Result<R>
+ where
+ G: gpui::Global,
+ {
+ self.#app_variable.read_global(callback)
+ }
}
};
@@ -1,6 +1,6 @@
use std::future::Future;
-use gpui::{App, Global, ReadGlobal, Task};
+use gpui::{App, AppContext, Global, ReadGlobal, Task};
use tokio::task::JoinError;
use util::defer;
@@ -32,20 +32,23 @@ pub struct Tokio {}
impl Tokio {
/// Spawns the given future on Tokio's thread pool, and returns it via a GPUI task
/// Note that the Tokio task will be cancelled if the GPUI task is dropped
- pub fn spawn<Fut, R>(cx: &mut App, f: Fut) -> Task<Result<R, JoinError>>
+ pub fn spawn<C, Fut, R>(cx: &mut C, f: Fut) -> C::Result<Task<Result<R, JoinError>>>
where
+ C: AppContext,
Fut: Future<Output = R> + Send + 'static,
R: Send + 'static,
{
- let join_handle = GlobalTokio::global(cx).runtime.spawn(f);
- let abort_handle = join_handle.abort_handle();
- let cancel = defer(move || {
- abort_handle.abort();
- });
- cx.background_executor().spawn(async move {
- let result = join_handle.await;
- drop(cancel);
- result
+ cx.read_global(|tokio: &GlobalTokio, cx| {
+ let join_handle = tokio.runtime.spawn(f);
+ let abort_handle = join_handle.abort_handle();
+ let cancel = defer(move || {
+ abort_handle.abort();
+ });
+ cx.background_spawn(async move {
+ let result = join_handle.await;
+ drop(cancel);
+ result
+ })
})
}