diff --git a/Cargo.lock b/Cargo.lock index f892f66da3..c12992e614 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5491,6 +5491,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "gpui_tokio" +version = "0.1.0" +dependencies = [ + "gpui", + "tokio", + "util", +] + [[package]] name = "grid" version = "0.13.0" @@ -10746,6 +10755,7 @@ dependencies = [ "git", "git_hosting_providers", "gpui", + "gpui_tokio", "http_client", "language", "language_extension", @@ -16439,6 +16449,7 @@ dependencies = [ "git_ui", "go_to_line", "gpui", + "gpui_tokio", "http_client", "image_viewer", "inline_completion_button", diff --git a/Cargo.toml b/Cargo.toml index fa79b66f51..9b1dd36557 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,6 @@ resolver = "2" members = [ "crates/activity_indicator", - "crates/zed_predict_tos", "crates/anthropic", "crates/assets", "crates/assistant", @@ -31,8 +30,8 @@ members = [ "crates/context_server_settings", "crates/copilot", "crates/db", - "crates/diagnostics", "crates/deepseek", + "crates/diagnostics", "crates/docs_preprocessor", "crates/editor", "crates/evals", @@ -51,10 +50,12 @@ members = [ "crates/fuzzy", "crates/git", "crates/git_hosting_providers", + "crates/git_ui", "crates/go_to_line", "crates/google_ai", "crates/gpui", "crates/gpui_macros", + "crates/gpui_tokio", "crates/html_to_markdown", "crates/http_client", "crates/image_viewer", @@ -103,6 +104,7 @@ members = [ "crates/remote_server", "crates/repl", "crates/reqwest_client", + "crates/reqwest_client", "crates/rich_text", "crates/rope", "crates/rpc", @@ -141,7 +143,6 @@ members = [ "crates/ui", "crates/ui_input", "crates/ui_macros", - "crates/reqwest_client", "crates/util", "crates/vcs_menu", "crates/vim", @@ -151,8 +152,8 @@ members = [ "crates/worktree", "crates/zed", "crates/zed_actions", + "crates/zed_predict_tos", "crates/zeta", - "crates/git_ui", # # Extensions @@ -253,6 +254,7 @@ gpui = { path = "crates/gpui", default-features = false, features = [ "http_client", ] } gpui_macros = { path = "crates/gpui_macros" } +gpui_tokio = { path = "crates/gpui_tokio" } html_to_markdown = { path = "crates/html_to_markdown" } http_client = { path = "crates/http_client" } image_viewer = { path = "crates/image_viewer" } diff --git a/crates/gpui_tokio/Cargo.toml b/crates/gpui_tokio/Cargo.toml new file mode 100644 index 0000000000..940548f1d6 --- /dev/null +++ b/crates/gpui_tokio/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "gpui_tokio" +version = "0.1.0" +edition.workspace = true +publish.workspace = true +license = "Apache-2.0" + +[lints] +workspace = true + +[lib] +path = "src/gpui_tokio.rs" +doctest = false + +[dependencies] +util.workspace = true +gpui.workspace = true +tokio = { workspace = true, features = ["rt", "rt-multi-thread"] } diff --git a/crates/gpui_tokio/LICENSE-APACHE b/crates/gpui_tokio/LICENSE-APACHE new file mode 120000 index 0000000000..1cd601d0a3 --- /dev/null +++ b/crates/gpui_tokio/LICENSE-APACHE @@ -0,0 +1 @@ +../../LICENSE-APACHE \ No newline at end of file diff --git a/crates/gpui_tokio/src/gpui_tokio.rs b/crates/gpui_tokio/src/gpui_tokio.rs new file mode 100644 index 0000000000..ecc17fa3ec --- /dev/null +++ b/crates/gpui_tokio/src/gpui_tokio.rs @@ -0,0 +1,55 @@ +use std::future::Future; + +use gpui::{App, Global, ReadGlobal, Task}; +use tokio::task::JoinError; +use util::defer; + +pub fn init(cx: &mut App) { + cx.set_global(GlobalTokio::new()); +} + +struct GlobalTokio { + runtime: tokio::runtime::Runtime, +} + +impl Global for GlobalTokio {} + +impl GlobalTokio { + fn new() -> Self { + let runtime = tokio::runtime::Builder::new_multi_thread() + // Since we now have two executors, let's try to keep our footprint small + .worker_threads(2) + .enable_all() + .build() + .expect("Failed to initialize Tokio"); + + Self { runtime } + } +} + +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(cx: &mut App, f: Fut) -> Task> + where + Fut: Future + 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 + }) + } + + pub fn handle(cx: &mut App) -> tokio::runtime::Handle { + GlobalTokio::global(cx).runtime.handle().clone() + } +} diff --git a/crates/remote_server/Cargo.toml b/crates/remote_server/Cargo.toml index a9baa0a6ad..f2238d91fa 100644 --- a/crates/remote_server/Cargo.toml +++ b/crates/remote_server/Cargo.toml @@ -36,6 +36,7 @@ futures.workspace = true git.workspace = true git_hosting_providers.workspace = true gpui.workspace = true +gpui_tokio.workspace = true http_client.workspace = true language.workspace = true language_extension.workspace = true diff --git a/crates/remote_server/src/unix.rs b/crates/remote_server/src/unix.rs index 3a856c2ecb..10ac263cc4 100644 --- a/crates/remote_server/src/unix.rs +++ b/crates/remote_server/src/unix.rs @@ -9,6 +9,7 @@ use futures::channel::mpsc; use futures::{select, select_biased, AsyncRead, AsyncWrite, AsyncWriteExt, FutureExt, SinkExt}; use git::GitHostingProviderRegistry; use gpui::{App, AppContext as _, Context, Entity, SemanticVersion, UpdateGlobal as _}; +use gpui_tokio::Tokio; use http_client::{read_proxy_from_env, Uri}; use language::LanguageRegistry; use node_runtime::{NodeBinaryOptions, NodeRuntime}; @@ -425,6 +426,7 @@ pub fn execute_run( settings::init(cx); let app_version = AppVersion::init(env!("ZED_PKG_VERSION")); release_channel::init(app_version, cx); + gpui_tokio::init(cx); HeadlessProject::init(cx); @@ -445,18 +447,21 @@ pub fn execute_run( let proxy_url = read_proxy_settings(cx); - let http_client = Arc::new( - ReqwestClient::proxy_and_user_agent( - proxy_url, - &format!( - "Zed-Server/{} ({}; {})", - env!("CARGO_PKG_VERSION"), - std::env::consts::OS, - std::env::consts::ARCH - ), + let http_client = { + let _guard = Tokio::handle(cx).enter(); + Arc::new( + ReqwestClient::proxy_and_user_agent( + proxy_url, + &format!( + "Zed-Server/{} ({}; {})", + env!("CARGO_PKG_VERSION"), + std::env::consts::OS, + std::env::consts::ARCH + ), + ) + .expect("Could not start HTTP client"), ) - .expect("Could not start HTTP client"), - ); + }; let node_runtime = NodeRuntime::new(http_client.clone(), node_settings_rx); diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 5e2befe108..7e53c12ae1 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -59,6 +59,7 @@ git_ui.workspace = true git_hosting_providers.workspace = true go_to_line.workspace = true gpui = { workspace = true, features = ["wayland", "x11", "font-kit"] } +gpui_tokio.workspace = true http_client.workspace = true image_viewer.workspace = true inline_completion_button.workspace = true diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 8fc4cef8de..35103fbba5 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -20,6 +20,7 @@ use futures::{future, StreamExt}; use git::GitHostingProviderRegistry; use gpui::{App, AppContext as _, Application, AsyncApp, UpdateGlobal as _}; +use gpui_tokio::Tokio; use http_client::{read_proxy_from_env, Uri}; use language::LanguageRegistry; use log::LevelFilter; @@ -279,6 +280,7 @@ fn main() { app.run(move |cx| { release_channel::init(app_version, cx); + gpui_tokio::init(cx); if let Some(build_sha) = option_env!("ZED_COMMIT_SHA") { AppCommitSha::set_global(AppCommitSha(build_sha.into()), cx); } @@ -302,8 +304,11 @@ fn main() { .ok() }) .or_else(read_proxy_from_env); - let http = ReqwestClient::proxy_and_user_agent(proxy_url, &user_agent) - .expect("could not start HTTP client"); + let http = { + let _guard = Tokio::handle(cx).enter(); + ReqwestClient::proxy_and_user_agent(proxy_url, &user_agent) + .expect("could not start HTTP client") + }; cx.set_http_client(Arc::new(http)); ::set_global(fs.clone(), cx);