`cx.background_executor().spawn(...)` -> `cx.background_spawn(...)` (#25103)

Michael Sloan created

Done automatically with

> ast-grep -p '$A.background_executor().spawn($B)' -r
'$A.background_spawn($B)' --update-all --globs "\!crates/gpui"

Followed by:

* `cargo fmt`
* Unexpected need to remove some trailing whitespace.
* Manually adding imports of `gpui::{AppContext as _}` which provides
`background_spawn`
* Added `AppContext as _` to existing use of `AppContext`

Release Notes:

- N/A

Change summary

crates/assistant/src/inline_assistant.rs                         |   5 
crates/assistant/src/terminal_inline_assistant.rs                |   2 
crates/assistant2/src/buffer_codegen.rs                          |   5 
crates/assistant2/src/context_picker/fetch_context_picker.rs     |   3 
crates/assistant2/src/context_picker/thread_context_picker.rs    |   2 
crates/assistant2/src/context_store.rs                           |   6 
crates/assistant2/src/terminal_codegen.rs                        |   4 
crates/assistant_context_editor/src/context.rs                   |   2 
crates/assistant_context_editor/src/context_store.rs             |  35 
crates/assistant_context_editor/src/patch.rs                     |   7 
crates/assistant_context_editor/src/slash_command.rs             |   4 
crates/assistant_context_editor/src/slash_command_picker.rs      |   3 
crates/assistant_slash_command/src/extension_slash_command.rs    |   4 
crates/assistant_slash_commands/src/auto_command.rs              |  95 
crates/assistant_slash_commands/src/cargo_workspace_command.rs   |   2 
crates/assistant_slash_commands/src/default_command.rs           |   2 
crates/assistant_slash_commands/src/delta_command.rs             |   2 
crates/assistant_slash_commands/src/diagnostics_command.rs       |   2 
crates/assistant_slash_commands/src/docs_command.rs              |   4 
crates/assistant_slash_commands/src/fetch_command.rs             |   2 
crates/assistant_slash_commands/src/file_command.rs              |   2 
crates/assistant_slash_commands/src/project_command.rs           |  79 
crates/assistant_slash_commands/src/prompt_command.rs            |   4 
crates/assistant_slash_commands/src/search_command.rs            |   3 
crates/assistant_slash_commands/src/streaming_example_command.rs |  75 
crates/assistant_slash_commands/src/symbols_command.rs           |   4 
crates/assistant_slash_commands/src/tab_command.rs               | 131 
crates/auto_update/src/auto_update.rs                            |   4 
crates/buffer_diff/src/buffer_diff.rs                            |  12 
crates/call/src/cross_platform/mod.rs                            |   4 
crates/call/src/cross_platform/room.rs                           |  46 
crates/call/src/macos/mod.rs                                     |   4 
crates/call/src/macos/room.rs                                    |  10 
crates/channel/src/channel_store.rs                              |  32 
crates/client/src/client.rs                                      |  14 
crates/client/src/telemetry.rs                                   |  42 
crates/client/src/test.rs                                        |   2 
crates/collab/src/tests/test_server.rs                           |  23 
crates/collab_ui/src/chat_panel.rs                               |   5 
crates/collab_ui/src/chat_panel/message_editor.rs                |   3 
crates/collab_ui/src/collab_panel.rs                             |   5 
crates/collab_ui/src/notification_panel.rs                       |   5 
crates/command_palette/src/command_palette.rs                    |   2 
crates/context_server/src/client.rs                              |   4 
crates/copilot/src/copilot.rs                                    |  16 
crates/db/src/db.rs                                              |   5 
crates/editor/src/display_map/wrap_map.rs                        |   4 
crates/editor/src/editor.rs                                      |  21 
crates/editor/src/element.rs                                     |   3 
crates/editor/src/git/blame.rs                                   |   7 
crates/editor/src/hunk_diff.rs                                   |  11 
crates/editor/src/indent_guides.rs                               |   8 
crates/editor/src/inlay_hint_cache.rs                            |  26 
crates/editor/src/items.rs                                       |  43 
crates/editor/src/tasks.rs                                       |   5 
crates/extension_host/src/extension_host.rs                      |  86 
crates/feedback/src/system_specs.rs                              |   4 
crates/file_finder/src/file_finder.rs                            |   2 
crates/git_ui/src/git_panel.rs                                   |   5 
crates/git_ui/src/project_diff.rs                                |   2 
crates/git_ui/src/repository_selector.rs                         |   3 
crates/image_viewer/src/image_viewer.rs                          |   2 
crates/journal/src/journal.rs                                    |   4 
crates/language/src/buffer.rs                                    |  10 
crates/language/src/language_registry.rs                         |  23 
crates/language_model/src/request.rs                             |   6 
crates/language_model_selector/src/language_model_selector.rs    |   3 
crates/language_models/src/provider/anthropic.rs                 |  79 
crates/language_models/src/provider/deepseek.rs                  |  40 
crates/language_models/src/provider/google.rs                    |  41 
crates/language_models/src/provider/mistral.rs                   |  37 
crates/language_models/src/provider/open_ai.rs                   |  53 
crates/livekit_client/examples/test_app.rs                       |   9 
crates/livekit_client/src/remote_video_track_view.rs             |   4 
crates/lsp/src/lsp.rs                                            |   4 
crates/markdown/src/markdown.rs                                  |   2 
crates/markdown_preview/src/markdown_preview_view.rs             |   2 
crates/multi_buffer/src/multi_buffer.rs                          |  32 
crates/outline_panel/src/outline_panel.rs                        |  13 
crates/project/src/buffer_store.rs                               | 101 
crates/project/src/environment.rs                                |   3 
crates/project/src/git.rs                                        |  14 
crates/project/src/image_store.rs                                |   2 
crates/project/src/lsp_store.rs                                  |  39 
crates/project/src/prettier_store.rs                             |  68 
crates/project/src/project.rs                                    |  44 
crates/project/src/project_tree.rs                               |   2 
crates/project/src/project_tree/server_tree.rs                   |   2 
crates/project/src/toolchain_store.rs                            |  19 
crates/project/src/worktree_store.rs                             |  50 
crates/project_panel/src/project_panel.rs                        |   5 
crates/prompt_library/src/prompt_library.rs                      |   3 
crates/prompt_library/src/prompts.rs                             | 159 -
crates/remote/src/ssh_session.rs                                 |  25 
crates/remote_server/src/headless_project.rs                     |  20 
crates/remote_server/src/unix.rs                                 |   5 
crates/repl/src/kernels/native_kernel.rs                         |   8 
crates/repl/src/kernels/remote_kernels.rs                        |   4 
crates/repl/src/notebook/cell.rs                                 |   3 
crates/repl/src/outputs/markdown.rs                              |   5 
crates/repl/src/repl_store.rs                                    |   2 
crates/semantic_index/src/embedding_index.rs                     |  14 
crates/semantic_index/src/project_index.rs                       |  13 
crates/semantic_index/src/semantic_index.rs                      |   6 
crates/semantic_index/src/summary_index.rs                       |  57 
crates/semantic_index/src/worktree_index.rs                      |   3 
crates/session/src/session.rs                                    |   4 
crates/task/src/static_source.rs                                 | 106 
crates/terminal/src/terminal.rs                                  |   8 
crates/terminal_view/src/terminal_panel.rs                       |  40 
crates/terminal_view/src/terminal_view.rs                        |  13 
crates/vim/src/command.rs                                        |  25 
crates/workspace/src/shared_screen/cross_platform.rs             |   2 
crates/workspace/src/workspace.rs                                |  11 
crates/worktree/src/worktree.rs                                  | 111 
crates/worktree/src/worktree_tests.rs                            |   8 
crates/zed/src/reliability.rs                                    |  74 
crates/zed/src/zed.rs                                            |   4 
crates/zed/src/zed/inline_completion_registry.rs                 |   2 
crates/zeta/src/zeta.rs                                          |   8 
120 files changed, 1,146 insertions(+), 1,267 deletions(-)

Detailed changes

crates/assistant/src/inline_assistant.rs 🔗

@@ -3012,7 +3012,7 @@ impl CodegenAlternative {
                     let executor = cx.background_executor().clone();
                     let message_id = message_id.clone();
                     let line_based_stream_diff: Task<anyhow::Result<()>> =
-                        cx.background_executor().spawn(async move {
+                        cx.background_spawn(async move {
                             let mut response_latency = None;
                             let request_start = Instant::now();
                             let diff = async {
@@ -3326,8 +3326,7 @@ impl CodegenAlternative {
 
         cx.spawn(|codegen, mut cx| async move {
             let (deleted_row_ranges, inserted_row_ranges) = cx
-                .background_executor()
-                .spawn(async move {
+                .background_spawn(async move {
                     let old_text = old_snapshot
                         .text_for_range(
                             Point::new(old_range.start.row, 0)

crates/assistant/src/terminal_inline_assistant.rs 🔗

@@ -1149,7 +1149,7 @@ impl Codegen {
 
                 let (mut hunks_tx, mut hunks_rx) = mpsc::channel(1);
 
-                let task = cx.background_executor().spawn({
+                let task = cx.background_spawn({
                     let message_id = message_id.clone();
                     let executor = cx.background_executor().clone();
                     async move {

crates/assistant2/src/buffer_codegen.rs 🔗

@@ -493,7 +493,7 @@ impl CodegenAlternative {
                     let executor = cx.background_executor().clone();
                     let message_id = message_id.clone();
                     let line_based_stream_diff: Task<anyhow::Result<()>> =
-                        cx.background_executor().spawn(async move {
+                        cx.background_spawn(async move {
                             let mut response_latency = None;
                             let request_start = Instant::now();
                             let diff = async {
@@ -807,8 +807,7 @@ impl CodegenAlternative {
 
         cx.spawn(|codegen, mut cx| async move {
             let (deleted_row_ranges, inserted_row_ranges) = cx
-                .background_executor()
-                .spawn(async move {
+                .background_spawn(async move {
                     let old_text = old_snapshot
                         .text_for_range(
                             Point::new(old_range.start.row, 0)

crates/assistant2/src/context_picker/fetch_context_picker.rs 🔗

@@ -208,8 +208,7 @@ impl PickerDelegate for FetchContextPickerDelegate {
         let confirm_behavior = self.confirm_behavior;
         cx.spawn_in(window, |this, mut cx| async move {
             let text = cx
-                .background_executor()
-                .spawn(Self::build_message(http_client, url.clone()))
+                .background_spawn(Self::build_message(http_client, url.clone()))
                 .await?;
 
             this.update_in(&mut cx, |this, window, cx| {

crates/assistant2/src/context_picker/thread_context_picker.rs 🔗

@@ -123,7 +123,7 @@ impl PickerDelegate for ThreadContextPickerDelegate {
         };
 
         let executor = cx.background_executor().clone();
-        let search_task = cx.background_executor().spawn(async move {
+        let search_task = cx.background_spawn(async move {
             if query.is_empty() {
                 threads
             } else {

crates/assistant2/src/context_store.rs 🔗

@@ -4,7 +4,7 @@ use std::sync::Arc;
 use anyhow::{anyhow, bail, Result};
 use collections::{BTreeMap, HashMap, HashSet};
 use futures::{self, future, Future, FutureExt};
-use gpui::{App, AsyncApp, Context, Entity, SharedString, Task, WeakEntity};
+use gpui::{App, AppContext as _, AsyncApp, Context, Entity, SharedString, Task, WeakEntity};
 use language::Buffer;
 use project::{ProjectPath, Worktree};
 use rope::Rope;
@@ -456,9 +456,7 @@ fn collect_buffer_info_and_text(
     };
     // Important to collect version at the same time as content so that staleness logic is correct.
     let content = buffer.as_rope().clone();
-    let text_task = cx
-        .background_executor()
-        .spawn(async move { to_fenced_codeblock(&path, content) });
+    let text_task = cx.background_spawn(async move { to_fenced_codeblock(&path, content) });
     (buffer_info, text_task)
 }
 

crates/assistant2/src/terminal_codegen.rs 🔗

@@ -1,7 +1,7 @@
 use crate::inline_prompt_editor::CodegenStatus;
 use client::telemetry::Telemetry;
 use futures::{channel::mpsc, SinkExt, StreamExt};
-use gpui::{App, Context, Entity, EventEmitter, Task};
+use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Task};
 use language_model::{LanguageModelRegistry, LanguageModelRequest};
 use language_models::report_assistant_event;
 use std::{sync::Arc, time::Instant};
@@ -53,7 +53,7 @@ impl TerminalCodegen {
 
                 let (mut hunks_tx, mut hunks_rx) = mpsc::channel(1);
 
-                let task = cx.background_executor().spawn({
+                let task = cx.background_spawn({
                     let message_id = message_id.clone();
                     let executor = cx.background_executor().clone();
                     async move {

crates/assistant_context_editor/src/context.rs 🔗

@@ -849,7 +849,7 @@ impl AssistantContext {
             .collect::<Vec<_>>();
         context_ops.extend(self.pending_ops.iter().cloned());
 
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let buffer_ops = buffer_ops.await;
             context_ops.sort_unstable_by_key(|op| op.timestamp());
             buffer_ops

crates/assistant_context_editor/src/context_store.rs 🔗

@@ -265,19 +265,18 @@ impl ContextStore {
                     local_versions.push(context.version(cx).to_proto(context_id.clone()));
                     let client = this.client.clone();
                     let project_id = envelope.payload.project_id;
-                    cx.background_executor()
-                        .spawn(async move {
-                            let operations = operations.await;
-                            for operation in operations {
-                                client.send(proto::UpdateContext {
-                                    project_id,
-                                    context_id: context_id.to_proto(),
-                                    operation: Some(operation),
-                                })?;
-                            }
-                            anyhow::Ok(())
-                        })
-                        .detach_and_log_err(cx);
+                    cx.background_spawn(async move {
+                        let operations = operations.await;
+                        for operation in operations {
+                            client.send(proto::UpdateContext {
+                                project_id,
+                                context_id: context_id.to_proto(),
+                                operation: Some(operation),
+                            })?;
+                        }
+                        anyhow::Ok(())
+                    })
+                    .detach_and_log_err(cx);
                 }
             }
 
@@ -401,8 +400,7 @@ impl ContextStore {
                 )
             })?;
             let operations = cx
-                .background_executor()
-                .spawn(async move {
+                .background_spawn(async move {
                     context_proto
                         .operations
                         .into_iter()
@@ -436,7 +434,7 @@ impl ContextStore {
         let languages = self.languages.clone();
         let project = self.project.clone();
         let telemetry = self.telemetry.clone();
-        let load = cx.background_executor().spawn({
+        let load = cx.background_spawn({
             let path = path.clone();
             async move {
                 let saved_context = fs.load(&path).await?;
@@ -539,8 +537,7 @@ impl ContextStore {
                 )
             })?;
             let operations = cx
-                .background_executor()
-                .spawn(async move {
+                .background_spawn(async move {
                     context_proto
                         .operations
                         .into_iter()
@@ -693,7 +690,7 @@ impl ContextStore {
     pub fn search(&self, query: String, cx: &App) -> Task<Vec<SavedContextMetadata>> {
         let metadata = self.contexts_metadata.clone();
         let executor = cx.background_executor().clone();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             if query.is_empty() {
                 metadata
             } else {

crates/assistant_context_editor/src/patch.rs 🔗

@@ -2,7 +2,7 @@ use anyhow::{anyhow, Context as _, Result};
 use collections::HashMap;
 use editor::ProposedChangesEditor;
 use futures::{future, TryFutureExt as _};
-use gpui::{App, AsyncApp, Entity, SharedString};
+use gpui::{App, AppContext as _, AsyncApp, Entity, SharedString};
 use language::{AutoindentMode, Buffer, BufferSnapshot};
 use project::{Project, ProjectPath};
 use std::{cmp, ops::Range, path::Path, sync::Arc};
@@ -258,8 +258,7 @@ impl AssistantEdit {
 
         let snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot())?;
         let suggestion = cx
-            .background_executor()
-            .spawn(async move { kind.resolve(&snapshot) })
+            .background_spawn(async move { kind.resolve(&snapshot) })
             .await;
 
         Ok((buffer, suggestion))
@@ -547,7 +546,7 @@ impl Eq for AssistantPatch {}
 #[cfg(test)]
 mod tests {
     use super::*;
-    use gpui::{App, AppContext as _};
+    use gpui::App;
     use language::{
         language_settings::AllLanguageSettings, Language, LanguageConfig, LanguageMatcher,
     };

crates/assistant_context_editor/src/slash_command.rs 🔗

@@ -4,7 +4,7 @@ pub use assistant_slash_command::SlashCommand;
 use assistant_slash_command::{AfterCompletion, SlashCommandLine, SlashCommandWorkingSet};
 use editor::{CompletionProvider, Editor};
 use fuzzy::{match_strings, StringMatchCandidate};
-use gpui::{App, Context, Entity, Task, WeakEntity, Window};
+use gpui::{App, AppContext as _, Context, Entity, Task, WeakEntity, Window};
 use language::{Anchor, Buffer, CompletionDocumentation, LanguageServerId, ToPoint};
 use parking_lot::Mutex;
 use project::CompletionIntent;
@@ -162,7 +162,7 @@ impl SlashCommandCompletionProvider {
             let editor = self.editor.clone();
             let workspace = self.workspace.clone();
             let arguments = arguments.to_vec();
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 Ok(completions
                     .await?
                     .into_iter()

crates/assistant_context_editor/src/slash_command_picker.rs 🔗

@@ -102,8 +102,7 @@ impl PickerDelegate for SlashCommandDelegate {
         let all_commands = self.all_commands.clone();
         cx.spawn_in(window, |this, mut cx| async move {
             let filtered_commands = cx
-                .background_executor()
-                .spawn(async move {
+                .background_spawn(async move {
                     if query.is_empty() {
                         all_commands
                     } else {

crates/assistant_slash_command/src/extension_slash_command.rs 🔗

@@ -103,7 +103,7 @@ impl SlashCommand for ExtensionSlashCommand {
     ) -> Task<Result<Vec<ArgumentCompletion>>> {
         let command = self.command.clone();
         let arguments = arguments.to_owned();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let completions = self
                 .extension
                 .complete_slash_command_argument(command, arguments)
@@ -135,7 +135,7 @@ impl SlashCommand for ExtensionSlashCommand {
     ) -> Task<SlashCommandResult> {
         let command = self.command.clone();
         let arguments = arguments.to_owned();
-        let output = cx.background_executor().spawn(async move {
+        let output = cx.background_spawn(async move {
             let delegate =
                 delegate.map(|delegate| Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _);
             let output = self

crates/assistant_slash_commands/src/auto_command.rs 🔗

@@ -82,7 +82,7 @@ impl SlashCommand for AutoCommand {
                 project_index.flush_summary_backlogs(cx)
             })?;
 
-            cx.background_executor().spawn(task).await;
+            cx.background_spawn(task).await;
 
             anyhow::Ok(Vec::new())
         })
@@ -129,7 +129,7 @@ impl SlashCommand for AutoCommand {
         // so you don't have to write it again.
         let original_prompt = argument.to_string();
 
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let commands = task.await?;
             let mut prompt = String::new();
 
@@ -285,57 +285,56 @@ async fn commands_for_summaries(
         })
         .collect::<Vec<_>>();
 
-    cx.background_executor()
-        .spawn(async move {
-            let futures = completion_streams
-                .into_iter()
-                .enumerate()
-                .map(|(ix, (stream, tx))| async move {
-                    let start = std::time::Instant::now();
-                    let events = stream.await?;
-                    log::info!("Time taken for awaiting /await chunk stream #{ix}: {:?}", start.elapsed());
-
-                    let completion: String = events
-                        .filter_map(|event| async {
-                            if let Ok(LanguageModelCompletionEvent::Text(text)) = event {
-                                Some(text)
-                            } else {
-                                None
-                            }
-                        })
-                        .collect()
-                        .await;
-
-                    log::info!("Time taken for all /auto chunks to come back for #{ix}: {:?}", start.elapsed());
-
-                    for line in completion.split('\n') {
-                        if let Some(first_space) = line.find(' ') {
-                            let command = &line[..first_space].trim();
-                            let arg = &line[first_space..].trim();
-
-                            tx.send(CommandToRun {
-                                name: command.to_string(),
-                                arg: arg.to_string(),
-                            })
-                            .await?;
-                        } else if !line.trim().is_empty() {
-                            // All slash-commands currently supported in context inference need a space for the argument.
-                            log::warn!(
-                                "Context inference returned a non-blank line that contained no spaces (meaning no argument for the slash command): {:?}",
-                                line
-                            );
+    cx.background_spawn(async move {
+        let futures = completion_streams
+            .into_iter()
+            .enumerate()
+            .map(|(ix, (stream, tx))| async move {
+                let start = std::time::Instant::now();
+                let events = stream.await?;
+                log::info!("Time taken for awaiting /await chunk stream #{ix}: {:?}", start.elapsed());
+
+                let completion: String = events
+                    .filter_map(|event| async {
+                        if let Ok(LanguageModelCompletionEvent::Text(text)) = event {
+                            Some(text)
+                        } else {
+                            None
                         }
+                    })
+                    .collect()
+                    .await;
+
+                log::info!("Time taken for all /auto chunks to come back for #{ix}: {:?}", start.elapsed());
+
+                for line in completion.split('\n') {
+                    if let Some(first_space) = line.find(' ') {
+                        let command = &line[..first_space].trim();
+                        let arg = &line[first_space..].trim();
+
+                        tx.send(CommandToRun {
+                            name: command.to_string(),
+                            arg: arg.to_string(),
+                        })
+                        .await?;
+                    } else if !line.trim().is_empty() {
+                        // All slash-commands currently supported in context inference need a space for the argument.
+                        log::warn!(
+                            "Context inference returned a non-blank line that contained no spaces (meaning no argument for the slash command): {:?}",
+                            line
+                        );
                     }
+                }
 
-                    anyhow::Ok(())
-                })
-                .collect::<Vec<_>>();
+                anyhow::Ok(())
+            })
+            .collect::<Vec<_>>();
 
-            let _ = futures::future::try_join_all(futures).await.log_err();
+        let _ = futures::future::try_join_all(futures).await.log_err();
 
-            let duration = all_start.elapsed();
-            eprintln!("All futures completed in {:?}", duration);
-        })
+        let duration = all_start.elapsed();
+        eprintln!("All futures completed in {:?}", duration);
+    })
         .await;
 
     drop(tx); // Close the channel so that rx.collect() won't hang. This is safe because all futures have completed.

crates/assistant_slash_commands/src/cargo_workspace_command.rs 🔗

@@ -132,7 +132,7 @@ impl SlashCommand for CargoWorkspaceSlashCommand {
             let project = workspace.project().clone();
             let fs = workspace.project().read(cx).fs().clone();
             let path = Self::path_to_cargo_toml(project, cx);
-            let output = cx.background_executor().spawn(async move {
+            let output = cx.background_spawn(async move {
                 let path = path.with_context(|| "Cargo.toml not found")?;
                 Self::build_message(fs, &path).await
             });

crates/assistant_slash_commands/src/default_command.rs 🔗

@@ -54,7 +54,7 @@ impl SlashCommand for DefaultSlashCommand {
         cx: &mut App,
     ) -> Task<SlashCommandResult> {
         let store = PromptStore::global(cx);
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let store = store.await?;
             let prompts = store.default_prompt_metadata();
 

crates/assistant_slash_commands/src/delta_command.rs 🔗

@@ -86,7 +86,7 @@ impl SlashCommand for DeltaSlashCommand {
             }
         }
 
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let mut output = SlashCommandOutput::default();
             let mut changes_detected = false;
 

crates/assistant_slash_commands/src/diagnostics_command.rs 🔗

@@ -129,7 +129,7 @@ impl SlashCommand for DiagnosticsSlashCommand {
 
         let paths = self.search_paths(query.clone(), cancellation_flag.clone(), &workspace, cx);
         let executor = cx.background_executor().clone();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let mut matches: Vec<String> = paths
                 .await
                 .into_iter()

crates/assistant_slash_commands/src/docs_command.rs 🔗

@@ -176,7 +176,7 @@ impl SlashCommand for DocsSlashCommand {
             .provider()
             .ok_or_else(|| anyhow!("no docs provider specified"))
             .and_then(|provider| IndexedDocsStore::try_global(provider, cx));
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             fn build_completions(items: Vec<String>) -> Vec<ArgumentCompletion> {
                 items
                     .into_iter()
@@ -284,7 +284,7 @@ impl SlashCommand for DocsSlashCommand {
 
         let args = DocsSlashCommandArgs::parse(arguments);
         let executor = cx.background_executor().clone();
-        let task = cx.background_executor().spawn({
+        let task = cx.background_spawn({
             let store = args
                 .provider()
                 .ok_or_else(|| anyhow!("no docs provider specified"))

crates/assistant_slash_commands/src/fetch_command.rs 🔗

@@ -151,7 +151,7 @@ impl SlashCommand for FetchSlashCommand {
         let http_client = workspace.read(cx).client().http_client();
         let url = argument.to_string();
 
-        let text = cx.background_executor().spawn({
+        let text = cx.background_spawn({
             let url = url.clone();
             async move { Self::build_message(http_client, &url).await }
         });

crates/assistant_slash_commands/src/file_command.rs 🔗

@@ -156,7 +156,7 @@ impl SlashCommand for FileSlashCommand {
             cx,
         );
         let comment_id = cx.theme().syntax().highlight_id("comment").map(HighlightId);
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             Ok(paths
                 .await
                 .into_iter()

crates/assistant_slash_commands/src/project_command.rs 🔗

@@ -130,49 +130,48 @@ impl SlashCommand for ProjectSlashCommand {
 
             let results = SemanticDb::load_results(results, &fs, &cx).await?;
 
-            cx.background_executor()
-                .spawn(async move {
-                    let mut output = "Project context:\n".to_string();
-                    let mut sections = Vec::new();
-
-                    for (ix, query) in search_queries.into_iter().enumerate() {
-                        let start_ix = output.len();
-                        writeln!(&mut output, "Results for {query}:").unwrap();
-                        let mut has_results = false;
-                        for result in &results {
-                            if result.query_index == ix {
-                                add_search_result_section(result, &mut output, &mut sections);
-                                has_results = true;
-                            }
-                        }
-                        if has_results {
-                            sections.push(SlashCommandOutputSection {
-                                range: start_ix..output.len(),
-                                icon: IconName::MagnifyingGlass,
-                                label: query.into(),
-                                metadata: None,
-                            });
-                            output.push('\n');
-                        } else {
-                            output.truncate(start_ix);
+            cx.background_spawn(async move {
+                let mut output = "Project context:\n".to_string();
+                let mut sections = Vec::new();
+
+                for (ix, query) in search_queries.into_iter().enumerate() {
+                    let start_ix = output.len();
+                    writeln!(&mut output, "Results for {query}:").unwrap();
+                    let mut has_results = false;
+                    for result in &results {
+                        if result.query_index == ix {
+                            add_search_result_section(result, &mut output, &mut sections);
+                            has_results = true;
                         }
                     }
-
-                    sections.push(SlashCommandOutputSection {
-                        range: 0..output.len(),
-                        icon: IconName::Book,
-                        label: "Project context".into(),
-                        metadata: None,
-                    });
-
-                    Ok(SlashCommandOutput {
-                        text: output,
-                        sections,
-                        run_commands_in_text: true,
+                    if has_results {
+                        sections.push(SlashCommandOutputSection {
+                            range: start_ix..output.len(),
+                            icon: IconName::MagnifyingGlass,
+                            label: query.into(),
+                            metadata: None,
+                        });
+                        output.push('\n');
+                    } else {
+                        output.truncate(start_ix);
                     }
-                    .to_event_stream())
-                })
-                .await
+                }
+
+                sections.push(SlashCommandOutputSection {
+                    range: 0..output.len(),
+                    icon: IconName::Book,
+                    label: "Project context".into(),
+                    metadata: None,
+                });
+
+                Ok(SlashCommandOutput {
+                    text: output,
+                    sections,
+                    run_commands_in_text: true,
+                }
+                .to_event_stream())
+            })
+            .await
         })
     }
 }

crates/assistant_slash_commands/src/prompt_command.rs 🔗

@@ -43,7 +43,7 @@ impl SlashCommand for PromptSlashCommand {
     ) -> Task<Result<Vec<ArgumentCompletion>>> {
         let store = PromptStore::global(cx);
         let query = arguments.to_owned().join(" ");
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let prompts = store.await?.search(query).await;
             Ok(prompts
                 .into_iter()
@@ -77,7 +77,7 @@ impl SlashCommand for PromptSlashCommand {
 
         let store = PromptStore::global(cx);
         let title = SharedString::from(title.clone());
-        let prompt = cx.background_executor().spawn({
+        let prompt = cx.background_spawn({
             let title = title.clone();
             async move {
                 let store = store.await?;

crates/assistant_slash_commands/src/search_command.rs 🔗

@@ -119,8 +119,7 @@ impl SlashCommand for SearchSlashCommand {
             let loaded_results = SemanticDb::load_results(results, &fs, &cx).await?;
 
             let output = cx
-                .background_executor()
-                .spawn(async move {
+                .background_spawn(async move {
                     let mut text = format!("Search results for {query}:\n");
                     let mut sections = Vec::new();
                     for loaded_result in &loaded_results {

crates/assistant_slash_commands/src/streaming_example_command.rs 🔗

@@ -63,56 +63,55 @@ impl SlashCommand for StreamingExampleSlashCommand {
         cx: &mut App,
     ) -> Task<SlashCommandResult> {
         let (events_tx, events_rx) = mpsc::unbounded();
-        cx.background_executor()
-            .spawn(async move {
-                events_tx.unbounded_send(Ok(SlashCommandEvent::StartSection {
-                    icon: IconName::FileRust,
-                    label: "Section 1".into(),
-                    metadata: None,
-                }))?;
-                events_tx.unbounded_send(Ok(SlashCommandEvent::Content(
-                    SlashCommandContent::Text {
-                        text: "Hello".into(),
-                        run_commands_in_text: false,
-                    },
-                )))?;
-                events_tx.unbounded_send(Ok(SlashCommandEvent::EndSection))?;
-
+        cx.background_spawn(async move {
+            events_tx.unbounded_send(Ok(SlashCommandEvent::StartSection {
+                icon: IconName::FileRust,
+                label: "Section 1".into(),
+                metadata: None,
+            }))?;
+            events_tx.unbounded_send(Ok(SlashCommandEvent::Content(
+                SlashCommandContent::Text {
+                    text: "Hello".into(),
+                    run_commands_in_text: false,
+                },
+            )))?;
+            events_tx.unbounded_send(Ok(SlashCommandEvent::EndSection))?;
+
+            Timer::after(Duration::from_secs(1)).await;
+
+            events_tx.unbounded_send(Ok(SlashCommandEvent::StartSection {
+                icon: IconName::FileRust,
+                label: "Section 2".into(),
+                metadata: None,
+            }))?;
+            events_tx.unbounded_send(Ok(SlashCommandEvent::Content(
+                SlashCommandContent::Text {
+                    text: "World".into(),
+                    run_commands_in_text: false,
+                },
+            )))?;
+            events_tx.unbounded_send(Ok(SlashCommandEvent::EndSection))?;
+
+            for n in 1..=10 {
                 Timer::after(Duration::from_secs(1)).await;
 
                 events_tx.unbounded_send(Ok(SlashCommandEvent::StartSection {
-                    icon: IconName::FileRust,
-                    label: "Section 2".into(),
+                    icon: IconName::StarFilled,
+                    label: format!("Section {n}").into(),
                     metadata: None,
                 }))?;
                 events_tx.unbounded_send(Ok(SlashCommandEvent::Content(
                     SlashCommandContent::Text {
-                        text: "World".into(),
+                        text: "lorem ipsum ".repeat(n).trim().into(),
                         run_commands_in_text: false,
                     },
                 )))?;
                 events_tx.unbounded_send(Ok(SlashCommandEvent::EndSection))?;
+            }
 
-                for n in 1..=10 {
-                    Timer::after(Duration::from_secs(1)).await;
-
-                    events_tx.unbounded_send(Ok(SlashCommandEvent::StartSection {
-                        icon: IconName::StarFilled,
-                        label: format!("Section {n}").into(),
-                        metadata: None,
-                    }))?;
-                    events_tx.unbounded_send(Ok(SlashCommandEvent::Content(
-                        SlashCommandContent::Text {
-                            text: "lorem ipsum ".repeat(n).trim().into(),
-                            run_commands_in_text: false,
-                        },
-                    )))?;
-                    events_tx.unbounded_send(Ok(SlashCommandEvent::EndSection))?;
-                }
-
-                anyhow::Ok(())
-            })
-            .detach_and_log_err(cx);
+            anyhow::Ok(())
+        })
+        .detach_and_log_err(cx);
 
         Task::ready(Ok(events_rx.boxed()))
     }

crates/assistant_slash_commands/src/symbols_command.rs 🔗

@@ -4,7 +4,7 @@ use assistant_slash_command::{
     SlashCommandResult,
 };
 use editor::Editor;
-use gpui::{Task, WeakEntity};
+use gpui::{AppContext as _, Task, WeakEntity};
 use language::{BufferSnapshot, LspAdapterDelegate};
 use std::sync::Arc;
 use std::{path::Path, sync::atomic::AtomicBool};
@@ -69,7 +69,7 @@ impl SlashCommand for OutlineSlashCommand {
             let snapshot = buffer.read(cx).snapshot();
             let path = snapshot.resolve_file_path(cx, true);
 
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 let outline = snapshot
                     .outline(None)
                     .context("no symbols for active tab")?;

crates/assistant_slash_commands/src/tab_command.rs 🔗

@@ -152,7 +152,7 @@ impl SlashCommand for TabSlashCommand {
             cx,
         );
 
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let mut output = SlashCommandOutput::default();
             for (full_path, buffer, _) in tab_items_search.await? {
                 append_buffer_to_output(&buffer, full_path.as_deref(), &mut output).log_err();
@@ -212,74 +212,73 @@ fn tab_items_for_queries(
                 })??;
 
         let background_executor = cx.background_executor().clone();
-        cx.background_executor()
-            .spawn(async move {
-                open_buffers.sort_by_key(|(_, _, timestamp)| *timestamp);
-                if empty_query
-                    || queries
-                        .iter()
-                        .any(|query| query == ALL_TABS_COMPLETION_ITEM)
-                {
-                    return Ok(open_buffers);
-                }
-
-                let matched_items = if strict_match {
-                    let match_candidates = open_buffers
-                        .iter()
-                        .enumerate()
-                        .filter_map(|(id, (full_path, ..))| {
-                            let path_string = full_path.as_deref()?.to_string_lossy().to_string();
-                            Some((id, path_string))
-                        })
-                        .fold(HashMap::default(), |mut candidates, (id, path_string)| {
-                            candidates
-                                .entry(path_string)
-                                .or_insert_with(Vec::new)
-                                .push(id);
-                            candidates
-                        });
+        cx.background_spawn(async move {
+            open_buffers.sort_by_key(|(_, _, timestamp)| *timestamp);
+            if empty_query
+                || queries
+                    .iter()
+                    .any(|query| query == ALL_TABS_COMPLETION_ITEM)
+            {
+                return Ok(open_buffers);
+            }
 
-                    queries
-                        .iter()
-                        .filter_map(|query| match_candidates.get(query))
-                        .flatten()
-                        .copied()
-                        .filter_map(|id| open_buffers.get(id))
-                        .cloned()
-                        .collect()
-                } else {
-                    let match_candidates = open_buffers
-                        .iter()
-                        .enumerate()
-                        .filter_map(|(id, (full_path, ..))| {
-                            let path_string = full_path.as_deref()?.to_string_lossy().to_string();
-                            Some(fuzzy::StringMatchCandidate::new(id, &path_string))
-                        })
-                        .collect::<Vec<_>>();
-                    let mut processed_matches = HashSet::default();
-                    let file_queries = queries.iter().map(|query| {
-                        fuzzy::match_strings(
-                            &match_candidates,
-                            query,
-                            true,
-                            usize::MAX,
-                            &cancel,
-                            background_executor.clone(),
-                        )
+            let matched_items = if strict_match {
+                let match_candidates = open_buffers
+                    .iter()
+                    .enumerate()
+                    .filter_map(|(id, (full_path, ..))| {
+                        let path_string = full_path.as_deref()?.to_string_lossy().to_string();
+                        Some((id, path_string))
+                    })
+                    .fold(HashMap::default(), |mut candidates, (id, path_string)| {
+                        candidates
+                            .entry(path_string)
+                            .or_insert_with(Vec::new)
+                            .push(id);
+                        candidates
                     });
 
-                    join_all(file_queries)
-                        .await
-                        .into_iter()
-                        .flatten()
-                        .filter(|string_match| processed_matches.insert(string_match.candidate_id))
-                        .filter_map(|string_match| open_buffers.get(string_match.candidate_id))
-                        .cloned()
-                        .collect()
-                };
-                Ok(matched_items)
-            })
-            .await
+                queries
+                    .iter()
+                    .filter_map(|query| match_candidates.get(query))
+                    .flatten()
+                    .copied()
+                    .filter_map(|id| open_buffers.get(id))
+                    .cloned()
+                    .collect()
+            } else {
+                let match_candidates = open_buffers
+                    .iter()
+                    .enumerate()
+                    .filter_map(|(id, (full_path, ..))| {
+                        let path_string = full_path.as_deref()?.to_string_lossy().to_string();
+                        Some(fuzzy::StringMatchCandidate::new(id, &path_string))
+                    })
+                    .collect::<Vec<_>>();
+                let mut processed_matches = HashSet::default();
+                let file_queries = queries.iter().map(|query| {
+                    fuzzy::match_strings(
+                        &match_candidates,
+                        query,
+                        true,
+                        usize::MAX,
+                        &cancel,
+                        background_executor.clone(),
+                    )
+                });
+
+                join_all(file_queries)
+                    .await
+                    .into_iter()
+                    .flatten()
+                    .filter(|string_match| processed_matches.insert(string_match.candidate_id))
+                    .filter_map(|string_match| open_buffers.get(string_match.candidate_id))
+                    .cloned()
+                    .collect()
+            };
+            Ok(matched_items)
+        })
+        .await
     })
 }
 

crates/auto_update/src/auto_update.rs 🔗

@@ -513,7 +513,7 @@ impl AutoUpdater {
         should_show: bool,
         cx: &App,
     ) -> Task<Result<()>> {
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             if should_show {
                 KEY_VALUE_STORE
                     .write_kvp(
@@ -531,7 +531,7 @@ impl AutoUpdater {
     }
 
     pub fn should_show_update_notification(&self, cx: &App) -> Task<Result<bool>> {
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             Ok(KEY_VALUE_STORE
                 .read_kvp(SHOULD_SHOW_UPDATE_NOTIFICATION_KEY)?
                 .is_some())

crates/buffer_diff/src/buffer_diff.rs 🔗

@@ -1,6 +1,6 @@
 use futures::{channel::oneshot, future::OptionFuture};
 use git2::{DiffLineType as GitDiffLineType, DiffOptions as GitOptions, Patch as GitPatch};
-use gpui::{App, AsyncApp, Context, Entity, EventEmitter};
+use gpui::{App, AppContext as _, AsyncApp, Context, Entity, EventEmitter};
 use language::{Language, LanguageRegistry};
 use rope::Rope;
 use std::{cmp, future::Future, iter, ops::Range, sync::Arc};
@@ -615,11 +615,9 @@ impl BufferDiff {
                 cx,
             )
         });
-        let base_text_snapshot = cx
-            .background_executor()
-            .spawn(OptionFuture::from(base_text_snapshot));
+        let base_text_snapshot = cx.background_spawn(OptionFuture::from(base_text_snapshot));
 
-        let hunks = cx.background_executor().spawn({
+        let hunks = cx.background_spawn({
             let buffer = buffer.clone();
             async move { compute_hunks(diff_base, buffer) }
         });
@@ -641,7 +639,7 @@ impl BufferDiff {
                 .clone()
                 .map(|buffer| buffer.as_rope().clone()),
         );
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             BufferDiffInner {
                 hunks: compute_hunks(diff_base, buffer),
                 base_text: diff_base_buffer,
@@ -998,7 +996,7 @@ mod tests {
     use std::fmt::Write as _;
 
     use super::*;
-    use gpui::{AppContext as _, TestAppContext};
+    use gpui::TestAppContext;
     use rand::{rngs::StdRng, Rng as _};
     use text::{Buffer, BufferId, Rope};
     use unindent::Unindent as _;

crates/call/src/cross_platform/mod.rs 🔗

@@ -241,7 +241,7 @@ impl ActiveCall {
                 })
                 .shared();
             self.pending_room_creation = Some(room.clone());
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 room.await.map_err(|err| anyhow!("{:?}", err))?;
                 anyhow::Ok(())
             })
@@ -278,7 +278,7 @@ impl ActiveCall {
         };
 
         let client = self.client.clone();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             client
                 .request(proto::CancelCall {
                     room_id,

crates/call/src/cross_platform/room.rs 🔗

@@ -13,7 +13,7 @@ use client::{
 use collections::{BTreeMap, HashMap, HashSet};
 use fs::Fs;
 use futures::{FutureExt, StreamExt};
-use gpui::{App, AppContext, AsyncApp, Context, Entity, EventEmitter, Task, WeakEntity};
+use gpui::{App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, Task, WeakEntity};
 use language::LanguageRegistry;
 #[cfg(not(all(target_os = "windows", target_env = "gnu")))]
 use livekit::{
@@ -255,7 +255,7 @@ impl Room {
     fn app_will_quit(&mut self, cx: &mut Context<Self>) -> impl Future<Output = ()> {
         let task = if self.status.is_online() {
             let leave = self.leave_internal(cx);
-            Some(cx.background_executor().spawn(async move {
+            Some(cx.background_spawn(async move {
                 leave.await.log_err();
             }))
         } else {
@@ -322,7 +322,7 @@ impl Room {
         self.clear_state(cx);
 
         let leave_room = self.client.request(proto::LeaveRoom {});
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             leave_room.await?;
             anyhow::Ok(())
         })
@@ -1248,7 +1248,7 @@ impl Room {
         };
 
         cx.notify();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             client
                 .request(proto::UpdateParticipantLocation {
                     room_id,
@@ -1373,11 +1373,10 @@ impl Room {
                 match publication {
                     Ok(publication) => {
                         if canceled {
-                            cx.background_executor()
-                                .spawn(async move {
-                                    participant.unpublish_track(&publication.sid()).await
-                                })
-                                .detach_and_log_err(cx)
+                            cx.background_spawn(async move {
+                                participant.unpublish_track(&publication.sid()).await
+                            })
+                            .detach_and_log_err(cx)
                         } else {
                             if live_kit.muted_by_user || live_kit.deafened {
                                 publication.mute();
@@ -1465,11 +1464,10 @@ impl Room {
                 match publication {
                     Ok(publication) => {
                         if canceled {
-                            cx.background_executor()
-                                .spawn(async move {
-                                    participant.unpublish_track(&publication.sid()).await
-                                })
-                                .detach()
+                            cx.background_spawn(async move {
+                                participant.unpublish_track(&publication.sid()).await
+                            })
+                            .detach()
                         } else {
                             live_kit.screen_track = LocalTrack::Published {
                                 track_publication: publication,
@@ -1561,9 +1559,10 @@ impl Room {
                 {
                     let local_participant = live_kit.room.local_participant();
                     let sid = track_publication.sid();
-                    cx.background_executor()
-                        .spawn(async move { local_participant.unpublish_track(&sid).await })
-                        .detach_and_log_err(cx);
+                    cx.background_spawn(
+                        async move { local_participant.unpublish_track(&sid).await },
+                    )
+                    .detach_and_log_err(cx);
                     cx.notify();
                 }
 
@@ -1722,13 +1721,12 @@ impl LiveKitRoom {
         }
 
         let participant = self.room.local_participant();
-        cx.background_executor()
-            .spawn(async move {
-                for sid in tracks_to_unpublish {
-                    participant.unpublish_track(&sid).await.log_err();
-                }
-            })
-            .detach();
+        cx.background_spawn(async move {
+            for sid in tracks_to_unpublish {
+                participant.unpublish_track(&sid).await.log_err();
+            }
+        })
+        .detach();
     }
 }
 

crates/call/src/macos/mod.rs 🔗

@@ -234,7 +234,7 @@ impl ActiveCall {
                 })
                 .shared();
             self.pending_room_creation = Some(room.clone());
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 room.await.map_err(|err| anyhow!("{:?}", err))?;
                 anyhow::Ok(())
             })
@@ -271,7 +271,7 @@ impl ActiveCall {
         };
 
         let client = self.client.clone();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             client
                 .request(proto::CancelCall {
                     room_id,

crates/call/src/macos/room.rs 🔗

@@ -311,7 +311,7 @@ impl Room {
     fn app_will_quit(&mut self, cx: &mut Context<Self>) -> impl Future<Output = ()> {
         let task = if self.status.is_online() {
             let leave = self.leave_internal(cx);
-            Some(cx.background_executor().spawn(async move {
+            Some(cx.background_spawn(async move {
                 leave.await.log_err();
             }))
         } else {
@@ -378,7 +378,7 @@ impl Room {
         self.clear_state(cx);
 
         let leave_room = self.client.request(proto::LeaveRoom {});
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             leave_room.await?;
             anyhow::Ok(())
         })
@@ -1268,7 +1268,7 @@ impl Room {
         };
 
         cx.notify();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             client
                 .request(proto::UpdateParticipantLocation {
                     room_id,
@@ -1385,9 +1385,7 @@ impl Room {
                                 live_kit.room.unpublish_track(publication);
                             } else {
                                 if live_kit.muted_by_user || live_kit.deafened {
-                                    cx.background_executor()
-                                        .spawn(publication.set_mute(true))
-                                        .detach();
+                                    cx.background_spawn(publication.set_mute(true)).detach();
                                 }
                                 live_kit.microphone_track = LocalTrack::Published {
                                     track_publication: publication,

crates/channel/src/channel_store.rs 🔗

@@ -514,8 +514,7 @@ impl ChannelStore {
                 }
             }
         };
-        cx.background_executor()
-            .spawn(async move { task.await.map_err(|error| anyhow!("{}", error)) })
+        cx.background_spawn(async move { task.await.map_err(|error| anyhow!("{}", error)) })
     }
 
     pub fn is_channel_admin(&self, channel_id: ChannelId) -> bool {
@@ -781,7 +780,7 @@ impl ChannelStore {
         cx: &mut Context<Self>,
     ) -> Task<Result<()>> {
         let client = self.client.clone();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             client
                 .request(proto::RespondToChannelInvite {
                     channel_id: channel_id.0,
@@ -975,21 +974,18 @@ impl ChannelStore {
 
                                 if let Some(operations) = operations {
                                     let client = this.client.clone();
-                                    cx.background_executor()
-                                        .spawn(async move {
-                                            let operations = operations.await;
-                                            for chunk in
-                                                language::proto::split_operations(operations)
-                                            {
-                                                client
-                                                    .send(proto::UpdateChannelBuffer {
-                                                        channel_id: channel_id.0,
-                                                        operations: chunk,
-                                                    })
-                                                    .ok();
-                                            }
-                                        })
-                                        .detach();
+                                    cx.background_spawn(async move {
+                                        let operations = operations.await;
+                                        for chunk in language::proto::split_operations(operations) {
+                                            client
+                                                .send(proto::UpdateChannelBuffer {
+                                                    channel_id: channel_id.0,
+                                                    operations: chunk,
+                                                })
+                                                .ok();
+                                        }
+                                    })
+                                    .detach();
                                     return true;
                                 }
                             }

crates/client/src/client.rs 🔗

@@ -19,7 +19,7 @@ use futures::{
     channel::oneshot, future::BoxFuture, AsyncReadExt, FutureExt, SinkExt, Stream, StreamExt,
     TryFutureExt as _, TryStreamExt,
 };
-use gpui::{actions, App, AsyncApp, Entity, Global, Task, WeakEntity};
+use gpui::{actions, App, AppContext as _, AsyncApp, Entity, Global, Task, WeakEntity};
 use http_client::{AsyncBody, HttpClient, HttpClientWithUrl};
 use parking_lot::RwLock;
 use postage::watch;
@@ -1064,7 +1064,7 @@ impl Client {
         let rpc_url = self.rpc_url(http, release_channel);
         let system_id = self.telemetry.system_id();
         let metrics_id = self.telemetry.metrics_id();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             use HttpOrHttps::*;
 
             #[derive(Debug)]
@@ -1743,7 +1743,7 @@ mod tests {
     use crate::test::FakeServer;
 
     use clock::FakeSystemClock;
-    use gpui::{AppContext as _, BackgroundExecutor, TestAppContext};
+    use gpui::{BackgroundExecutor, TestAppContext};
     use http_client::FakeHttpClient;
     use parking_lot::Mutex;
     use proto::TypedEnvelope;
@@ -1806,7 +1806,7 @@ mod tests {
 
         // Time out when client tries to connect.
         client.override_authenticate(move |cx| {
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 Ok(Credentials {
                     user_id,
                     access_token: "token".into(),
@@ -1814,7 +1814,7 @@ mod tests {
             })
         });
         client.override_establish_connection(|_, cx| {
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 future::pending::<()>().await;
                 unreachable!()
             })
@@ -1848,7 +1848,7 @@ mod tests {
         // Time out when re-establishing the connection.
         server.allow_connections();
         client.override_establish_connection(|_, cx| {
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 future::pending::<()>().await;
                 unreachable!()
             })
@@ -1887,7 +1887,7 @@ mod tests {
             move |cx| {
                 let auth_count = auth_count.clone();
                 let dropped_auth_count = dropped_auth_count.clone();
-                cx.background_executor().spawn(async move {
+                cx.background_spawn(async move {
                     *auth_count.lock() += 1;
                     let _drop = util::defer(move || *dropped_auth_count.lock() += 1);
                     future::pending::<()>().await;

crates/client/src/telemetry.rs 🔗

@@ -5,7 +5,7 @@ use anyhow::Result;
 use clock::SystemClock;
 use futures::channel::mpsc;
 use futures::{Future, StreamExt};
-use gpui::{App, BackgroundExecutor, Task};
+use gpui::{App, AppContext as _, BackgroundExecutor, Task};
 use http_client::{self, AsyncBody, HttpClient, HttpClientWithUrl, Method, Request};
 use parking_lot::Mutex;
 use release_channel::ReleaseChannel;
@@ -219,18 +219,17 @@ impl Telemetry {
         }));
         Self::log_file_path();
 
-        cx.background_executor()
-            .spawn({
-                let state = state.clone();
-                let os_version = os_version();
-                state.lock().os_version = Some(os_version.clone());
-                async move {
-                    if let Some(tempfile) = File::create(Self::log_file_path()).log_err() {
-                        state.lock().log_file = Some(tempfile);
-                    }
+        cx.background_spawn({
+            let state = state.clone();
+            let os_version = os_version();
+            state.lock().os_version = Some(os_version.clone());
+            async move {
+                if let Some(tempfile) = File::create(Self::log_file_path()).log_err() {
+                    state.lock().log_file = Some(tempfile);
                 }
-            })
-            .detach();
+            }
+        })
+        .detach();
 
         cx.observe_global::<SettingsStore>({
             let state = state.clone();
@@ -252,17 +251,16 @@ impl Telemetry {
         let (tx, mut rx) = mpsc::unbounded();
         ::telemetry::init(tx);
 
-        cx.background_executor()
-            .spawn({
-                let this = Arc::downgrade(&this);
-                async move {
-                    while let Some(event) = rx.next().await {
-                        let Some(state) = this.upgrade() else { break };
-                        state.report_event(Event::Flexible(event))
-                    }
+        cx.background_spawn({
+            let this = Arc::downgrade(&this);
+            async move {
+                while let Some(event) = rx.next().await {
+                    let Some(state) = this.upgrade() else { break };
+                    state.report_event(Event::Flexible(event))
                 }
-            })
-            .detach();
+            }
+        })
+        .detach();
 
         // We should only ever have one instance of Telemetry, leak the subscription to keep it alive
         // rather than store in TelemetryState, complicating spawn as subscriptions are not Send

crates/client/src/test.rs 🔗

@@ -85,7 +85,7 @@ impl FakeServer {
                             Connection::in_memory(cx.background_executor().clone());
                         let (connection_id, io, incoming) =
                             peer.add_test_connection(server_conn, cx.background_executor().clone());
-                        cx.background_executor().spawn(io).detach();
+                        cx.background_spawn(io).detach();
                         {
                             let mut state = state.lock();
                             state.connection_id = Some(connection_id);

crates/collab/src/tests/test_server.rs 🔗

@@ -244,18 +244,17 @@ impl TestServer {
                             .await
                             .expect("retrieving user failed")
                             .unwrap();
-                        cx.background_executor()
-                            .spawn(server.handle_connection(
-                                server_conn,
-                                client_name,
-                                Principal::User(user),
-                                ZedVersion(SemanticVersion::new(1, 0, 0)),
-                                None,
-                                None,
-                                Some(connection_id_tx),
-                                Executor::Deterministic(cx.background_executor().clone()),
-                            ))
-                            .detach();
+                        cx.background_spawn(server.handle_connection(
+                            server_conn,
+                            client_name,
+                            Principal::User(user),
+                            ZedVersion(SemanticVersion::new(1, 0, 0)),
+                            None,
+                            None,
+                            Some(connection_id_tx),
+                            Executor::Deterministic(cx.background_executor().clone()),
+                        ))
+                        .detach();
                         let connection_id = connection_id_rx.await.map_err(|e| {
                             EstablishConnectionError::Other(anyhow!(
                                 "{} (is server shutting down?)",

crates/collab_ui/src/chat_panel.rs 🔗

@@ -201,8 +201,7 @@ impl ChatPanel {
     ) -> Task<Result<Entity<Self>>> {
         cx.spawn(|mut cx| async move {
             let serialized_panel = if let Some(panel) = cx
-                .background_executor()
-                .spawn(async move { KEY_VALUE_STORE.read_kvp(CHAT_PANEL_KEY) })
+                .background_spawn(async move { KEY_VALUE_STORE.read_kvp(CHAT_PANEL_KEY) })
                 .await
                 .log_err()
                 .flatten()
@@ -227,7 +226,7 @@ impl ChatPanel {
 
     fn serialize(&mut self, cx: &mut Context<Self>) {
         let width = self.width;
-        self.pending_serialization = cx.background_executor().spawn(
+        self.pending_serialization = cx.background_spawn(
             async move {
                 KEY_VALUE_STORE
                     .write_kvp(

crates/collab_ui/src/chat_panel/message_editor.rs 🔗

@@ -454,8 +454,7 @@ impl MessageEditor {
         mut cx: AsyncWindowContext,
     ) {
         let (buffer, ranges) = cx
-            .background_executor()
-            .spawn(async move {
+            .background_spawn(async move {
                 let ranges = MENTIONS_SEARCH.search(&buffer, None).await;
                 (buffer, ranges)
             })

crates/collab_ui/src/collab_panel.rs 🔗

@@ -319,8 +319,7 @@ impl CollabPanel {
         mut cx: AsyncWindowContext,
     ) -> anyhow::Result<Entity<Self>> {
         let serialized_panel = cx
-            .background_executor()
-            .spawn(async move { KEY_VALUE_STORE.read_kvp(COLLABORATION_PANEL_KEY) })
+            .background_spawn(async move { KEY_VALUE_STORE.read_kvp(COLLABORATION_PANEL_KEY) })
             .await
             .map_err(|_| anyhow::anyhow!("Failed to read collaboration panel from key value store"))
             .log_err()
@@ -351,7 +350,7 @@ impl CollabPanel {
     fn serialize(&mut self, cx: &mut Context<Self>) {
         let width = self.width;
         let collapsed_channels = self.collapsed_channels.clone();
-        self.pending_serialization = cx.background_executor().spawn(
+        self.pending_serialization = cx.background_spawn(
             async move {
                 KEY_VALUE_STORE
                     .write_kvp(

crates/collab_ui/src/notification_panel.rs 🔗

@@ -183,8 +183,7 @@ impl NotificationPanel {
     ) -> Task<Result<Entity<Self>>> {
         cx.spawn(|mut cx| async move {
             let serialized_panel = if let Some(panel) = cx
-                .background_executor()
-                .spawn(async move { KEY_VALUE_STORE.read_kvp(NOTIFICATION_PANEL_KEY) })
+                .background_spawn(async move { KEY_VALUE_STORE.read_kvp(NOTIFICATION_PANEL_KEY) })
                 .await
                 .log_err()
                 .flatten()
@@ -209,7 +208,7 @@ impl NotificationPanel {
 
     fn serialize(&mut self, cx: &mut Context<Self>) {
         let width = self.width;
-        self.pending_serialization = cx.background_executor().spawn(
+        self.pending_serialization = cx.background_spawn(
             async move {
                 KEY_VALUE_STORE
                     .write_kvp(

crates/command_palette/src/command_palette.rs 🔗

@@ -281,7 +281,7 @@ impl PickerDelegate for CommandPaletteDelegate {
             query = alias.to_string();
         }
         let (mut tx, mut rx) = postage::dispatch::channel(1);
-        let task = cx.background_executor().spawn({
+        let task = cx.background_spawn({
             let mut commands = self.all_commands.clone();
             let hit_counts = cx.global::<HitCounts>().clone();
             let executor = cx.background_executor().clone();

crates/context_server/src/client.rs 🔗

@@ -1,7 +1,7 @@
 use anyhow::{anyhow, Context as _, Result};
 use collections::HashMap;
 use futures::{channel::oneshot, io::BufWriter, select, AsyncRead, AsyncWrite, FutureExt};
-use gpui::{AsyncApp, BackgroundExecutor, Task};
+use gpui::{AppContext as _, AsyncApp, BackgroundExecutor, Task};
 use parking_lot::Mutex;
 use postage::barrier;
 use serde::{de::DeserializeOwned, Deserialize, Serialize};
@@ -192,7 +192,7 @@ impl Client {
             let (stdout, stderr) = futures::join!(stdout_input_task, stderr_input_task);
             stdout.or(stderr)
         });
-        let output_task = cx.background_executor().spawn({
+        let output_task = cx.background_spawn({
             Self::handle_output(
                 stdin,
                 outbound_rx,

crates/copilot/src/copilot.rs 🔗

@@ -234,8 +234,7 @@ impl RegisteredBuffer {
                 let new_snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot()).ok()?;
 
                 let content_changes = cx
-                    .background_executor()
-                    .spawn({
+                    .background_spawn({
                         let new_snapshot = new_snapshot.clone();
                         async move {
                             new_snapshot
@@ -588,8 +587,7 @@ impl Copilot {
                 }
             };
 
-            cx.background_executor()
-                .spawn(task.map_err(|err| anyhow!("{:?}", err)))
+            cx.background_spawn(task.map_err(|err| anyhow!("{:?}", err)))
         } else {
             // If we're downloading, wait until download is finished
             // If we're in a stuck state, display to the user
@@ -601,7 +599,7 @@ impl Copilot {
         self.update_sign_in_status(request::SignInStatus::NotSignedIn, cx);
         if let CopilotServer::Running(RunningCopilotServer { lsp: server, .. }) = &self.server {
             let server = server.clone();
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 server
                     .request::<request::SignOut>(request::SignOutParams {})
                     .await?;
@@ -631,7 +629,7 @@ impl Copilot {
 
         cx.notify();
 
-        cx.background_executor().spawn(start_task)
+        cx.background_spawn(start_task)
     }
 
     pub fn language_server(&self) -> Option<&Arc<LanguageServer>> {
@@ -813,7 +811,7 @@ impl Copilot {
                 .request::<request::NotifyAccepted>(request::NotifyAcceptedParams {
                     uuid: completion.uuid.clone(),
                 });
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             request.await?;
             Ok(())
         })
@@ -837,7 +835,7 @@ impl Copilot {
                         .map(|completion| completion.uuid.clone())
                         .collect(),
                 });
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             request.await?;
             Ok(())
         })
@@ -884,7 +882,7 @@ impl Copilot {
             .map(|file| file.path().to_path_buf())
             .unwrap_or_default();
 
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let (version, snapshot) = snapshot.await?;
             let result = lsp
                 .request::<R>(request::GetCompletionsParams {

crates/db/src/db.rs 🔗

@@ -4,7 +4,7 @@ pub mod query;
 // Re-export
 pub use anyhow;
 use anyhow::Context as _;
-use gpui::App;
+use gpui::{App, AppContext};
 pub use indoc::indoc;
 pub use paths::database_dir;
 pub use smol;
@@ -192,8 +192,7 @@ pub fn write_and_log<F>(cx: &App, db_write: impl FnOnce() -> F + Send + 'static)
 where
     F: Future<Output = anyhow::Result<()>> + Send,
 {
-    cx.background_executor()
-        .spawn(async move { db_write().await.log_err() })
+    cx.background_spawn(async move { db_write().await.log_err() })
         .detach()
 }
 

crates/editor/src/display_map/wrap_map.rs 🔗

@@ -171,7 +171,7 @@ impl WrapMap {
 
             let text_system = cx.text_system().clone();
             let (font, font_size) = self.font_with_size.clone();
-            let task = cx.background_executor().spawn(async move {
+            let task = cx.background_spawn(async move {
                 let mut line_wrapper = text_system.line_wrapper(font, font_size);
                 let tab_snapshot = new_snapshot.tab_snapshot.clone();
                 let range = TabPoint::zero()..tab_snapshot.max_point();
@@ -255,7 +255,7 @@ impl WrapMap {
                 let mut snapshot = self.snapshot.clone();
                 let text_system = cx.text_system().clone();
                 let (font, font_size) = self.font_with_size.clone();
-                let update_task = cx.background_executor().spawn(async move {
+                let update_task = cx.background_spawn(async move {
                     let mut edits = Patch::default();
                     let mut line_wrapper = text_system.line_wrapper(font, font_size);
                     for (tab_snapshot, tab_edits) in pending_edits {

crates/editor/src/editor.rs 🔗

@@ -4798,7 +4798,7 @@ impl Editor {
             let Some(matches_task) = editor
                 .read_with(&mut cx, |editor, cx| {
                     let buffer = editor.buffer().read(cx).snapshot(cx);
-                    cx.background_executor().spawn(async move {
+                    cx.background_spawn(async move {
                         let mut ranges = Vec::new();
                         let buffer_ranges =
                             vec![buffer.anchor_before(0)..buffer.anchor_after(buffer.len())];
@@ -10221,13 +10221,12 @@ impl Editor {
                 return;
             }
             let new_rows =
-                cx.background_executor()
-                    .spawn({
-                        let snapshot = display_snapshot.clone();
-                        async move {
-                            Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
-                        }
-                    })
+                cx.background_spawn({
+                    let snapshot = display_snapshot.clone();
+                    async move {
+                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
+                    }
+                })
                     .await;
 
             let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
@@ -10989,7 +10988,7 @@ impl Editor {
                 HoverLink::InlayHint(lsp_location, server_id) => {
                     let computation =
                         self.compute_target_location(lsp_location, server_id, window, cx);
-                    cx.background_executor().spawn(async move {
+                    cx.background_spawn(async move {
                         let location = computation.await?;
                         Ok(TargetTaskResult::Location(location))
                     })
@@ -15587,7 +15586,7 @@ fn snippet_completions(
     let scope = language.map(|language| language.default_scope());
     let executor = cx.background_executor().clone();
 
-    cx.background_executor().spawn(async move {
+    cx.background_spawn(async move {
         let classifier = CharClassifier::new(scope).for_completion(true);
         let mut last_word = chars
             .chars()
@@ -15717,7 +15716,7 @@ impl CompletionProvider for Entity<Project> {
         self.update(cx, |project, cx| {
             let snippets = snippet_completions(project, buffer, buffer_position, cx);
             let project_completions = project.completions(buffer, buffer_position, options, cx);
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 let mut completions = project_completions.await?;
                 let snippets_completions = snippets.await?;
                 completions.extend(snippets_completions);

crates/editor/src/element.rs 🔗

@@ -5264,8 +5264,7 @@ impl EditorElement {
                 Some(cx.spawn_in(window, |editor, mut cx| async move {
                     let scrollbar_size = scrollbar_layout.hitbox.size;
                     let scrollbar_markers = cx
-                        .background_executor()
-                        .spawn(async move {
+                        .background_spawn(async move {
                             let max_point = snapshot.display_snapshot.buffer_snapshot.max_point();
                             let mut marker_quads = Vec::new();
                             if scrollbar_settings.git_diff {

crates/editor/src/git/blame.rs 🔗

@@ -4,7 +4,7 @@ use git::{
     blame::{Blame, BlameEntry},
     parse_git_remote_url, GitHostingProvider, GitHostingProviderRegistry, Oid,
 };
-use gpui::{App, Context, Entity, Subscription, Task};
+use gpui::{App, AppContext as _, Context, Entity, Subscription, Task};
 use http_client::HttpClient;
 use language::{markdown, Bias, Buffer, BufferSnapshot, Edit, LanguageRegistry, ParsedMarkdown};
 use multi_buffer::RowInfo;
@@ -360,8 +360,7 @@ impl GitBlame {
 
         self.task = cx.spawn(|this, mut cx| async move {
             let result = cx
-                .background_executor()
-                .spawn({
+                .background_spawn({
                     let snapshot = snapshot.clone();
                     async move {
                         let Some(Blame {
@@ -549,7 +548,7 @@ async fn parse_markdown(text: &str, language_registry: &Arc<LanguageRegistry>) -
 #[cfg(test)]
 mod tests {
     use super::*;
-    use gpui::{AppContext as _, Context};
+    use gpui::Context;
     use language::{Point, Rope};
     use project::FakeFs;
     use rand::prelude::*;

crates/editor/src/hunk_diff.rs 🔗

@@ -1,7 +1,7 @@
 use collections::{HashMap, HashSet};
 use git::diff::DiffHunkStatus;
 use gpui::{
-    Action, AppContext, Corner, CursorStyle, Focusable as _, Hsla, Model, MouseButton,
+    Action, AppContext as _, Corner, CursorStyle, Focusable as _, Hsla, Model, MouseButton,
     Subscription, Task,
 };
 use language::{Buffer, BufferId, Point};
@@ -372,7 +372,7 @@ impl Editor {
 
         self.diff_map
             .hunk_update_tasks
-            .insert(None, cx.background_executor().spawn(new_toggle_task));
+            .insert(None, cx.background_spawn(new_toggle_task));
     }
 
     pub(super) fn expand_diff_hunk(
@@ -1089,10 +1089,9 @@ impl Editor {
                 .ok();
         });
 
-        diff_map.hunk_update_tasks.insert(
-            Some(buffer_id),
-            cx.background_executor().spawn(new_sync_task),
-        );
+        diff_map
+            .hunk_update_tasks
+            .insert(Some(buffer_id), cx.background_spawn(new_sync_task));
     }
 
     fn go_to_subsequent_hunk(

crates/editor/src/indent_guides.rs 🔗

@@ -1,7 +1,7 @@
 use std::{ops::Range, time::Duration};
 
 use collections::HashSet;
-use gpui::{App, Context, Task, Window};
+use gpui::{App, AppContext as _, Context, Task, Window};
 use language::language_settings::language_settings;
 use multi_buffer::{IndentGuide, MultiBufferRow};
 use text::{LineIndent, Point};
@@ -102,9 +102,7 @@ impl Editor {
 
             let snapshot = snapshot.clone();
 
-            let task = cx
-                .background_executor()
-                .spawn(resolve_indented_range(snapshot, cursor_row));
+            let task = cx.background_spawn(resolve_indented_range(snapshot, cursor_row));
 
             // Try to resolve the indent in a short amount of time, otherwise move it to a background task.
             match cx
@@ -115,7 +113,7 @@ impl Editor {
                 Err(future) => {
                     state.pending_refresh =
                         Some(cx.spawn_in(window, |editor, mut cx| async move {
-                            let result = cx.background_executor().spawn(future).await;
+                            let result = cx.background_spawn(future).await;
                             editor
                                 .update(&mut cx, |editor, _| {
                                     editor.active_indent_guides_state.active_indent_range = result;

crates/editor/src/inlay_hint_cache.rs 🔗

@@ -19,7 +19,7 @@ use crate::{
 use anyhow::Context as _;
 use clock::Global;
 use futures::future;
-use gpui::{AsyncApp, Context, Entity, Task, Window};
+use gpui::{AppContext as _, AsyncApp, Context, Entity, Task, Window};
 use language::{language_settings::InlayHintKind, Buffer, BufferSnapshot};
 use parking_lot::RwLock;
 use project::{InlayHint, ResolveState};
@@ -996,19 +996,17 @@ fn fetch_and_update_hints(
 
         let background_task_buffer_snapshot = buffer_snapshot.clone();
         let background_fetch_range = fetch_range.clone();
-        let new_update = cx
-            .background_executor()
-            .spawn(async move {
-                calculate_hint_updates(
-                    query.excerpt_id,
-                    invalidate,
-                    background_fetch_range,
-                    new_hints,
-                    &background_task_buffer_snapshot,
-                    cached_excerpt_hints,
-                    &visible_hints,
-                )
-            })
+        let new_update = cx.background_spawn(async move {
+            calculate_hint_updates(
+                query.excerpt_id,
+                invalidate,
+                background_fetch_range,
+                new_hints,
+                &background_task_buffer_snapshot,
+                cached_excerpt_hints,
+                &visible_hints,
+            )
+        })
             .await;
         if let Some(new_update) = new_update {
             log::debug!(

crates/editor/src/items.rs 🔗

@@ -1225,28 +1225,27 @@ impl SerializableItem for Editor {
         let snapshot = buffer.read(cx).snapshot();
 
         Some(cx.spawn_in(window, |_this, cx| async move {
-            cx.background_executor()
-                .spawn(async move {
-                    let (contents, language) = if serialize_dirty_buffers && is_dirty {
-                        let contents = snapshot.text();
-                        let language = snapshot.language().map(|lang| lang.name().to_string());
-                        (Some(contents), language)
-                    } else {
-                        (None, None)
-                    };
+            cx.background_spawn(async move {
+                let (contents, language) = if serialize_dirty_buffers && is_dirty {
+                    let contents = snapshot.text();
+                    let language = snapshot.language().map(|lang| lang.name().to_string());
+                    (Some(contents), language)
+                } else {
+                    (None, None)
+                };
 
-                    let editor = SerializedEditor {
-                        abs_path,
-                        contents,
-                        language,
-                        mtime,
-                    };
-                    DB.save_serialized_editor(item_id, workspace_id, editor)
-                        .await
-                        .context("failed to save serialized editor")
-                })
-                .await
-                .context("failed to save contents of buffer")?;
+                let editor = SerializedEditor {
+                    abs_path,
+                    contents,
+                    language,
+                    mtime,
+                };
+                DB.save_serialized_editor(item_id, workspace_id, editor)
+                    .await
+                    .context("failed to save serialized editor")
+            })
+            .await
+            .context("failed to save contents of buffer")?;
 
             Ok(())
         }))
@@ -1540,7 +1539,7 @@ impl SearchableItem for Editor {
                 ranges.iter().cloned().collect::<Vec<_>>()
             });
 
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let mut ranges = Vec::new();
 
             let search_within_ranges = if search_within_ranges.is_empty() {

crates/editor/src/tasks.rs 🔗

@@ -1,6 +1,6 @@
 use crate::Editor;
 
-use gpui::{App, Task as AsyncTask, Window};
+use gpui::{App, AppContext as _, Task as AsyncTask, Window};
 use project::Location;
 use task::{TaskContext, TaskVariables, VariableName};
 use text::{ToOffset, ToPoint};
@@ -88,7 +88,6 @@ pub fn task_context(
     };
     editor.update(cx, |editor, cx| {
         let context_task = task_context_with_editor(editor, window, cx);
-        cx.background_executor()
-            .spawn(async move { context_task.await.unwrap_or_default() })
+        cx.background_spawn(async move { context_task.await.unwrap_or_default() })
     })
 }

crates/extension_host/src/extension_host.rs 🔗

@@ -324,10 +324,7 @@ impl ExtensionStore {
                 load_initial_extensions.await;
 
                 let mut index_changed = false;
-                let mut debounce_timer = cx
-                    .background_executor()
-                    .spawn(futures::future::pending())
-                    .fuse();
+                let mut debounce_timer = cx.background_spawn(futures::future::pending()).fuse();
                 loop {
                     select_biased! {
                         _ = debounce_timer => {
@@ -370,7 +367,7 @@ impl ExtensionStore {
         // Watch the installed extensions directory for changes. Whenever changes are
         // detected, rebuild the extension index, and load/unload any extensions that
         // have been added, removed, or modified.
-        this.tasks.push(cx.background_executor().spawn({
+        this.tasks.push(cx.background_spawn({
             let fs = this.fs.clone();
             let reload_tx = this.reload_tx.clone();
             let installed_dir = this.installed_dir.clone();
@@ -886,20 +883,19 @@ impl ExtensionStore {
                 }
             });
 
-            cx.background_executor()
-                .spawn({
-                    let extension_source_path = extension_source_path.clone();
-                    async move {
-                        builder
-                            .compile_extension(
-                                &extension_source_path,
-                                &mut extension_manifest,
-                                CompileExtensionOptions { release: false },
-                            )
-                            .await
-                    }
-                })
-                .await?;
+            cx.background_spawn({
+                let extension_source_path = extension_source_path.clone();
+                async move {
+                    builder
+                        .compile_extension(
+                            &extension_source_path,
+                            &mut extension_manifest,
+                            CompileExtensionOptions { release: false },
+                        )
+                        .await
+                }
+            })
+            .await?;
 
             let output_path = &extensions_dir.join(extension_id.as_ref());
             if let Some(metadata) = fs.metadata(output_path).await? {
@@ -937,7 +933,7 @@ impl ExtensionStore {
         };
 
         cx.notify();
-        let compile = cx.background_executor().spawn(async move {
+        let compile = cx.background_spawn(async move {
             let mut manifest = ExtensionManifest::load(fs, &path).await?;
             builder
                 .compile_extension(
@@ -1192,35 +1188,33 @@ impl ExtensionStore {
         cx.emit(Event::ExtensionsUpdated);
 
         cx.spawn(|this, mut cx| async move {
-            cx.background_executor()
-                .spawn({
-                    let fs = fs.clone();
-                    async move {
-                        for theme_path in themes_to_add.into_iter() {
-                            proxy
-                                .load_user_theme(theme_path, fs.clone())
-                                .await
-                                .log_err();
-                        }
+            cx.background_spawn({
+                let fs = fs.clone();
+                async move {
+                    for theme_path in themes_to_add.into_iter() {
+                        proxy
+                            .load_user_theme(theme_path, fs.clone())
+                            .await
+                            .log_err();
+                    }
 
-                        for (icon_theme_path, icons_root_path) in icon_themes_to_add.into_iter() {
+                    for (icon_theme_path, icons_root_path) in icon_themes_to_add.into_iter() {
+                        proxy
+                            .load_icon_theme(icon_theme_path, icons_root_path, fs.clone())
+                            .await
+                            .log_err();
+                    }
+
+                    for snippets_path in &snippets_to_add {
+                        if let Some(snippets_contents) = fs.load(snippets_path).await.log_err() {
                             proxy
-                                .load_icon_theme(icon_theme_path, icons_root_path, fs.clone())
-                                .await
+                                .register_snippet(snippets_path, &snippets_contents)
                                 .log_err();
                         }
-
-                        for snippets_path in &snippets_to_add {
-                            if let Some(snippets_contents) = fs.load(snippets_path).await.log_err()
-                            {
-                                proxy
-                                    .register_snippet(snippets_path, &snippets_contents)
-                                    .log_err();
-                            }
-                        }
                     }
-                })
-                .await;
+                }
+            })
+            .await;
 
             let mut wasm_extensions = Vec::new();
             for extension in extension_entries {
@@ -1304,7 +1298,7 @@ impl ExtensionStore {
         let extensions_dir = self.installed_dir.clone();
         let index_path = self.index_path.clone();
         let proxy = self.proxy.clone();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let start_time = Instant::now();
             let mut index = ExtensionIndex::default();
 
@@ -1494,7 +1488,7 @@ impl ExtensionStore {
             return Task::ready(Err(anyhow!("extension no longer installed")));
         };
         let fs = self.fs.clone();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             const EXTENSION_TOML: &str = "extension.toml";
             const EXTENSION_WASM: &str = "extension.wasm";
             const CONFIG_TOML: &str = "config.toml";

crates/feedback/src/system_specs.rs 🔗

@@ -1,5 +1,5 @@
 use client::telemetry;
-use gpui::{App, Task, Window};
+use gpui::{App, AppContext as _, Task, Window};
 use human_bytes::human_bytes;
 use release_channel::{AppCommitSha, AppVersion, ReleaseChannel};
 use serde::Serialize;
@@ -44,7 +44,7 @@ impl SystemSpecs {
             None
         };
 
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let os_version = telemetry::os_version();
             SystemSpecs {
                 app_version,

crates/file_finder/src/file_finder.rs 🔗

@@ -127,7 +127,7 @@ impl FileFinder {
                 let abs_path = abs_path?;
                 if project.is_local() {
                     let fs = fs.clone();
-                    Some(cx.background_executor().spawn(async move {
+                    Some(cx.background_spawn(async move {
                         if fs.is_file(&abs_path).await {
                             Some(FoundPath::new(project_path, Some(abs_path)))
                         } else {

crates/git_ui/src/git_panel.rs 🔗

@@ -337,7 +337,7 @@ impl GitPanel {
 
     fn serialize(&mut self, cx: &mut Context<Self>) {
         let width = self.width;
-        self.pending_serialization = cx.background_executor().spawn(
+        self.pending_serialization = cx.background_spawn(
             async move {
                 KEY_VALUE_STORE
                     .write_kvp(
@@ -1055,8 +1055,7 @@ impl GitPanel {
         let task = if self.has_staged_changes() {
             // Repository serializes all git operations, so we can just send a commit immediately
             let commit_task = active_repository.read(cx).commit(message.into(), None);
-            cx.background_executor()
-                .spawn(async move { commit_task.await? })
+            cx.background_spawn(async move { commit_task.await? })
         } else {
             let changed_files = self
                 .entries

crates/git_ui/src/project_diff.rs 🔗

@@ -7,7 +7,7 @@ use editor::{scroll::Autoscroll, Editor, EditorEvent, ToPoint};
 use feature_flags::FeatureFlagViewExt;
 use futures::StreamExt;
 use gpui::{
-    actions, AnyElement, AnyView, App, AppContext, AsyncWindowContext, Entity, EventEmitter,
+    actions, AnyElement, AnyView, App, AppContext as _, AsyncWindowContext, Entity, EventEmitter,
     FocusHandle, Focusable, Render, Subscription, Task, WeakEntity,
 };
 use language::{Anchor, Buffer, Capability, OffsetRangeExt, Point};

crates/git_ui/src/repository_selector.rs 🔗

@@ -177,8 +177,7 @@ impl PickerDelegate for RepositorySelectorDelegate {
 
         cx.spawn_in(window, |this, mut cx| async move {
             let filtered_repositories = cx
-                .background_executor()
-                .spawn(async move {
+                .background_spawn(async move {
                     if query.is_empty() {
                         all_repositories
                     } else {

crates/image_viewer/src/image_viewer.rs 🔗

@@ -252,7 +252,7 @@ impl SerializableItem for ImageView {
         let workspace_id = workspace.database_id()?;
         let image_path = self.image_item.read(cx).file.as_local()?.abs_path(cx);
 
-        Some(cx.background_executor().spawn({
+        Some(cx.background_spawn({
             async move {
                 IMAGE_VIEWER
                     .save_image_path(item_id, workspace_id, image_path)

crates/journal/src/journal.rs 🔗

@@ -2,7 +2,7 @@ use anyhow::Result;
 use chrono::{Datelike, Local, NaiveTime, Timelike};
 use editor::scroll::Autoscroll;
 use editor::Editor;
-use gpui::{actions, App, Context, Window};
+use gpui::{actions, App, AppContext as _, Context, Window};
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
 use settings::{Settings, SettingsSources};
@@ -87,7 +87,7 @@ pub fn new_journal_entry(workspace: &Workspace, window: &mut Window, cx: &mut Ap
     let now = now.time();
     let entry_heading = heading_entry(now, &settings.hour_format);
 
-    let create_entry = cx.background_executor().spawn(async move {
+    let create_entry = cx.background_spawn(async move {
         std::fs::create_dir_all(month_dir)?;
         OpenOptions::new()
             .create(true)

crates/language/src/buffer.rs 🔗

@@ -940,7 +940,7 @@ impl Buffer {
         }
 
         let text_operations = self.text.operations().clone();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let since = since.unwrap_or_default();
             operations.extend(
                 text_operations
@@ -1135,7 +1135,7 @@ impl Buffer {
         let old_snapshot = self.text.snapshot();
         let mut branch_buffer = self.text.branch();
         let mut syntax_snapshot = self.syntax_map.lock().snapshot();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             if !edits.is_empty() {
                 if let Some(language) = language.clone() {
                     syntax_snapshot.reparse(&old_snapshot, registry.clone(), language);
@@ -1499,7 +1499,7 @@ impl Buffer {
         let mut syntax_snapshot = syntax_map.snapshot();
         drop(syntax_map);
 
-        let parse_task = cx.background_executor().spawn({
+        let parse_task = cx.background_spawn({
             let language = language.clone();
             let language_registry = language_registry.clone();
             async move {
@@ -1578,7 +1578,7 @@ impl Buffer {
 
     fn request_autoindent(&mut self, cx: &mut Context<Self>) {
         if let Some(indent_sizes) = self.compute_autoindents() {
-            let indent_sizes = cx.background_executor().spawn(indent_sizes);
+            let indent_sizes = cx.background_spawn(indent_sizes);
             match cx
                 .background_executor()
                 .block_with_timeout(Duration::from_micros(500), indent_sizes)
@@ -1907,7 +1907,7 @@ impl Buffer {
         let old_text = self.as_rope().clone();
         let line_ending = self.line_ending();
         let base_version = self.version();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let ranges = trailing_whitespace_ranges(&old_text);
             let empty = Arc::<str>::from("");
             Diff {

crates/language/src/language_registry.rs 🔗

@@ -940,6 +940,8 @@ impl LanguageRegistry {
         binary: lsp::LanguageServerBinary,
         cx: gpui::AsyncApp,
     ) -> Option<lsp::LanguageServer> {
+        use gpui::AppContext as _;
+
         let mut state = self.state.write();
         let fake_entry = state.fake_server_entries.get_mut(&name)?;
         let (server, mut fake_server) = lsp::FakeLanguageServer::new(
@@ -956,17 +958,16 @@ impl LanguageRegistry {
         }
 
         let tx = fake_entry.tx.clone();
-        cx.background_executor()
-            .spawn(async move {
-                if fake_server
-                    .try_receive_notification::<lsp::notification::Initialized>()
-                    .await
-                    .is_some()
-                {
-                    tx.unbounded_send(fake_server.clone()).ok();
-                }
-            })
-            .detach();
+        cx.background_spawn(async move {
+            if fake_server
+                .try_receive_notification::<lsp::notification::Initialized>()
+                .await
+                .is_some()
+            {
+                tx.unbounded_send(fake_server.clone()).ok();
+            }
+        })
+        .detach();
 
         Some(server)
     }

crates/language_model/src/request.rs 🔗

@@ -3,7 +3,9 @@ use std::io::{Cursor, Write};
 use crate::role::Role;
 use crate::LanguageModelToolUse;
 use base64::write::EncoderWriter;
-use gpui::{point, size, App, DevicePixels, Image, ObjectFit, RenderImage, Size, Task};
+use gpui::{
+    point, size, App, AppContext as _, DevicePixels, Image, ObjectFit, RenderImage, Size, Task,
+};
 use image::{codecs::png::PngEncoder, imageops::resize, DynamicImage, ImageDecoder};
 use serde::{Deserialize, Serialize};
 use ui::{px, SharedString};
@@ -30,7 +32,7 @@ const ANTHROPIC_SIZE_LIMT: f32 = 1568.;
 
 impl LanguageModelImage {
     pub fn from_image(data: Image, cx: &mut App) -> Task<Option<Self>> {
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             match data.format() {
                 gpui::ImageFormat::Png
                 | gpui::ImageFormat::Jpeg

crates/language_model_selector/src/language_model_selector.rs 🔗

@@ -228,8 +228,7 @@ impl PickerDelegate for LanguageModelPickerDelegate {
 
         cx.spawn_in(window, |this, mut cx| async move {
             let filtered_models = cx
-                .background_executor()
-                .spawn(async move {
+                .background_spawn(async move {
                     let displayed_models = if configured_providers.is_empty() {
                         all_models
                     } else {

crates/language_models/src/provider/anthropic.rs 🔗

@@ -252,54 +252,53 @@ pub fn count_anthropic_tokens(
     request: LanguageModelRequest,
     cx: &App,
 ) -> BoxFuture<'static, Result<usize>> {
-    cx.background_executor()
-        .spawn(async move {
-            let messages = request.messages;
-            let mut tokens_from_images = 0;
-            let mut string_messages = Vec::with_capacity(messages.len());
+    cx.background_spawn(async move {
+        let messages = request.messages;
+        let mut tokens_from_images = 0;
+        let mut string_messages = Vec::with_capacity(messages.len());
 
-            for message in messages {
-                use language_model::MessageContent;
+        for message in messages {
+            use language_model::MessageContent;
 
-                let mut string_contents = String::new();
+            let mut string_contents = String::new();
 
-                for content in message.content {
-                    match content {
-                        MessageContent::Text(text) => {
-                            string_contents.push_str(&text);
-                        }
-                        MessageContent::Image(image) => {
-                            tokens_from_images += image.estimate_tokens();
-                        }
-                        MessageContent::ToolUse(_tool_use) => {
-                            // TODO: Estimate token usage from tool uses.
-                        }
-                        MessageContent::ToolResult(tool_result) => {
-                            string_contents.push_str(&tool_result.content);
-                        }
+            for content in message.content {
+                match content {
+                    MessageContent::Text(text) => {
+                        string_contents.push_str(&text);
+                    }
+                    MessageContent::Image(image) => {
+                        tokens_from_images += image.estimate_tokens();
+                    }
+                    MessageContent::ToolUse(_tool_use) => {
+                        // TODO: Estimate token usage from tool uses.
+                    }
+                    MessageContent::ToolResult(tool_result) => {
+                        string_contents.push_str(&tool_result.content);
                     }
                 }
+            }
 
-                if !string_contents.is_empty() {
-                    string_messages.push(tiktoken_rs::ChatCompletionRequestMessage {
-                        role: match message.role {
-                            Role::User => "user".into(),
-                            Role::Assistant => "assistant".into(),
-                            Role::System => "system".into(),
-                        },
-                        content: Some(string_contents),
-                        name: None,
-                        function_call: None,
-                    });
-                }
+            if !string_contents.is_empty() {
+                string_messages.push(tiktoken_rs::ChatCompletionRequestMessage {
+                    role: match message.role {
+                        Role::User => "user".into(),
+                        Role::Assistant => "assistant".into(),
+                        Role::System => "system".into(),
+                    },
+                    content: Some(string_contents),
+                    name: None,
+                    function_call: None,
+                });
             }
+        }
 
-            // Tiktoken doesn't yet support these models, so we manually use the
-            // same tokenizer as GPT-4.
-            tiktoken_rs::num_tokens_from_messages("gpt-4", &string_messages)
-                .map(|tokens| tokens + tokens_from_images)
-        })
-        .boxed()
+        // Tiktoken doesn't yet support these models, so we manually use the
+        // same tokenizer as GPT-4.
+        tiktoken_rs::num_tokens_from_messages("gpt-4", &string_messages)
+            .map(|tokens| tokens + tokens_from_images)
+    })
+    .boxed()
 }
 
 impl AnthropicModel {

crates/language_models/src/provider/deepseek.rs 🔗

@@ -3,7 +3,8 @@ use collections::BTreeMap;
 use editor::{Editor, EditorElement, EditorStyle};
 use futures::{future::BoxFuture, stream::BoxStream, FutureExt, StreamExt};
 use gpui::{
-    AnyView, AppContext, AsyncApp, Entity, FontStyle, Subscription, Task, TextStyle, WhiteSpace,
+    AnyView, AppContext as _, AsyncApp, Entity, FontStyle, Subscription, Task, TextStyle,
+    WhiteSpace,
 };
 use http_client::HttpClient;
 use language_model::{
@@ -269,26 +270,25 @@ impl LanguageModel for DeepSeekLanguageModel {
         request: LanguageModelRequest,
         cx: &App,
     ) -> BoxFuture<'static, Result<usize>> {
-        cx.background_executor()
-            .spawn(async move {
-                let messages = request
-                    .messages
-                    .into_iter()
-                    .map(|message| tiktoken_rs::ChatCompletionRequestMessage {
-                        role: match message.role {
-                            Role::User => "user".into(),
-                            Role::Assistant => "assistant".into(),
-                            Role::System => "system".into(),
-                        },
-                        content: Some(message.string_contents()),
-                        name: None,
-                        function_call: None,
-                    })
-                    .collect::<Vec<_>>();
+        cx.background_spawn(async move {
+            let messages = request
+                .messages
+                .into_iter()
+                .map(|message| tiktoken_rs::ChatCompletionRequestMessage {
+                    role: match message.role {
+                        Role::User => "user".into(),
+                        Role::Assistant => "assistant".into(),
+                        Role::System => "system".into(),
+                    },
+                    content: Some(message.string_contents()),
+                    name: None,
+                    function_call: None,
+                })
+                .collect::<Vec<_>>();
 
-                tiktoken_rs::num_tokens_from_messages("gpt-4", &messages)
-            })
-            .boxed()
+            tiktoken_rs::num_tokens_from_messages("gpt-4", &messages)
+        })
+        .boxed()
     }
 
     fn stream_completion(

crates/language_models/src/provider/google.rs 🔗

@@ -330,28 +330,27 @@ pub fn count_google_tokens(
 ) -> BoxFuture<'static, Result<usize>> {
     // We couldn't use the GoogleLanguageModelProvider to count tokens because the github copilot doesn't have the access to google_ai directly.
     // So we have to use tokenizer from tiktoken_rs to count tokens.
-    cx.background_executor()
-        .spawn(async move {
-            let messages = request
-                .messages
-                .into_iter()
-                .map(|message| tiktoken_rs::ChatCompletionRequestMessage {
-                    role: match message.role {
-                        Role::User => "user".into(),
-                        Role::Assistant => "assistant".into(),
-                        Role::System => "system".into(),
-                    },
-                    content: Some(message.string_contents()),
-                    name: None,
-                    function_call: None,
-                })
-                .collect::<Vec<_>>();
+    cx.background_spawn(async move {
+        let messages = request
+            .messages
+            .into_iter()
+            .map(|message| tiktoken_rs::ChatCompletionRequestMessage {
+                role: match message.role {
+                    Role::User => "user".into(),
+                    Role::Assistant => "assistant".into(),
+                    Role::System => "system".into(),
+                },
+                content: Some(message.string_contents()),
+                name: None,
+                function_call: None,
+            })
+            .collect::<Vec<_>>();
 
-            // Tiktoken doesn't yet support these models, so we manually use the
-            // same tokenizer as GPT-4.
-            tiktoken_rs::num_tokens_from_messages("gpt-4", &messages)
-        })
-        .boxed()
+        // Tiktoken doesn't yet support these models, so we manually use the
+        // same tokenizer as GPT-4.
+        tiktoken_rs::num_tokens_from_messages("gpt-4", &messages)
+    })
+    .boxed()
 }
 
 struct ConfigurationView {

crates/language_models/src/provider/mistral.rs 🔗

@@ -281,26 +281,25 @@ impl LanguageModel for MistralLanguageModel {
         request: LanguageModelRequest,
         cx: &App,
     ) -> BoxFuture<'static, Result<usize>> {
-        cx.background_executor()
-            .spawn(async move {
-                let messages = request
-                    .messages
-                    .into_iter()
-                    .map(|message| tiktoken_rs::ChatCompletionRequestMessage {
-                        role: match message.role {
-                            Role::User => "user".into(),
-                            Role::Assistant => "assistant".into(),
-                            Role::System => "system".into(),
-                        },
-                        content: Some(message.string_contents()),
-                        name: None,
-                        function_call: None,
-                    })
-                    .collect::<Vec<_>>();
+        cx.background_spawn(async move {
+            let messages = request
+                .messages
+                .into_iter()
+                .map(|message| tiktoken_rs::ChatCompletionRequestMessage {
+                    role: match message.role {
+                        Role::User => "user".into(),
+                        Role::Assistant => "assistant".into(),
+                        Role::System => "system".into(),
+                    },
+                    content: Some(message.string_contents()),
+                    name: None,
+                    function_call: None,
+                })
+                .collect::<Vec<_>>();
 
-                tiktoken_rs::num_tokens_from_messages("gpt-4", &messages)
-            })
-            .boxed()
+            tiktoken_rs::num_tokens_from_messages("gpt-4", &messages)
+        })
+        .boxed()
     }
 
     fn stream_completion(

crates/language_models/src/provider/open_ai.rs 🔗

@@ -343,34 +343,31 @@ pub fn count_open_ai_tokens(
     model: open_ai::Model,
     cx: &App,
 ) -> BoxFuture<'static, Result<usize>> {
-    cx.background_executor()
-        .spawn(async move {
-            let messages = request
-                .messages
-                .into_iter()
-                .map(|message| tiktoken_rs::ChatCompletionRequestMessage {
-                    role: match message.role {
-                        Role::User => "user".into(),
-                        Role::Assistant => "assistant".into(),
-                        Role::System => "system".into(),
-                    },
-                    content: Some(message.string_contents()),
-                    name: None,
-                    function_call: None,
-                })
-                .collect::<Vec<_>>();
-
-            match model {
-                open_ai::Model::Custom { .. }
-                | open_ai::Model::O1Mini
-                | open_ai::Model::O1
-                | open_ai::Model::O3Mini => {
-                    tiktoken_rs::num_tokens_from_messages("gpt-4", &messages)
-                }
-                _ => tiktoken_rs::num_tokens_from_messages(model.id(), &messages),
-            }
-        })
-        .boxed()
+    cx.background_spawn(async move {
+        let messages = request
+            .messages
+            .into_iter()
+            .map(|message| tiktoken_rs::ChatCompletionRequestMessage {
+                role: match message.role {
+                    Role::User => "user".into(),
+                    Role::Assistant => "assistant".into(),
+                    Role::System => "system".into(),
+                },
+                content: Some(message.string_contents()),
+                name: None,
+                function_call: None,
+            })
+            .collect::<Vec<_>>();
+
+        match model {
+            open_ai::Model::Custom { .. }
+            | open_ai::Model::O1Mini
+            | open_ai::Model::O1
+            | open_ai::Model::O3Mini => tiktoken_rs::num_tokens_from_messages("gpt-4", &messages),
+            _ => tiktoken_rs::num_tokens_from_messages(model.id(), &messages),
+        }
+    })
+    .boxed()
 }
 
 struct ConfigurationView {

crates/livekit_client/examples/test_app.rs 🔗

@@ -302,11 +302,10 @@ impl LivekitWindow {
         if let Some(track) = self.screen_share_track.take() {
             self.screen_share_stream.take();
             let participant = self.room.local_participant();
-            cx.background_executor()
-                .spawn(async move {
-                    participant.unpublish_track(&track.sid()).await.unwrap();
-                })
-                .detach();
+            cx.background_spawn(async move {
+                participant.unpublish_track(&track.sid()).await.unwrap();
+            })
+            .detach();
             cx.notify();
         } else {
             let participant = self.room.local_participant();

crates/livekit_client/src/remote_video_track_view.rs 🔗

@@ -1,7 +1,9 @@
 use crate::track::RemoteVideoTrack;
 use anyhow::Result;
 use futures::StreamExt as _;
-use gpui::{AppContext, Context, Empty, Entity, EventEmitter, IntoElement, Render, Task, Window};
+use gpui::{
+    AppContext as _, Context, Empty, Entity, EventEmitter, IntoElement, Render, Task, Window,
+};
 
 pub struct RemoteVideoTrackView {
     track: RemoteVideoTrack,

crates/lsp/src/lsp.rs 🔗

@@ -6,7 +6,7 @@ pub use lsp_types::*;
 use anyhow::{anyhow, Context as _, Result};
 use collections::HashMap;
 use futures::{channel::oneshot, io::BufWriter, select, AsyncRead, AsyncWrite, Future, FutureExt};
-use gpui::{App, AsyncApp, BackgroundExecutor, SharedString, Task};
+use gpui::{App, AppContext as _, AsyncApp, BackgroundExecutor, SharedString, Task};
 use notification::DidChangeWorkspaceFolders;
 use parking_lot::{Mutex, RwLock};
 use postage::{barrier, prelude::Stream};
@@ -448,7 +448,7 @@ impl LanguageServer {
             let (stdout, stderr) = futures::join!(stdout_input_task, stderr_input_task);
             stdout.or(stderr)
         });
-        let output_task = cx.background_executor().spawn({
+        let output_task = cx.background_spawn({
             Self::handle_output(
                 stdin,
                 outbound_rx,

crates/markdown/src/markdown.rs 🔗

@@ -178,7 +178,7 @@ impl Markdown {
 
         let text = self.source.clone();
         let parse_text_only = self.options.parse_links_only;
-        let parsed = cx.background_executor().spawn(async move {
+        let parsed = cx.background_spawn(async move {
             let text = SharedString::from(text);
             let events = match parse_text_only {
                 true => Arc::from(parse_links_only(text.as_ref())),

crates/markdown_preview/src/markdown_preview_view.rs 🔗

@@ -383,7 +383,7 @@ impl MarkdownPreviewView {
                 (contents, file_location)
             })?;
 
-            let parsing_task = cx.background_executor().spawn(async move {
+            let parsing_task = cx.background_spawn(async move {
                 parse_markdown(&contents, file_location, Some(language_registry)).await
             });
             let contents = parsing_task.await;

crates/multi_buffer/src/multi_buffer.rs 🔗

@@ -13,7 +13,7 @@ use buffer_diff::{
 use clock::ReplicaId;
 use collections::{BTreeMap, Bound, HashMap, HashSet};
 use futures::{channel::mpsc, SinkExt};
-use gpui::{App, Context, Entity, EntityId, EventEmitter, Task};
+use gpui::{App, AppContext as _, Context, Entity, EntityId, EventEmitter, Task};
 use itertools::Itertools;
 use language::{
     language_settings::{language_settings, IndentGuideSettings, LanguageSettings},
@@ -51,9 +51,6 @@ use text::{
 use theme::SyntaxTheme;
 use util::post_inc;
 
-#[cfg(any(test, feature = "test-support"))]
-use gpui::AppContext as _;
-
 const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize];
 
 #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
@@ -1580,20 +1577,19 @@ impl MultiBuffer {
 
             buffer_ids.push(buffer_id);
 
-            cx.background_executor()
-                .spawn({
-                    let mut excerpt_ranges_tx = excerpt_ranges_tx.clone();
-
-                    async move {
-                        let (excerpt_ranges, counts) =
-                            build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
-                        excerpt_ranges_tx
-                            .send((buffer_id, buffer.clone(), ranges, excerpt_ranges, counts))
-                            .await
-                            .ok();
-                    }
-                })
-                .detach()
+            cx.background_spawn({
+                let mut excerpt_ranges_tx = excerpt_ranges_tx.clone();
+
+                async move {
+                    let (excerpt_ranges, counts) =
+                        build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count);
+                    excerpt_ranges_tx
+                        .send((buffer_id, buffer.clone(), ranges, excerpt_ranges, counts))
+                        .await
+                        .ok();
+                }
+            })
+            .detach()
         }
 
         cx.spawn(move |this, mut cx| async move {

crates/outline_panel/src/outline_panel.rs 🔗

@@ -171,7 +171,7 @@ impl SearchState {
                 })
                 .collect(),
             highlight_search_match_tx,
-            _search_match_highlighter: cx.background_executor().spawn(async move {
+            _search_match_highlighter: cx.background_spawn(async move {
                 while let Ok(highlight_arguments) = highlight_search_match_rx.recv().await {
                     let needs_init = highlight_arguments.search_data.get().is_none();
                     let search_data = highlight_arguments.search_data.get_or_init(|| {
@@ -681,8 +681,7 @@ impl OutlinePanel {
         mut cx: AsyncWindowContext,
     ) -> anyhow::Result<Entity<Self>> {
         let serialized_panel = cx
-            .background_executor()
-            .spawn(async move { KEY_VALUE_STORE.read_kvp(OUTLINE_PANEL_KEY) })
+            .background_spawn(async move { KEY_VALUE_STORE.read_kvp(OUTLINE_PANEL_KEY) })
             .await
             .context("loading outline panel")
             .log_err()
@@ -849,7 +848,7 @@ impl OutlinePanel {
     fn serialize(&mut self, cx: &mut Context<Self>) {
         let width = self.width;
         let active = Some(self.active);
-        self.pending_serialization = cx.background_executor().spawn(
+        self.pending_serialization = cx.background_spawn(
             async move {
                 KEY_VALUE_STORE
                     .write_kvp(
@@ -2631,8 +2630,7 @@ impl OutlinePanel {
                 new_depth_map,
                 new_children_count,
             )) = cx
-                .background_executor()
-                .spawn(async move {
+                .background_spawn(async move {
                     let mut processed_external_buffers = HashSet::default();
                     let mut new_worktree_entries =
                         BTreeMap::<WorktreeId, HashMap<ProjectEntryId, GitEntry>>::default();
@@ -3224,8 +3222,7 @@ impl OutlinePanel {
                     (buffer_id, excerpt_id),
                     cx.spawn_in(window, |outline_panel, mut cx| async move {
                         let fetched_outlines = cx
-                            .background_executor()
-                            .spawn(async move {
+                            .background_spawn(async move {
                                 buffer_snapshot
                                     .outline_items_containing(
                                         excerpt_range.context,

crates/project/src/buffer_store.rs 🔗

@@ -346,7 +346,7 @@ impl RemoteBufferStore {
     fn open_unstaged_diff(&self, buffer_id: BufferId, cx: &App) -> Task<Result<Option<String>>> {
         let project_id = self.project_id;
         let client = self.upstream_client.clone();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let response = client
                 .request(proto::OpenUnstagedDiff {
                     project_id,
@@ -366,7 +366,7 @@ impl RemoteBufferStore {
 
         let project_id = self.project_id;
         let client = self.upstream_client.clone();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let response = client
                 .request(proto::OpenUncommittedDiff {
                     project_id,
@@ -402,9 +402,7 @@ impl RemoteBufferStore {
                 return Ok(buffer);
             }
 
-            cx.background_executor()
-                .spawn(async move { rx.await? })
-                .await
+            cx.background_spawn(async move { rx.await? }).await
         })
     }
 
@@ -843,8 +841,7 @@ impl LocalBufferStore {
             let snapshot =
                 worktree_handle.update(&mut cx, |tree, _| tree.as_local().unwrap().snapshot())?;
             let diff_bases_changes_by_buffer = cx
-                .background_executor()
-                .spawn(async move {
+                .background_spawn(async move {
                     diff_state_updates
                         .into_iter()
                         .filter_map(
@@ -1129,8 +1126,7 @@ impl LocalBufferStore {
             cx.spawn(move |_, mut cx| async move {
                 let loaded = load_file.await?;
                 let text_buffer = cx
-                    .background_executor()
-                    .spawn(async move { text::Buffer::new(0, buffer_id, loaded.text) })
+                    .background_spawn(async move { text::Buffer::new(0, buffer_id, loaded.text) })
                     .await;
                 cx.insert_entity(reservation, |_| {
                     Buffer::build(text_buffer, Some(loaded.file), Capability::ReadWrite)
@@ -1347,8 +1343,7 @@ impl BufferStore {
             }
         };
 
-        cx.background_executor()
-            .spawn(async move { task.await.map_err(|e| anyhow!("{e}")) })
+        cx.background_spawn(async move { task.await.map_err(|e| anyhow!("{e}")) })
     }
 
     pub fn open_unstaged_diff(
@@ -1388,8 +1383,7 @@ impl BufferStore {
             }
         };
 
-        cx.background_executor()
-            .spawn(async move { task.await.map_err(|e| anyhow!("{e}")) })
+        cx.background_spawn(async move { task.await.map_err(|e| anyhow!("{e}")) })
     }
 
     pub fn open_uncommitted_diff(
@@ -1409,7 +1403,7 @@ impl BufferStore {
                     BufferStoreState::Local(this) => {
                         let committed_text = this.load_committed_text(&buffer, cx);
                         let staged_text = this.load_staged_text(&buffer, cx);
-                        cx.background_executor().spawn(async move {
+                        cx.background_spawn(async move {
                             let committed_text = committed_text.await?;
                             let staged_text = staged_text.await?;
                             let diff_bases_change = if committed_text == staged_text {
@@ -1445,8 +1439,7 @@ impl BufferStore {
             }
         };
 
-        cx.background_executor()
-            .spawn(async move { task.await.map_err(|e| anyhow!("{e}")) })
+        cx.background_spawn(async move { task.await.map_err(|e| anyhow!("{e}")) })
     }
 
     async fn open_diff_internal(
@@ -1587,7 +1580,7 @@ impl BufferStore {
                     anyhow::Ok(Some((repo, relative_path, content)))
                 });
 
-                cx.background_executor().spawn(async move {
+                cx.background_spawn(async move {
                     let Some((repo, relative_path, content)) = blame_params? else {
                         return Ok(None);
                     };
@@ -2106,24 +2099,23 @@ impl BufferStore {
                     })
                     .log_err();
 
-                cx.background_executor()
-                    .spawn(
-                        async move {
-                            let operations = operations.await;
-                            for chunk in split_operations(operations) {
-                                client
-                                    .request(proto::UpdateBuffer {
-                                        project_id,
-                                        buffer_id: buffer_id.into(),
-                                        operations: chunk,
-                                    })
-                                    .await?;
-                            }
-                            anyhow::Ok(())
+                cx.background_spawn(
+                    async move {
+                        let operations = operations.await;
+                        for chunk in split_operations(operations) {
+                            client
+                                .request(proto::UpdateBuffer {
+                                    project_id,
+                                    buffer_id: buffer_id.into(),
+                                    operations: chunk,
+                                })
+                                .await?;
                         }
-                        .log_err(),
-                    )
-                    .detach();
+                        anyhow::Ok(())
+                    }
+                    .log_err(),
+                )
+                .detach();
             }
         }
         Ok(response)
@@ -2558,27 +2550,26 @@ impl BufferStore {
 
             if client.send(initial_state).log_err().is_some() {
                 let client = client.clone();
-                cx.background_executor()
-                    .spawn(async move {
-                        let mut chunks = split_operations(operations).peekable();
-                        while let Some(chunk) = chunks.next() {
-                            let is_last = chunks.peek().is_none();
-                            client.send(proto::CreateBufferForPeer {
-                                project_id,
-                                peer_id: Some(peer_id),
-                                variant: Some(proto::create_buffer_for_peer::Variant::Chunk(
-                                    proto::BufferChunk {
-                                        buffer_id: buffer_id.into(),
-                                        operations: chunk,
-                                        is_last,
-                                    },
-                                )),
-                            })?;
-                        }
-                        anyhow::Ok(())
-                    })
-                    .await
-                    .log_err();
+                cx.background_spawn(async move {
+                    let mut chunks = split_operations(operations).peekable();
+                    while let Some(chunk) = chunks.next() {
+                        let is_last = chunks.peek().is_none();
+                        client.send(proto::CreateBufferForPeer {
+                            project_id,
+                            peer_id: Some(peer_id),
+                            variant: Some(proto::create_buffer_for_peer::Variant::Chunk(
+                                proto::BufferChunk {
+                                    buffer_id: buffer_id.into(),
+                                    operations: chunk,
+                                    is_last,
+                                },
+                            )),
+                        })?;
+                    }
+                    anyhow::Ok(())
+                })
+                .await
+                .log_err();
             }
             Ok(())
         })

crates/project/src/environment.rs 🔗

@@ -135,8 +135,7 @@ impl ProjectEnvironment {
 
         cx.spawn(|this, mut cx| async move {
             let (mut shell_env, error_message) = cx
-                .background_executor()
-                .spawn({
+                .background_spawn({
                     let worktree_abs_path = worktree_abs_path.clone();
                     async move {
                         load_worktree_shell_environment(&worktree_abs_path, &load_direnv).await

crates/project/src/git.rs 🔗

@@ -11,8 +11,8 @@ use git::{
     status::{GitSummary, TrackedSummary},
 };
 use gpui::{
-    App, AppContext, AsyncApp, Context, Entity, EventEmitter, SharedString, Subscription, Task,
-    WeakEntity,
+    App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, SharedString, Subscription,
+    Task, WeakEntity,
 };
 use language::{Buffer, LanguageRegistry};
 use rpc::proto::{git_reset, ToProto};
@@ -242,10 +242,7 @@ impl GitStore {
             mpsc::unbounded::<(Message, oneshot::Sender<Result<()>>)>();
         cx.spawn(|_, cx| async move {
             while let Some((msg, respond)) = update_receiver.next().await {
-                let result = cx
-                    .background_executor()
-                    .spawn(Self::process_git_msg(msg))
-                    .await;
+                let result = cx.background_spawn(Self::process_git_msg(msg)).await;
                 respond.send(result).ok();
             }
         })
@@ -841,15 +838,14 @@ impl Repository {
         match self.git_repo.clone() {
             GitRepo::Local(git_repository) => {
                 let commit = commit.to_string();
-                cx.background_executor()
-                    .spawn(async move { git_repository.show(&commit) })
+                cx.background_spawn(async move { git_repository.show(&commit) })
             }
             GitRepo::Remote {
                 project_id,
                 client,
                 worktree_id,
                 work_directory_id,
-            } => cx.background_executor().spawn(async move {
+            } => cx.background_spawn(async move {
                 let resp = client
                     .request(proto::GitShow {
                         project_id: project_id.0,

crates/project/src/image_store.rs 🔗

@@ -404,7 +404,7 @@ impl ImageStore {
             }
         };
 
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             Self::wait_for_loading_image(loading_watch)
                 .await
                 .map_err(|e| e.cloned())

crates/project/src/lsp_store.rs 🔗

@@ -2144,7 +2144,7 @@ impl LocalLspStore {
         cx: &mut Context<LspStore>,
     ) -> Task<Result<Vec<(Range<Anchor>, String)>>> {
         let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let snapshot = snapshot?;
             let mut lsp_edits = lsp_edits
                 .into_iter()
@@ -3282,16 +3282,15 @@ impl LspStore {
             }
         } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
             let buffer_id = buffer.read(cx).remote_id().to_proto();
-            cx.background_executor()
-                .spawn(async move {
-                    upstream_client
-                        .request(proto::RegisterBufferWithLanguageServers {
-                            project_id: upstream_project_id,
-                            buffer_id,
-                        })
-                        .await
-                })
-                .detach();
+            cx.background_spawn(async move {
+                upstream_client
+                    .request(proto::RegisterBufferWithLanguageServers {
+                        project_id: upstream_project_id,
+                        buffer_id,
+                    })
+                    .await
+            })
+            .detach();
         } else {
             panic!("oops!");
         }
@@ -6707,7 +6706,7 @@ impl LspStore {
                     return Err(anyhow!("No language server {id}"));
                 };
 
-                Ok(cx.background_executor().spawn(async move {
+                Ok(cx.background_spawn(async move {
                     let can_resolve = server
                         .capabilities()
                         .completion_provider
@@ -7375,9 +7374,7 @@ impl LspStore {
                     .map(|b| b.read(cx).remote_id().to_proto())
                     .collect(),
             });
-            cx.background_executor()
-                .spawn(request)
-                .detach_and_log_err(cx);
+            cx.background_spawn(request).detach_and_log_err(cx);
         } else {
             let Some(local) = self.as_local_mut() else {
                 return;
@@ -7406,9 +7403,7 @@ impl LspStore {
                 .collect::<Vec<_>>();
 
             cx.spawn(|this, mut cx| async move {
-                cx.background_executor()
-                    .spawn(futures::future::join_all(tasks))
-                    .await;
+                cx.background_spawn(futures::future::join_all(tasks)).await;
                 this.update(&mut cx, |this, cx| {
                     for buffer in buffers {
                         this.register_buffer_with_language_servers(&buffer, true, cx);
@@ -7737,9 +7732,7 @@ impl LspStore {
                     },
                 )),
             });
-            cx.background_executor()
-                .spawn(request)
-                .detach_and_log_err(cx);
+            cx.background_spawn(request).detach_and_log_err(cx);
         } else if let Some(local) = self.as_local() {
             let servers = buffers
                 .into_iter()
@@ -7795,9 +7788,7 @@ impl LspStore {
                     ),
                 ),
             });
-            cx.background_executor()
-                .spawn(request)
-                .detach_and_log_err(cx);
+            cx.background_spawn(request).detach_and_log_err(cx);
         }
     }
 

crates/project/src/prettier_store.rs 🔗

@@ -12,7 +12,7 @@ use futures::{
     stream::FuturesUnordered,
     FutureExt,
 };
-use gpui::{AsyncApp, Context, Entity, EventEmitter, Task, WeakEntity};
+use gpui::{AppContext as _, AsyncApp, Context, Entity, EventEmitter, Task, WeakEntity};
 use language::{
     language_settings::{Formatter, LanguageSettings, SelectedFormatter},
     Buffer, LanguageRegistry, LocalFile,
@@ -121,8 +121,7 @@ impl PrettierStore {
                 let installed_prettiers = self.prettier_instances.keys().cloned().collect();
                 cx.spawn(|lsp_store, mut cx| async move {
                     match cx
-                        .background_executor()
-                        .spawn(async move {
+                        .background_spawn(async move {
                             Prettier::locate_prettier_installation(
                                 fs.as_ref(),
                                 &installed_prettiers,
@@ -234,8 +233,7 @@ impl PrettierStore {
                     .unwrap_or_default();
                 cx.spawn(|lsp_store, mut cx| async move {
                     match cx
-                        .background_executor()
-                        .spawn(async move {
+                        .background_spawn(async move {
                             Prettier::locate_prettier_ignore(
                                 fs.as_ref(),
                                 &prettier_ignores,
@@ -483,31 +481,30 @@ impl PrettierStore {
                     }))
                     .collect::<Vec<_>>();
 
-            cx.background_executor()
-                .spawn(async move {
-                    let _: Vec<()> = future::join_all(prettiers_to_reload.into_iter().map(|(worktree_id, prettier_path, prettier_instance)| {
-                        async move {
-                            if let Some(instance) = prettier_instance.prettier {
-                                match instance.await {
-                                    Ok(prettier) => {
-                                        prettier.clear_cache().log_err().await;
-                                    },
-                                    Err(e) => {
-                                        match prettier_path {
-                                            Some(prettier_path) => log::error!(
-                                                "Failed to clear prettier {prettier_path:?} cache for worktree {worktree_id:?} on prettier settings update: {e:#}"
-                                            ),
-                                            None => log::error!(
-                                                "Failed to clear default prettier cache for worktree {worktree_id:?} on prettier settings update: {e:#}"
-                                            ),
-                                        }
-                                    },
-                                }
+            cx.background_spawn(async move {
+                let _: Vec<()> = future::join_all(prettiers_to_reload.into_iter().map(|(worktree_id, prettier_path, prettier_instance)| {
+                    async move {
+                        if let Some(instance) = prettier_instance.prettier {
+                            match instance.await {
+                                Ok(prettier) => {
+                                    prettier.clear_cache().log_err().await;
+                                },
+                                Err(e) => {
+                                    match prettier_path {
+                                        Some(prettier_path) => log::error!(
+                                            "Failed to clear prettier {prettier_path:?} cache for worktree {worktree_id:?} on prettier settings update: {e:#}"
+                                        ),
+                                        None => log::error!(
+                                            "Failed to clear default prettier cache for worktree {worktree_id:?} on prettier settings update: {e:#}"
+                                        ),
+                                    }
+                                },
                             }
                         }
-                    }))
-                    .await;
-                })
+                    }
+                }))
+                .await;
+            })
                 .detach();
         }
     }
@@ -539,7 +536,7 @@ impl PrettierStore {
         }) {
             Some(locate_from) => {
                 let installed_prettiers = self.prettier_instances.keys().cloned().collect();
-                cx.background_executor().spawn(async move {
+                cx.background_spawn(async move {
                     Prettier::locate_prettier_installation(
                         fs.as_ref(),
                         &installed_prettiers,
@@ -631,13 +628,12 @@ impl PrettierStore {
                         })?;
                         if needs_install {
                             let installed_plugins = new_plugins.clone();
-                            cx.background_executor()
-                                .spawn(async move {
-                                    install_prettier_packages(fs.as_ref(), new_plugins, node).await?;
-                                    // Save the server file last, so the reinstall need could be determined by the absence of the file.
-                                    save_prettier_server_file(fs.as_ref()).await?;
-                                    anyhow::Ok(())
-                                })
+                            cx.background_spawn(async move {
+                                install_prettier_packages(fs.as_ref(), new_plugins, node).await?;
+                                // Save the server file last, so the reinstall need could be determined by the absence of the file.
+                                save_prettier_server_file(fs.as_ref()).await?;
+                                anyhow::Ok(())
+                            })
                                 .await
                                 .context("prettier & plugins install")
                                 .map_err(Arc::new)?;

crates/project/src/project.rs 🔗

@@ -562,7 +562,7 @@ impl DirectoryLister {
             }
             DirectoryLister::Local(fs) => {
                 let fs = fs.clone();
-                cx.background_executor().spawn(async move {
+                cx.background_spawn(async move {
                     let mut results = vec![];
                     let expanded = shellexpand::tilde(&path);
                     let query = Path::new(expanded.as_ref());
@@ -1163,13 +1163,12 @@ impl Project {
                 .read(cx)
                 .shutdown_processes(Some(proto::ShutdownRemoteServer {}));
 
-            cx.background_executor()
-                .spawn(async move {
-                    if let Some(shutdown) = shutdown {
-                        shutdown.await;
-                    }
-                })
-                .detach()
+            cx.background_spawn(async move {
+                if let Some(shutdown) = shutdown {
+                    shutdown.await;
+                }
+            })
+            .detach()
         }
 
         match &self.client_state {
@@ -3138,7 +3137,7 @@ impl Project {
                     let buffer = buffer.clone();
                     let query = query.clone();
                     let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot())?;
-                    chunk_results.push(cx.background_executor().spawn(async move {
+                    chunk_results.push(cx.background_spawn(async move {
                         let ranges = query
                             .search(&snapshot, None)
                             .await
@@ -3377,7 +3376,7 @@ impl Project {
         cx: &mut Context<Self>,
     ) -> Task<Option<ResolvedPath>> {
         let resolve_task = self.resolve_abs_path(path, cx);
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let resolved_path = resolve_task.await;
             resolved_path.filter(|path| path.is_file())
         })
@@ -3391,7 +3390,7 @@ impl Project {
         if self.is_local() {
             let expanded = PathBuf::from(shellexpand::tilde(&path).into_owned());
             let fs = self.fs.clone();
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 let path = expanded.as_path();
                 let metadata = fs.metadata(path).await.ok().flatten();
 
@@ -3409,7 +3408,7 @@ impl Project {
                     project_id: SSH_PROJECT_ID,
                     path: request_path.to_proto(),
                 });
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 let response = request.await.log_err()?;
                 if response.exists {
                     Some(ResolvedPath::AbsPath {
@@ -3490,7 +3489,7 @@ impl Project {
             };
 
             let response = session.read(cx).proto_client().request(request);
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 let response = response.await?;
                 Ok(response.entries.into_iter().map(PathBuf::from).collect())
             })
@@ -3906,8 +3905,7 @@ impl Project {
             if let Some(remote_id) = this.remote_id() {
                 let mut payload = envelope.payload.clone();
                 payload.project_id = remote_id;
-                cx.background_executor()
-                    .spawn(this.client.request(payload))
+                cx.background_spawn(this.client.request(payload))
                     .detach_and_log_err(cx);
             }
             this.buffer_store.clone()
@@ -3924,8 +3922,7 @@ impl Project {
             if let Some(ssh) = &this.ssh_client {
                 let mut payload = envelope.payload.clone();
                 payload.project_id = SSH_PROJECT_ID;
-                cx.background_executor()
-                    .spawn(ssh.read(cx).proto_client().request(payload))
+                cx.background_spawn(ssh.read(cx).proto_client().request(payload))
                     .detach_and_log_err(cx);
             }
             this.buffer_store.clone()
@@ -4146,7 +4143,7 @@ impl Project {
                         if let Some(buffer) = this.buffer_for_id(buffer_id, cx) {
                             let operations =
                                 buffer.read(cx).serialize_ops(Some(remote_version), cx);
-                            cx.background_executor().spawn(async move {
+                            cx.background_spawn(async move {
                                 let operations = operations.await;
                                 for chunk in split_operations(operations) {
                                     client
@@ -4169,12 +4166,11 @@ 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.background_executor()
-                    .spawn(client.request(proto::OpenBufferById {
-                        project_id,
-                        id: id.into(),
-                    }))
-                    .detach();
+                cx.background_spawn(client.request(proto::OpenBufferById {
+                    project_id,
+                    id: id.into(),
+                }))
+                .detach();
             }
 
             futures::future::join_all(send_updates_for_buffers)

crates/project/src/project_tree.rs 🔗

@@ -13,7 +13,7 @@ use std::{
 };
 
 use collections::HashMap;
-use gpui::{App, AppContext, Context, Entity, EventEmitter, Subscription};
+use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Subscription};
 use language::{CachedLspAdapter, LspAdapterDelegate};
 use lsp::LanguageServerName;
 use path_trie::{LabelPresence, RootPathTrie, TriePath};

crates/project/src/project_tree/server_tree.rs 🔗

@@ -15,7 +15,7 @@ use std::{
 };
 
 use collections::{HashMap, IndexMap};
-use gpui::{App, AppContext, Entity, Subscription};
+use gpui::{App, AppContext as _, Entity, Subscription};
 use itertools::Itertools;
 use language::{
     language_settings::AllLanguageSettings, Attach, LanguageName, LanguageRegistry,

crates/project/src/toolchain_store.rs 🔗

@@ -325,16 +325,15 @@ impl LocalToolchainStore {
                 .ok()?
                 .await;
 
-            cx.background_executor()
-                .spawn(async move {
-                    let language = registry
-                        .language_for_name(language_name.as_ref())
-                        .await
-                        .ok()?;
-                    let toolchains = language.toolchain_lister()?;
-                    Some(toolchains.list(root.to_path_buf(), project_env).await)
-                })
-                .await
+            cx.background_spawn(async move {
+                let language = registry
+                    .language_for_name(language_name.as_ref())
+                    .await
+                    .ok()?;
+                let toolchains = language.toolchain_lister()?;
+                Some(toolchains.list(root.to_path_buf(), project_env).await)
+            })
+            .await
         })
     }
     pub(crate) fn active_toolchain(

crates/project/src/worktree_store.rs 🔗

@@ -13,7 +13,9 @@ use futures::{
     FutureExt, SinkExt,
 };
 use git::repository::Branch;
-use gpui::{App, AsyncApp, Context, Entity, EntityId, EventEmitter, Task, WeakEntity};
+use gpui::{
+    App, AppContext as _, AsyncApp, Context, Entity, EntityId, EventEmitter, Task, WeakEntity,
+};
 use postage::oneshot;
 use rpc::{
     proto::{self, FromProto, ToProto, SSH_PROJECT_ID},
@@ -179,8 +181,7 @@ impl WorktreeStore {
             Task::ready(Ok((tree, relative_path)))
         } else {
             let worktree = self.create_worktree(abs_path, visible, cx);
-            cx.background_executor()
-                .spawn(async move { Ok((worktree.await?, PathBuf::new())) })
+            cx.background_spawn(async move { Ok((worktree.await?, PathBuf::new())) })
         }
     }
 
@@ -679,7 +680,7 @@ impl WorktreeStore {
         let (output_tx, output_rx) = smol::channel::bounded(64);
         let (matching_paths_tx, matching_paths_rx) = smol::channel::unbounded();
 
-        let input = cx.background_executor().spawn({
+        let input = cx.background_spawn({
             let fs = fs.clone();
             let query = query.clone();
             async move {
@@ -696,7 +697,7 @@ impl WorktreeStore {
             }
         });
         const MAX_CONCURRENT_FILE_SCANS: usize = 64;
-        let filters = cx.background_executor().spawn(async move {
+        let filters = cx.background_spawn(async move {
             let fs = &fs;
             let query = &query;
             executor
@@ -712,25 +713,24 @@ impl WorktreeStore {
                 })
                 .await;
         });
-        cx.background_executor()
-            .spawn(async move {
-                let mut matched = 0;
-                while let Ok(mut receiver) = output_rx.recv().await {
-                    let Some(path) = receiver.next().await else {
-                        continue;
-                    };
-                    let Ok(_) = matching_paths_tx.send(path).await else {
-                        break;
-                    };
-                    matched += 1;
-                    if matched == limit {
-                        break;
-                    }
+        cx.background_spawn(async move {
+            let mut matched = 0;
+            while let Ok(mut receiver) = output_rx.recv().await {
+                let Some(path) = receiver.next().await else {
+                    continue;
+                };
+                let Ok(_) = matching_paths_tx.send(path).await else {
+                    break;
+                };
+                matched += 1;
+                if matched == limit {
+                    break;
                 }
-                drop(input);
-                drop(filters);
-            })
-            .detach();
+            }
+            drop(input);
+            drop(filters);
+        })
+        .detach();
         matching_paths_rx
     }
 
@@ -934,7 +934,7 @@ impl WorktreeStore {
                     }),
                 });
 
-                cx.background_executor().spawn(async move {
+                cx.background_spawn(async move {
                     let response = request.await?;
 
                     let branches = response
@@ -1021,7 +1021,7 @@ impl WorktreeStore {
                     branch_name: new_branch,
                 });
 
-                cx.background_executor().spawn(async move {
+                cx.background_spawn(async move {
                     request.await?;
                     Ok(())
                 })

crates/project_panel/src/project_panel.rs 🔗

@@ -544,8 +544,7 @@ impl ProjectPanel {
         mut cx: AsyncWindowContext,
     ) -> Result<Entity<Self>> {
         let serialized_panel = cx
-            .background_executor()
-            .spawn(async move { KEY_VALUE_STORE.read_kvp(PROJECT_PANEL_KEY) })
+            .background_spawn(async move { KEY_VALUE_STORE.read_kvp(PROJECT_PANEL_KEY) })
             .await
             .map_err(|e| anyhow!("Failed to load project panel: {}", e))
             .log_err()
@@ -627,7 +626,7 @@ impl ProjectPanel {
 
     fn serialize(&mut self, cx: &mut Context<Self>) {
         let width = self.width;
-        self.pending_serialization = cx.background_executor().spawn(
+        self.pending_serialization = cx.background_spawn(
             async move {
                 KEY_VALUE_STORE
                     .write_kvp(

crates/prompt_library/src/prompt_library.rs 🔗

@@ -218,8 +218,7 @@ impl PickerDelegate for PromptPickerDelegate {
         let prev_prompt_id = self.matches.get(self.selected_index).map(|mat| mat.id);
         cx.spawn_in(window, |this, mut cx| async move {
             let (matches, selected_index) = cx
-                .background_executor()
-                .spawn(async move {
+                .background_spawn(async move {
                     let matches = search.await;
 
                     let selected_index = prev_prompt_id

crates/prompt_library/src/prompts.rs 🔗

@@ -2,7 +2,7 @@ use anyhow::Result;
 use assets::Assets;
 use fs::Fs;
 use futures::StreamExt;
-use gpui::{App, AssetSource};
+use gpui::{App, AppContext as _, AssetSource};
 use handlebars::{Handlebars, RenderError};
 use language::{BufferSnapshot, LanguageName, Point};
 use parking_lot::Mutex;
@@ -103,103 +103,102 @@ impl PromptBuilder {
         handlebars: Arc<Mutex<Handlebars<'static>>>,
     ) {
         let templates_dir = paths::prompt_overrides_dir(params.repo_path.as_deref());
-        params.cx.background_executor()
-            .spawn(async move {
-                let Some(parent_dir) = templates_dir.parent() else {
-                    return;
-                };
-
-                let mut found_dir_once = false;
-                loop {
-                    // Check if the templates directory exists and handle its status
-                    // If it exists, log its presence and check if it's a symlink
-                    // If it doesn't exist:
-                    //   - Log that we're using built-in prompts
-                    //   - Check if it's a broken symlink and log if so
-                    //   - Set up a watcher to detect when it's created
-                    // After the first check, set the `found_dir_once` flag
-                    // This allows us to avoid logging when looping back around after deleting the prompt overrides directory.
-                    let dir_status = params.fs.is_dir(&templates_dir).await;
-                    let symlink_status = params.fs.read_link(&templates_dir).await.ok();
-                    if dir_status {
-                        let mut log_message = format!("Prompt template overrides directory found at {}", templates_dir.display());
+        params.cx.background_spawn(async move {
+            let Some(parent_dir) = templates_dir.parent() else {
+                return;
+            };
+
+            let mut found_dir_once = false;
+            loop {
+                // Check if the templates directory exists and handle its status
+                // If it exists, log its presence and check if it's a symlink
+                // If it doesn't exist:
+                //   - Log that we're using built-in prompts
+                //   - Check if it's a broken symlink and log if so
+                //   - Set up a watcher to detect when it's created
+                // After the first check, set the `found_dir_once` flag
+                // This allows us to avoid logging when looping back around after deleting the prompt overrides directory.
+                let dir_status = params.fs.is_dir(&templates_dir).await;
+                let symlink_status = params.fs.read_link(&templates_dir).await.ok();
+                if dir_status {
+                    let mut log_message = format!("Prompt template overrides directory found at {}", templates_dir.display());
+                    if let Some(target) = symlink_status {
+                        log_message.push_str(" -> ");
+                        log_message.push_str(&target.display().to_string());
+                    }
+                    log::info!("{}.", log_message);
+                } else {
+                    if !found_dir_once {
+                        log::info!("No prompt template overrides directory found at {}. Using built-in prompts.", templates_dir.display());
                         if let Some(target) = symlink_status {
-                            log_message.push_str(" -> ");
-                            log_message.push_str(&target.display().to_string());
-                        }
-                        log::info!("{}.", log_message);
-                    } else {
-                        if !found_dir_once {
-                            log::info!("No prompt template overrides directory found at {}. Using built-in prompts.", templates_dir.display());
-                            if let Some(target) = symlink_status {
-                                log::info!("Symlink found pointing to {}, but target is invalid.", target.display());
-                            }
+                            log::info!("Symlink found pointing to {}, but target is invalid.", target.display());
                         }
+                    }
 
-                        if params.fs.is_dir(parent_dir).await {
-                            let (mut changes, _watcher) = params.fs.watch(parent_dir, Duration::from_secs(1)).await;
-                            while let Some(changed_paths) = changes.next().await {
-                                if changed_paths.iter().any(|p| &p.path == &templates_dir) {
-                                    let mut log_message = format!("Prompt template overrides directory detected at {}", templates_dir.display());
-                                    if let Ok(target) = params.fs.read_link(&templates_dir).await {
-                                        log_message.push_str(" -> ");
-                                        log_message.push_str(&target.display().to_string());
-                                    }
-                                    log::info!("{}.", log_message);
-                                    break;
+                    if params.fs.is_dir(parent_dir).await {
+                        let (mut changes, _watcher) = params.fs.watch(parent_dir, Duration::from_secs(1)).await;
+                        while let Some(changed_paths) = changes.next().await {
+                            if changed_paths.iter().any(|p| &p.path == &templates_dir) {
+                                let mut log_message = format!("Prompt template overrides directory detected at {}", templates_dir.display());
+                                if let Ok(target) = params.fs.read_link(&templates_dir).await {
+                                    log_message.push_str(" -> ");
+                                    log_message.push_str(&target.display().to_string());
                                 }
+                                log::info!("{}.", log_message);
+                                break;
                             }
-                        } else {
-                            return;
                         }
+                    } else {
+                        return;
                     }
+                }
 
-                    found_dir_once = true;
+                found_dir_once = true;
 
-                    // Initial scan of the prompt overrides directory
-                    if let Ok(mut entries) = params.fs.read_dir(&templates_dir).await {
-                        while let Some(Ok(file_path)) = entries.next().await {
-                            if file_path.to_string_lossy().ends_with(".hbs") {
-                                if let Ok(content) = params.fs.load(&file_path).await {
-                                    let file_name = file_path.file_stem().unwrap().to_string_lossy();
-                                    log::debug!("Registering prompt template override: {}", file_name);
-                                    handlebars.lock().register_template_string(&file_name, content).log_err();
-                                }
+                // Initial scan of the prompt overrides directory
+                if let Ok(mut entries) = params.fs.read_dir(&templates_dir).await {
+                    while let Some(Ok(file_path)) = entries.next().await {
+                        if file_path.to_string_lossy().ends_with(".hbs") {
+                            if let Ok(content) = params.fs.load(&file_path).await {
+                                let file_name = file_path.file_stem().unwrap().to_string_lossy();
+                                log::debug!("Registering prompt template override: {}", file_name);
+                                handlebars.lock().register_template_string(&file_name, content).log_err();
                             }
                         }
                     }
+                }
 
-                    // Watch both the parent directory and the template overrides directory:
-                    // - Monitor the parent directory to detect if the template overrides directory is deleted.
-                    // - Monitor the template overrides directory to re-register templates when they change.
-                    // Combine both watch streams into a single stream.
-                    let (parent_changes, parent_watcher) = params.fs.watch(parent_dir, Duration::from_secs(1)).await;
-                    let (changes, watcher) = params.fs.watch(&templates_dir, Duration::from_secs(1)).await;
-                    let mut combined_changes = futures::stream::select(changes, parent_changes);
-
-                    while let Some(changed_paths) = combined_changes.next().await {
-                        if changed_paths.iter().any(|p| &p.path == &templates_dir) {
-                            if !params.fs.is_dir(&templates_dir).await {
-                                log::info!("Prompt template overrides directory removed. Restoring built-in prompt templates.");
-                                Self::register_built_in_templates(&mut handlebars.lock()).log_err();
-                                break;
-                            }
+                // Watch both the parent directory and the template overrides directory:
+                // - Monitor the parent directory to detect if the template overrides directory is deleted.
+                // - Monitor the template overrides directory to re-register templates when they change.
+                // Combine both watch streams into a single stream.
+                let (parent_changes, parent_watcher) = params.fs.watch(parent_dir, Duration::from_secs(1)).await;
+                let (changes, watcher) = params.fs.watch(&templates_dir, Duration::from_secs(1)).await;
+                let mut combined_changes = futures::stream::select(changes, parent_changes);
+
+                while let Some(changed_paths) = combined_changes.next().await {
+                    if changed_paths.iter().any(|p| &p.path == &templates_dir) {
+                        if !params.fs.is_dir(&templates_dir).await {
+                            log::info!("Prompt template overrides directory removed. Restoring built-in prompt templates.");
+                            Self::register_built_in_templates(&mut handlebars.lock()).log_err();
+                            break;
                         }
-                        for event in changed_paths {
-                            if event.path.starts_with(&templates_dir) && event.path.extension().map_or(false, |ext| ext == "hbs") {
-                                log::info!("Reloading prompt template override: {}", event.path.display());
-                                if let Some(content) = params.fs.load(&event.path).await.log_err() {
-                                    let file_name = event.path.file_stem().unwrap().to_string_lossy();
-                                    handlebars.lock().register_template_string(&file_name, content).log_err();
-                                }
+                    }
+                    for event in changed_paths {
+                        if event.path.starts_with(&templates_dir) && event.path.extension().map_or(false, |ext| ext == "hbs") {
+                            log::info!("Reloading prompt template override: {}", event.path.display());
+                            if let Some(content) = params.fs.load(&event.path).await.log_err() {
+                                let file_name = event.path.file_stem().unwrap().to_string_lossy();
+                                handlebars.lock().register_template_string(&file_name, content).log_err();
                             }
                         }
                     }
-
-                    drop(watcher);
-                    drop(parent_watcher);
                 }
-            })
+
+                drop(watcher);
+                drop(parent_watcher);
+            }
+        })
             .detach();
     }
 

crates/remote/src/ssh_session.rs 🔗

@@ -17,7 +17,7 @@ use futures::{
     select, select_biased, AsyncReadExt as _, Future, FutureExt as _, StreamExt as _,
 };
 use gpui::{
-    App, AppContext, AsyncApp, BorrowAppContext, Context, Entity, EventEmitter, Global,
+    App, AppContext as _, AsyncApp, BorrowAppContext, Context, Entity, EventEmitter, Global,
     SemanticVersion, Task, WeakEntity,
 };
 use itertools::Itertools;
@@ -1158,12 +1158,11 @@ impl SshRemoteClient {
                 c.connections.insert(
                     opts.clone(),
                     ConnectionPoolEntry::Connecting(
-                        cx.background_executor()
-                            .spawn({
-                                let connection = connection.clone();
-                                async move { Ok(connection.clone()) }
-                            })
-                            .shared(),
+                        cx.background_spawn({
+                            let connection = connection.clone();
+                            async move { Ok(connection.clone()) }
+                        })
+                        .shared(),
                     ),
                 );
             })
@@ -1358,7 +1357,7 @@ impl RemoteConnection for SshRemoteConnection {
             ))
             .output();
 
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let output = output.await?;
 
             if !output.status.success() {
@@ -1679,14 +1678,14 @@ impl SshRemoteConnection {
         let mut stderr_buffer = Vec::new();
         let mut stderr_offset = 0;
 
-        let stdin_task = cx.background_executor().spawn(async move {
+        let stdin_task = cx.background_spawn(async move {
             while let Some(outgoing) = outgoing_rx.next().await {
                 write_message(&mut child_stdin, &mut stdin_buffer, outgoing).await?;
             }
             anyhow::Ok(())
         });
 
-        let stdout_task = cx.background_executor().spawn({
+        let stdout_task = cx.background_spawn({
             let mut connection_activity_tx = connection_activity_tx.clone();
             async move {
                 loop {
@@ -1711,7 +1710,7 @@ impl SshRemoteConnection {
             }
         });
 
-        let stderr_task: Task<anyhow::Result<()>> = cx.background_executor().spawn(async move {
+        let stderr_task: Task<anyhow::Result<()>> = cx.background_spawn(async move {
             loop {
                 stderr_buffer.resize(stderr_offset + 1024, 0);
 
@@ -2449,7 +2448,7 @@ mod fake {
         },
         select_biased, FutureExt, SinkExt, StreamExt,
     };
-    use gpui::{App, AsyncApp, SemanticVersion, Task, TestAppContext};
+    use gpui::{App, AppContext as _, AsyncApp, SemanticVersion, Task, TestAppContext};
     use release_channel::ReleaseChannel;
     use rpc::proto::Envelope;
 
@@ -2533,7 +2532,7 @@ mod fake {
                 &self.server_cx.get(cx),
             );
 
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 loop {
                     select_biased! {
                         server_to_client = server_outgoing_rx.next().fuse() => {

crates/remote_server/src/headless_project.rs 🔗

@@ -240,8 +240,7 @@ impl HeadlessProject {
                 operation,
                 is_local: true,
             } => cx
-                .background_executor()
-                .spawn(self.session.request(proto::UpdateBuffer {
+                .background_spawn(self.session.request(proto::UpdateBuffer {
                     project_id: SSH_PROJECT_ID,
                     buffer_id: buffer.read(cx).remote_id().to_proto(),
                     operations: vec![serialize_operation(operation)],
@@ -302,15 +301,14 @@ impl HeadlessProject {
                     message: prompt.message.clone(),
                 });
                 let prompt = prompt.clone();
-                cx.background_executor()
-                    .spawn(async move {
-                        let response = request.await?;
-                        if let Some(action_response) = response.action_response {
-                            prompt.respond(action_response as usize).await;
-                        }
-                        anyhow::Ok(())
-                    })
-                    .detach();
+                cx.background_spawn(async move {
+                    let response = request.await?;
+                    if let Some(action_response) = response.action_response {
+                        prompt.respond(action_response as usize).await;
+                    }
+                    anyhow::Ok(())
+                })
+                .detach();
             }
             _ => {}
         }

crates/remote_server/src/unix.rs 🔗

@@ -311,7 +311,7 @@ fn start_server(
             let mut output_buffer = Vec::new();
 
             let (mut stdin_msg_tx, mut stdin_msg_rx) = mpsc::unbounded::<Envelope>();
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 while let Ok(msg) = read_message(&mut stdin_stream, &mut input_buffer).await {
                     if let Err(_) = stdin_msg_tx.send(msg).await {
                         break;
@@ -487,8 +487,7 @@ pub fn execute_run(
 
         handle_panic_requests(&project, &session);
 
-        cx.background_executor()
-            .spawn(async move { cleanup_old_binaries() })
+        cx.background_spawn(async move { cleanup_old_binaries() })
             .detach();
 
         mem::forget(project);

crates/repl/src/kernels/native_kernel.rs 🔗

@@ -5,7 +5,7 @@ use futures::{
     stream::{SelectAll, StreamExt},
     AsyncBufReadExt as _, SinkExt as _,
 };
-use gpui::{App, Entity, EntityId, Task, Window};
+use gpui::{App, AppContext as _, Entity, EntityId, Task, Window};
 use jupyter_protocol::{
     connection_info::{ConnectionInfo, Transport},
     ExecutionState, JupyterKernelspec, JupyterMessage, JupyterMessageContent, KernelInfoReply,
@@ -211,7 +211,7 @@ impl NativeRunningKernel {
                 futures::channel::mpsc::channel(100);
             let (mut shell_request_tx, mut shell_request_rx) = futures::channel::mpsc::channel(100);
 
-            let routing_task = cx.background_executor().spawn({
+            let routing_task = cx.background_spawn({
                 async move {
                     while let Some(message) = request_rx.next().await {
                         match message.content {
@@ -229,7 +229,7 @@ impl NativeRunningKernel {
                 }
             });
 
-            let shell_task = cx.background_executor().spawn({
+            let shell_task = cx.background_spawn({
                 async move {
                     while let Some(message) = shell_request_rx.next().await {
                         shell_socket.send(message).await.ok();
@@ -240,7 +240,7 @@ impl NativeRunningKernel {
                 }
             });
 
-            let control_task = cx.background_executor().spawn({
+            let control_task = cx.background_spawn({
                 async move {
                     while let Some(message) = control_request_rx.next().await {
                         control_socket.send(message).await.ok();

crates/repl/src/kernels/remote_kernels.rs 🔗

@@ -1,5 +1,5 @@
 use futures::{channel::mpsc, SinkExt as _};
-use gpui::{App, Entity, Task, Window};
+use gpui::{App, AppContext as _, Entity, Task, Window};
 use http_client::{AsyncBody, HttpClient, Request};
 use jupyter_protocol::{ExecutionState, JupyterKernelspec, JupyterMessage, KernelInfoReply};
 
@@ -189,7 +189,7 @@ impl RemoteRunningKernel {
             let (request_tx, mut request_rx) =
                 futures::channel::mpsc::channel::<JupyterMessage>(100);
 
-            let routing_task = cx.background_executor().spawn({
+            let routing_task = cx.background_spawn({
                 async move {
                     while let Some(message) = request_rx.next().await {
                         w.send(message).await.ok();

crates/repl/src/notebook/cell.rs 🔗

@@ -134,8 +134,7 @@ impl Cell {
 
                         cx.spawn_in(window, |this, mut cx| async move {
                             let parsed_markdown = cx
-                                .background_executor()
-                                .spawn(async move {
+                                .background_spawn(async move {
                                     parse_markdown(&source, None, Some(languages)).await
                                 })
                                 .await;

crates/repl/src/outputs/markdown.rs 🔗

@@ -19,9 +19,8 @@ impl MarkdownView {
     pub fn from(text: String, cx: &mut Context<Self>) -> Self {
         let task = cx.spawn(|markdown_view, mut cx| {
             let text = text.clone();
-            let parsed = cx
-                .background_executor()
-                .spawn(async move { parse_markdown(&text, None, None).await });
+            let parsed =
+                cx.background_spawn(async move { parse_markdown(&text, None, None).await });
 
             async move {
                 let content = parsed.await;

crates/repl/src/repl_store.rs 🔗

@@ -164,7 +164,7 @@ impl ReplStore {
 
         let remote_kernel_specifications = self.get_remote_kernel_specifications(cx);
 
-        let all_specs = cx.background_executor().spawn(async move {
+        let all_specs = cx.background_spawn(async move {
             let mut all_specs = local_kernel_specifications
                 .await?
                 .into_iter()

crates/semantic_index/src/embedding_index.rs 🔗

@@ -10,7 +10,7 @@ use fs::Fs;
 use fs::MTime;
 use futures::{stream::StreamExt, FutureExt as _};
 use futures_batch::ChunksTimeoutStreamExt;
-use gpui::{App, Entity, Task};
+use gpui::{App, AppContext as _, Entity, Task};
 use heed::types::{SerdeBincode, Str};
 use language::LanguageRegistry;
 use log;
@@ -102,7 +102,7 @@ impl EmbeddingIndex {
         let db_connection = self.db_connection.clone();
         let db = self.db;
         let entries_being_indexed = self.entry_ids_being_indexed.clone();
-        let task = cx.background_executor().spawn(async move {
+        let task = cx.background_spawn(async move {
             let txn = db_connection
                 .read_txn()
                 .context("failed to create read transaction")?;
@@ -185,7 +185,7 @@ impl EmbeddingIndex {
         let (updated_entries_tx, updated_entries_rx) = channel::bounded(512);
         let (deleted_entry_ranges_tx, deleted_entry_ranges_rx) = channel::bounded(128);
         let entries_being_indexed = self.entry_ids_being_indexed.clone();
-        let task = cx.background_executor().spawn(async move {
+        let task = cx.background_spawn(async move {
             for (path, entry_id, status) in updated_entries.iter() {
                 match status {
                     project::PathChange::Added
@@ -278,7 +278,7 @@ impl EmbeddingIndex {
     ) -> EmbedFiles {
         let embedding_provider = embedding_provider.clone();
         let (embedded_files_tx, embedded_files_rx) = channel::bounded(512);
-        let task = cx.background_executor().spawn(async move {
+        let task = cx.background_spawn(async move {
             let mut chunked_file_batches =
                 pin!(chunked_files.chunks_timeout(512, Duration::from_secs(2)));
             while let Some(chunked_files) = chunked_file_batches.next().await {
@@ -361,7 +361,7 @@ impl EmbeddingIndex {
         let db_connection = self.db_connection.clone();
         let db = self.db;
 
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let mut deleted_entry_ranges = pin!(deleted_entry_ranges);
             let mut embedded_files = pin!(embedded_files);
             loop {
@@ -397,7 +397,7 @@ impl EmbeddingIndex {
     pub fn paths(&self, cx: &App) -> Task<Result<Vec<Arc<Path>>>> {
         let connection = self.db_connection.clone();
         let db = self.db;
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let tx = connection
                 .read_txn()
                 .context("failed to create read transaction")?;
@@ -413,7 +413,7 @@ impl EmbeddingIndex {
     pub fn chunks_for_path(&self, path: Arc<Path>, cx: &App) -> Task<Result<Vec<EmbeddedChunk>>> {
         let connection = self.db_connection.clone();
         let db = self.db;
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let tx = connection
                 .read_txn()
                 .context("failed to create read transaction")?;

crates/semantic_index/src/project_index.rs 🔗

@@ -7,7 +7,9 @@ use anyhow::{anyhow, Context as _, Result};
 use collections::HashMap;
 use fs::Fs;
 use futures::FutureExt;
-use gpui::{App, Context, Entity, EntityId, EventEmitter, Subscription, Task, WeakEntity};
+use gpui::{
+    App, AppContext as _, Context, Entity, EntityId, EventEmitter, Subscription, Task, WeakEntity,
+};
 use language::LanguageRegistry;
 use log;
 use project::{Project, Worktree, WorktreeId};
@@ -250,7 +252,7 @@ impl ProjectIndex {
                         let worktree_id = index.worktree().read(cx).id();
                         let db_connection = index.db_connection().clone();
                         let db = *index.embedding_index().db();
-                        cx.background_executor().spawn(async move {
+                        cx.background_spawn(async move {
                             let txn = db_connection
                                 .read_txn()
                                 .context("failed to create read transaction")?;
@@ -432,7 +434,7 @@ impl ProjectIndex {
                         let file_digest_db = summary_index.file_digest_db();
                         let summary_db = summary_index.summary_db();
 
-                        cx.background_executor().spawn(async move {
+                        cx.background_spawn(async move {
                             let txn = db_connection
                                 .read_txn()
                                 .context("failed to create db read transaction")?;
@@ -519,8 +521,9 @@ impl ProjectIndex {
 
                 index
                     .read_with(&cx, |index, cx| {
-                        cx.background_executor()
-                            .spawn(index.summary_index().flush_backlog(worktree_abs_path, cx))
+                        cx.background_spawn(
+                            index.summary_index().flush_backlog(worktree_abs_path, cx),
+                        )
                     })?
                     .await
             })

crates/semantic_index/src/semantic_index.rs 🔗

@@ -42,8 +42,7 @@ impl SemanticDb {
         cx: &mut AsyncApp,
     ) -> Result<Self> {
         let db_connection = cx
-            .background_executor()
-            .spawn(async move {
+            .background_spawn(async move {
                 std::fs::create_dir_all(&db_path)?;
                 unsafe {
                     heed::EnvOpenOptions::new()
@@ -432,8 +431,7 @@ mod tests {
                 let worktree = search_result.worktree.read(cx);
                 let entry_abs_path = worktree.abs_path().join(&search_result.path);
                 let fs = project.read(cx).fs().clone();
-                cx.background_executor()
-                    .spawn(async move { fs.load(&entry_abs_path).await.unwrap() })
+                cx.background_spawn(async move { fs.load(&entry_abs_path).await.unwrap() })
             })
             .await;
 

crates/semantic_index/src/summary_index.rs 🔗

@@ -3,7 +3,7 @@ use arrayvec::ArrayString;
 use fs::{Fs, MTime};
 use futures::{stream::StreamExt, TryFutureExt};
 use futures_batch::ChunksTimeoutStreamExt;
-use gpui::{App, Entity, Task};
+use gpui::{App, AppContext as _, Entity, Task};
 use heed::{
     types::{SerdeBincode, Str},
     RoTxn,
@@ -254,7 +254,7 @@ impl SummaryIndex {
         let db_connection = self.db_connection.clone();
         let db = self.summary_db;
         let (needs_summary_tx, needs_summary_rx) = channel::bounded(512);
-        let task = cx.background_executor().spawn(async move {
+        let task = cx.background_spawn(async move {
             let mut might_need_summary = pin!(might_need_summary);
             while let Some(file) = might_need_summary.next().await {
                 let tx = db_connection
@@ -291,7 +291,7 @@ impl SummaryIndex {
         let db_connection = self.db_connection.clone();
         let digest_db = self.file_digest_db;
         let backlog = Arc::clone(&self.backlog);
-        let task = cx.background_executor().spawn(async move {
+        let task = cx.background_spawn(async move {
             let txn = db_connection
                 .read_txn()
                 .context("failed to create read transaction")?;
@@ -368,7 +368,7 @@ impl SummaryIndex {
         let db_connection = self.db_connection.clone();
         let digest_db = self.file_digest_db;
         let backlog = Arc::clone(&self.backlog);
-        let task = cx.background_executor().spawn(async move {
+        let task = cx.background_spawn(async move {
             let txn = db_connection
                 .read_txn()
                 .context("failed to create read transaction")?;
@@ -538,7 +538,7 @@ impl SummaryIndex {
             .available_models(cx)
             .find(|model| &model.id() == &summary_model_id)
         else {
-            return cx.background_executor().spawn(async move {
+            return cx.background_spawn(async move {
                 Err(anyhow!("Couldn't find the preferred summarization model ({:?}) in the language registry's available models", summary_model_id))
             });
         };
@@ -566,31 +566,30 @@ impl SummaryIndex {
         let code_len = code.len();
         cx.spawn(|cx| async move {
             let stream = model.stream_completion(request, &cx);
-            cx.background_executor()
-                .spawn(async move {
-                    let answer: String = stream
-                        .await?
-                        .filter_map(|event| async {
-                            if let Ok(LanguageModelCompletionEvent::Text(text)) = event {
-                                Some(text)
-                            } else {
-                                None
-                            }
-                        })
-                        .collect()
-                        .await;
+            cx.background_spawn(async move {
+                let answer: String = stream
+                    .await?
+                    .filter_map(|event| async {
+                        if let Ok(LanguageModelCompletionEvent::Text(text)) = event {
+                            Some(text)
+                        } else {
+                            None
+                        }
+                    })
+                    .collect()
+                    .await;
 
-                    log::info!(
-                        "It took {:?} to summarize {:?} bytes of code.",
-                        start.elapsed(),
-                        code_len
-                    );
+                log::info!(
+                    "It took {:?} to summarize {:?} bytes of code.",
+                    start.elapsed(),
+                    code_len
+                );
 
-                    log::debug!("Summary was: {:?}", &answer);
+                log::debug!("Summary was: {:?}", &answer);
 
-                    Ok(answer)
-                })
-                .await
+                Ok(answer)
+            })
+            .await
 
             // TODO if summarization failed, put it back in the backlog!
         })
@@ -604,7 +603,7 @@ impl SummaryIndex {
         let db_connection = self.db_connection.clone();
         let digest_db = self.file_digest_db;
         let summary_db = self.summary_db;
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let mut summaries = pin!(summaries.chunks_timeout(4096, Duration::from_secs(2)));
             while let Some(summaries) = summaries.next().await {
                 let mut txn = db_connection.write_txn()?;
@@ -650,7 +649,7 @@ impl SummaryIndex {
                 backlog.drain().collect()
             };
 
-            let task = cx.background_executor().spawn(async move {
+            let task = cx.background_spawn(async move {
                 tx.send(needs_summary).await?;
                 Ok(())
             });

crates/semantic_index/src/worktree_index.rs 🔗

@@ -52,8 +52,7 @@ impl WorktreeIndex {
         cx.spawn(|mut cx| async move {
             let entries_being_indexed = Arc::new(IndexingEntrySet::new(status_tx));
             let (embedding_index, summary_index) = cx
-                .background_executor()
-                .spawn({
+                .background_spawn({
                     let entries_being_indexed = Arc::clone(&entries_being_indexed);
                     let db_connection = db_connection.clone();
                     async move {

crates/session/src/session.rs 🔗

@@ -1,7 +1,7 @@
 use std::time::Duration;
 
 use db::kvp::KEY_VALUE_STORE;
-use gpui::{AnyWindowHandle, Context, Subscription, Task, WindowId};
+use gpui::{AnyWindowHandle, AppContext as _, Context, Subscription, Task, WindowId};
 use util::ResultExt;
 use uuid::Uuid;
 
@@ -88,7 +88,7 @@ impl AppSession {
 
     fn app_will_quit(&mut self, cx: &mut Context<Self>) -> Task<()> {
         if let Some(windows) = cx.window_stack() {
-            cx.background_executor().spawn(store_window_stack(windows))
+            cx.background_spawn(store_window_stack(windows))
         } else {
             Task::ready(())
         }

crates/task/src/static_source.rs 🔗

@@ -3,7 +3,7 @@
 use std::sync::Arc;
 
 use futures::{channel::mpsc::UnboundedSender, StreamExt};
-use gpui::App;
+use gpui::{App, AppContext};
 use parking_lot::RwLock;
 use serde::Deserialize;
 use util::ResultExt;
@@ -33,35 +33,34 @@ impl<T: PartialEq + 'static + Sync> TrackedFile<T> {
         T: for<'a> Deserialize<'a> + Default + Send,
     {
         let parsed_contents: Arc<RwLock<T>> = Arc::default();
-        cx.background_executor()
-            .spawn({
-                let parsed_contents = parsed_contents.clone();
-                async move {
-                    while let Some(new_contents) = tracker.next().await {
-                        if Arc::strong_count(&parsed_contents) == 1 {
-                            // We're no longer being observed. Stop polling.
-                            break;
-                        }
-                        if !new_contents.trim().is_empty() {
-                            let Some(new_contents) =
-                                serde_json_lenient::from_str::<T>(&new_contents).log_err()
-                            else {
-                                continue;
-                            };
-                            let mut contents = parsed_contents.write();
-                            if *contents != new_contents {
-                                *contents = new_contents;
-                                if notification_outlet.unbounded_send(()).is_err() {
-                                    // Whoever cared about contents is not around anymore.
-                                    break;
-                                }
+        cx.background_spawn({
+            let parsed_contents = parsed_contents.clone();
+            async move {
+                while let Some(new_contents) = tracker.next().await {
+                    if Arc::strong_count(&parsed_contents) == 1 {
+                        // We're no longer being observed. Stop polling.
+                        break;
+                    }
+                    if !new_contents.trim().is_empty() {
+                        let Some(new_contents) =
+                            serde_json_lenient::from_str::<T>(&new_contents).log_err()
+                        else {
+                            continue;
+                        };
+                        let mut contents = parsed_contents.write();
+                        if *contents != new_contents {
+                            *contents = new_contents;
+                            if notification_outlet.unbounded_send(()).is_err() {
+                                // Whoever cared about contents is not around anymore.
+                                break;
                             }
                         }
                     }
-                    anyhow::Ok(())
                 }
-            })
-            .detach_and_log_err(cx);
+                anyhow::Ok(())
+            }
+        })
+        .detach_and_log_err(cx);
         Self { parsed_contents }
     }
 
@@ -75,39 +74,38 @@ impl<T: PartialEq + 'static + Sync> TrackedFile<T> {
         T: Default + Send,
     {
         let parsed_contents: Arc<RwLock<T>> = Arc::default();
-        cx.background_executor()
-            .spawn({
-                let parsed_contents = parsed_contents.clone();
-                async move {
-                    while let Some(new_contents) = tracker.next().await {
-                        if Arc::strong_count(&parsed_contents) == 1 {
-                            // We're no longer being observed. Stop polling.
-                            break;
-                        }
+        cx.background_spawn({
+            let parsed_contents = parsed_contents.clone();
+            async move {
+                while let Some(new_contents) = tracker.next().await {
+                    if Arc::strong_count(&parsed_contents) == 1 {
+                        // We're no longer being observed. Stop polling.
+                        break;
+                    }
 
-                        if !new_contents.trim().is_empty() {
-                            let Some(new_contents) =
-                                serde_json_lenient::from_str::<U>(&new_contents).log_err()
-                            else {
-                                continue;
-                            };
-                            let Some(new_contents) = new_contents.try_into().log_err() else {
-                                continue;
-                            };
-                            let mut contents = parsed_contents.write();
-                            if *contents != new_contents {
-                                *contents = new_contents;
-                                if notification_outlet.unbounded_send(()).is_err() {
-                                    // Whoever cared about contents is not around anymore.
-                                    break;
-                                }
+                    if !new_contents.trim().is_empty() {
+                        let Some(new_contents) =
+                            serde_json_lenient::from_str::<U>(&new_contents).log_err()
+                        else {
+                            continue;
+                        };
+                        let Some(new_contents) = new_contents.try_into().log_err() else {
+                            continue;
+                        };
+                        let mut contents = parsed_contents.write();
+                        if *contents != new_contents {
+                            *contents = new_contents;
+                            if notification_outlet.unbounded_send(()).is_err() {
+                                // Whoever cared about contents is not around anymore.
+                                break;
                             }
                         }
                     }
-                    anyhow::Ok(())
                 }
-            })
-            .detach_and_log_err(cx);
+                anyhow::Ok(())
+            }
+        })
+        .detach_and_log_err(cx);
         Self {
             parsed_contents: Default::default(),
         }

crates/terminal/src/terminal.rs 🔗

@@ -58,9 +58,9 @@ use std::{
 use thiserror::Error;
 
 use gpui::{
-    actions, black, px, AnyWindowHandle, App, Bounds, ClipboardItem, Context, EventEmitter, Hsla,
-    Keystroke, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point,
-    Rgba, ScrollWheelEvent, SharedString, Size, Task, TouchPhase,
+    actions, black, px, AnyWindowHandle, App, AppContext as _, Bounds, ClipboardItem, Context,
+    EventEmitter, Hsla, Keystroke, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent,
+    MouseUpEvent, Pixels, Point, Rgba, ScrollWheelEvent, SharedString, Size, Task, TouchPhase,
 };
 
 use crate::mappings::{colors::to_alac_rgb, keys::to_esc_str};
@@ -1633,7 +1633,7 @@ impl Terminal {
         cx: &Context<Self>,
     ) -> Task<Vec<RangeInclusive<AlacPoint>>> {
         let term = self.term.clone();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let term = term.lock();
 
             all_search_matches(&term, &mut searcher).collect()

crates/terminal_view/src/terminal_panel.rs 🔗

@@ -222,8 +222,7 @@ impl TerminalPanel {
         mut cx: AsyncWindowContext,
     ) -> Result<Entity<Self>> {
         let serialized_panel = cx
-            .background_executor()
-            .spawn(async move { KEY_VALUE_STORE.read_kvp(TERMINAL_PANEL_KEY) })
+            .background_spawn(async move { KEY_VALUE_STORE.read_kvp(TERMINAL_PANEL_KEY) })
             .await
             .log_err()
             .flatten()
@@ -742,25 +741,24 @@ impl TerminalPanel {
                     ))
                 })
                 .ok()?;
-            cx.background_executor()
-                .spawn(
-                    async move {
-                        KEY_VALUE_STORE
-                            .write_kvp(
-                                TERMINAL_PANEL_KEY.into(),
-                                serde_json::to_string(&SerializedTerminalPanel {
-                                    items,
-                                    active_item_id: None,
-                                    height,
-                                    width,
-                                })?,
-                            )
-                            .await?;
-                        anyhow::Ok(())
-                    }
-                    .log_err(),
-                )
-                .await;
+            cx.background_spawn(
+                async move {
+                    KEY_VALUE_STORE
+                        .write_kvp(
+                            TERMINAL_PANEL_KEY.into(),
+                            serde_json::to_string(&SerializedTerminalPanel {
+                                items,
+                                active_item_id: None,
+                                height,
+                                width,
+                            })?,
+                        )
+                        .await?;
+                    anyhow::Ok(())
+                }
+                .log_err(),
+            )
+            .await;
             Some(())
         });
     }

crates/terminal_view/src/terminal_view.rs 🔗

@@ -976,7 +976,7 @@ fn possible_open_paths_metadata(
     potential_paths: HashSet<PathBuf>,
     cx: &mut Context<TerminalView>,
 ) -> Task<Vec<(PathWithPosition, Metadata)>> {
-    cx.background_executor().spawn(async move {
+    cx.background_spawn(async move {
         let mut canonical_paths = HashSet::default();
         for path in potential_paths {
             if let Ok(canonical) = fs.canonicalize(&path).await {
@@ -1378,9 +1378,12 @@ impl Item for TerminalView {
     ) {
         if self.terminal().read(cx).task().is_none() {
             if let Some((new_id, old_id)) = workspace.database_id().zip(self.workspace_id) {
-                cx.background_executor()
-                    .spawn(TERMINAL_DB.update_workspace_id(new_id, old_id, cx.entity_id().as_u64()))
-                    .detach();
+                cx.background_spawn(TERMINAL_DB.update_workspace_id(
+                    new_id,
+                    old_id,
+                    cx.entity_id().as_u64(),
+                ))
+                .detach();
             }
             self.workspace_id = workspace.database_id();
         }
@@ -1421,7 +1424,7 @@ impl SerializableItem for TerminalView {
         }
 
         if let Some((cwd, workspace_id)) = terminal.working_directory().zip(self.workspace_id) {
-            Some(cx.background_executor().spawn(async move {
+            Some(cx.background_spawn(async move {
                 TERMINAL_DB
                     .save_working_directory(item_id, workspace_id, cwd)
                     .await

crates/vim/src/command.rs 🔗

@@ -7,7 +7,7 @@ use editor::{
     scroll::Autoscroll,
     Bias, Editor, ToPoint,
 };
-use gpui::{actions, impl_internal_actions, Action, App, Context, Global, Window};
+use gpui::{actions, impl_internal_actions, Action, App, AppContext as _, Context, Global, Window};
 use itertools::Itertools;
 use language::Point;
 use multi_buffer::MultiBufferRow;
@@ -1185,8 +1185,7 @@ impl OnMatchingLines {
                     .clip_point(Point::new(range.end.0 + 1, 0), Bias::Left);
             cx.spawn_in(window, |editor, mut cx| async move {
                 let new_selections = cx
-                    .background_executor()
-                    .spawn(async move {
+                    .background_spawn(async move {
                         let mut line = String::new();
                         let mut new_selections = Vec::new();
                         let chunks = snapshot
@@ -1513,22 +1512,20 @@ impl ShellExec {
             if let Some(mut stdin) = running.stdin.take() {
                 if let Some(snapshot) = input_snapshot {
                     let range = range.clone();
-                    cx.background_executor()
-                        .spawn(async move {
-                            for chunk in snapshot.text_for_range(range) {
-                                if stdin.write_all(chunk.as_bytes()).log_err().is_none() {
-                                    return;
-                                }
+                    cx.background_spawn(async move {
+                        for chunk in snapshot.text_for_range(range) {
+                            if stdin.write_all(chunk.as_bytes()).log_err().is_none() {
+                                return;
                             }
-                            stdin.flush().log_err();
-                        })
-                        .detach();
+                        }
+                        stdin.flush().log_err();
+                    })
+                    .detach();
                 }
             };
 
             let output = cx
-                .background_executor()
-                .spawn(async move { running.wait_with_output() })
+                .background_spawn(async move { running.wait_with_output() })
                 .await;
 
             let Some(output) = output.log_err() else {

crates/workspace/src/shared_screen/cross_platform.rs 🔗

@@ -5,7 +5,7 @@ use crate::{
 use call::{RemoteVideoTrack, RemoteVideoTrackView};
 use client::{proto::PeerId, User};
 use gpui::{
-    div, AppContext, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement,
+    div, AppContext as _, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement,
     ParentElement, Render, SharedString, Styled,
 };
 use std::sync::Arc;

crates/workspace/src/workspace.rs 🔗

@@ -4337,8 +4337,7 @@ impl Workspace {
             self.update_active_view_for_followers(window, cx);
 
             if let Some(database_id) = self.database_id {
-                cx.background_executor()
-                    .spawn(persistence::DB.update_timestamp(database_id))
+                cx.background_spawn(persistence::DB.update_timestamp(database_id))
                     .detach();
             }
         } else {
@@ -4626,8 +4625,7 @@ impl Workspace {
                 if let Ok(Some(task)) = this.update_in(cx, |workspace, window, cx| {
                     item.serialize(workspace, false, window, cx)
                 }) {
-                    cx.background_executor()
-                        .spawn(async move { task.await.log_err() })
+                    cx.background_spawn(async move { task.await.log_err() })
                         .detach();
                 }
             }
@@ -4965,8 +4963,7 @@ impl Workspace {
     ) {
         self.centered_layout = !self.centered_layout;
         if let Some(database_id) = self.database_id() {
-            cx.background_executor()
-                .spawn(DB.set_centered_layout(database_id, self.centered_layout))
+            cx.background_spawn(DB.set_centered_layout(database_id, self.centered_layout))
                 .detach_and_log_err(cx);
         }
         cx.notify();
@@ -6223,7 +6220,7 @@ fn serialize_ssh_project(
         Option<SerializedWorkspace>,
     )>,
 > {
-    cx.background_executor().spawn(async move {
+    cx.background_spawn(async move {
         let serialized_ssh_project = persistence::DB
             .get_or_create_ssh_project(
                 connection_options.host.clone(),

crates/worktree/src/worktree.rs 🔗

@@ -791,23 +791,22 @@ impl Worktree {
 
             // Apply updates to a separate snapshot in a background task, then
             // send them to a foreground task which updates the model.
-            cx.background_executor()
-                .spawn(async move {
-                    while let Some(update) = background_updates_rx.next().await {
+            cx.background_spawn(async move {
+                while let Some(update) = background_updates_rx.next().await {
+                    {
+                        let mut lock = background_snapshot.lock();
+                        if let Err(error) = lock
+                            .0
+                            .apply_remote_update(update.clone(), &settings.file_scan_inclusions)
                         {
-                            let mut lock = background_snapshot.lock();
-                            if let Err(error) = lock
-                                .0
-                                .apply_remote_update(update.clone(), &settings.file_scan_inclusions)
-                            {
-                                log::error!("error applying worktree update: {}", error);
-                            }
-                            lock.1.push(update);
+                            log::error!("error applying worktree update: {}", error);
                         }
-                        snapshot_updated_tx.send(()).await.ok();
+                        lock.1.push(update);
                     }
-                })
-                .detach();
+                    snapshot_updated_tx.send(()).await.ok();
+                }
+            })
+            .detach();
 
             // On the foreground task, update to the latest snapshot and notify
             // any update observer of all updates that led to that snapshot.
@@ -991,7 +990,7 @@ impl Worktree {
             Worktree::Local(this) => {
                 let path = Arc::from(path);
                 let snapshot = this.snapshot();
-                cx.background_executor().spawn(async move {
+                cx.background_spawn(async move {
                     if let Some(repo) = snapshot.repository_for_path(&path) {
                         if let Some(repo_path) = repo.relativize(&path).log_err() {
                             if let Some(git_repo) =
@@ -1015,7 +1014,7 @@ impl Worktree {
             Worktree::Local(this) => {
                 let path = Arc::from(path);
                 let snapshot = this.snapshot();
-                cx.background_executor().spawn(async move {
+                cx.background_spawn(async move {
                     if let Some(repo) = snapshot.repository_for_path(&path) {
                         if let Some(repo_path) = repo.relativize(&path).log_err() {
                             if let Some(git_repo) =
@@ -1431,7 +1430,7 @@ impl LocalWorktree {
         let git_hosting_provider_registry = GitHostingProviderRegistry::try_global(cx);
         let settings = self.settings.clone();
         let (scan_states_tx, mut scan_states_rx) = mpsc::unbounded();
-        let background_scanner = cx.background_executor().spawn({
+        let background_scanner = cx.background_spawn({
             let abs_path = snapshot.abs_path.as_path().to_path_buf();
             let background = cx.background_executor().clone();
             async move {
@@ -1668,7 +1667,7 @@ impl LocalWorktree {
         let is_private = self.is_path_private(path.as_ref());
 
         let worktree = cx.weak_entity();
-        cx.background_executor().spawn(async move {
+        cx.background_spawn(async move {
             let abs_path = abs_path?;
             let content = fs.load_bytes(&abs_path).await?;
 
@@ -1774,7 +1773,7 @@ impl LocalWorktree {
         let path_excluded = self.settings.is_path_excluded(&abs_path);
         let fs = self.fs.clone();
         let task_abs_path = abs_path.clone();
-        let write = cx.background_executor().spawn(async move {
+        let write = cx.background_spawn(async move {
             if is_dir {
                 fs.create_dir(&task_abs_path)
                     .await
@@ -1838,7 +1837,7 @@ impl LocalWorktree {
             return Task::ready(Err(anyhow!("invalid path {path:?}")));
         };
 
-        let write = cx.background_executor().spawn({
+        let write = cx.background_spawn({
             let fs = fs.clone();
             let abs_path = abs_path.clone();
             async move { fs.save(&abs_path, &text, line_ending).await }
@@ -1890,7 +1889,7 @@ impl LocalWorktree {
         let abs_path = self.absolutize(&entry.path);
         let fs = self.fs.clone();
 
-        let delete = cx.background_executor().spawn(async move {
+        let delete = cx.background_spawn(async move {
             if entry.is_file() {
                 if trash {
                     fs.trash_file(&abs_path?, Default::default()).await?;
@@ -1964,7 +1963,7 @@ impl LocalWorktree {
         let abs_path = abs_new_path.clone();
         let fs = self.fs.clone();
         let case_sensitive = self.fs_case_sensitive;
-        let rename = cx.background_executor().spawn(async move {
+        let rename = cx.background_spawn(async move {
             let abs_old_path = abs_old_path?;
             let abs_new_path = abs_new_path;
 
@@ -2033,7 +2032,7 @@ impl LocalWorktree {
             };
         let abs_new_path = self.absolutize(&new_path);
         let fs = self.fs.clone();
-        let copy = cx.background_executor().spawn(async move {
+        let copy = cx.background_spawn(async move {
             copy_recursive(
                 fs.as_ref(),
                 &abs_old_path?,
@@ -2085,27 +2084,26 @@ impl LocalWorktree {
             .collect::<Vec<_>>();
 
         cx.spawn(|this, cx| async move {
-            cx.background_executor()
-                .spawn(async move {
-                    for (source, target) in paths {
-                        copy_recursive(
-                            fs.as_ref(),
-                            &source,
-                            &target,
-                            fs::CopyOptions {
-                                overwrite: overwrite_existing_files,
-                                ..Default::default()
-                            },
-                        )
-                        .await
-                        .with_context(|| {
-                            anyhow!("Failed to copy file from {source:?} to {target:?}")
-                        })?;
-                    }
-                    Ok::<(), anyhow::Error>(())
-                })
-                .await
-                .log_err();
+            cx.background_spawn(async move {
+                for (source, target) in paths {
+                    copy_recursive(
+                        fs.as_ref(),
+                        &source,
+                        &target,
+                        fs::CopyOptions {
+                            overwrite: overwrite_existing_files,
+                            ..Default::default()
+                        },
+                    )
+                    .await
+                    .with_context(|| {
+                        anyhow!("Failed to copy file from {source:?} to {target:?}")
+                    })?;
+                }
+                Ok::<(), anyhow::Error>(())
+            })
+            .await
+            .log_err();
             let mut refresh = cx.read_entity(
                 &this.upgrade().with_context(|| "Dropped worktree")?,
                 |this, _| {
@@ -2117,13 +2115,12 @@ impl LocalWorktree {
                 },
             )??;
 
-            cx.background_executor()
-                .spawn(async move {
-                    refresh.next().await;
-                    Ok::<(), anyhow::Error>(())
-                })
-                .await
-                .log_err();
+            cx.background_spawn(async move {
+                refresh.next().await;
+                Ok::<(), anyhow::Error>(())
+            })
+            .await
+            .log_err();
 
             let this = this.upgrade().with_context(|| "Dropped worktree")?;
             cx.read_entity(&this, |this, _| {
@@ -2142,7 +2139,7 @@ impl LocalWorktree {
     ) -> Option<Task<Result<()>>> {
         let path = self.entry_for_id(entry_id)?.path.clone();
         let mut refresh = self.refresh_entries_for_paths(vec![path]);
-        Some(cx.background_executor().spawn(async move {
+        Some(cx.background_spawn(async move {
             refresh.next().await;
             Ok(())
         }))
@@ -2155,7 +2152,7 @@ impl LocalWorktree {
     ) -> Option<Task<Result<()>>> {
         let path = self.entry_for_id(entry_id).unwrap().path.clone();
         let mut rx = self.add_path_prefix_to_scan(path.clone());
-        Some(cx.background_executor().spawn(async move {
+        Some(cx.background_spawn(async move {
             rx.next().await;
             Ok(())
         }))
@@ -2229,7 +2226,7 @@ impl LocalWorktree {
             .ok();
 
         let worktree_id = cx.entity_id().as_u64();
-        let _maintain_remote_snapshot = cx.background_executor().spawn(async move {
+        let _maintain_remote_snapshot = cx.background_spawn(async move {
             let mut is_first = true;
             while let Some((snapshot, entry_changes, repo_changes)) = snapshots_rx.next().await {
                 let update = if is_first {
@@ -3719,16 +3716,14 @@ impl language::LocalFile for File {
         let worktree = self.worktree.read(cx).as_local().unwrap();
         let abs_path = worktree.absolutize(&self.path);
         let fs = worktree.fs.clone();
-        cx.background_executor()
-            .spawn(async move { fs.load(&abs_path?).await })
+        cx.background_spawn(async move { fs.load(&abs_path?).await })
     }
 
     fn load_bytes(&self, cx: &App) -> Task<Result<Vec<u8>>> {
         let worktree = self.worktree.read(cx).as_local().unwrap();
         let abs_path = worktree.absolutize(&self.path);
         let fs = worktree.fs.clone();
-        cx.background_executor()
-            .spawn(async move { fs.load_bytes(&abs_path?).await })
+        cx.background_spawn(async move { fs.load_bytes(&abs_path?).await })
     }
 }
 

crates/worktree/src/worktree_tests.rs 🔗

@@ -11,7 +11,7 @@ use git::{
     },
     GITIGNORE,
 };
-use gpui::{BorrowAppContext, Context, Task, TestAppContext};
+use gpui::{AppContext as _, BorrowAppContext, Context, Task, TestAppContext};
 use parking_lot::Mutex;
 use postage::stream::Stream;
 use pretty_assertions::assert_eq;
@@ -1954,7 +1954,7 @@ fn randomly_mutate_worktree(
                 new_path
             );
             let task = worktree.rename_entry(entry.id, new_path, cx);
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 task.await?.to_included().unwrap();
                 Ok(())
             })
@@ -1969,7 +1969,7 @@ fn randomly_mutate_worktree(
                     child_path,
                 );
                 let task = worktree.create_entry(child_path, is_dir, cx);
-                cx.background_executor().spawn(async move {
+                cx.background_spawn(async move {
                     task.await?;
                     Ok(())
                 })
@@ -1977,7 +1977,7 @@ fn randomly_mutate_worktree(
                 log::info!("overwriting file {:?} ({})", entry.path, entry.id.0);
                 let task =
                     worktree.write_file(entry.path.clone(), "".into(), Default::default(), cx);
-                cx.background_executor().spawn(async move {
+                cx.background_spawn(async move {
                     task.await?;
                     Ok(())
                 })

crates/zed/src/reliability.rs 🔗

@@ -4,7 +4,7 @@ use backtrace::{self, Backtrace};
 use chrono::Utc;
 use client::{telemetry, TelemetrySettings};
 use db::kvp::KEY_VALUE_STORE;
-use gpui::{App, SemanticVersion};
+use gpui::{App, AppContext as _, SemanticVersion};
 use http_client::{self, HttpClient, HttpClientWithUrl, HttpRequestExt, Method};
 use paths::{crashes_dir, crashes_retired_dir};
 use project::Project;
@@ -205,35 +205,34 @@ pub fn init(
             ssh_client.update(cx, |client, cx| {
                 if TelemetrySettings::get_global(cx).diagnostics {
                     let request = client.proto_client().request(proto::GetPanicFiles {});
-                    cx.background_executor()
-                        .spawn(async move {
-                            let panic_files = request.await?;
-                            for file in panic_files.file_contents {
-                                let panic: Option<Panic> = serde_json::from_str(&file)
-                                    .log_err()
-                                    .or_else(|| {
-                                        file.lines()
-                                            .next()
-                                            .and_then(|line| serde_json::from_str(line).ok())
-                                    })
-                                    .unwrap_or_else(|| {
-                                        log::error!("failed to deserialize panic file {:?}", file);
-                                        None
-                                    });
-
-                                if let Some(mut panic) = panic {
-                                    panic.session_id = session_id.clone();
-                                    panic.system_id = system_id.clone();
-                                    panic.installation_id = installation_id.clone();
-
-                                    upload_panic(&http_client, &panic_report_url, panic, &mut None)
-                                        .await?;
-                                }
+                    cx.background_spawn(async move {
+                        let panic_files = request.await?;
+                        for file in panic_files.file_contents {
+                            let panic: Option<Panic> = serde_json::from_str(&file)
+                                .log_err()
+                                .or_else(|| {
+                                    file.lines()
+                                        .next()
+                                        .and_then(|line| serde_json::from_str(line).ok())
+                                })
+                                .unwrap_or_else(|| {
+                                    log::error!("failed to deserialize panic file {:?}", file);
+                                    None
+                                });
+
+                            if let Some(mut panic) = panic {
+                                panic.session_id = session_id.clone();
+                                panic.system_id = system_id.clone();
+                                panic.installation_id = installation_id.clone();
+
+                                upload_panic(&http_client, &panic_report_url, panic, &mut None)
+                                    .await?;
                             }
+                        }
 
-                            anyhow::Ok(())
-                        })
-                        .detach_and_log_err(cx);
+                        anyhow::Ok(())
+                    })
+                    .detach_and_log_err(cx);
                 }
             })
         }
@@ -450,18 +449,17 @@ fn upload_panics_and_crashes(
     cx: &App,
 ) {
     let telemetry_settings = *client::TelemetrySettings::get_global(cx);
-    cx.background_executor()
-        .spawn(async move {
-            let most_recent_panic =
-                upload_previous_panics(http.clone(), &panic_report_url, telemetry_settings)
-                    .await
-                    .log_err()
-                    .flatten();
-            upload_previous_crashes(http, most_recent_panic, installation_id, telemetry_settings)
+    cx.background_spawn(async move {
+        let most_recent_panic =
+            upload_previous_panics(http.clone(), &panic_report_url, telemetry_settings)
                 .await
                 .log_err()
-        })
-        .detach()
+                .flatten();
+        upload_previous_crashes(http, most_recent_panic, installation_id, telemetry_settings)
+            .await
+            .log_err()
+    })
+    .detach()
 }
 
 /// Uploads panics via `zed.dev`.

crates/zed/src/zed.rs 🔗

@@ -956,7 +956,7 @@ fn install_cli(
                 Some(LINUX_PROMPT_DETAIL),
                 &["Ok"],
             );
-            cx.background_executor().spawn(prompt).detach();
+            cx.background_spawn(prompt).detach();
             return Ok(());
         }
         let path = install_cli::install_cli(cx.deref())
@@ -1335,7 +1335,7 @@ fn show_markdown_app_notification<F>(
 ) where
     F: 'static + Send + Sync + Fn(&mut Window, &mut Context<MessageNotification>),
 {
-    let parsed_markdown = cx.background_executor().spawn(async move {
+    let parsed_markdown = cx.background_spawn(async move {
         let file_location_directory = None;
         let language_registry = None;
         markdown_preview::markdown_parser::parse_markdown(

crates/zed/src/zed/inline_completion_registry.rs 🔗

@@ -3,7 +3,7 @@ use collections::HashMap;
 use copilot::{Copilot, CopilotCompletionProvider};
 use editor::{Editor, EditorMode};
 use feature_flags::{FeatureFlagAppExt, PredictEditsFeatureFlag};
-use gpui::{AnyWindowHandle, App, AppContext, Context, Entity, WeakEntity};
+use gpui::{AnyWindowHandle, App, AppContext as _, Context, Entity, WeakEntity};
 use language::language_settings::{all_language_settings, EditPredictionProvider};
 use settings::SettingsStore;
 use std::{cell::RefCell, rc::Rc, sync::Arc};

crates/zeta/src/zeta.rs 🔗

@@ -419,8 +419,7 @@ impl Zeta {
             }
 
             let values = cx
-                .background_executor()
-                .spawn({
+                .background_spawn({
                     let snapshot = snapshot.clone();
                     let path = path.clone();
                     async move {
@@ -813,8 +812,7 @@ and then another
             let output_excerpt: Arc<str> = output_excerpt.into();
 
             let edits: Arc<[(Range<Anchor>, String)]> = cx
-                .background_executor()
-                .spawn({
+                .background_spawn({
                     let output_excerpt = output_excerpt.clone();
                     let editable_range = editable_range.clone();
                     let snapshot = snapshot.clone();
@@ -1127,7 +1125,7 @@ impl LicenseDetectionWatcher {
                 .map(|file| worktree.load_file(file, cx))
                 .collect::<ArrayVec<_, { LICENSE_FILES_TO_CHECK.len() }>>();
 
-            cx.background_executor().spawn(async move {
+            cx.background_spawn(async move {
                 for loaded_file in loaded_files.into_iter() {
                     let Ok(loaded_file) = loaded_file.await else {
                         continue;