diff --git a/crates/ai2/src/providers/open_ai/completion.rs b/crates/ai2/src/providers/open_ai/completion.rs index eca5611027..1582659e71 100644 --- a/crates/ai2/src/providers/open_ai/completion.rs +++ b/crates/ai2/src/providers/open_ai/completion.rs @@ -4,7 +4,7 @@ use futures::{ future::BoxFuture, io::BufReader, stream::BoxStream, AsyncBufReadExt, AsyncReadExt, FutureExt, Stream, StreamExt, }; -use gpui2::{AppContext, Executor}; +use gpui2::{AppContext, BackgroundExecutor}; use isahc::{http::StatusCode, Request, RequestExt}; use parking_lot::RwLock; use serde::{Deserialize, Serialize}; @@ -105,7 +105,7 @@ pub struct OpenAIResponseStreamEvent { pub async fn stream_completion( credential: ProviderCredential, - executor: Arc, + executor: Arc, request: Box, ) -> Result>> { let api_key = match credential { @@ -198,11 +198,11 @@ pub async fn stream_completion( pub struct OpenAICompletionProvider { model: OpenAILanguageModel, credential: Arc>, - executor: Arc, + executor: Arc, } impl OpenAICompletionProvider { - pub fn new(model_name: &str, executor: Arc) -> Self { + pub fn new(model_name: &str, executor: Arc) -> Self { let model = OpenAILanguageModel::load(model_name); let credential = Arc::new(RwLock::new(ProviderCredential::NoCredentials)); Self { diff --git a/crates/ai2/src/providers/open_ai/embedding.rs b/crates/ai2/src/providers/open_ai/embedding.rs index fc49c15134..dde4af1273 100644 --- a/crates/ai2/src/providers/open_ai/embedding.rs +++ b/crates/ai2/src/providers/open_ai/embedding.rs @@ -1,7 +1,7 @@ use anyhow::{anyhow, Result}; use async_trait::async_trait; use futures::AsyncReadExt; -use gpui2::Executor; +use gpui2::BackgroundExecutor; use gpui2::{serde_json, AppContext}; use isahc::http::StatusCode; use isahc::prelude::Configurable; @@ -35,7 +35,7 @@ pub struct OpenAIEmbeddingProvider { model: OpenAILanguageModel, credential: Arc>, pub client: Arc, - pub executor: Arc, + pub executor: Arc, rate_limit_count_rx: watch::Receiver>, rate_limit_count_tx: Arc>>>, } @@ -66,7 +66,7 @@ struct OpenAIEmbeddingUsage { } impl OpenAIEmbeddingProvider { - pub fn new(client: Arc, executor: Arc) -> Self { + pub fn new(client: Arc, executor: Arc) -> Self { let (rate_limit_count_tx, rate_limit_count_rx) = watch::channel_with(None); let rate_limit_count_tx = Arc::new(Mutex::new(rate_limit_count_tx)); diff --git a/crates/audio2/src/audio2.rs b/crates/audio2/src/audio2.rs index d04587d74e..5a27b79349 100644 --- a/crates/audio2/src/audio2.rs +++ b/crates/audio2/src/audio2.rs @@ -1,6 +1,6 @@ use assets::SoundRegistry; use futures::{channel::mpsc, StreamExt}; -use gpui2::{AppContext, AssetSource, Executor}; +use gpui2::{AppContext, AssetSource, BackgroundExecutor}; use rodio::{OutputStream, OutputStreamHandle}; use util::ResultExt; @@ -34,7 +34,7 @@ impl Sound { } pub struct Audio { - tx: mpsc::UnboundedSender>, + tx: mpsc::UnboundedSender>, } struct AudioState { @@ -60,8 +60,8 @@ impl AudioState { } impl Audio { - pub fn new(executor: &Executor) -> Self { - let (tx, mut rx) = mpsc::unbounded::>(); + pub fn new(executor: &BackgroundExecutor) -> Self { + let (tx, mut rx) = mpsc::unbounded::>(); executor .spawn_on_main(|| async move { let mut audio = AudioState { diff --git a/crates/call2/src/room.rs b/crates/call2/src/room.rs index b7bac52a8b..556f9e778e 100644 --- a/crates/call2/src/room.rs +++ b/crates/call2/src/room.rs @@ -445,7 +445,8 @@ impl Room { // Wait for client to re-establish a connection to the server. { - let mut reconnection_timeout = cx.executor().timer(RECONNECT_TIMEOUT).fuse(); + let mut reconnection_timeout = + cx.background_executor().timer(RECONNECT_TIMEOUT).fuse(); let client_reconnection = async { let mut remaining_attempts = 3; while remaining_attempts > 0 { diff --git a/crates/client2/src/client2.rs b/crates/client2/src/client2.rs index 19e8685c28..435d5f1840 100644 --- a/crates/client2/src/client2.rs +++ b/crates/client2/src/client2.rs @@ -505,7 +505,7 @@ impl Client { }, &cx, ); - cx.executor().timer(delay).await; + cx.background_executor().timer(delay).await; delay = delay .mul_f32(rng.gen_range(1.0..=2.0)) .min(reconnect_interval); @@ -763,7 +763,8 @@ impl Client { self.set_status(Status::Reconnecting, cx); } - let mut timeout = futures::FutureExt::fuse(cx.executor().timer(CONNECTION_TIMEOUT)); + let mut timeout = + futures::FutureExt::fuse(cx.background_executor().timer(CONNECTION_TIMEOUT)); futures::select_biased! { connection = self.establish_connection(&credentials, cx).fuse() => { match connection { @@ -814,7 +815,7 @@ impl Client { conn: Connection, cx: &AsyncAppContext, ) -> Result<()> { - let executor = cx.executor(); + let executor = cx.background_executor(); log::info!("add connection to peer"); let (connection_id, handle_io, mut incoming) = self.peer.add_connection(conn, { let executor = executor.clone(); @@ -978,7 +979,7 @@ impl Client { .header("x-zed-protocol-version", rpc2::PROTOCOL_VERSION); let http = self.http.clone(); - cx.executor().spawn(async move { + cx.background_executor().spawn(async move { let mut rpc_url = Self::get_rpc_url(http, use_preview_server).await?; let rpc_host = rpc_url .host_str() @@ -1382,7 +1383,7 @@ mod tests { use super::*; use crate::test::FakeServer; - use gpui2::{Context, Executor, TestAppContext}; + use gpui2::{BackgroundExecutor, Context, TestAppContext}; use parking_lot::Mutex; use std::future; use util::http::FakeHttpClient; @@ -1422,7 +1423,7 @@ mod tests { } #[gpui2::test(iterations = 10)] - async fn test_connection_timeout(executor: Executor, cx: &mut TestAppContext) { + async fn test_connection_timeout(executor: BackgroundExecutor, cx: &mut TestAppContext) { let user_id = 5; let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); let mut status = client.status(); @@ -1490,7 +1491,10 @@ mod tests { } #[gpui2::test(iterations = 10)] - async fn test_authenticating_more_than_once(cx: &mut TestAppContext, executor: Executor) { + async fn test_authenticating_more_than_once( + cx: &mut TestAppContext, + executor: BackgroundExecutor, + ) { let auth_count = Arc::new(Mutex::new(0)); let dropped_auth_count = Arc::new(Mutex::new(0)); let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); diff --git a/crates/client2/src/test.rs b/crates/client2/src/test.rs index f30547dcfc..61f94580c3 100644 --- a/crates/client2/src/test.rs +++ b/crates/client2/src/test.rs @@ -1,7 +1,7 @@ use crate::{Client, Connection, Credentials, EstablishConnectionError, UserStore}; use anyhow::{anyhow, Result}; use futures::{stream::BoxStream, StreamExt}; -use gpui2::{Context, Executor, Model, TestAppContext}; +use gpui2::{BackgroundExecutor, Context, Model, TestAppContext}; use parking_lot::Mutex; use rpc2::{ proto::{self, GetPrivateUserInfo, GetPrivateUserInfoResponse}, @@ -14,7 +14,7 @@ pub struct FakeServer { peer: Arc, state: Arc>, user_id: u64, - executor: Executor, + executor: BackgroundExecutor, } #[derive(Default)] @@ -79,10 +79,10 @@ impl FakeServer { } let (client_conn, server_conn, _) = - Connection::in_memory(cx.executor().clone()); + Connection::in_memory(cx.background_executor().clone()); let (connection_id, io, incoming) = - peer.add_test_connection(server_conn, cx.executor().clone()); - cx.executor().spawn(io).detach(); + peer.add_test_connection(server_conn, cx.background_executor().clone()); + cx.background_executor().spawn(io).detach(); { let mut state = state.lock(); state.connection_id = Some(connection_id); diff --git a/crates/copilot2/src/copilot2.rs b/crates/copilot2/src/copilot2.rs index 083c491656..3d50834e94 100644 --- a/crates/copilot2/src/copilot2.rs +++ b/crates/copilot2/src/copilot2.rs @@ -208,7 +208,7 @@ impl RegisteredBuffer { let new_snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot()).ok()?; let content_changes = cx - .executor() + .background_executor() .spawn({ let new_snapshot = new_snapshot.clone(); async move { diff --git a/crates/editor/src/test/editor_lsp_test_context.rs b/crates/editor/src/test/editor_lsp_test_context.rs index 3e2f38a0b6..59b1cbce05 100644 --- a/crates/editor/src/test/editor_lsp_test_context.rs +++ b/crates/editor/src/test/editor_lsp_test_context.rs @@ -266,9 +266,9 @@ impl<'a> EditorLspTestContext<'a> { ) -> futures::channel::mpsc::UnboundedReceiver<()> where T: 'static + request::Request, - T::Params: 'static + Send, - F: 'static + Send + FnMut(lsp::Url, T::Params, gpui::AsyncAppContext) -> Fut, - Fut: 'static + Send + Future>, + T::Params: 'static, + F: 'static + FnMut(lsp::Url, T::Params, gpui::AsyncAppContext) -> Fut, + Fut: 'static + Future>, { let url = self.buffer_lsp_url.clone(); self.lsp.handle_request::(move |params, cx| { diff --git a/crates/fs2/src/fs2.rs b/crates/fs2/src/fs2.rs index 6ff8676473..82b5aead07 100644 --- a/crates/fs2/src/fs2.rs +++ b/crates/fs2/src/fs2.rs @@ -288,7 +288,7 @@ impl Fs for RealFs { pub struct FakeFs { // Use an unfair lock to ensure tests are deterministic. state: Mutex, - executor: gpui2::Executor, + executor: gpui2::BackgroundExecutor, } #[cfg(any(test, feature = "test-support"))] @@ -434,7 +434,7 @@ lazy_static::lazy_static! { #[cfg(any(test, feature = "test-support"))] impl FakeFs { - pub fn new(executor: gpui2::Executor) -> Arc { + pub fn new(executor: gpui2::BackgroundExecutor) -> Arc { Arc::new(Self { executor, state: Mutex::new(FakeFsState { @@ -1222,11 +1222,11 @@ pub fn copy_recursive<'a>( #[cfg(test)] mod tests { use super::*; - use gpui2::Executor; + use gpui2::BackgroundExecutor; use serde_json::json; #[gpui2::test] - async fn test_fake_fs(executor: Executor) { + async fn test_fake_fs(executor: BackgroundExecutor) { let fs = FakeFs::new(executor.clone()); fs.insert_tree( "/root", diff --git a/crates/fuzzy2/src/paths.rs b/crates/fuzzy2/src/paths.rs index f6c5fba6c9..4990b9e5b5 100644 --- a/crates/fuzzy2/src/paths.rs +++ b/crates/fuzzy2/src/paths.rs @@ -1,4 +1,4 @@ -use gpui2::Executor; +use gpui2::BackgroundExecutor; use std::{ borrow::Cow, cmp::{self, Ordering}, @@ -134,7 +134,7 @@ pub async fn match_path_sets<'a, Set: PathMatchCandidateSet<'a>>( smart_case: bool, max_results: usize, cancel_flag: &AtomicBool, - executor: Executor, + executor: BackgroundExecutor, ) -> Vec { let path_count: usize = candidate_sets.iter().map(|s| s.len()).sum(); if path_count == 0 { diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index cdc3f8172d..b3747f3cbf 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -14,8 +14,8 @@ pub use test_context::*; use crate::{ current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AppMetadata, AssetSource, - ClipboardItem, Context, DispatchPhase, DisplayId, Executor, FocusEvent, FocusHandle, FocusId, - KeyBinding, Keymap, LayoutId, MainThread, MainThreadOnly, Pixels, Platform, Point, Render, + BackgroundExecutor, ClipboardItem, Context, DispatchPhase, DisplayId, FocusEvent, FocusHandle, + FocusId, ForegroundExecutor, KeyBinding, Keymap, LayoutId, Pixels, Platform, Point, Render, SharedString, SubscriberSet, Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, View, Window, WindowContext, WindowHandle, WindowId, }; @@ -26,17 +26,18 @@ use parking_lot::Mutex; use slotmap::SlotMap; use std::{ any::{type_name, Any, TypeId}, - borrow::Borrow, + cell::RefCell, marker::PhantomData, mem, ops::{Deref, DerefMut}, path::PathBuf, - sync::{atomic::Ordering::SeqCst, Arc, Weak}, + rc::{Rc, Weak}, + sync::{atomic::Ordering::SeqCst, Arc}, time::Duration, }; use util::http::{self, HttpClient}; -pub struct App(Arc>); +pub struct App(Rc>); /// Represents an application before it is fully launched. Once your app is /// configured, you'll start the app with `App::run`. @@ -54,13 +55,12 @@ impl App { /// app is fully launched. pub fn run(self, on_finish_launching: F) where - F: 'static + FnOnce(&mut MainThread), + F: 'static + FnOnce(&mut AppContext), { let this = self.0.clone(); - let platform = self.0.lock().platform.clone(); - platform.borrow_on_main_thread().run(Box::new(move || { - let cx = &mut *this.lock(); - let cx = unsafe { mem::transmute::<&mut AppContext, &mut MainThread>(cx) }; + let platform = self.0.borrow().platform.clone(); + platform.run(Box::new(move || { + let cx = &mut *this.borrow_mut(); on_finish_launching(cx); })); } @@ -71,16 +71,12 @@ impl App { where F: 'static + FnMut(Vec, &mut AppContext), { - let this = Arc::downgrade(&self.0); - self.0 - .lock() - .platform - .borrow_on_main_thread() - .on_open_urls(Box::new(move |urls| { - if let Some(app) = this.upgrade() { - callback(urls, &mut app.lock()); - } - })); + let this = Rc::downgrade(&self.0); + self.0.borrow().platform.on_open_urls(Box::new(move |urls| { + if let Some(app) = this.upgrade() { + callback(urls, &mut *app.borrow_mut()); + } + })); self } @@ -88,29 +84,25 @@ impl App { where F: 'static + FnMut(&mut AppContext), { - let this = Arc::downgrade(&self.0); - self.0 - .lock() - .platform - .borrow_on_main_thread() - .on_reopen(Box::new(move || { - if let Some(app) = this.upgrade() { - callback(&mut app.lock()); - } - })); + let this = Rc::downgrade(&self.0); + self.0.borrow_mut().platform.on_reopen(Box::new(move || { + if let Some(app) = this.upgrade() { + callback(&mut app.borrow_mut()); + } + })); self } pub fn metadata(&self) -> AppMetadata { - self.0.lock().app_metadata.clone() + self.0.borrow().app_metadata.clone() } - pub fn executor(&self) -> Executor { - self.0.lock().executor.clone() + pub fn background_executor(&self) -> BackgroundExecutor { + self.0.borrow().background_executor.clone() } pub fn text_system(&self) -> Arc { - self.0.lock().text_system.clone() + self.0.borrow().text_system.clone() } } @@ -122,15 +114,16 @@ type QuitHandler = Box BoxFuture<'static, ()> + Se type ReleaseListener = Box; pub struct AppContext { - this: Weak>, - pub(crate) platform: MainThreadOnly, + this: Weak>, + pub(crate) platform: Rc, app_metadata: AppMetadata, text_system: Arc, flushing_effects: bool, pending_updates: usize, pub(crate) active_drag: Option, pub(crate) next_frame_callbacks: HashMap>, - pub(crate) executor: Executor, + pub(crate) background_executor: BackgroundExecutor, + pub(crate) foreground_executor: ForegroundExecutor, pub(crate) svg_renderer: SvgRenderer, asset_source: Arc, pub(crate) image_cache: ImageCache, @@ -156,11 +149,12 @@ pub struct AppContext { impl AppContext { pub(crate) fn new( - platform: Arc, + platform: Rc, asset_source: Arc, http_client: Arc, - ) -> Arc> { - let executor = platform.executor(); + ) -> Rc> { + let executor = platform.background_executor(); + let foreground_executor = platform.foreground_executor(); assert!( executor.is_main_thread(), "must construct App on main thread" @@ -175,16 +169,17 @@ impl AppContext { app_version: platform.app_version().ok(), }; - Arc::new_cyclic(|this| { - Mutex::new(AppContext { + Rc::new_cyclic(|this| { + RefCell::new(AppContext { this: this.clone(), text_system, - platform: MainThreadOnly::new(platform, executor.clone()), + platform, app_metadata, flushing_effects: false, pending_updates: 0, next_frame_callbacks: Default::default(), - executor, + background_executor: executor, + foreground_executor, svg_renderer: SvgRenderer::new(asset_source.clone()), asset_source, image_cache: ImageCache::new(http_client), @@ -225,7 +220,7 @@ impl AppContext { let futures = futures::future::join_all(futures); if self - .executor + .background_executor .block_with_timeout(Duration::from_millis(100), futures) .is_err() { @@ -244,7 +239,6 @@ impl AppContext { pub fn refresh(&mut self) { self.pending_effects.push_back(Effect::Refresh); } - pub(crate) fn update(&mut self, update: impl FnOnce(&mut Self) -> R) -> R { self.pending_updates += 1; let result = update(self); @@ -258,7 +252,7 @@ impl AppContext { } pub(crate) fn read_window( - &mut self, + &self, id: WindowId, read: impl FnOnce(&WindowContext) -> R, ) -> Result { @@ -295,6 +289,68 @@ impl AppContext { }) } + /// Opens a new window with the given option and the root view returned by the given function. + /// The function is invoked with a `WindowContext`, which can be used to interact with window-specific + /// functionality. + pub fn open_window( + &mut self, + options: crate::WindowOptions, + build_root_view: impl FnOnce(&mut WindowContext) -> View + Send + 'static, + ) -> WindowHandle { + self.update(|cx| { + let id = cx.windows.insert(None); + let handle = WindowHandle::new(id); + let mut window = Window::new(handle.into(), options, cx); + let root_view = build_root_view(&mut WindowContext::mutable(cx, &mut window)); + window.root_view.replace(root_view.into()); + cx.windows.get_mut(id).unwrap().replace(window); + handle + }) + } + + pub(crate) fn platform(&self) -> &Rc { + &self.platform + } + + /// Instructs the platform to activate the application by bringing it to the foreground. + pub fn activate(&self, ignoring_other_apps: bool) { + self.platform().activate(ignoring_other_apps); + } + + /// Writes data to the platform clipboard. + pub fn write_to_clipboard(&self, item: ClipboardItem) { + self.platform().write_to_clipboard(item) + } + + /// Reads data from the platform clipboard. + pub fn read_from_clipboard(&self) -> Option { + self.platform().read_from_clipboard() + } + + /// Writes credentials to the platform keychain. + pub fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Result<()> { + self.platform().write_credentials(url, username, password) + } + + /// Reads credentials from the platform keychain. + pub fn read_credentials(&self, url: &str) -> Result)>> { + self.platform().read_credentials(url) + } + + /// Deletes credentials from the platform keychain. + pub fn delete_credentials(&self, url: &str) -> Result<()> { + self.platform().delete_credentials(url) + } + + /// Directs the platform's default browser to open the given URL. + pub fn open_url(&self, url: &str) { + self.platform().open_url(url); + } + + pub fn path_for_auxiliary_executable(&self, name: &str) -> Result { + self.platform().path_for_auxiliary_executable(name) + } + pub(crate) fn push_effect(&mut self, effect: Effect) { match &effect { Effect::Notify { emitter } => { @@ -473,67 +529,24 @@ impl AppContext { pub fn to_async(&self) -> AsyncAppContext { AsyncAppContext { app: unsafe { mem::transmute(self.this.clone()) }, - executor: self.executor.clone(), + background_executor: self.background_executor.clone(), + foreground_executor: self.foreground_executor.clone(), } } /// Obtains a reference to the executor, which can be used to spawn futures. - pub fn executor(&self) -> &Executor { - &self.executor - } - - /// Runs the given closure on the main thread, where interaction with the platform - /// is possible. The given closure will be invoked with a `MainThread`, which - /// has platform-specific methods that aren't present on `AppContext`. - pub fn run_on_main( - &mut self, - f: impl FnOnce(&mut MainThread) -> R + Send + 'static, - ) -> Task - where - R: Send + 'static, - { - if self.executor.is_main_thread() { - Task::ready(f(unsafe { - mem::transmute::<&mut AppContext, &mut MainThread>(self) - })) - } else { - let this = self.this.upgrade().unwrap(); - self.executor.run_on_main(move || { - let cx = &mut *this.lock(); - cx.update(|cx| f(unsafe { mem::transmute::<&mut Self, &mut MainThread>(cx) })) - }) - } - } - - /// Spawns the future returned by the given function on the main thread, where interaction with - /// the platform is possible. The given closure will be invoked with a `MainThread`, - /// which has platform-specific methods that aren't present on `AsyncAppContext`. The future will be - /// polled exclusively on the main thread. - // todo!("I think we need somehow to prevent the MainThread from implementing Send") - pub fn spawn_on_main( - &self, - f: impl FnOnce(MainThread) -> F + Send + 'static, - ) -> Task - where - F: Future + 'static, - R: Send + 'static, - { - let cx = self.to_async(); - self.executor.spawn_on_main(move || f(MainThread(cx))) + pub fn executor(&self) -> &BackgroundExecutor { + &self.background_executor } /// Spawns the future returned by the given function on the thread pool. The closure will be invoked /// with AsyncAppContext, which allows the application state to be accessed across await points. - pub fn spawn(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task + pub fn spawn(&self, f: impl FnOnce(AsyncAppContext) -> Fut) -> Task where - Fut: Future + Send + 'static, - R: Send + 'static, + Fut: Future + 'static, + R: 'static, { - let cx = self.to_async(); - self.executor.spawn(async move { - let future = f(cx); - future.await - }) + self.foreground_executor.spawn(f(self.to_async())) } /// Schedules the given function to be run at the end of the current effect cycle, allowing entities @@ -597,7 +610,7 @@ impl AppContext { /// Access the global of the given type mutably. A default value is assigned if a global of this type has not /// yet been assigned. - pub fn default_global(&mut self) -> &mut G { + pub fn default_global(&mut self) -> &mut G { let global_type = TypeId::of::(); self.push_effect(Effect::NotifyGlobalObservers { global_type }); self.globals_by_type @@ -608,7 +621,7 @@ impl AppContext { } /// Set the value of the global of the given type. - pub fn set_global(&mut self, global: G) { + pub fn set_global(&mut self, global: G) { let global_type = TypeId::of::(); self.push_effect(Effect::NotifyGlobalObservers { global_type }); self.globals_by_type.insert(global_type, Box::new(global)); @@ -717,7 +730,7 @@ impl Context for AppContext { /// Build an entity that is owned by the application. The given function will be invoked with /// a `ModelContext` and must return an object representing the entity. A `Model` will be returned /// which can be used to access the entity in a context. - fn build_model( + fn build_model( &mut self, build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, ) -> Model { @@ -747,107 +760,6 @@ impl Context for AppContext { } } -impl MainThread -where - C: Borrow, -{ - pub(crate) fn platform(&self) -> &dyn Platform { - self.0.borrow().platform.borrow_on_main_thread() - } - - /// Instructs the platform to activate the application by bringing it to the foreground. - pub fn activate(&self, ignoring_other_apps: bool) { - self.platform().activate(ignoring_other_apps); - } - - /// Writes data to the platform clipboard. - pub fn write_to_clipboard(&self, item: ClipboardItem) { - self.platform().write_to_clipboard(item) - } - - /// Reads data from the platform clipboard. - pub fn read_from_clipboard(&self) -> Option { - self.platform().read_from_clipboard() - } - - /// Writes credentials to the platform keychain. - pub fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Result<()> { - self.platform().write_credentials(url, username, password) - } - - /// Reads credentials from the platform keychain. - pub fn read_credentials(&self, url: &str) -> Result)>> { - self.platform().read_credentials(url) - } - - /// Deletes credentials from the platform keychain. - pub fn delete_credentials(&self, url: &str) -> Result<()> { - self.platform().delete_credentials(url) - } - - /// Directs the platform's default browser to open the given URL. - pub fn open_url(&self, url: &str) { - self.platform().open_url(url); - } - - pub fn path_for_auxiliary_executable(&self, name: &str) -> Result { - self.platform().path_for_auxiliary_executable(name) - } -} - -impl MainThread { - fn update(&mut self, update: impl FnOnce(&mut Self) -> R) -> R { - self.0.update(|cx| { - update(unsafe { - std::mem::transmute::<&mut AppContext, &mut MainThread>(cx) - }) - }) - } - - pub(crate) fn update_window( - &mut self, - id: WindowId, - update: impl FnOnce(&mut MainThread) -> R, - ) -> Result { - self.0.update_window(id, |cx| { - update(unsafe { - std::mem::transmute::<&mut WindowContext, &mut MainThread>(cx) - }) - }) - } - - /// Opens a new window with the given option and the root view returned by the given function. - /// The function is invoked with a `WindowContext`, which can be used to interact with window-specific - /// functionality. - pub fn open_window( - &mut self, - options: crate::WindowOptions, - build_root_view: impl FnOnce(&mut WindowContext) -> View + Send + 'static, - ) -> WindowHandle { - self.update(|cx| { - let id = cx.windows.insert(None); - let handle = WindowHandle::new(id); - let mut window = Window::new(handle.into(), options, cx); - let root_view = build_root_view(&mut WindowContext::mutable(cx, &mut window)); - window.root_view.replace(root_view.into()); - cx.windows.get_mut(id).unwrap().replace(window); - handle - }) - } - - /// Update the global of the given type with a closure. Unlike `global_mut`, this method provides - /// your closure with mutable access to the `MainThread` and the global simultaneously. - pub fn update_global( - &mut self, - update: impl FnOnce(&mut G, &mut MainThread) -> R, - ) -> R { - self.0.update_global(|global, cx| { - let cx = unsafe { mem::transmute::<&mut AppContext, &mut MainThread>(cx) }; - update(global, cx) - }) - } -} - /// These effects are processed at the end of each application update cycle. pub(crate) enum Effect { Notify { @@ -855,7 +767,7 @@ pub(crate) enum Effect { }, Emit { emitter: EntityId, - event: Box, + event: Box, }, FocusChanged { window_id: WindowId, @@ -905,15 +817,3 @@ pub(crate) struct AnyDrag { pub view: AnyView, pub cursor_offset: Point, } - -#[cfg(test)] -mod tests { - use super::AppContext; - - #[test] - fn test_app_context_send_sync() { - // This will not compile if `AppContext` does not implement `Send` - fn assert_send() {} - assert_send::(); - } -} diff --git a/crates/gpui2/src/app/async_context.rs b/crates/gpui2/src/app/async_context.rs index 042a75848e..fb941b91b8 100644 --- a/crates/gpui2/src/app/async_context.rs +++ b/crates/gpui2/src/app/async_context.rs @@ -1,16 +1,16 @@ use crate::{ - AnyWindowHandle, AppContext, Context, Executor, MainThread, Model, ModelContext, Result, Task, - WindowContext, + AnyWindowHandle, AppContext, BackgroundExecutor, Context, ForegroundExecutor, Model, + ModelContext, Result, Task, WindowContext, }; use anyhow::anyhow; use derive_more::{Deref, DerefMut}; -use parking_lot::Mutex; -use std::{future::Future, sync::Weak}; +use std::{cell::RefCell, future::Future, rc::Weak}; #[derive(Clone)] pub struct AsyncAppContext { - pub(crate) app: Weak>, - pub(crate) executor: Executor, + pub(crate) app: Weak>, + pub(crate) background_executor: BackgroundExecutor, + pub(crate) foreground_executor: ForegroundExecutor, } impl Context for AsyncAppContext { @@ -22,14 +22,14 @@ impl Context for AsyncAppContext { build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, ) -> Self::Result> where - T: 'static + Send, + T: 'static, { let app = self .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; - let mut lock = app.lock(); // Need this to compile - Ok(lock.build_model(build_model)) + let mut app = app.borrow_mut(); + Ok(app.build_model(build_model)) } fn update_model( @@ -41,8 +41,8 @@ impl Context for AsyncAppContext { .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; - let mut lock = app.lock(); // Need this to compile - Ok(lock.update_model(handle, update)) + let mut app = app.borrow_mut(); + Ok(app.update_model(handle, update)) } } @@ -52,13 +52,17 @@ impl AsyncAppContext { .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; - let mut lock = app.lock(); // Need this to compile + let mut lock = app.borrow_mut(); lock.refresh(); Ok(()) } - pub fn executor(&self) -> &Executor { - &self.executor + pub fn background_executor(&self) -> &BackgroundExecutor { + &self.background_executor + } + + pub fn foreground_executor(&self) -> &ForegroundExecutor { + &self.foreground_executor } pub fn update(&self, f: impl FnOnce(&mut AppContext) -> R) -> Result { @@ -66,7 +70,7 @@ impl AsyncAppContext { .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; - let mut lock = app.lock(); + let mut lock = app.borrow_mut(); Ok(f(&mut *lock)) } @@ -79,7 +83,7 @@ impl AsyncAppContext { .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; - let mut app_context = app.lock(); + let app_context = app.borrow(); app_context.read_window(handle.id, update) } @@ -92,44 +96,16 @@ impl AsyncAppContext { .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; - let mut app_context = app.lock(); + let mut app_context = app.borrow_mut(); app_context.update_window(handle.id, update) } - pub fn spawn(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task - where - Fut: Future + Send + 'static, - R: Send + 'static, - { - let this = self.clone(); - self.executor.spawn(async move { f(this).await }) - } - - pub fn spawn_on_main( - &self, - f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static, - ) -> Task + pub fn spawn(&self, f: impl FnOnce(AsyncAppContext) -> Fut) -> Task where Fut: Future + 'static, - R: Send + 'static, + R: 'static, { - let this = self.clone(); - self.executor.spawn_on_main(|| f(this)) - } - - pub fn run_on_main( - &self, - f: impl FnOnce(&mut MainThread) -> R + Send + 'static, - ) -> Result> - where - R: Send + 'static, - { - let app = self - .app - .upgrade() - .ok_or_else(|| anyhow!("app was released"))?; - let mut app_context = app.lock(); - Ok(app_context.run_on_main(f)) + self.foreground_executor.spawn(f(self.clone())) } pub fn has_global(&self) -> Result { @@ -137,8 +113,8 @@ impl AsyncAppContext { .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; - let lock = app.lock(); // Need this to compile - Ok(lock.has_global::()) + let app = app.borrow_mut(); + Ok(app.has_global::()) } pub fn read_global(&self, read: impl FnOnce(&G, &AppContext) -> R) -> Result { @@ -146,8 +122,8 @@ impl AsyncAppContext { .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; - let lock = app.lock(); // Need this to compile - Ok(read(lock.global(), &lock)) + let app = app.borrow_mut(); // Need this to compile + Ok(read(app.global(), &app)) } pub fn try_read_global( @@ -155,8 +131,8 @@ impl AsyncAppContext { read: impl FnOnce(&G, &AppContext) -> R, ) -> Option { let app = self.app.upgrade()?; - let lock = app.lock(); // Need this to compile - Some(read(lock.try_global()?, &lock)) + let app = app.borrow_mut(); + Some(read(app.try_global()?, &app)) } pub fn update_global( @@ -167,8 +143,8 @@ impl AsyncAppContext { .app .upgrade() .ok_or_else(|| anyhow!("app was released"))?; - let mut lock = app.lock(); // Need this to compile - Ok(lock.update_global(update)) + let mut app = app.borrow_mut(); + Ok(app.update_global(update)) } } @@ -224,7 +200,7 @@ impl Context for AsyncWindowContext { build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, ) -> Result> where - T: 'static + Send, + T: 'static, { self.app .update_window(self.window, |cx| cx.build_model(build_model)) @@ -239,14 +215,3 @@ impl Context for AsyncWindowContext { .update_window(self.window, |cx| cx.update_model(handle, update)) } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_async_app_context_send_sync() { - fn assert_send_sync() {} - assert_send_sync::(); - } -} diff --git a/crates/gpui2/src/app/entity_map.rs b/crates/gpui2/src/app/entity_map.rs index ecd171d1f8..4a4b178e1e 100644 --- a/crates/gpui2/src/app/entity_map.rs +++ b/crates/gpui2/src/app/entity_map.rs @@ -59,7 +59,7 @@ impl EntityMap { /// Insert an entity into a slot obtained by calling `reserve`. pub fn insert(&mut self, slot: Slot, entity: T) -> Model where - T: 'static + Send, + T: 'static, { let model = slot.0; self.entities.insert(model.entity_id, Box::new(entity)); diff --git a/crates/gpui2/src/app/model_context.rs b/crates/gpui2/src/app/model_context.rs index 8a4576c052..f0fc1f07f0 100644 --- a/crates/gpui2/src/app/model_context.rs +++ b/crates/gpui2/src/app/model_context.rs @@ -1,6 +1,6 @@ use crate::{ - AppContext, AsyncAppContext, Context, Effect, Entity, EntityId, EventEmitter, MainThread, - Model, Reference, Subscription, Task, WeakModel, + AppContext, AsyncAppContext, Context, Effect, Entity, EntityId, EventEmitter, Model, Reference, + Subscription, Task, WeakModel, }; use derive_more::{Deref, DerefMut}; use futures::FutureExt; @@ -191,36 +191,20 @@ impl<'a, T: 'static> ModelContext<'a, T> { result } - pub fn spawn( - &self, - f: impl FnOnce(WeakModel, AsyncAppContext) -> Fut + Send + 'static, - ) -> Task + pub fn spawn(&self, f: impl FnOnce(WeakModel, AsyncAppContext) -> Fut) -> Task where T: 'static, - Fut: Future + Send + 'static, - R: Send + 'static, + Fut: Future + 'static, + R: 'static, { let this = self.weak_model(); self.app.spawn(|cx| f(this, cx)) } - - pub fn spawn_on_main( - &self, - f: impl FnOnce(WeakModel, MainThread) -> Fut + Send + 'static, - ) -> Task - where - Fut: Future + 'static, - R: Send + 'static, - { - let this = self.weak_model(); - self.app.spawn_on_main(|cx| f(this, cx)) - } } impl<'a, T> ModelContext<'a, T> where T: EventEmitter, - T::Event: Send, { pub fn emit(&mut self, event: T::Event) { self.app.pending_effects.push_back(Effect::Emit { @@ -234,13 +218,10 @@ impl<'a, T> Context for ModelContext<'a, T> { type ModelContext<'b, U> = ModelContext<'b, U>; type Result = U; - fn build_model( + fn build_model( &mut self, build_model: impl FnOnce(&mut Self::ModelContext<'_, U>) -> U, - ) -> Model - where - U: 'static + Send, - { + ) -> Model { self.app.build_model(build_model) } diff --git a/crates/gpui2/src/app/test_context.rs b/crates/gpui2/src/app/test_context.rs index cd59f9234f..e3bf8eb7da 100644 --- a/crates/gpui2/src/app/test_context.rs +++ b/crates/gpui2/src/app/test_context.rs @@ -1,15 +1,16 @@ use crate::{ - AnyWindowHandle, AppContext, AsyncAppContext, Context, EventEmitter, Executor, MainThread, - Model, ModelContext, Result, Task, TestDispatcher, TestPlatform, WindowContext, + AnyWindowHandle, AppContext, AsyncAppContext, BackgroundExecutor, Context, EventEmitter, + ForegroundExecutor, Model, ModelContext, Result, Task, TestDispatcher, TestPlatform, + WindowContext, }; use futures::SinkExt; -use parking_lot::Mutex; -use std::{future::Future, sync::Arc}; +use std::{cell::RefCell, future::Future, rc::Rc, sync::Arc}; #[derive(Clone)] pub struct TestAppContext { - pub app: Arc>, - pub executor: Executor, + pub app: Rc>, + pub background_executor: BackgroundExecutor, + pub foreground_executor: ForegroundExecutor, } impl Context for TestAppContext { @@ -21,10 +22,10 @@ impl Context for TestAppContext { build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, ) -> Self::Result> where - T: 'static + Send, + T: 'static, { - let mut lock = self.app.lock(); - lock.build_model(build_model) + let mut app = self.app.borrow_mut(); + app.build_model(build_model) } fn update_model( @@ -32,39 +33,45 @@ impl Context for TestAppContext { handle: &Model, update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, ) -> Self::Result { - let mut lock = self.app.lock(); - lock.update_model(handle, update) + let mut app = self.app.borrow_mut(); + app.update_model(handle, update) } } impl TestAppContext { pub fn new(dispatcher: TestDispatcher) -> Self { - let executor = Executor::new(Arc::new(dispatcher)); - let platform = Arc::new(TestPlatform::new(executor.clone())); + let dispatcher = Arc::new(dispatcher); + let background_executor = BackgroundExecutor::new(dispatcher.clone()); + let foreground_executor = ForegroundExecutor::new(dispatcher); + let platform = Rc::new(TestPlatform::new( + background_executor.clone(), + foreground_executor.clone(), + )); let asset_source = Arc::new(()); let http_client = util::http::FakeHttpClient::with_404_response(); Self { app: AppContext::new(platform, asset_source, http_client), - executor, + background_executor, + foreground_executor, } } pub fn quit(&self) { - self.app.lock().quit(); + self.app.borrow_mut().quit(); } pub fn refresh(&mut self) -> Result<()> { - let mut lock = self.app.lock(); - lock.refresh(); + let mut app = self.app.borrow_mut(); + app.refresh(); Ok(()) } - pub fn executor(&self) -> &Executor { - &self.executor + pub fn executor(&self) -> &BackgroundExecutor { + &self.background_executor } pub fn update(&self, f: impl FnOnce(&mut AppContext) -> R) -> R { - let mut cx = self.app.lock(); + let mut cx = self.app.borrow_mut(); cx.update(f) } @@ -73,7 +80,7 @@ impl TestAppContext { handle: AnyWindowHandle, read: impl FnOnce(&WindowContext) -> R, ) -> R { - let mut app_context = self.app.lock(); + let app_context = self.app.borrow(); app_context.read_window(handle.id, read).unwrap() } @@ -82,57 +89,33 @@ impl TestAppContext { handle: AnyWindowHandle, update: impl FnOnce(&mut WindowContext) -> R, ) -> R { - let mut app = self.app.lock(); + let mut app = self.app.borrow_mut(); app.update_window(handle.id, update).unwrap() } - pub fn spawn(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task - where - Fut: Future + Send + 'static, - R: Send + 'static, - { - let cx = self.to_async(); - self.executor.spawn(async move { f(cx).await }) - } - - pub fn spawn_on_main( - &self, - f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static, - ) -> Task + pub fn spawn(&self, f: impl FnOnce(AsyncAppContext) -> Fut) -> Task where Fut: Future + 'static, - R: Send + 'static, + R: 'static, { - let cx = self.to_async(); - self.executor.spawn_on_main(|| f(cx)) - } - - pub fn run_on_main( - &self, - f: impl FnOnce(&mut MainThread) -> R + Send + 'static, - ) -> Task - where - R: Send + 'static, - { - let mut app_context = self.app.lock(); - app_context.run_on_main(f) + self.foreground_executor.spawn(f(self.to_async())) } pub fn has_global(&self) -> bool { - let lock = self.app.lock(); - lock.has_global::() + let app = self.app.borrow(); + app.has_global::() } pub fn read_global(&self, read: impl FnOnce(&G, &AppContext) -> R) -> R { - let lock = self.app.lock(); - read(lock.global(), &lock) + let app = self.app.borrow(); + read(app.global(), &app) } pub fn try_read_global( &self, read: impl FnOnce(&G, &AppContext) -> R, ) -> Option { - let lock = self.app.lock(); + let lock = self.app.borrow(); Some(read(lock.try_global()?, &lock)) } @@ -140,14 +123,15 @@ impl TestAppContext { &mut self, update: impl FnOnce(&mut G, &mut AppContext) -> R, ) -> R { - let mut lock = self.app.lock(); + let mut lock = self.app.borrow_mut(); lock.update_global(update) } pub fn to_async(&self) -> AsyncAppContext { AsyncAppContext { - app: Arc::downgrade(&self.app), - executor: self.executor.clone(), + app: Rc::downgrade(&self.app), + background_executor: self.background_executor.clone(), + foreground_executor: self.foreground_executor.clone(), } } diff --git a/crates/gpui2/src/assets.rs b/crates/gpui2/src/assets.rs index 39c8562b69..0437b3d6de 100644 --- a/crates/gpui2/src/assets.rs +++ b/crates/gpui2/src/assets.rs @@ -8,7 +8,7 @@ use std::{ sync::atomic::{AtomicUsize, Ordering::SeqCst}, }; -pub trait AssetSource: 'static + Send + Sync { +pub trait AssetSource: 'static + Sync { fn load(&self, path: &str) -> Result>; fn list(&self, path: &str) -> Result>; } diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index a715ed30ee..8bd6bcc700 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -4,7 +4,7 @@ pub(crate) use smallvec::SmallVec; use std::{any::Any, mem}; pub trait Element { - type ElementState: 'static + Send; + type ElementState: 'static; fn id(&self) -> Option; @@ -97,7 +97,7 @@ impl> RenderedElement { impl ElementObject for RenderedElement where E: Element, - E::ElementState: 'static + Send, + E::ElementState: 'static, { fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext) { let frame_state = if let Some(id) = self.element.id() { @@ -170,16 +170,14 @@ where } } -pub struct AnyElement(Box + Send>); - -unsafe impl Send for AnyElement {} +pub struct AnyElement(Box>); impl AnyElement { pub fn new(element: E) -> Self where V: 'static, - E: 'static + Element + Send, - E::ElementState: Any + Send, + E: 'static + Element, + E::ElementState: Any, { AnyElement(Box::new(RenderedElement::new(element))) } diff --git a/crates/gpui2/src/executor.rs b/crates/gpui2/src/executor.rs index 70c8f4b3ec..d0b65fa10e 100644 --- a/crates/gpui2/src/executor.rs +++ b/crates/gpui2/src/executor.rs @@ -6,6 +6,7 @@ use std::{ marker::PhantomData, mem, pin::Pin, + rc::Rc, sync::{ atomic::{AtomicBool, Ordering::SeqCst}, Arc, @@ -17,10 +18,16 @@ use util::TryFutureExt; use waker_fn::waker_fn; #[derive(Clone)] -pub struct Executor { +pub struct BackgroundExecutor { dispatcher: Arc, } +#[derive(Clone)] +pub struct ForegroundExecutor { + dispatcher: Arc, + not_send: PhantomData>, +} + #[must_use] pub enum Task { Ready(Option), @@ -61,7 +68,7 @@ impl Future for Task { } } -impl Executor { +impl BackgroundExecutor { pub fn new(dispatcher: Arc) -> Self { Self { dispatcher } } @@ -79,63 +86,6 @@ impl Executor { Task::Spawned(task) } - /// Enqueues the given closure to run on the application's event loop. - /// Returns the result asynchronously. - pub fn run_on_main(&self, func: F) -> Task - where - F: FnOnce() -> R + Send + 'static, - R: Send + 'static, - { - if self.dispatcher.is_main_thread() { - Task::ready(func()) - } else { - self.spawn_on_main(move || async move { func() }) - } - } - - /// Enqueues the given closure to be run on the application's event loop. The - /// closure returns a future which will be run to completion on the main thread. - pub fn spawn_on_main(&self, func: impl FnOnce() -> F + Send + 'static) -> Task - where - F: Future + 'static, - R: Send + 'static, - { - let (runnable, task) = async_task::spawn( - { - let this = self.clone(); - async move { - let task = this.spawn_on_main_local(func()); - task.await - } - }, - { - let dispatcher = self.dispatcher.clone(); - move |runnable| dispatcher.dispatch_on_main_thread(runnable) - }, - ); - runnable.schedule(); - Task::Spawned(task) - } - - /// Enqueues the given closure to be run on the application's event loop. Must - /// be called on the main thread. - pub fn spawn_on_main_local(&self, future: impl Future + 'static) -> Task - where - R: 'static, - { - assert!( - self.dispatcher.is_main_thread(), - "must be called on main thread" - ); - - let dispatcher = self.dispatcher.clone(); - let (runnable, task) = async_task::spawn_local(future, move |runnable| { - dispatcher.dispatch_on_main_thread(runnable) - }); - runnable.schedule(); - Task::Spawned(task) - } - pub fn block(&self, future: impl Future) -> R { pin_mut!(future); let (parker, unparker) = parking::pair(); @@ -261,8 +211,31 @@ impl Executor { } } +impl ForegroundExecutor { + pub fn new(dispatcher: Arc) -> Self { + Self { + dispatcher, + not_send: PhantomData, + } + } + + /// Enqueues the given closure to be run on any thread. The closure returns + /// a future which will be run to completion on any available thread. + pub fn spawn(&self, future: impl Future + 'static) -> Task + where + R: 'static, + { + let dispatcher = self.dispatcher.clone(); + let (runnable, task) = async_task::spawn_local(future, move |runnable| { + dispatcher.dispatch_on_main_thread(runnable) + }); + runnable.schedule(); + Task::Spawned(task) + } +} + pub struct Scope<'a> { - executor: Executor, + executor: BackgroundExecutor, futures: Vec + Send + 'static>>>, tx: Option>, rx: mpsc::Receiver<()>, @@ -270,7 +243,7 @@ pub struct Scope<'a> { } impl<'a> Scope<'a> { - fn new(executor: Executor) -> Self { + fn new(executor: BackgroundExecutor) -> Self { let (tx, rx) = mpsc::channel(1); Self { executor, diff --git a/crates/gpui2/src/gpui2.rs b/crates/gpui2/src/gpui2.rs index 8625866a44..755df91b93 100644 --- a/crates/gpui2/src/gpui2.rs +++ b/crates/gpui2/src/gpui2.rs @@ -68,24 +68,20 @@ use derive_more::{Deref, DerefMut}; use std::{ any::{Any, TypeId}, borrow::{Borrow, BorrowMut}, - mem, ops::{Deref, DerefMut}, - sync::Arc, }; use taffy::TaffyLayoutEngine; -type AnyBox = Box; +type AnyBox = Box; pub trait Context { type ModelContext<'a, T>; type Result; - fn build_model( + fn build_model( &mut self, build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, - ) -> Self::Result> - where - T: 'static + Send; + ) -> Self::Result>; fn update_model( &mut self, @@ -102,7 +98,7 @@ pub trait VisualContext: Context { build_view_state: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, ) -> Self::Result> where - V: 'static + Send; + V: 'static; fn update_view( &mut self, @@ -127,100 +123,6 @@ pub enum GlobalKey { Type(TypeId), } -#[repr(transparent)] -pub struct MainThread(T); - -impl Deref for MainThread { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for MainThread { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl Context for MainThread { - type ModelContext<'a, T> = MainThread>; - type Result = C::Result; - - fn build_model( - &mut self, - build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, - ) -> Self::Result> - where - T: 'static + Send, - { - self.0.build_model(|cx| { - let cx = unsafe { - mem::transmute::< - &mut C::ModelContext<'_, T>, - &mut MainThread>, - >(cx) - }; - build_model(cx) - }) - } - - fn update_model( - &mut self, - handle: &Model, - update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, - ) -> Self::Result { - self.0.update_model(handle, |entity, cx| { - let cx = unsafe { - mem::transmute::< - &mut C::ModelContext<'_, T>, - &mut MainThread>, - >(cx) - }; - update(entity, cx) - }) - } -} - -impl VisualContext for MainThread { - type ViewContext<'a, 'w, V> = MainThread>; - - fn build_view( - &mut self, - build_view_state: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, - ) -> Self::Result> - where - V: 'static + Send, - { - self.0.build_view(|cx| { - let cx = unsafe { - mem::transmute::< - &mut C::ViewContext<'_, '_, V>, - &mut MainThread>, - >(cx) - }; - build_view_state(cx) - }) - } - - fn update_view( - &mut self, - view: &View, - update: impl FnOnce(&mut V, &mut Self::ViewContext<'_, '_, V>) -> R, - ) -> Self::Result { - self.0.update_view(view, |view_state, cx| { - let cx = unsafe { - mem::transmute::< - &mut C::ViewContext<'_, '_, V>, - &mut MainThread>, - >(cx) - }; - update(view_state, cx) - }) - } -} - pub trait BorrowAppContext { fn with_text_style(&mut self, style: TextStyleRefinement, f: F) -> R where @@ -333,32 +235,3 @@ impl<'a, T> DerefMut for Reference<'a, T> { } } } - -pub(crate) struct MainThreadOnly { - executor: Executor, - value: Arc, -} - -impl Clone for MainThreadOnly { - fn clone(&self) -> Self { - Self { - executor: self.executor.clone(), - value: self.value.clone(), - } - } -} - -/// Allows a value to be accessed only on the main thread, allowing a non-`Send` type -/// to become `Send`. -impl MainThreadOnly { - pub(crate) fn new(value: Arc, executor: Executor) -> Self { - Self { executor, value } - } - - pub(crate) fn borrow_on_main_thread(&self) -> &T { - assert!(self.executor.is_main_thread()); - &self.value - } -} - -unsafe impl Send for MainThreadOnly {} diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index 5a37c3ee7a..020cb82cd2 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -50,7 +50,7 @@ pub trait StatelessInteractive: Element { fn on_mouse_down( mut self, button: MouseButton, - handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext) + Send + 'static, + handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext) + 'static, ) -> Self where Self: Sized, @@ -71,7 +71,7 @@ pub trait StatelessInteractive: Element { fn on_mouse_up( mut self, button: MouseButton, - handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext) + Send + 'static, + handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext) + 'static, ) -> Self where Self: Sized, @@ -92,7 +92,7 @@ pub trait StatelessInteractive: Element { fn on_mouse_down_out( mut self, button: MouseButton, - handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext) + Send + 'static, + handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext) + 'static, ) -> Self where Self: Sized, @@ -113,7 +113,7 @@ pub trait StatelessInteractive: Element { fn on_mouse_up_out( mut self, button: MouseButton, - handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext) + Send + 'static, + handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext) + 'static, ) -> Self where Self: Sized, @@ -133,7 +133,7 @@ pub trait StatelessInteractive: Element { fn on_mouse_move( mut self, - handler: impl Fn(&mut V, &MouseMoveEvent, &mut ViewContext) + Send + 'static, + handler: impl Fn(&mut V, &MouseMoveEvent, &mut ViewContext) + 'static, ) -> Self where Self: Sized, @@ -150,7 +150,7 @@ pub trait StatelessInteractive: Element { fn on_scroll_wheel( mut self, - handler: impl Fn(&mut V, &ScrollWheelEvent, &mut ViewContext) + Send + 'static, + handler: impl Fn(&mut V, &ScrollWheelEvent, &mut ViewContext) + 'static, ) -> Self where Self: Sized, @@ -178,7 +178,7 @@ pub trait StatelessInteractive: Element { fn on_action( mut self, - listener: impl Fn(&mut V, &A, DispatchPhase, &mut ViewContext) + Send + 'static, + listener: impl Fn(&mut V, &A, DispatchPhase, &mut ViewContext) + 'static, ) -> Self where Self: Sized, @@ -196,7 +196,7 @@ pub trait StatelessInteractive: Element { fn on_key_down( mut self, - listener: impl Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext) + Send + 'static, + listener: impl Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext) + 'static, ) -> Self where Self: Sized, @@ -214,7 +214,7 @@ pub trait StatelessInteractive: Element { fn on_key_up( mut self, - listener: impl Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext) + Send + 'static, + listener: impl Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext) + 'static, ) -> Self where Self: Sized, @@ -258,9 +258,9 @@ pub trait StatelessInteractive: Element { self } - fn on_drop( + fn on_drop( mut self, - listener: impl Fn(&mut V, View, &mut ViewContext) + Send + 'static, + listener: impl Fn(&mut V, View, &mut ViewContext) + 'static, ) -> Self where Self: Sized, @@ -303,7 +303,7 @@ pub trait StatefulInteractive: StatelessInteractive { fn on_click( mut self, - listener: impl Fn(&mut V, &ClickEvent, &mut ViewContext) + Send + 'static, + listener: impl Fn(&mut V, &ClickEvent, &mut ViewContext) + 'static, ) -> Self where Self: Sized, @@ -316,11 +316,11 @@ pub trait StatefulInteractive: StatelessInteractive { fn on_drag( mut self, - listener: impl Fn(&mut V, &mut ViewContext) -> View + Send + 'static, + listener: impl Fn(&mut V, &mut ViewContext) -> View + 'static, ) -> Self where Self: Sized, - W: 'static + Send + Render, + W: 'static + Render, { debug_assert!( self.stateful_interaction().drag_listener.is_none(), @@ -335,7 +335,7 @@ pub trait StatefulInteractive: StatelessInteractive { } } -pub trait ElementInteraction: 'static + Send { +pub trait ElementInteraction: 'static { fn as_stateless(&self) -> &StatelessInteraction; fn as_stateless_mut(&mut self) -> &mut StatelessInteraction; fn as_stateful(&self) -> Option<&StatefulInteraction>; @@ -672,7 +672,7 @@ impl From for StatefulInteraction { } } -type DropListener = dyn Fn(&mut V, AnyView, &mut ViewContext) + 'static + Send; +type DropListener = dyn Fn(&mut V, AnyView, &mut ViewContext) + 'static; pub struct StatelessInteraction { pub dispatch_context: DispatchContext, @@ -1077,32 +1077,25 @@ pub struct FocusEvent { } pub type MouseDownListener = Box< - dyn Fn(&mut V, &MouseDownEvent, &Bounds, DispatchPhase, &mut ViewContext) - + Send - + 'static, + dyn Fn(&mut V, &MouseDownEvent, &Bounds, DispatchPhase, &mut ViewContext) + 'static, >; pub type MouseUpListener = Box< - dyn Fn(&mut V, &MouseUpEvent, &Bounds, DispatchPhase, &mut ViewContext) - + Send - + 'static, + dyn Fn(&mut V, &MouseUpEvent, &Bounds, DispatchPhase, &mut ViewContext) + 'static, >; pub type MouseMoveListener = Box< - dyn Fn(&mut V, &MouseMoveEvent, &Bounds, DispatchPhase, &mut ViewContext) - + Send - + 'static, + dyn Fn(&mut V, &MouseMoveEvent, &Bounds, DispatchPhase, &mut ViewContext) + 'static, >; pub type ScrollWheelListener = Box< dyn Fn(&mut V, &ScrollWheelEvent, &Bounds, DispatchPhase, &mut ViewContext) - + Send + 'static, >; -pub type ClickListener = Box) + Send + 'static>; +pub type ClickListener = Box) + 'static>; pub(crate) type DragListener = - Box, &mut ViewContext) -> AnyDrag + Send + 'static>; + Box, &mut ViewContext) -> AnyDrag + 'static>; pub type KeyListener = Box< dyn Fn( @@ -1112,6 +1105,5 @@ pub type KeyListener = Box< DispatchPhase, &mut ViewContext, ) -> Option> - + Send + 'static, >; diff --git a/crates/gpui2/src/platform.rs b/crates/gpui2/src/platform.rs index cacb1922f6..7c2dbcce18 100644 --- a/crates/gpui2/src/platform.rs +++ b/crates/gpui2/src/platform.rs @@ -5,9 +5,9 @@ mod mac; mod test; use crate::{ - AnyWindowHandle, Bounds, DevicePixels, Executor, Font, FontId, FontMetrics, FontRun, - GlobalPixels, GlyphId, InputEvent, LineLayout, Pixels, Point, RenderGlyphParams, - RenderImageParams, RenderSvgParams, Result, Scene, SharedString, Size, + AnyWindowHandle, BackgroundExecutor, Bounds, DevicePixels, Font, FontId, FontMetrics, FontRun, + ForegroundExecutor, GlobalPixels, GlyphId, InputEvent, LineLayout, Pixels, Point, + RenderGlyphParams, RenderImageParams, RenderSvgParams, Result, Scene, SharedString, Size, }; use anyhow::anyhow; use async_task::Runnable; @@ -35,12 +35,13 @@ pub use test::*; pub use time::UtcOffset; #[cfg(target_os = "macos")] -pub(crate) fn current_platform() -> Arc { - Arc::new(MacPlatform::new()) +pub(crate) fn current_platform() -> Rc { + Rc::new(MacPlatform::new()) } pub(crate) trait Platform: 'static { - fn executor(&self) -> Executor; + fn background_executor(&self) -> BackgroundExecutor; + fn foreground_executor(&self) -> ForegroundExecutor; fn text_system(&self) -> Arc; fn run(&self, on_finish_launching: Box); diff --git a/crates/gpui2/src/platform/mac/platform.rs b/crates/gpui2/src/platform/mac/platform.rs index 881dd69bc8..8dd94f052e 100644 --- a/crates/gpui2/src/platform/mac/platform.rs +++ b/crates/gpui2/src/platform/mac/platform.rs @@ -1,9 +1,9 @@ use super::BoolExt; use crate::{ - AnyWindowHandle, ClipboardItem, CursorStyle, DisplayId, Executor, InputEvent, MacDispatcher, - MacDisplay, MacDisplayLinker, MacTextSystem, MacWindow, PathPromptOptions, Platform, - PlatformDisplay, PlatformTextSystem, PlatformWindow, Result, SemanticVersion, VideoTimestamp, - WindowOptions, + AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId, ForegroundExecutor, + InputEvent, MacDispatcher, MacDisplay, MacDisplayLinker, MacTextSystem, MacWindow, + PathPromptOptions, Platform, PlatformDisplay, PlatformTextSystem, PlatformWindow, Result, + SemanticVersion, VideoTimestamp, WindowOptions, }; use anyhow::anyhow; use block::ConcreteBlock; @@ -143,7 +143,8 @@ unsafe fn build_classes() { pub struct MacPlatform(Mutex); pub struct MacPlatformState { - executor: Executor, + background_executor: BackgroundExecutor, + foreground_executor: ForegroundExecutor, text_system: Arc, display_linker: MacDisplayLinker, pasteboard: id, @@ -164,8 +165,10 @@ pub struct MacPlatformState { impl MacPlatform { pub fn new() -> Self { + let dispatcher = Arc::new(MacDispatcher); Self(Mutex::new(MacPlatformState { - executor: Executor::new(Arc::new(MacDispatcher)), + background_executor: BackgroundExecutor::new(dispatcher.clone()), + foreground_executor: ForegroundExecutor::new(dispatcher.clone()), text_system: Arc::new(MacTextSystem::new()), display_linker: MacDisplayLinker::new(), pasteboard: unsafe { NSPasteboard::generalPasteboard(nil) }, @@ -345,8 +348,12 @@ impl MacPlatform { } impl Platform for MacPlatform { - fn executor(&self) -> Executor { - self.0.lock().executor.clone() + fn background_executor(&self) -> BackgroundExecutor { + self.0.lock().background_executor.clone() + } + + fn foreground_executor(&self) -> crate::ForegroundExecutor { + self.0.lock().foreground_executor.clone() } fn text_system(&self) -> Arc { @@ -457,6 +464,10 @@ impl Platform for MacPlatform { } } + // fn add_status_item(&self, _handle: AnyWindowHandle) -> Box { + // Box::new(StatusItem::add(self.fonts())) + // } + fn displays(&self) -> Vec> { MacDisplay::all() .into_iter() @@ -464,10 +475,6 @@ impl Platform for MacPlatform { .collect() } - // fn add_status_item(&self, _handle: AnyWindowHandle) -> Box { - // Box::new(StatusItem::add(self.fonts())) - // } - fn display(&self, id: DisplayId) -> Option> { MacDisplay::find_by_id(id).map(|screen| Rc::new(screen) as Rc<_>) } @@ -481,7 +488,7 @@ impl Platform for MacPlatform { handle: AnyWindowHandle, options: WindowOptions, ) -> Box { - Box::new(MacWindow::open(handle, options, self.executor())) + Box::new(MacWindow::open(handle, options, self.foreground_executor())) } fn set_display_link_output_callback( @@ -589,8 +596,8 @@ impl Platform for MacPlatform { let path = path.to_path_buf(); self.0 .lock() - .executor - .spawn_on_main_local(async move { + .background_executor + .spawn(async move { let full_path = ns_string(path.to_str().unwrap_or("")); let root_full_path = ns_string(""); let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace]; @@ -674,23 +681,6 @@ impl Platform for MacPlatform { } } - fn path_for_auxiliary_executable(&self, name: &str) -> Result { - unsafe { - let bundle: id = NSBundle::mainBundle(); - if bundle.is_null() { - Err(anyhow!("app is not running inside a bundle")) - } else { - let name = ns_string(name); - let url: id = msg_send![bundle, URLForAuxiliaryExecutable: name]; - if url.is_null() { - Err(anyhow!("resource not found")) - } else { - ns_url_to_path(url) - } - } - } - } - // fn on_menu_command(&self, callback: Box) { // self.0.lock().menu_command = Some(callback); // } @@ -717,6 +707,23 @@ impl Platform for MacPlatform { // } // } + fn path_for_auxiliary_executable(&self, name: &str) -> Result { + unsafe { + let bundle: id = NSBundle::mainBundle(); + if bundle.is_null() { + Err(anyhow!("app is not running inside a bundle")) + } else { + let name = ns_string(name); + let url: id = msg_send![bundle, URLForAuxiliaryExecutable: name]; + if url.is_null() { + Err(anyhow!("resource not found")) + } else { + ns_url_to_path(url) + } + } + } + } + fn set_cursor_style(&self, style: CursorStyle) { unsafe { let new_cursor: id = match style { diff --git a/crates/gpui2/src/platform/mac/window.rs b/crates/gpui2/src/platform/mac/window.rs index dbdb60469b..bf62e2e0dc 100644 --- a/crates/gpui2/src/platform/mac/window.rs +++ b/crates/gpui2/src/platform/mac/window.rs @@ -1,10 +1,10 @@ use super::{display_bounds_from_native, ns_string, MacDisplay, MetalRenderer, NSRange}; use crate::{ - display_bounds_to_native, point, px, size, AnyWindowHandle, Bounds, Executor, ExternalPaths, - FileDropEvent, GlobalPixels, InputEvent, KeyDownEvent, Keystroke, Modifiers, - ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, - PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point, Scene, Size, - Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions, WindowPromptLevel, + display_bounds_to_native, point, px, size, AnyWindowHandle, Bounds, ExternalPaths, + FileDropEvent, ForegroundExecutor, GlobalPixels, InputEvent, KeyDownEvent, Keystroke, + Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, + Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point, Scene, + Size, Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions, WindowPromptLevel, }; use block::ConcreteBlock; use cocoa::{ @@ -315,7 +315,7 @@ struct InsertText { struct MacWindowState { handle: AnyWindowHandle, - executor: Executor, + executor: ForegroundExecutor, native_window: id, renderer: MetalRenderer, scene_to_render: Option, @@ -451,7 +451,11 @@ unsafe impl Send for MacWindowState {} pub struct MacWindow(Arc>); impl MacWindow { - pub fn open(handle: AnyWindowHandle, options: WindowOptions, executor: Executor) -> Self { + pub fn open( + handle: AnyWindowHandle, + options: WindowOptions, + executor: ForegroundExecutor, + ) -> Self { unsafe { let pool = NSAutoreleasePool::new(nil); @@ -674,13 +678,10 @@ impl MacWindow { impl Drop for MacWindow { fn drop(&mut self) { - let this = self.0.clone(); - let executor = self.0.lock().executor.clone(); - executor - .run_on_main(move || unsafe { - this.lock().native_window.close(); - }) - .detach(); + let native_window = self.0.lock().native_window; + unsafe { + native_window.close(); + } } } @@ -807,7 +808,7 @@ impl PlatformWindow for MacWindow { let native_window = self.0.lock().native_window; let executor = self.0.lock().executor.clone(); executor - .spawn_on_main_local(async move { + .spawn(async move { let _: () = msg_send![ alert, beginSheetModalForWindow: native_window @@ -824,7 +825,7 @@ impl PlatformWindow for MacWindow { let window = self.0.lock().native_window; let executor = self.0.lock().executor.clone(); executor - .spawn_on_main_local(async move { + .spawn(async move { unsafe { let _: () = msg_send![window, makeKeyAndOrderFront: nil]; } @@ -872,25 +873,17 @@ impl PlatformWindow for MacWindow { fn zoom(&self) { let this = self.0.lock(); let window = this.native_window; - this.executor - .spawn_on_main_local(async move { - unsafe { - window.zoom_(nil); - } - }) - .detach(); + unsafe { + window.zoom_(nil); + } } fn toggle_full_screen(&self) { let this = self.0.lock(); let window = this.native_window; - this.executor - .spawn_on_main_local(async move { - unsafe { - window.toggleFullScreen_(nil); - } - }) - .detach(); + unsafe { + window.toggleFullScreen_(nil); + } } fn on_input(&self, callback: Box bool>) { @@ -1189,7 +1182,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { lock.synthetic_drag_counter += 1; let executor = lock.executor.clone(); executor - .spawn_on_main_local(synthetic_drag( + .spawn(synthetic_drag( weak_window_state, lock.synthetic_drag_counter, event.clone(), @@ -1317,7 +1310,7 @@ extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) let executor = lock.executor.clone(); drop(lock); executor - .spawn_on_main_local(async move { + .spawn(async move { let mut lock = window_state.as_ref().lock(); if let Some(mut callback) = lock.activate_callback.take() { drop(lock); diff --git a/crates/gpui2/src/platform/test/dispatcher.rs b/crates/gpui2/src/platform/test/dispatcher.rs index 52a25d352c..98a7897752 100644 --- a/crates/gpui2/src/platform/test/dispatcher.rs +++ b/crates/gpui2/src/platform/test/dispatcher.rs @@ -215,58 +215,3 @@ impl PlatformDispatcher for TestDispatcher { Some(self) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::Executor; - use std::sync::Arc; - - #[test] - fn test_dispatch() { - let dispatcher = TestDispatcher::new(StdRng::seed_from_u64(0)); - let executor = Executor::new(Arc::new(dispatcher)); - - let result = executor.block(async { executor.run_on_main(|| 1).await }); - assert_eq!(result, 1); - - let result = executor.block({ - let executor = executor.clone(); - async move { - executor - .spawn_on_main({ - let executor = executor.clone(); - assert!(executor.is_main_thread()); - || async move { - assert!(executor.is_main_thread()); - let result = executor - .spawn({ - let executor = executor.clone(); - async move { - assert!(!executor.is_main_thread()); - - let result = executor - .spawn_on_main({ - let executor = executor.clone(); - || async move { - assert!(executor.is_main_thread()); - 2 - } - }) - .await; - - assert!(!executor.is_main_thread()); - result - } - }) - .await; - assert!(executor.is_main_thread()); - result - } - }) - .await - } - }); - assert_eq!(result, 2); - } -} diff --git a/crates/gpui2/src/platform/test/platform.rs b/crates/gpui2/src/platform/test/platform.rs index 4d86c434d0..524611b620 100644 --- a/crates/gpui2/src/platform/test/platform.rs +++ b/crates/gpui2/src/platform/test/platform.rs @@ -1,21 +1,29 @@ -use crate::{DisplayId, Executor, Platform, PlatformTextSystem}; +use crate::{BackgroundExecutor, DisplayId, ForegroundExecutor, Platform, PlatformTextSystem}; use anyhow::{anyhow, Result}; use std::sync::Arc; pub struct TestPlatform { - executor: Executor, + background_executor: BackgroundExecutor, + foreground_executor: ForegroundExecutor, } impl TestPlatform { - pub fn new(executor: Executor) -> Self { - TestPlatform { executor } + pub fn new(executor: BackgroundExecutor, foreground_executor: ForegroundExecutor) -> Self { + TestPlatform { + background_executor: executor, + foreground_executor, + } } } // todo!("implement out what our tests needed in GPUI 1") impl Platform for TestPlatform { - fn executor(&self) -> Executor { - self.executor.clone() + fn background_executor(&self) -> BackgroundExecutor { + self.background_executor.clone() + } + + fn foreground_executor(&self) -> ForegroundExecutor { + self.foreground_executor.clone() } fn text_system(&self) -> Arc { diff --git a/crates/gpui2/src/subscription.rs b/crates/gpui2/src/subscription.rs index 3bf28792bb..c42a007622 100644 --- a/crates/gpui2/src/subscription.rs +++ b/crates/gpui2/src/subscription.rs @@ -21,8 +21,8 @@ struct SubscriberSetState { impl SubscriberSet where - EmitterKey: 'static + Send + Ord + Clone + Debug, - Callback: 'static + Send, + EmitterKey: 'static + Ord + Clone + Debug, + Callback: 'static, { pub fn new() -> Self { Self(Arc::new(Mutex::new(SubscriberSetState { @@ -96,7 +96,7 @@ where #[must_use] pub struct Subscription { - unsubscribe: Option>, + unsubscribe: Option>, } impl Subscription { diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index f1d54e7ae0..06b20a3088 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -4,10 +4,13 @@ use crate::{ Size, ViewContext, VisualContext, WeakModel, WindowContext, }; use anyhow::{Context, Result}; -use std::{any::TypeId, marker::PhantomData}; +use std::{ + any::{Any, TypeId}, + marker::PhantomData, +}; pub trait Render: 'static + Sized { - type Element: Element + 'static + Send; + type Element: Element + 'static; fn render(&mut self, cx: &mut ViewContext) -> Self::Element; } @@ -163,7 +166,7 @@ impl Component for EraseViewState Element for EraseViewState { - type ElementState = AnyBox; + type ElementState = Box; fn id(&self) -> Option { Element::id(&self.view) @@ -343,7 +346,7 @@ impl From> for AnyView { } impl Element for AnyView { - type ElementState = AnyBox; + type ElementState = Box; fn id(&self) -> Option { Some(self.model.entity_id.into()) diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 3997a3197f..1ef8012828 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -3,12 +3,11 @@ use crate::{ Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, LayoutId, - MainThread, MainThreadOnly, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, - MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformWindow, - Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams, - RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, Subscription, - TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, WeakModel, WeakView, - WindowOptions, SUBPIXEL_VARIANTS, + Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, + MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, + Reference, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, + Shadow, SharedString, Size, Style, Subscription, TaffyLayoutEngine, Task, Underline, + UnderlineStyle, View, VisualContext, WeakModel, WeakView, WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::Result; use collections::HashMap; @@ -52,7 +51,7 @@ pub enum DispatchPhase { Capture, } -type AnyListener = Box; +type AnyListener = Box; type AnyKeyListener = Box< dyn Fn( &dyn Any, @@ -60,10 +59,9 @@ type AnyKeyListener = Box< DispatchPhase, &mut WindowContext, ) -> Option> - + Send + 'static, >; -type AnyFocusListener = Box; +type AnyFocusListener = Box; slotmap::new_key_type! { pub struct FocusId; } @@ -159,7 +157,7 @@ impl Drop for FocusHandle { // Holds the state for a specific window. pub struct Window { handle: AnyWindowHandle, - platform_window: MainThreadOnly>, + platform_window: Box, display_id: DisplayId, sprite_atlas: Arc, rem_size: Pixels, @@ -194,7 +192,7 @@ impl Window { pub(crate) fn new( handle: AnyWindowHandle, options: WindowOptions, - cx: &mut MainThread, + cx: &mut AppContext, ) -> Self { let platform_window = cx.platform().open_window(handle, options); let display_id = platform_window.display().id(); @@ -209,12 +207,7 @@ impl Window { cx.window.scale_factor = scale_factor; cx.window.scene_builder = SceneBuilder::new(); cx.window.content_size = content_size; - cx.window.display_id = cx - .window - .platform_window - .borrow_on_main_thread() - .display() - .id(); + cx.window.display_id = cx.window.platform_window.display().id(); cx.window.dirty = true; }) .log_err(); @@ -230,8 +223,6 @@ impl Window { }) }); - let platform_window = MainThreadOnly::new(Arc::new(platform_window), cx.executor.clone()); - Window { handle, platform_window, @@ -378,26 +369,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { self.notify(); } - /// Schedule the given closure to be run on the main thread. It will be invoked with - /// a `MainThread`, which provides access to platform-specific functionality - /// of the window. - pub fn run_on_main( - &mut self, - f: impl FnOnce(&mut MainThread>) -> R + Send + 'static, - ) -> Task> - where - R: Send + 'static, - { - if self.executor.is_main_thread() { - Task::ready(Ok(f(unsafe { - mem::transmute::<&mut Self, &mut MainThread>(self) - }))) - } else { - let id = self.window.handle.id; - self.app.run_on_main(move |cx| cx.update_window(id, f)) - } - } - /// Create an `AsyncWindowContext`, which has a static lifetime and can be held across /// await points in async code. pub fn to_async(&self) -> AsyncWindowContext { @@ -408,44 +379,39 @@ impl<'a, 'w> WindowContext<'a, 'w> { pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + Send + 'static) { let f = Box::new(f); let display_id = self.window.display_id; - self.run_on_main(move |cx| { - if let Some(callbacks) = cx.next_frame_callbacks.get_mut(&display_id) { - callbacks.push(f); - // If there was already a callback, it means that we already scheduled a frame. - if callbacks.len() > 1 { - return; - } - } else { - let async_cx = cx.to_async(); - cx.next_frame_callbacks.insert(display_id, vec![f]); - cx.platform().set_display_link_output_callback( - display_id, - Box::new(move |_current_time, _output_time| { - let _ = async_cx.update(|cx| { - let callbacks = cx - .next_frame_callbacks - .get_mut(&display_id) - .unwrap() - .drain(..) - .collect::>(); - for callback in callbacks { - callback(cx); - } - cx.run_on_main(move |cx| { - if cx.next_frame_callbacks.get(&display_id).unwrap().is_empty() { - cx.platform().stop_display_link(display_id); - } - }) - .detach(); - }); - }), - ); + if let Some(callbacks) = self.next_frame_callbacks.get_mut(&display_id) { + callbacks.push(f); + // If there was already a callback, it means that we already scheduled a frame. + if callbacks.len() > 1 { + return; } + } else { + let async_cx = self.to_async(); + self.next_frame_callbacks.insert(display_id, vec![f]); + self.platform().set_display_link_output_callback( + display_id, + Box::new(move |_current_time, _output_time| { + let _ = async_cx.update(|cx| { + let callbacks = cx + .next_frame_callbacks + .get_mut(&display_id) + .unwrap() + .drain(..) + .collect::>(); + for callback in callbacks { + callback(cx); + } - cx.platform().start_display_link(display_id); - }) - .detach(); + if cx.next_frame_callbacks.get(&display_id).unwrap().is_empty() { + cx.platform().stop_display_link(display_id); + } + }); + }), + ); + } + + self.platform().start_display_link(display_id); } /// Spawn the future returned by the given closure on the application thread pool. @@ -453,17 +419,16 @@ impl<'a, 'w> WindowContext<'a, 'w> { /// use within your future. pub fn spawn( &mut self, - f: impl FnOnce(AnyWindowHandle, AsyncWindowContext) -> Fut + Send + 'static, + f: impl FnOnce(AnyWindowHandle, AsyncWindowContext) -> Fut, ) -> Task where - R: Send + 'static, - Fut: Future + Send + 'static, + R: 'static, + Fut: Future + 'static, { let window = self.window.handle; self.app.spawn(move |app| { let cx = AsyncWindowContext::new(app, window); - let future = f(window, cx); - async move { future.await } + f(window, cx) }) } @@ -569,7 +534,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { /// a specific need to register a global listener. pub fn on_mouse_event( &mut self, - handler: impl Fn(&Event, DispatchPhase, &mut WindowContext) + Send + 'static, + handler: impl Fn(&Event, DispatchPhase, &mut WindowContext) + 'static, ) { let order = self.window.z_index_stack.clone(); self.window @@ -906,14 +871,8 @@ impl<'a, 'w> WindowContext<'a, 'w> { self.window.root_view = Some(root_view); let scene = self.window.scene_builder.build(); - self.run_on_main(|cx| { - cx.window - .platform_window - .borrow_on_main_thread() - .draw(scene); - cx.window.dirty = false; - }) - .detach(); + self.window.platform_window.draw(scene); + self.window.dirty = false; } fn start_frame(&mut self) { @@ -1246,7 +1205,7 @@ impl Context for WindowContext<'_, '_> { build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, ) -> Model where - T: 'static + Send, + T: 'static, { let slot = self.app.entities.reserve(); let model = build_model(&mut ModelContext::mutable(&mut *self.app, slot.downgrade())); @@ -1276,7 +1235,7 @@ impl VisualContext for WindowContext<'_, '_> { build_view_state: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, ) -> Self::Result> where - V: 'static + Send, + V: 'static, { let slot = self.app.entities.reserve(); let view = View { @@ -1422,7 +1381,7 @@ pub trait BorrowWindow: BorrowMut + BorrowMut { f: impl FnOnce(Option, &mut Self) -> (R, S), ) -> R where - S: 'static + Send, + S: 'static, { self.with_element_id(id, |global_id, cx| { if let Some(any) = cx @@ -1460,7 +1419,7 @@ pub trait BorrowWindow: BorrowMut + BorrowMut { f: impl FnOnce(Option, &mut Self) -> (R, S), ) -> R where - S: 'static + Send, + S: 'static, { if let Some(element_id) = element_id { self.with_element_state(element_id, f) @@ -1772,30 +1731,13 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { result } - pub fn run_on_main( - &mut self, - view: &mut V, - f: impl FnOnce(&mut V, &mut MainThread>) -> R + Send + 'static, - ) -> Task> - where - R: Send + 'static, - { - if self.executor.is_main_thread() { - let cx = unsafe { mem::transmute::<&mut Self, &mut MainThread>(self) }; - Task::ready(Ok(f(view, cx))) - } else { - let view = self.view().upgrade().unwrap(); - self.window_cx.run_on_main(move |cx| view.update(cx, f)) - } - } - pub fn spawn( &mut self, - f: impl FnOnce(WeakView, AsyncWindowContext) -> Fut + Send + 'static, + f: impl FnOnce(WeakView, AsyncWindowContext) -> Fut, ) -> Task where - R: Send + 'static, - Fut: Future + Send + 'static, + R: 'static, + Fut: Future + 'static, { let view = self.view(); self.window_cx.spawn(move |_, cx| { @@ -1833,7 +1775,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { pub fn on_mouse_event( &mut self, - handler: impl Fn(&mut V, &Event, DispatchPhase, &mut ViewContext) + Send + 'static, + handler: impl Fn(&mut V, &Event, DispatchPhase, &mut ViewContext) + 'static, ) { let handle = self.view().upgrade().unwrap(); self.window_cx.on_mouse_event(move |event, phase, cx| { @@ -1862,13 +1804,10 @@ impl<'a, 'w, V> Context for ViewContext<'a, 'w, V> { type ModelContext<'b, U> = ModelContext<'b, U>; type Result = U; - fn build_model( + fn build_model( &mut self, build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, - ) -> Model - where - T: 'static + Send, - { + ) -> Model { self.window_cx.build_model(build_model) } @@ -1884,7 +1823,7 @@ impl<'a, 'w, V> Context for ViewContext<'a, 'w, V> { impl VisualContext for ViewContext<'_, '_, V> { type ViewContext<'a, 'w, V2> = ViewContext<'a, 'w, V2>; - fn build_view( + fn build_view( &mut self, build_view: impl FnOnce(&mut Self::ViewContext<'_, '_, W>) -> W, ) -> Self::Result> { diff --git a/crates/language2/src/language2.rs b/crates/language2/src/language2.rs index 717a80619b..8233caf62f 100644 --- a/crates/language2/src/language2.rs +++ b/crates/language2/src/language2.rs @@ -17,7 +17,7 @@ use futures::{ future::{BoxFuture, Shared}, FutureExt, TryFutureExt as _, }; -use gpui2::{AppContext, AsyncAppContext, Executor, Task}; +use gpui2::{AppContext, AsyncAppContext, BackgroundExecutor, Task}; pub use highlight_map::HighlightMap; use lazy_static::lazy_static; use lsp2::{CodeActionKind, LanguageServerBinary}; @@ -631,7 +631,7 @@ pub struct LanguageRegistry { lsp_binary_paths: Mutex< HashMap>>>>, >, - executor: Option, + executor: Option, lsp_binary_status_tx: LspBinaryStatusSender, } @@ -680,7 +680,7 @@ impl LanguageRegistry { Self::new(Task::ready(())) } - pub fn set_executor(&mut self, executor: Executor) { + pub fn set_executor(&mut self, executor: BackgroundExecutor) { self.executor = Some(executor); } @@ -916,7 +916,7 @@ impl LanguageRegistry { } let servers_tx = servers_tx.clone(); - cx.executor() + cx.background_executor() .spawn(async move { if fake_server .try_receive_notification::() diff --git a/crates/lsp2/src/lsp2.rs b/crates/lsp2/src/lsp2.rs index 27b7b36e73..70f908b45e 100644 --- a/crates/lsp2/src/lsp2.rs +++ b/crates/lsp2/src/lsp2.rs @@ -5,7 +5,7 @@ pub use lsp_types::*; use anyhow::{anyhow, Context, Result}; use collections::HashMap; use futures::{channel::oneshot, io::BufWriter, AsyncRead, AsyncWrite, FutureExt}; -use gpui2::{AsyncAppContext, Executor, Task}; +use gpui2::{AsyncAppContext, BackgroundExecutor, Task}; use parking_lot::Mutex; use postage::{barrier, prelude::Stream}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; @@ -62,7 +62,7 @@ pub struct LanguageServer { notification_handlers: Arc>>, response_handlers: Arc>>>, io_handlers: Arc>>, - executor: Executor, + executor: BackgroundExecutor, #[allow(clippy::type_complexity)] io_tasks: Mutex>, Task>)>>, output_done_rx: Mutex>, @@ -248,7 +248,7 @@ impl LanguageServer { let (stdout, stderr) = futures::join!(stdout_input_task, stderr_input_task); stdout.or(stderr) }); - let output_task = cx.executor().spawn({ + let output_task = cx.background_executor().spawn({ Self::handle_output( stdin, outbound_rx, @@ -269,7 +269,7 @@ impl LanguageServer { code_action_kinds, next_id: Default::default(), outbound_tx, - executor: cx.executor().clone(), + executor: cx.background_executor().clone(), io_tasks: Mutex::new(Some((input_task, output_task))), output_done_rx: Mutex::new(Some(output_done_rx)), root_path: root_path.to_path_buf(), @@ -670,10 +670,10 @@ impl LanguageServer { match serde_json::from_str(params) { Ok(params) => { let response = f(params, cx.clone()); - cx.executor() - .spawn_on_main({ + cx.foreground_executor() + .spawn({ let outbound_tx = outbound_tx.clone(); - move || async move { + async move { let response = match response.await { Ok(result) => Response { jsonrpc: JSON_RPC_VERSION, @@ -769,7 +769,7 @@ impl LanguageServer { next_id: &AtomicUsize, response_handlers: &Mutex>>, outbound_tx: &channel::Sender, - executor: &Executor, + executor: &BackgroundExecutor, params: T::Params, ) -> impl 'static + Future> where @@ -1048,7 +1048,7 @@ impl FakeLanguageServer { let result = handler(params, cx.clone()); let responded_tx = responded_tx.clone(); async move { - cx.executor().simulate_random_delay().await; + cx.background_executor().simulate_random_delay().await; let result = result.await; responded_tx.unbounded_send(()).ok(); result diff --git a/crates/project2/src/project2.rs b/crates/project2/src/project2.rs index 41b6296367..748e619e96 100644 --- a/crates/project2/src/project2.rs +++ b/crates/project2/src/project2.rs @@ -26,8 +26,8 @@ use futures::{ }; use globset::{Glob, GlobSet, GlobSetBuilder}; use gpui2::{ - AnyModel, AppContext, AsyncAppContext, Context, Entity, EventEmitter, Executor, Model, - ModelContext, Task, WeakModel, + AnyModel, AppContext, AsyncAppContext, BackgroundExecutor, Context, Entity, EventEmitter, + Model, ModelContext, Task, WeakModel, }; use itertools::Itertools; use language2::{ @@ -207,7 +207,7 @@ impl DelayedDebounced { let previous_task = self.task.take(); self.task = Some(cx.spawn(move |project, mut cx| async move { - let mut timer = cx.executor().timer(delay).fuse(); + let mut timer = cx.background_executor().timer(delay).fuse(); if let Some(previous_task) = previous_task { previous_task.await; } @@ -1453,7 +1453,7 @@ impl Project { }; if client.send(initial_state).log_err().is_some() { let client = client.clone(); - cx.executor() + cx.background_executor() .spawn(async move { let mut chunks = split_operations(operations).peekable(); while let Some(chunk) = chunks.next() { @@ -2436,7 +2436,7 @@ impl Project { Duration::from_secs(1); let task = cx.spawn(move |this, mut cx| async move { - cx.executor().timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE).await; + cx.background_executor().timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE).await; if let Some(this) = this.upgrade() { this.update(&mut cx, |this, cx| { this.disk_based_diagnostics_finished( @@ -3477,7 +3477,7 @@ impl Project { }); const PROCESS_TIMEOUT: Duration = Duration::from_secs(5); - let mut timeout = cx.executor().timer(PROCESS_TIMEOUT).fuse(); + let mut timeout = cx.background_executor().timer(PROCESS_TIMEOUT).fuse(); let mut errored = false; if let Some(mut process) = process { @@ -5741,7 +5741,7 @@ impl Project { async fn background_search( unnamed_buffers: Vec>, opened_buffers: HashMap, (Model, BufferSnapshot)>, - executor: Executor, + executor: BackgroundExecutor, fs: Arc, workers: usize, query: SearchQuery, @@ -6376,7 +6376,7 @@ impl Project { let snapshot = worktree_handle.update(&mut cx, |tree, _| tree.as_local().unwrap().snapshot())?; let diff_bases_by_buffer = cx - .executor() + .background_executor() .spawn(async move { future_buffers .into_iter() @@ -7983,7 +7983,7 @@ impl Project { // Any incomplete buffers have open requests waiting. Request that the host sends // creates these buffers for us again to unblock any waiting futures. for id in incomplete_buffer_ids { - cx.executor() + cx.background_executor() .spawn(client.request(proto::OpenBufferById { project_id, id })) .detach(); } @@ -8438,7 +8438,7 @@ impl Project { let fs = self.fs.clone(); cx.spawn(move |this, mut cx| async move { let prettier_dir = match cx - .executor() + .background_executor() .spawn(Prettier::locate( worktree_path.zip(buffer_path).map( |(worktree_root_path, starting_path)| LocateStart { diff --git a/crates/project2/src/worktree.rs b/crates/project2/src/worktree.rs index 6a13bc3599..dd90df81b3 100644 --- a/crates/project2/src/worktree.rs +++ b/crates/project2/src/worktree.rs @@ -22,7 +22,8 @@ use futures::{ use fuzzy2::CharBag; use git::{DOT_GIT, GITIGNORE}; use gpui2::{ - AppContext, AsyncAppContext, Context, EventEmitter, Executor, Model, ModelContext, Task, + AppContext, AsyncAppContext, BackgroundExecutor, Context, EventEmitter, Model, ModelContext, + Task, }; use language2::{ proto::{ @@ -600,7 +601,7 @@ impl LocalWorktree { .update(&mut cx, |t, cx| t.as_local().unwrap().load(&path, cx))? .await?; let text_buffer = cx - .executor() + .background_executor() .spawn(async move { text::Buffer::new(0, id, contents) }) .await; cx.build_model(|_| Buffer::build(text_buffer, diff_base, Some(Arc::new(file)))) @@ -888,7 +889,7 @@ impl LocalWorktree { if let Some(repo) = snapshot.git_repositories.get(&*repo.work_directory) { let repo = repo.repo_ptr.clone(); index_task = Some( - cx.executor() + cx.background_executor() .spawn(async move { repo.lock().load_index_text(&repo_path) }), ); } @@ -3012,7 +3013,7 @@ struct BackgroundScanner { state: Mutex, fs: Arc, status_updates_tx: UnboundedSender, - executor: Executor, + executor: BackgroundExecutor, scan_requests_rx: channel::Receiver, path_prefixes_to_scan_rx: channel::Receiver>, next_entry_id: Arc, @@ -3032,7 +3033,7 @@ impl BackgroundScanner { next_entry_id: Arc, fs: Arc, status_updates_tx: UnboundedSender, - executor: Executor, + executor: BackgroundExecutor, scan_requests_rx: channel::Receiver, path_prefixes_to_scan_rx: channel::Receiver>, ) -> Self { diff --git a/crates/rpc2/src/conn.rs b/crates/rpc2/src/conn.rs index 902e9822d5..ec3c5b68cf 100644 --- a/crates/rpc2/src/conn.rs +++ b/crates/rpc2/src/conn.rs @@ -34,7 +34,7 @@ impl Connection { #[cfg(any(test, feature = "test-support"))] pub fn in_memory( - executor: gpui2::Executor, + executor: gpui2::BackgroundExecutor, ) -> (Self, Self, std::sync::Arc) { use std::sync::{ atomic::{AtomicBool, Ordering::SeqCst}, @@ -53,7 +53,7 @@ impl Connection { #[allow(clippy::type_complexity)] fn channel( killed: Arc, - executor: gpui2::Executor, + executor: gpui2::BackgroundExecutor, ) -> ( Box>, Box>>, diff --git a/crates/rpc2/src/peer.rs b/crates/rpc2/src/peer.rs index 6dfb170f4c..367eba2b4e 100644 --- a/crates/rpc2/src/peer.rs +++ b/crates/rpc2/src/peer.rs @@ -342,7 +342,7 @@ impl Peer { pub fn add_test_connection( self: &Arc, connection: Connection, - executor: gpui2::Executor, + executor: gpui2::BackgroundExecutor, ) -> ( ConnectionId, impl Future> + Send, diff --git a/crates/settings2/src/settings_file.rs b/crates/settings2/src/settings_file.rs index 2105035605..c3903c1c22 100644 --- a/crates/settings2/src/settings_file.rs +++ b/crates/settings2/src/settings_file.rs @@ -2,7 +2,7 @@ use crate::{settings_store::SettingsStore, Settings}; use anyhow::Result; use fs2::Fs; use futures::{channel::mpsc, StreamExt}; -use gpui2::{AppContext, Executor}; +use gpui2::{AppContext, BackgroundExecutor}; use std::{io::ErrorKind, path::PathBuf, str, sync::Arc, time::Duration}; use util::{paths, ResultExt}; @@ -28,7 +28,7 @@ pub fn test_settings() -> String { } pub fn watch_config_file( - executor: &Executor, + executor: &BackgroundExecutor, fs: Arc, path: PathBuf, ) -> mpsc::UnboundedReceiver { diff --git a/crates/sqlez/src/thread_safe_connection.rs b/crates/sqlez/src/thread_safe_connection.rs index ffadb3af41..54241b6d72 100644 --- a/crates/sqlez/src/thread_safe_connection.rs +++ b/crates/sqlez/src/thread_safe_connection.rs @@ -336,13 +336,13 @@ mod test { FOREIGN KEY(dock_pane) REFERENCES panes(pane_id), FOREIGN KEY(active_pane) REFERENCES panes(pane_id) ) STRICT; - + CREATE TABLE panes( pane_id INTEGER PRIMARY KEY, workspace_id INTEGER NOT NULL, active INTEGER NOT NULL, -- Boolean - FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) - ON DELETE CASCADE + FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) + ON DELETE CASCADE ON UPDATE CASCADE ) STRICT; "] diff --git a/crates/vim/src/test/vim_test_context.rs b/crates/vim/src/test/vim_test_context.rs index 7cee320373..94b5820d90 100644 --- a/crates/vim/src/test/vim_test_context.rs +++ b/crates/vim/src/test/vim_test_context.rs @@ -133,9 +133,9 @@ impl<'a> VimTestContext<'a> { ) -> futures::channel::mpsc::UnboundedReceiver<()> where T: 'static + request::Request, - T::Params: 'static + Send, - F: 'static + Send + FnMut(lsp::Url, T::Params, gpui::AsyncAppContext) -> Fut, - Fut: 'static + Send + Future>, + T::Params: 'static, + F: 'static + FnMut(lsp::Url, T::Params, gpui::AsyncAppContext) -> Fut, + Fut: 'static + Future>, { self.cx.handle_request::(handler) } diff --git a/crates/zed2/src/main.rs b/crates/zed2/src/main.rs index 82eacd9710..20b14a249a 100644 --- a/crates/zed2/src/main.rs +++ b/crates/zed2/src/main.rs @@ -62,20 +62,26 @@ fn main() { log::info!("========== starting zed =========="); let app = App::production(Arc::new(Assets)); - let installation_id = app.executor().block(installation_id()).ok(); + let installation_id = app.background_executor().block(installation_id()).ok(); let session_id = Uuid::new_v4().to_string(); init_panic_hook(&app, installation_id.clone(), session_id.clone()); let fs = Arc::new(RealFs); - let user_settings_file_rx = - watch_config_file(&app.executor(), fs.clone(), paths::SETTINGS.clone()); - let _user_keymap_file_rx = - watch_config_file(&app.executor(), fs.clone(), paths::KEYMAP.clone()); + let user_settings_file_rx = watch_config_file( + &app.background_executor(), + fs.clone(), + paths::SETTINGS.clone(), + ); + let _user_keymap_file_rx = watch_config_file( + &app.background_executor(), + fs.clone(), + paths::KEYMAP.clone(), + ); let login_shell_env_loaded = if stdout_is_a_pty() { Task::ready(()) } else { - app.executor().spawn(async { + app.background_executor().spawn(async { load_login_shell_environment().await.log_err(); }) };